case-kの備忘録

日々の備忘録です。データ分析とか基盤系に興味あります。

entrykitのテンプレート機能を使い、Nginxの設定を環境変数で制御する

entrykitのテンプレート機能を使ってNginxのDockerfileを作ります。

Code

github.com

entrykitとは

コンテナ起動時にテンプレートファイルを元に設定ファイルを作ることができます。コンテナは設定ファイルに直接記載するのではなく、ポータビリティを高めるために環境変数で制御することを推奨しています。例えばNginxでは設定ファイルに直接環境変数を埋め込む仕組みがないため entrykitを使い制御します。

qiita.com

Nginxのイメージを取得

まずはDocker HubにあるNginxのイメージを取得し、設定ファイルの中身を確認したいと思います。

$ docker search --limit 5 nginx
NAME                      DESCRIPTION                                     STARS               OFFICIAL            AUTOMATED
nginx                     Official build of Nginx.                        12705               [OK]
jwilder/nginx-proxy       Automated Nginx reverse proxy for docker con…   1745                                    [OK]
richarvey/nginx-php-fpm   Container running Nginx + PHP-FPM capable of…   758                                     [OK]
bitnami/nginx             Bitnami nginx Docker Image                      75                                      [OK]
nginx/nginx-ingress       NGINX Ingress Controller for Kubernetes         25
$ docker pull nginx
$ docker container run -d -p 8080:80 nginx:latest

コンテナ内の設定ファイルを確認

Docker HubからPULLしてきたコンテナの設定ファイルを確認します。

# cat /etc/nginx/nginx.conf

user  nginx;
worker_processes  1;

error_log  /var/log/nginx/error.log warn;
pid        /var/run/nginx.pid;


events {
    worker_connections  1024;
}


