シェルスクリプトマガジン

test

シェルスクリプトの書き方入門(Vol.65記載)

投稿日:2020.03.25 | カテゴリー: コード

筆者:大津 真

本連載ではシェルスクリプトの書き方をやさしく紹介します。対象とす
るシェルは、多くのLinuxディストリビューションが標準シェルとして
採用する「Bash」です。第1回目となる今回は、シェルスクリプトの概要
と作成、実行の方法を解説します。

シェルスクリプトマガジン Vol.65は以下のリンク先でご購入できます。

図4 ホスト名と日時を表示するシェルスクリプト「 today1.sh 」

hostname
date '+ 今日は%Y 年%m 月%d 日(%a) です'

図5 シバンを追加したシェルスクリプト「 today2.sh 」

#!/bin/bash
hostname
date '+ 今日は%Y 年%m 月%d 日(%a) です'

図6 コメントを追加したシェルスクリプト「 today3.sh 」

#!/bin/bash
# ホスト名と今日の日時を表示する
# ver.1.0 2020/2/1
hostname
date '+ 今日は%Y 年%m 月%d 日(%a) です'

図8 コマンド置換を使用したシェルスクリプト「today4.sh」

#!/bin/bash
# ホスト名と今日の日時を表示する
# ver.1.1 2020/2/1
echo " ホスト名は$(hostname) です"
date '+ 今日は%Y 年%m 月%d 日(%a) です'

香川大学SLPからお届け!(Vol.65掲載)

投稿日:2020.03.25 | カテゴリー: コード

筆者:重松 亜夢

 はじめまして!香川大学の重松亜夢です。2019年秋にSLPの所長を引き継ぎま
した。SLPの最近の主な活動はチーム開発です。2019年12月には部員が最近の活動をブログに投稿し、Advent Calendarを作成しました。また、2020年1月には餅つきで親交を深めました。
 今回は、Webアプリケーションに認証機能を実装します。具体的には、米Google社の「Google Cloud Platform」のAPIを使って「Googleでログイン」を実装します。

シェルスクリプトマガジン Vol.65は以下のリンク先でご購入できます。

図9 「.env」ファイルに記述する内容

SAMPLE_HOST="localhost:1323"
GOOGLE_CLIENT_ID="クライアントID"
GOOGLE_CLIENT_SECRET="クライアントシークレット"

図10 「main.go」ファイルに記述する内容

package main
import (
  route "example.com/user_name/sample-app/route"
)
func main() {
  route.Echo.Logger.Fatal(route.Echo.Start(":1323"))
}

図11 「router.go」ファイルに記述する内容

package route
import (
  "fmt"
  "log"
  "os"
  "example.com/user_name/sample-app/handler"
  "github.com/joho/godotenv"
  "github.com/labstack/echo/v4"
  "github.com/labstack/echo/v4/middleware"
  "github.com/stretchr/gomniauth"
  "github.com/stretchr/gomniauth/providers/google"
  "github.com/stretchr/signature"
)
var Echo *echo.Echo
func init() {
  e := echo.New()
  err := setupOAuth()
  if err != nil {
    log.Fatal("Error loading .env file")
  }
  e.Use(middleware.Logger())
  e.GET("/auth/login/:provider", handler.LoginHandler)
  e.GET("/auth/callback/:provider", handler.CallbackHandler)
  Echo = e
}

図12 「router.go」ファイルに追記する内容

func setupOAuth() error {
  err := godotenv.Load()
  if err != nil {
    return err
  }
  host := os.Getenv("SAMPLE_HOST")
  googleCallbackURL := fmt.Sprintf("http://%s/auth/callback/google", host)
  gomniauth.SetSecurityKey(signature.RandomKey(64))
  gomniauth.WithProviders(
    google.New(
      os.Getenv("GOOGLE_CLIENT_ID"),
      os.Getenv("GOOGLE_CLIENT_SECRET"),
      googleCallbackURL,
    ),
  )
  return nil
}

図13 「sesseion.go」ファイルに記述する内容

