HEARTBEATS

nginxをdockerで動かす時のTips 3選

   

こんにちは。CTOの馬場です。

最近利用する機会が増えてきたdockerネタです。 nginxを動かすときのTipsを3つ紹介します。

foregroudで起動する

dockerではコマンドをforegroundで動かさないとコンテナが停止してしまいます。 nginxはデフォルトはデーモンとして動くので、foregroundで動くように設定しましょう。

nginx.confで設定するならこうです。

daemon off;

Dockerfileの起動コマンドで指定するならこうです。

CMD ["/usr/sbin/nginx", "-g", "daemon off;"]

動的な設定を外部化する

イメージの中に設定値を入れちゃうのはダサいですよね。 コンテナ起動時に動的に設定したいものです。

dockerの場合は docker run 時に -e で環境変数を指定できるので使いましょう。

docker run -d -e MYENV1="hoge" myimage

nginx.confで環境変数を利用するにはperlモジュール( ngx_http_perl_module )かluaモジュール( ngx_lua )を使います。 どちらのモジュールもUbuntu14.04のnginx-extraパッケージに入ってます。

まずはenvディレクティブで読み込みたい環境変数を指定します。

env APP_HOST;

perlモジュールであれば perl_set を使います。 perl_set は httpコンテキストで利用できます。

perl_set $app_host 'sub { return $ENV{"APP_HOST"}; }';

perlモジュールのかわりにluaモジュールを使う場合は set_by_lua を使います。 set_by_lua はserver, server if, location, location ifコンテキストで利用できます。

set_by_lua $app_host 'return os.getenv("APP_HOST")';

設定をもっと動的にしたい場合は設定値をRedisなどに持たせる形がよいでしょう。 これはバックエンドサーバを動的に切り替える例です。 luaであればこのように書きます。 社内ではdockerのホストにこのnginxを起動した上で定期的にdockerのコンテナ状況を監視して、自動的に http://<コンテナ名>.<ローカルのFQDN>/ で各コンテナのwebアプリケーションにアクセスできるようにしています。

location / {
  set $upstream "";
  rewrite_by_lua '
    local res = ngx.location.capture("/redis")
    if res.status == ngx.HTTP_OK then
      ngx.var.upstream  = res.body
    else
      ngx.exit(ngx.HTTP_FORBIDDEN)
    end
  ';
  proxy_pass http://$upstream;
}
location /redis {
  internal;
  set         $redis_key $host;
  redis_pass  127.0.0.1:6379;
  default_type  text/html;
}

このアイデアの元ネタは lua-nginx-module の紹介 ならびに Nginx+Lua+Redisによる動的なリバースプロキシの実装案 - hibomaのはてなダイアリー です

ログを外部に保存する

dockerコンテナ上に永続ファイルを保存するのはナンセンスです。 でもログは保存したい。 けど1コンテナ1プロセスでやるならfluentd同梱は厳しい...

docker run 時に -v でホストのディレクトリをマウントできるのでこれを利用しましょう。 ホストの /tmp/container1_nginx_log/var/log/nginx にマウントする場合は以下のようにします。

docker run -d -v /tmp/container1_nginx_log:/var/log/nginx myimage

nginx1.7.1からはログがsyslogに出力できます。 元ネタは nginx-1.7.1でsyslogにログを飛ばせるようになったので試してみた - Dマイナー志向 です。 nginx.confで設定するならこうです。

access_log syslog:server=logserver,facility=local1 main;
error_log syslog:server=logserver,facility=local2 notice; 

Dockerfileの起動コマンドで指定するならこうです。

CMD ["/usr/sbin/nginx", "-g", "access_log syslog:server=logserver,facility=local1 main; error_log syslog:server=logserver,facility=local2 notice;"]

まとめ

docker楽しい!✌('ω'✌ )三✌('ω')✌三( ✌'ω')✌

nginx+lua/perl楽しい!!!✌('ω'✌ )三✌('ω')✌三( ✌'ω')✌

でも環境構築での時間の使いすぎには注意しましょう。