タイトルがうまく表現できないので説明すると、
+-------------------------------------+
| |
| +-------+ +-----+ |
--(req)--|--> | nginx | --(proxy)--> | app | |
| +-------+ +-----+ |
| |
+-------------------------------------+
このnginxがproxyするリクエストのヘッダーを起動時の環境変数で制御したいという話。
$ OVERRIDE_UA=iPhone docker-compose up
$ docker-compose up
appでスマホUAかどうかをチェックしてリダイレクトなどありまして、ローカル開発時はそれをバイパスしたいってのがモチベーション。
変更前のDockerファイルとdocker-compose.yml(nginx部分のみ)
FROM nginx:latest
ADD nginx.conf /etc/nginx/nginx.conf
services:
nginx:
build:
context: .
dockerfile: Dockerfiles/proxy
ports:
- "80:80"
1. perlモジュールが使えるnginx:perlイメージを利用する
perl
タグのものだとngx_http_perl_moduleが含まれている。
ただしnginxプロセス起動時にperlモジュールを有効にする必要があるみたいなので、
Perl module not enabled with alpine Dockerfile? · Issue #124 · nginxinc/docker-nginx
CMDディレクティブを上書く。
FROM nginx:perl
ADD nginx.conf /etc/nginx/nginx.conf
CMD ["nginx", "-g", "daemon off; load_module /etc/nginx/modules/ngx_http_perl_module-debug.so;"]
2. コンテナに環境変数を引き継ぐ
Environment variables in Compose | Docker Documentation
docker-compose.ymlでenvironment
を記述すれば環境変数を渡せる。また値を記述しなければdocker-composeコマンド実行時の環境変数が引き継がれる。
services:
nginx:
build:
context: .
dockerfile: Dockerfiles/proxy
ports:
- "80:80"
environment:
- OVERRIDE_UA
3. nginx.confで環境変数を読み込む
上記記事にある通り、nginx.conf上で環境変数を制御するためにngx_http_perl_moduleが必要だったのです。
--- a/nginx.conf
+++ b/nginx.conf
@@ -1,6 +1,8 @@
user nginx;
worker_processes 1;
+env OVERRIDE_UA;
+
error_log /var/log/nginx/error.log warn;
pid /var/run/nginx.pid;
@@ -11,6 +13,8 @@ events {
http {
+ perl_set $override_ua 'sub { return $ENV{"OVERRIDE_UA"}; }';
+
include /etc/nginx/mime.types;
default_type application/octet-stream;
@@ -29,6 +33,7 @@ http {
proxy_set_header Host $host;
proxy_set_header Client-Ip $remote_addr;
+ proxy_set_header User-Agent $override_ua;
server {
listen 80;
4. 「上書く」or「上書かない」の制御を行う
proxy - nginx: Why I can't put proxy_set_header inside an if clause? - Server Fault
にある通り、nginx.confのif内ではproxy_set_headerが使えない。値の有無で制御しようと思ったがダメっぽい。
dirtyな方法だと思うが、起動時にコンテナ内でnginx.confを弄る方法をとってみた。
perl -pi -e "s/# proxy_set_header User-Agent/proxy_set_header User-Agent/" /etc/nginx/nginx.conf
if [ -z "$OVERRIDE_UA" ]; then
perl -pi -e "s/proxy_set_header User-Agent/# proxy_set_header User-Agent/" /etc/nginx/nginx.conf
fi
nginx -g "daemon off; load_module /etc/nginx/modules/ngx_http_perl_module-debug.so;"
FROM nginx:perl
ADD nginx.conf /etc/nginx/nginx.conf
ADD run_nginx.sh /
CMD ["sh", "/run_nginx.sh"]
5. 実行
これで期待した制御が実現できた。
$ OVERRIDE_UA=iPhone docker-compose up
$ docker-compose up