package handler
import (
  "net/http"
  "github.com/labstack/echo/v4"
  "github.com/stretchr/gomniauth"
  "github.com/stretchr/objx"
)
func LoginHandler(c echo.Context) error {
  provider, err := gomniauth.Provider(c.Param("provider"))
  if err != nil {
    return err
  }
  authURL, err := provider.GetBeginAuthURL(nil, nil)
  if err != nil {
    return err
  }
  return c.Redirect(http.StatusTemporaryRedirect, authURL)
}

図13 「sesseion.go」ファイルに記述する内容

package handler
import (
  "net/http"
  "github.com/labstack/echo/v4"
  "github.com/stretchr/gomniauth"
  "github.com/stretchr/objx"
)
func LoginHandler(c echo.Context) error {
  provider, err := gomniauth.Provider(c.Param("provider"))
  if err != nil {
    return err
  }
  authURL, err := provider.GetBeginAuthURL(nil, nil)
  if err != nil {
    return err
  }
  return c.Redirect(http.StatusTemporaryRedirect, authURL)
}

図14 「sesseion.go」ファイルに追記する内容

func CallbackHandler(c echo.Context) error {
  provider, err := gomniauth.Provider(c.Param("provider"))
  if err != nil {
    return err
  }
  omap, err := objx.FromURLQuery(c.QueryString())
  if err != nil {
    return err
  }
  _, err = provider.CompleteAuth(omap)
  if err != nil {
    return err
  }
  return c.String(http.StatusOK, "Login Success!")
}

図16 「sesseion.go」ファイルのCallbackHandler関数の変更コード

  creds, err := provider.CompleteAuth(omap)
  if err != nil {
    return err
  }
  user, err := provider.GetUser(creds)
  if err != nil {
    return err
  }
  authCookieValue := objx.New(map[string]interface{}{
    "name":      user.Name(),
    "email":     user.Email(),
    "avatarURL": user.AvatarURL(),
  }).MustBase64()
  cookie := &http.Cookie{
    Name:    "auth",
    Value:   authCookieValue,
    Path:    "/",
    Expires: time.Now().Add(24 * time.Hour),
  }
  c.SetCookie(cookie)
  return c.Redirect(http.StatusTemporaryRedirect, "/")

図17 「router.go」ファイルに追記する内容

type TemplateRenderer struct {
  templates *template.Template
}
func (t *TemplateRenderer) Render(w io.Writer, 
                                  name string, data interface{},
                                  c echo.Context) error {
  return t.templates.ExecuteTemplate(w, name, data)
}

図18 「router.go」ファイルのinit関数に挿入する内容

  renderer := &TemplateRenderer{
    templates: template.Must(template.ParseGlob("templates/*.html")),
  }
  e.Renderer = renderer
  e.GET("/", handler.MainPageHandler)

図19 「handler.go」ファイルに記述する内容

package handler
import (
  "net/http"
  "github.com/labstack/echo/v4"
  "github.com/stretchr/objx"
)
func MainPageHandler(c echo.Context) error {
  auth, err := c.Cookie("auth")
  if err != nil {
    return c.Render(http.StatusOK, 
                    "welcome", map[string]interface{}{
      "title": "Welcome",
    })
  }
  userData := objx.MustFromBase64(auth.Value)
  return c.Render(http.StatusOK, "top", map[string]interface{}{
    "name":      userData["name"],
    "email":     userData["email"],
    "avatarURL": userData["avatarURL"],
    "title":     "TopPage",
  })
}

図20 「index.html」ファイルに記述する内容

{{define "top"}}
  {{template "head" .}}
  <img src={{.avatarURL}} width="10%">
  <h2>Hello, {{.name}}</h2>
  Your Email : {{.email}}
{{end}}
{{define "welcome"}}
  {{template "head" .}}
  <h1>ようこそ</h1>
  <ul>
    <li>
      <a href="/auth/login/google">Googleでログイン</a>
    </li>
  </ul>
{{end}}

図21 「base.html」ファイルに記述する内容

{{define "head"}}
  <title>{{ .title }} / Sample-App</title>
{{end}}

図23 「router.go」ファイルのinit関数定義部分に挿入する内容

