DockerとAlpineOSとLet'sEncryptとcronと

 WebアプリをDockerコンテナでホスティングしたい。DockerってことでOSはAlpineで。Webアプリはイマドキ全ページHTTPSも普通だが、そこに金はかけたくないのでLet's Encryptで。まあHTTPSは、NginxのリバースプロキシをWebアプリの前に用意してそいつに任せよう。そんな構成を考えていたときのプラクティス。

 Let's Encryptの使用を考える。Let's Encryptは証明書を無料で取れるものだがその有効期間は短め。cronで定期的に証明書のアップデートをかける必要がある。
 処理としては、証明書のアップデートが必要か判断され、必要な場合のみ、certbotを使ったチャレンジが実行される。チャレンジにはいくつか方法があるが、certbotにサーバを立ててもらう方法が楽である。certbotにサーバを立ててもらっている間はコンフリクトが起こらないように、Nginxにはいったん止まってもらうのがよい。チャレンジが終わって証明書がアップデートされたら、その新しい証明書とともに起動し直してもらう。
 つまり、Let's Encryptで証明書を定期アップデートしていく構成を考えるなら、Nginxには一時的に止まってもらうタイミングが必要になりえるということ。

 Nginxを使ったリバースプロキシをコンテナで用意する場合、たいていはそのDockerfileの最終行には下記のように書いてある。
CMD ["/usr/sbin/nginx", "-g", "daemon off;"]

Dockerコンテナはなにかしらがフォアグラウンドで動いていないと停止してしまう。だからNginxをフォアグラウンドで動かすことで、コンテナはダウンせずに走り続ける。
 しかし前段で、Nginxには、証明書アップデート時には止まってもらう必要が出てくるかもしれないと書いた。じゃあどうやってコンテナを走らせ続ける?

 フォアグラウンドにはcronに動いてもらうことにする。Alpineでのcronは下記の通りである。ヘルプを見たくて-hを付けたら、そんなオプションねーよと言いつつヘルプを返してくれた。
/ # crond -h

crond: unrecognized option: h
BusyBox v1.25.1 (2016-10-26 16:15:20 GMT) multi-call binary.

Usage: crond -fbS -l N -d N -L LOGFILE -c DIR

-f Foreground
-b Background (default)
-S Log to syslog (default)
-l N Set log level. Most verbose:0, default:8
-d N Set log level, log to stderr
-L FILE Log to FILE
-c DIR Cron dir. Default:/var/spool/cron/crontabs

 cronをフォアグラウンドで行うオプションがあるのでそれを実行すれば、コンテナはダウンせずに走り続ける。もちろんcronによる定期処理として、Let's Encryptの証明書アップデートチェックを行う。
certbot renew --pre-hook "nginx -s stop" --post-hook "nginx"

Nginxはデーモンで実行しておく。フォアグラウンドではcronが動いている。だから証明書アップデートのためにNginxをいったん止めることになってもなにも問題はない。

 そんなことで証明書更新を自動でやってくれるリバースプロキシコンテナとしてできたのが下記。
https://github.com/hMatoba/cdcc
comment: 0