http {
    include       /etc/nginx/mime.types;
    default_type  application/octet-stream;

    log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                      '$status $body_bytes_sent "$http_referer" '
                      '"$http_user_agent" "$http_x_forwarded_for"';

    access_log  /var/log/nginx/access.log  main;

    sendfile        on;
    #tcp_nopush     on;

    keepalive_timeout  65;

    #gzip  on;

    include /etc/nginx/conf.d/*.conf;
}
  • worker_processes :Nginxのworkerプロセス数
  • worker_connections:workerプロセスが開ける最大コネクション数
  • keepalive_timeout:クライアントからの接続を維持する秒数
  • gzip:レスポンスのGZIPを有効にするか

include /etc/nginx/conf.d/*.confに合致するファイルをロードししています。

# cat /etc/nginx/conf.d/default.conf
server {
    listen       80;
    server_name  localhost;

    #charset koi8-r;
    #access_log  /var/log/nginx/host.access.log  main;

    location / {
        root   /usr/share/nginx/html;
        index  index.html index.htm;
    }

    #error_page  404              /404.html;

    # redirect server error pages to the static page /50x.html
    #
    error_page   500 502 503 504  /50x.html;
    location = /50x.html {
        root   /usr/share/nginx/html;
    }

    # proxy the PHP scripts to Apache listening on 127.0.0.1:80
    #
    #location ~ \.php$ {
    #    proxy_pass   http://127.0.0.1;
    #}

    # pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000
    #
    #location ~ \.php$ {
    #    root           html;
    #    fastcgi_pass   127.0.0.1:9000;
    #    fastcgi_index  index.php;
    #    fastcgi_param  SCRIPT_FILENAME  /scripts$fastcgi_script_name;
    #    include        fastcgi_params;
    #}

    # deny access to .htaccess files, if Apache's document root
    # concurs with nginx's one
    #
    #location ~ /\.ht {
    #    deny  all;
    #}
}

デフォルトのルートディレクトリは次のようになってます。

  location / {
        root   /usr/share/nginx/html;
        index  index.html index.htm;
    }

環境変数を制御

entrykitのテンプレート機能(tmplファイル)を使い環境変数の制御を行います。entrykitを使うとDocker起動時にテンプレートファイルを元に設定ファイルのレンダリングが可能になります。
Dockerfileを作る際にはテンプレートファイルを次のようにコピーします。

COPY etc/nginx/nginx.conf.tmpl /etc/nginx/
COPY etc/nginx/conf.d/ /etc/nginx/conf.d/

entrykitでテンプレートから設定ファイルを生成します。renderで指定するパスは.tmplを付けずに完成後のパスを指定します。

ENTRYPOINT [ \
  "render", \
      "/etc/nginx/nginx.conf", \
      "--", \
  "render", \
      "/etc/nginx/conf.d/upstream.conf", \
      "--", \
  "render", \
      "/etc/nginx/conf.d/public.conf", \
      "--" \
]

設定ファイルを作成

entrykitのテンプレート機能を前提に設定ファイルを作ります。プロキシサーバとして使うので次のようにします。

ログ:etc/nginx/conf.d/log.conf

JSONフォーマットでログを出力できるよう定義します。

log_format json '{'
                 '"time":"$time_iso8601",'
                 '"remote_addr":"$remote_addr",'
                 '"request":"$request",'
                 '"request_method":"$request_method",'
                 '"request_length":"$request_length",'
                 '"request_uri":"$request_uri",'
                 '"uri":"$uri",'
                 '"query_string":"$query_string",'
                 '"status":"$status",'
                 '"bytes_sent":"$bytes_sent",'
                 '"body_bytes_sent":"$body_bytes_sent",'
                 '"referer":"$http_referer",'
                 '"useragent":"$http_user_agent",'
                 '"forwardedfor":"$http_x_forwarded_for",'
                 '"request_time":"$request_time",'
                 '"upstream_response_time":"$upstream_response_time"'
                '}';
バックエンドサーバ振り分けーetc/nginx/conf.d/upstream.conf.tmpl

リクエストを振り分ける先のバックエンドサーバを定義します。

upstream backend {
    server {{ var "BACKEND_HOST" }} max_fails={{ var "BACKEND_MAX_FAILS" | default 3 }} fail_timeout={{ var "BACKEND_FAIL_TIMEOUT" | default "10s" }};
}

環境変数

  • BACKEND_HOST:バックエンドの宛先
  • BACKEND_MAX_FAILS:fail_timeoutの秒間の失敗回数上限
  • BACKEND_FAIL_TIMEOUT:失敗したと判断する秒間
  • default:デフォルト値

Module ngx_http_upstream_module

ルーティング- etc/nginx/conf.d/public.conf.tmpl

HTTPリクエストのルーティングを制御する設定ファイルを作ります。

server {
    listen {{ var "SERVER_PORT" | default "80" }} default_server;
    server_name {{ var "SERVER_NAME" | default "localhost" }};
    charset utf-8;

    location / {
        proxy_pass http://backend;
        proxy_pass_request_headers on;
        proxy_set_header host $host;
        {{ if var "LOG_STDOUT" }}
        access_log  /dev/stdout json;
        error_log   /dev/stderr;
        {{ else }}
        access_log  /var/log/nginx/backend_access.log json;
        error_log   /var/log/nginx/backend_error.log;
        {{ end }}
        {{ if var "BASIC_AUTH_FILE" }}
        auth_basic "Restricted";
        auth_basic_user_file {{ var "BASIC_AUTH_FILE" }};
        {{ end }}
    }
}

SERVER_PORT:デフォルト値80
proxy_pass :upstrem.confで定義したものを採用
LOG_STDOUT:環境変数に値が設定されていれば、アクセスログをファイルではなく標準出力にする

Dockerfileを作成する

それではDockerfileを作成します。環境変数はDockerfileではなくマニフェストファイルで与える方が好ましいですが、ここでは便器上Dockerfileに記載します。

# Dockerfile
FROM nginx:latest

RUN apt-get update
RUN apt-get install -y wget
RUN wget https://github.com/progrium/entrykit/releases/download/v0.4.0/entrykit_0.4.0_linux_x86_64.tgz
RUN tar -xvzf entrykit_0.4.0_linux_x86_64.tgz
RUN rm entrykit_0.4.0_linux_x86_64.tgz
RUN mv entrykit /usr/local/bin/
RUN entrykit --symlink

RUN rm /etc/nginx/conf.d/*
COPY etc/nginx/nginx.conf.tmpl /etc/nginx/
COPY etc/nginx/conf.d/ /etc/nginx/conf.d/


ENTRYPOINT [ \
  "render", \
      "/etc/nginx/nginx.conf", \
      "--", \
  "render", \
      "/etc/nginx/conf.d/upstream.conf", \
      "--", \
  "render", \
      "/etc/nginx/conf.d/public.conf", \
      "--" \
]

CMD ["nginx", "-g", "daemon off;"]

作成したDockerfileをビルドします。

$ docker image build -t nginx:01 .
$ docker run -d -p 8080:80 nginx:01

Docker Compose

環境変数を使いNginxをプロキシサーバとしてExpressのアプリを可視化します。

version: '3'
services:
  nginx:
    build:
      context: .
      dockerfile: Dockerfile
    image: nginx   
    container_name: nginx 
    ports:
      - 8888:80
    environment:
      WORKER_PROCESSES: 2
      WORKER_CONNECTIONS: 1024
      KEEPALIVE_TIMEOUT: "65"
      GZIP: "on"
      BACKEND_HOST: app:3000
      BACKEND_MAX_FAILS: 3
      BACKEND_FAIL_TIMEOUT: 10s
      SERVER_PORT: 80
      SERVER_NAME: todo_app_nginx
      LOG_STDOUT: "true"

  app:
    build:
      context: .
      dockerfile: Dockerfile-app
    image: app                 
    container_name: app 
    ports:         
      - 3000:3000
    volumes:
      - ./myapp:/src
    command: [sh, -c, npm install && npm start]
$ docker-compose up --build

curlコマンドでlocalhost:8888でlocalhost:3000のExpressアプリを確認します。

$ curl http://localhost:8888/
<!DOCTYPE html>
<html>
  <head>
    <title>Express</title>
    <link rel='stylesheet' href='/stylesheets/style.css' />
  </head>
  <body>
    <h1>Express</h1>
    <p>Welcome to Express</p>
  </body>
</html>


参考
docker の nginx イメージの設定ファイルを眺めながら、独自ページを表示します。 - Qiita
Docker/Kubernetes 実践コンテナ開発入門:書籍案内|技術評論社