e.Pre(middleware.RemoveTrailingSlash())
e.Group("", authCheckMiddleware())

図24 「router.go」ファイルの末尾に追記する内容

func authCheckMiddleware() echo.MiddlewareFunc {
  return func(next echo.HandlerFunc) echo.HandlerFunc {
    return func(c echo.Context) error {
      _, err := c.Cookie("auth")
      if err != nil {
        return c.Redirect(http.StatusTemporaryRedirect, "/")
      }
      return next(c)
    }
  }
}

図25 認証後だけアクセスできるルートを設定する例

authCheck := e.Group("", authCheckMiddleware())
authCheck.GET("/fuga", handler.SamplePage)

バーティカルバーの極意(Vol.65掲載)

投稿日:2020.03.25 | カテゴリー: コード

筆者:飯尾 淳

 今回はデータ分析から少し離れてフラクタル図形について語りましょ
う。例として、縦棒(バーティカルバー)と横棒が縦横無尽に組み合わさっ た図形であるヒルベルト曲線を考えます。ヒルベルト曲線はフラクタル図形の一つで、自己相似性という特徴を持ちます。本記事ではこれを描画するプログラムを紹介します。シンプルなプログラムでこんなにも複雑な図形を描くことができるのかと驚くはずです。

シェルスクリプトマガジン Vol.65は以下のリンク先でご購入できます。

図4 図を出力するためのHTMLコード

<!DOCTYPE html>
<html>
  <head>
    <title>Hilbert Curve</title>
    <meta charset="utf-8">
    <meta name="description" content="Drawing Hilbert curve">
    <meta name="author" content="Jun Iio">
    <meta name="viewport" content="width=device-width,initial-scale=1">
  </head>
  <body>
    <canvas id="theCanvas" width="1000" height="1000"></canvas>
    <script src="hilbert.js"></script>
  </body>
</html>

図5 1次ヒルベルト曲線を描くJavaScriptコード

// the canvas and its graphic context
var cs  = document.getElementById('theCanvas');
var ctx = cs.getContext('2d');

ctx.lineWidth   = 5;
ctx.strokeStyle = 'black';

ctx.beginPath();
[ [0.25, 0.25], [0.25, 0.75], [0.75, 0.75], [0.75, 0.25] ]
	.map(p => [p[0]*cs.width, p[1]*cs.height])
    	.forEach(p => { ctx.lineTo(p[0],p[1]); });
ctx.stroke();

図7 n次のヒルベルト曲線を描く手続き

function hilbert(n, R) {
  if (n > 1) {
    hilbert(n-1, R’=f(R,"左上"));
    hilbert(n-1, R’=f(R,"左下"));
    hilbert(n-1, R’=f(R,"右下"));
    hilbert(n-1, R’=f(R,"右上"));
  } else {
    (Rで示される座標上で1次のヒルベルト曲線を描くコード)
  }

図10 座標変換ルールを格納した 配列を定義するコード

var tm = [
  // tm[0]
    [ [   0,  1/2,   0],
      [ 1/2,    0,   0],
      [   0,    0,   1] ],
  // tm[1]
    [ [ 1/2,    0,   0], 
      [   0,  1/2, 1/2], 
      [   0,    0,   1] ],
  // tm[2]
    [ [ 1/2,    0, 1/2],
      [   0,  1/2, 1/2], 
      [   0,    0,   1] ],
  // tm[3]
    [ [   0, -1/2,   1], 
      [-1/2,    0, 1/2], 
      [   0,    0,   1] ]
]

図11 1次から8次までのヒルベルト曲線を描くコード

// the canvas and its graphic context
var cs  = document.getElementById('theCanvas');
var ctx = cs.getContext('2d');

// line style
var colors = [ 'gray', 'navy', 'purple', 'brown',
                'red', 'orange', 'yellowgreen', 'skyblue' ];
var widths = [5, 4, 3, 2, 2, 1, 1, 0.5 ];

var tm = [
  [ [  0,  1/2,   0], [ 1/2,   0,   0], [0, 0, 1] ],
  [ [1/2,    0,   0], [   0, 1/2, 1/2], [0, 0, 1] ],
  [ [1/2,    0, 1/2], [   0, 1/2, 1/2], [0, 0, 1] ],
  [ [  0, -1/2,   1], [-1/2,   0, 1/2], [0, 0, 1] ]
];
var E = [ [ 1, 0, 0], [0, 1, 0], [0, 0, 1] ];

function affine_transform(m, p) {
  return [ m[0][0] * p[0] + m[0][1] * p[1] + m[0][2],
           m[1][0] * p[0] + m[1][1] * p[1] + m[1][2] ];
}

function mat_mul(m0, m1) {
  return [ [m0[0][0]*m1[0][0]+m0[0][1]*m1[1][0]+m0[0][2]*m1[2][0],
            m0[0][0]*m1[0][1]+m0[0][1]*m1[1][1]+m0[0][2]*m1[2][1],
            m0[0][0]*m1[0][2]+m0[0][1]*m1[1][2]+m0[0][2]*m1[2][2]],
           [m0[1][0]*m1[0][0]+m0[1][1]*m1[1][0]+m0[1][2]*m1[2][0],
            m0[1][0]*m1[0][1]+m0[1][1]*m1[1][1]+m0[1][2]*m1[2][1],
            m0[1][0]*m1[0][2]+m0[1][1]*m1[1][2]+m0[1][2]*m1[2][2]],
           [m0[2][0]*m1[0][0]+m0[2][1]*m1[1][0]+m0[2][2]*m1[2][0],
            m0[2][0]*m1[0][1]+m0[2][1]*m1[1][1]+m0[2][2]*m1[2][1],
            m0[2][0]*m1[0][2]+m0[2][1]*m1[1][2]+m0[2][2]*m1[2][2]] ];
}
function hilbert(n, m) {
  if (n > 0) {
    tm.forEach(mm => { hilbert(n-1, mat_mul(m, mm)); });
  } else {
    [ [0.25, 0.25], [0.25, 0.75], [0.75, 0.75], [0.75, 0.25] ]
        .map(p => affine_transform(m, p))
        .map(p => [p[0]*cs.width, p[1]*cs.height])
        .forEach(p => { ctx.lineTo(p[0],p[1]); });
  }
}

function drawHilbert(i) {
  ctx.beginPath();
  ctx.lineWidth   = widths[i];
  ctx.strokeStyle = colors[i];
  hilbert(i, E);
  ctx.stroke();
}

for(i=0; i<colors.length; i++) { drawHilbert(i); }

レッドハットのプロダクト(Vol.65記載)

投稿日:2020.03.25 | カテゴリー: コード

筆者:松田 絵里奈

「Red Hat Decision Manager」は、OSSの「Drools」がベースのルールエンジンです。同製品で業務ロジックを実装することで、アプリから業務ロジックを分離でき、メンテナンスが容易になります。また、複雑なロジックでも簡単で分かりやすい形式で記述できます。

シェルスクリプトマガジン Vol.65は以下のリンク先でご購入できます。

図11 pom.xml(抜粋)

(略)
    <dependencies>
        <dependency>
          <groupId>org.kie</groupId>
          <artifactId>kie-api</artifactId>
        </dependency>
        <dependency>
          <groupId>org.drools</groupId>
          <artifactId>drools-core</artifactId>
        </dependency>
        <dependency>
          <groupId>org.drools</groupId>
          <artifactId>drools-decisiontables</artifactId>
        </dependency>
    </dependencies>
(略)

図12 過去利用状況ファクト(過去利用状況.java)

package com.example.rhdm;

public class 過去利用状況 {

    private String ユーザーID;
    private int 過去利用回数;
    private int 過去利用額計;
    public String get ユーザーID() {
        return ユーザーID;
    }
    public void set ユーザーID(String ユーザーid) {
        ユーザーID = ユーザーid;
    }
    public int get 過去利用回数() {
        return 過去利用回数;
    }
    public void set 過去利用回数(int 過去利用回数) {
        this.過去利用回数 = 過去利用回数;
    }
    public int get 過去利用額計() {
        return 過去利用額計;
    }
    public void set 過去利用額計(int 過去利用額計) {
        this.過去利用額計 = 過去利用額計;
    }
}

図13 今回利用ファクト(今回利用.java)

package com.example.rhdm;

public class 今回利用 {

    private String ユーザーID;
    private int 利用額;
    private String 割引ランク;
    private int 割引率;
    
    public String get ユーザーID() {
        return ユーザーID;
    }
    public void set ユーザーID(String ユーザーid) {
        ユーザーID = ユーザーid;
    }
    public int get 利用額() {
        return 利用額;
    }
    public void set 利用額(int 利用額) {
        this.利用額 = 利用額;
    }
    public String get 割引ランク() {
        return 割引ランク;
    }
    public void set 割引ランク(String 割引ランク) {
        this.割引ランク = 割引ランク;
    }
    public int get 割引率() {
        return 割引率;
    }
    public void set 割引率(int 割引率) {
        this.割引率 = 割引率;
    }
}

図14 最初の/src/main/resources/割引決定.drlファイル

package com.example.rhdm

import com.example.rhdm.*

dialect "java"

rule "利用回数2回未満、利用額1万未満"
    when
        $過去利用:過去利用状況(過去利用回数 < 2, 過去利用額計 < 10000)
        $今回利用:今回利用(ユーザーID == $過去利用.ユーザーID)
    then        
//      modify($今回利用) {set 割引ランク("X")}
        $今回利用.set 割引ランク("X");
        System.out.println($今回利用.get ユーザーID() + "の割引ランクは" + $今回利用.get 割引ランク() + "です");
 end

図16 ルールを動かすためのJavaクラス

package com.example.rhdm;

import org.kie.api.KieServices;
import org.kie.api.runtime.KieContainer;
import org.kie.api.runtime.KieSession;

public class DrlTest {

    public static final void main(String[] args) {
        try {
        KieServices ks = KieServices.Factory.get();
            KieContainer kContainer = ks.getKieClasspathContainer();
            // 実行対象ルールを指定
KieSession kSession = kContainer.newKieSession("ksession-rules");
            // ファクトを生成
             過去利用状況 fact1 = new 過去利用状況();
            fact1.setユーザーID("A001");
            fact1.set過去利用回数(1);
            fact1.set過去利用額計(5000);
            今回利用 fact2 = new 今回利用();
            fact2.setユーザーID("A001");
            // ルールエンジンにファクトをインサート
            kSession.insert(fact1);
            kSession.insert(fact2);
            // ルール実行
kSession.fireAllRules();
        } catch (Throwable t) {
            t.printStackTrace();
        }
    }
}

図17 追加するルール

rule "利用回数2回未満、利用額1万以上"
    when
        $過去利用:過去利用状況(過去利用回数 < 2, 過去利用額計 >= 10000)
        $今回利用:今回利用(ユーザーID == $過去利用.ユーザーID)
    then
        $今回利用.set割引ランク("E");
        System.out.println($今回利用.getユーザーID() + "の割引ランクは"+ $今回利用.get割引ランク() + "です");
end

rule "利用回数2回以上5回未満、利用額1万未満"
    when
        $過去利用:過去利用状況(過去利用回数 >= 2, 過去利用回数 < 5, 過去利用額計 < 10000)
        $今回利用:今回利用(ユーザーID == $過去利用.ユーザーID)
    then
        $今回利用.set割引ランク("E");
        System.out.println($今回利用.getユーザーID() + "の割引ランクは"+ $今回利用.get割引ランク() + "です");
end

rule "利用回数2回以上5回未満、利用額1万以上"
    when
        $過去利用:過去利用状況(過去利用回数 >= 2, 過去利用回数 < 5, 過去利用額計 >= 10000)
        $今回利用:今回利用(ユーザーID == $過去利用.ユーザーID)
    then
        $今回利用.set割引ランク("D");
        System.out.println($今回利用.getユーザーID() + "の割引ランクは"+ $今回利用.get割引ランク() + "です");
end

図18 さらに追加するルール

rule "割引ランクX割引率設定"
    when
        $今回利用:今回利用(割引ランク == "X")
    then
        $今回利用.set割引率(0);
        System.out.println($今回利用.getユーザーID() + "の割引率は"+ $今回利用.get割引率() + "です");
end

rule "割引ランクE割引率設定"
    when
        $今回利用:今回利用(割引ランク == "E")
    then
        $今回利用.set割引率(3);
        System.out.println($今回利用.getユーザーID() + "の割引率は"+ $今回利用.get割引率() + "です");
end

rule "割引ランクD割引率設定"
    when
        $今回利用:今回利用(割引ランク == "D")
    then
        $今回利用.set割引率(5);
        System.out.println($今回利用.getユーザーID() + "の割引率は"+ $今回利用.get割引率() + "です");
end

ラズパイ入門ボードで学ぶ電子回路の制御(Vol.65掲載)

投稿日:2020.03.25 | カテゴリー: コード

筆者:米田 聡

シェルスクリプトマガジンでは、小型コンピュータボード「Raspberry Pi」(ラズパイ)は2種類の拡張ボードを制作しています。第12回は、最初に作成した「ラズパイ入門ボード」に「ロータリエンコーダ」を接続し、オーディオのボリュームのようなコントローラを実装します。

シェルスクリプトマガジン Vol.65は以下のリンク先でご購入できます。

図5 ロータリエンコーダ用のクラスファイル(rotary.py)

import RPi.GPIO as GPIO
import time

P_A = 21
P_B = 25

class rotaryenc():

  def __init__(self, phase_a = P_A, phase_b = P_B):
    self.phase_a = phase_a
    self.phase_b = phase_b

    GPIO.setmode(GPIO.BCM)
    GPIO.setup(phase_a, GPIO.IN)
    GPIO.setup(phase_b, GPIO.IN)

    GPIO.add_event_detect(phase_a, GPIO.RISING, callback=self.__changeStatus)

    self.__callback = None
    self.prev_forward_time = 0
    self.prev_backward_time = 0

  def __changeStatus(self, gpio):
    pa = GPIO.input(self.phase_a)
    pb = GPIO.input(self.phase_b)
    if pa == GPIO.LOW:     # チャタリング等
      return

    value = 0
    current = time.time()
    if pb == GPIO.LOW: # 時計回り
      value = 1
      if self.prev_forward_time != 0:
        if (current - self.prev_forward_time) < 0.1:    # 100ms以内
          value = 10
      self.prev_forward_time = current
      self.prev_backward_time = 0
    if pb == GPIO.HIGH:
      value = -1
      if self.prev_backward_time != 0:
        if (current - self.prev_backward_time) < 0.1:    # 100ms以内
          value = -10
      self.prev_forward_time = 0
      self.prev_backward_time = current

    if value != 0 and self.__callback is not None:
      self.__callback(value)
    
  def registerCallback(self, c):
    self.__callback = c
    return
    
  def unregisterCallback(self):
    self.__callback = None

  def __del__(self):
    GPIO.cleanup()

図6 テスト用のサンプルプログラム(test.py)

from rotary import rotaryenc
from EbOled import EbOled
import time

# OLED
oled = EbOled()
oled.begin()
oled.clear()
oled.display()

value = 0

def callback(r):
  global value
  value += r
  oled.drawString('value=' + str(value))
  oled.display()

re = rotaryenc()
re.registerCallback(callback)
try:
  time.sleep(120)
except KeyboardInterrupt:
  pass

特集2 NGINX Plus徹底解説(Vol.65記載)

投稿日:2020.03.25 | カテゴリー: コード

著者:髙田 知典

「NGINX」(エンジンエックス)は、人気の高いWebサーバーソフトウエ
アです。「NGINX Plus」は、オープンソース版のNGINXにさまざまな
機能拡張を施した商用版です。追加された拡張機能を利用すること
で、システムの可用性と堅牢性の向上や、運用の簡素化を実現できま
す。本特集では、NGINX Plusの機能や試用方法などを紹介します。

シェルスクリプトマガジン Vol.65は以下のリンク先でご購入できます。

Part2 オープンソース版NGINX とNGINX Plus の違い

図2 アクティブヘルスチェックの設定例

upstream my_upstream {
    zone my_upstream 64k;
    server server1.example.com slow_start=30s;
    server server2.example.com slow_start=30s;
}
server {
    location / {
        proxy_pass http://my_upstream;
        health_check interval=5s uri=/test.php match=statusok;
    }
}
match statusok {
    status 200;
    header Content-Type = text/html;
    body ~ "Server[0-9]+ is alive";
}

図3 Sticky cookie の設定例

upstream my_upstream {
    server server1.example.com;
    server server2.example.com;
    sticky cookie srv_id expires=1h;
}

図4 Sticky route の設定例

map $cookie_jsessionid $route_cookie {
    ~.+\.(?P<route>\w+)$ $route;
}
map $request_uri $route_uri {
    ~jsessionid=.+\.(?P<route>\w+)$ $route;
}
upstream backend {
    server backend1.example.com route=a;
    server backend2.example.com route=b;
    sticky route $route_cookie $route_uri;
}

図5 Sticky learnの設定例

upstream backend {
   server backend1.example.com;
   server backend2.example.com;
   sticky learn
       create=$upstream_cookie_examplecookie
       lookup=$cookie_examplecookie
       zone=client_sessions:1m
       timeout=1h;
}

図6 DNS名をAレコード情報を使って解決する設定例

resolver 10.0.0.2 valid=10s;
upstream backends {
    zone backends 64k;
    server backends.example.com:8080 resolve;
}
server {
    location / {
        proxy_pass http://backends;
    }
}

図7 DNS名をSRVレコード情報を使って解決する設定例

resolver 10.0.0.2 valid=10s;
upstream backends {
    zone backends 64k;
    server backends.example.com service=_http._tcp resolve;
}
server {
    location / {
        proxy_pass http://backends;
    }
}

図9 コンテンツキャッシュのパージ設定例

http {
(略)
    proxy_cache_path /data/nginx/cache levels=1:2 keys_zone=mycache:10m purger=on;
    map $request_method $purge_method {
        PURGE 1;
        default 0;
    }
    server {
        listen 80;
        server_name www.example.com;
        location / {
            proxy_pass https://localhost:8002;
            proxy_cache mycache;
            proxy_cache_purge $purge_method;
        }
    }
    geo $purge_allowed {
       default 0;
       10.0.0.1 1;
       192.168.0.0/24 1;
    }
    map $request_method $purge_method {
       PURGE $purge_allowed;
       default 0;
    }
}

図15 nginx-sync.confの設定例

NODES="node2.example.com node3.example.com node4.example.com"
CONFPATHS="/etc/nginx/nginx.conf /etc/nginx/conf.d"
EXCLUDE="default.conf"

図16 NGINX Plus APIの設定例

http {
(略)
    # Configuration of the server group
    upstream appservers {
        # 共有メモリーにサーバーグループ構成を保存するようにゾーンを設定
        zone appservers 64k;
        server appserv1.example.com      weight=5;
        server appserv2.example.com:8080 fail_timeout=5s;
        server reserve1.example.com:8080 backup;
        server reserve2.example.com:8080 backup;
    }
    server {
            location / {
            proxy_pass http://appservers;
            health_check;
        }
        location /api {
        # GET以外のメソッドをBasic認証で制限
            limit_except GET {
                auth_basic "NGINX Plus API";
                auth_basic_user_file /etc/nginx/.htpasswd;
            }
        # APIを書き込みモードで動作させる
            api write=on;
        # アクセス元をローカルホストのみに制限
            allow 127.0.0.1;
            deny  all;
        }
    }
}

図18 stateファイルの設定を追加した例

http {
(略)
    # Configuration of the server group
    upstream appservers {
        zone appservers 64k;
        state /var/lib/nginx/state/appservers.conf;
        # server appserv1.example.com      weight=5;
        # server appserv2.example.com:8080 fail_timeout=5s;
        # server reserve1.example.com:8080 backup;
        # server reserve2.example.com:8080 backup;
    }
}

図19 キーバリューストアの設定例

http {
    # キーバリューストアの定義
    keyval_zone zone=blacklist:1M state=/tmp/blacklist.json;
    keyval $remote_addr $black_list zone=blacklist;
    server {
    listen 80;
        location / {
            root /usr/share/nginx/html;
            if ($black_list = 0) {
                return 403;
            }
        }
        location /api {
            # GET以外のメソッドをベーシック認証で制限
            limit_except GET {
            auth_basic "NGINX Plus API";
            auth_basic_user_file /etc/nginx/.htpasswd;
            }
            # APIを書き込みモードで動作させる
            api write=on;
            #アクセス元をローカルホストのみに制限
            allow 127.0.0.1;
            deny  all;
        }
    }
}

シェルスクリプトマガジンvol.65 Web掲載記事まとめ

投稿日:2020.03.25 | カテゴリー: コード

004 レポート WebブラウザMicrosoft Edgeの新版
005 レポート 仮想マシン構築・運用ソフト「Multipass」
006 NEWS FLASH
008 特集1 知っておきたいDebian/やまねひでき
026 特集2 NGINX Plus徹底解説/髙田知典 コード掲載
042 特別企画 詳説 OpenPOWER/OpenCAPI/河井裕
050 ラズパイ入門ボードで学ぶ 電子回路の制御/米田聡 コード掲載
054 レッドハットのプロダクト/松田絵里奈 コード掲載
064 姐のNOGYO
066 漢のUNIX/後藤大地
072 円滑コミュニケーションが世界を救う!/濱口誠一
074 バーティカルバーの極意/飯尾淳 コード掲載
080 中小企業手作りIT化奮戦記/菅雄一
084 やっつける/桑原滝弥、イケヤシロウ
086 Webアプリの正しい作り方/しょっさん
096 法林浩之のFIGHTING TALKS/法林浩之
098 香川大学SLPからお届け!/重松亜夢 コード掲載
106 MySQL Shellを使おう/梶山隆輔
114 シェルスクリプトの書き方入門/大津真 コード掲載
120 Techパズル/gori.sh
122 コラム「社訓」/シェル魔人

Vol.65

投稿日:2020.03.25 | カテゴリー: バックナンバー

 「自由なソフトウエアによるOSを作り上げたい」という志を共にするボランティアの開発者の協力によって開発が続いているLinuxディストリビューションがあります。それが「Debian」(デビアン)です。特集1では、Debianの概要、最新の安定版であるDebian 10の特徴やインストール方法、導入時や使いこなしの注意点を解説します。Red Hat Enterprise Linux(RHEL)やUbuntuに引けを取らない、Debainに注目してみてください。
 特集2では、オープンソースのWebサーバーソフトウエアとして人気が高い「NGINX」の商用版「NGINX Plus」について解説します。オープンソース版にはない機能により、システムの可用性と堅牢性の向上や、運用の簡素化を実現できます。試用も可能なので、特集2を読んで実際に試してみてください。
 ソフトウエアだけでなく、ハードウエアのオープン(オープンソース)化も進んでいます。特集3では、米IBM社が開発した、POWERプロセッサに関連する技術をオープン化にするコミュニティ「OpenPOWER」と、プロセッサ拡張バス標準「CAPI」のオープンな仕様である「OpenCAPI」について分かりやすく紹介します。
 このほか、二つの連載を開始しました。一つは、オープンソースソフトウエアを基に開発されている米Red Hat製品を紹介する「レッドハットのプロダクト」。もう一つは、初めての人や初心者にもシェルスクリプトの書き方を紹介する「シェルスクリプトの書き方入門」です。
 今回も読み応え十分のシェルスクリプトマガジン Vol.65。お見逃しなく!

※記事掲載のコードはこちら。記事の補足情報はこちら

※読者アンケートはこちら

Vol.65 補足情報

投稿日:2020.03.25 | カテゴリー: コード

目次

p.2の「ラズパイセンサーボードで学ぶ」は「ラズパイ入門ボードで学ぶ」の誤りです。お詫びして訂正いたします。

情報は随時更新致します。

  • shell-mag ブログの 2020年3月 のアーカイブを表示しています。

  • -->