DockerとSupervisordでコンテナ内サービスを管理する方法【実践チュートリアル】
数日前、筆者はDockerに関する長編の詳細ガイドを公開しました。DockerはLXCをベースとしたOSレベルの仮想化技術であり、コンテナ化されたアプリケーションを高速・軽量かつ安全にプロビジョニングする手段を提供してくれます。まさに魅力的な技術です。
ところが、最初のサービスであるSSHやApacheをテストする際に、一つの課題に直面しました。それは、これらのサービスの「制御」です。コンテナの中にはinitスクリプトもsystemdも存在せず、正直なところ、あえてそれらを導入したくないケースもあります。とはいえ、サービスを起動・停止し、適切に管理するための仕組みはどうしても必要です。そこで登場するのがsupervisordです。本記事ではその導入方法を解説します。それでは始めましょう。
Supervisordとは
Supervisordは、プロセスを監視・制御するために設計されたプロセス制御システムです。initの置き換えを目的としたものではなく、プロセスを独自のフレームワーク内にカプセル化し、起動時に自動的にプロセスを立ち上げることができます。まさに私たちが求めている挙動です。現時点でこれ以上の深掘りは不要でしょう。
Supervisordのセットアップ
基本的にsupervisordはPythonモジュールです。setuptoolsに含まれるeasy_installコマンドでインストールでき、setuptools自体はPythonのdistutilsパッケージの拡張にあたります。はい、ここで少し話が複雑になってきますね。幸い、ほとんどのLinuxディストリビューションにはeasy_installが同梱されており、今回のテスト環境であるCentOSも例外ではありません。
作業を進めるには、まずコンテナ内にsupervisordをインストールします。続いてイメージをコミットし、それをベースラインとして、前述のSSHやApacheといったサービスを含むビルドに活用します。まずはホスト側にインストールしてみましょう。問題なく成功するはずです。
easy_install supervisor
Searching for supervisor
Reading https://pypi.python.org/simple/supervisor/
Best match: supervisor 3.1.3
Downloading https://pypi.python.org/packages/source/s/supervisor/
supervisor-3.1.3.tar.gz#md5=aad263c4fbc070de63dd354864d5e552
Processing supervisor-3.1.3.tar.gz
Writing /tmp/easy_install-vbOcMG/supervisor-3.1.3/setup.cfg
Running supervisor-3.1.3/setup.py -q bdist_egg --dist-dir
/tmp/easy_install-vbOcMG/supervisor-3.1.3/egg-dist-tmp-i96mIs
warning: no previously-included files matching '*' found under directory 'docs/.build'
Adding supervisor 3.1.3 to easy-install.pth file
Installing echo_supervisord_conf script to /usr/bin
Installing pidproxy script to /usr/bin
Installing supervisorctl script to /usr/bin
Installing supervisord script to /usr/bin
Installed
/usr/lib/python2.7/site-packages/supervisor-3.1.3-py2.7.egg
Processing dependencies for supervisor
Searching for meld3>=0.6.5
Reading https://pypi.python.org/simple/meld3/
Best match: meld3 1.0.2
Downloading https://pypi.python.org/packages/source/m/meld3/
meld3-1.0.2.tar.gz#md5=3ccc78cd79cffd63a751ad7684c02c91
Processing meld3-1.0.2.tar.gz
Writing /tmp/easy_install-wnhLVS/meld3-1.0.2/setup.cfg
Running meld3-1.0.2/setup.py -q bdist_egg --dist-dir
/tmp/easy_install-wnhLVS/meld3-1.0.2/egg-dist-tmp-Lp88cX
zip_safe flag not set; analyzing archive contents...
Adding meld3 1.0.2 to easy-install.pth file
Installed /usr/lib/python2.7/site-packages/meld3-1.0.2-py2.7.egg
Finished processing dependencies for supervisor
一方、コンテナ内で同じコマンドを実行するとエラーになります。コンテナに組み込まれたPython環境は不完全で、一部のモジュールが欠けているためです。
# easy_install supervisor
Traceback (most recent call last):
File "/usr/bin/easy_install", line 5, in <module>
from pkg_resources import load_entry_point
ImportError: No module named pkg_resources
この場合は、easy_installを手動でセットアップする必要があります。次のコマンドを実行しましょう。
wget https://bitbucket.org/pypa/setuptools/raw/ ->
-> bootstrap/ez_setup.py -O - | python
Supervisordの設定
次のステップは、コンテナ用の設定ファイルを作成することです。設定ファイルはホスト側で作成し、DockerfileのCOPY命令を使ってビルドプロセス中にイメージへコピーします。
COPY ./supervisord.conf /etc/supervisord.conf
設定内容は、たとえば以下のようになります。
[supervisord]
nodaemon=true
[program:sshd]
command=/usr/sbin/sshd -D
[program:httpd]
command=/bin/bash -c "exec /usr/sbin/httpd -DFOREGROUND"
ここには何が書かれているのでしょうか。各角括弧のペアがひとつのセクションを定義しています。[supervisord]セクションでは、バックグラウンドのデーモンとして動作するのではなく、フォアグラウンドで起動するよう指定しています。
[program:sshd]セクションでは対応するコマンドを実行し、実質的にSSHDをバックグラウンドで動かしています。[program:httpd]セクションでは、別のシェル上でWebサーバーをフォアグラウンド起動しています。利用可能なオプションは他にも多数ありますが、現時点ではsupervisordを使い始めるための最小限の構成です。
コンテナの実行とトラブルシューティング
イメージをビルドして実行すれば、supervisordが起動し、各プロセスを立ち上げてくれるはずです。しかしその前に、よくあるエラーへの対処法を確認しておきましょう。まず遭遇しがちなのが、次のエラーです。
docker run -ti -p 22 -p 80 image-3:latest
/usr/lib/python2.7/site-packages/supervisor-3.1.3-py2.7.egg/
supervisor/options.py:296: UserWarning: Supervisord is running as root and it is searching for its configuration file in default locations (including its current working directory); you probably want to specify a "-c" argument specifying an absolute path to a configuration file for improved security.
'Supervisord is running as root and it is searching '
Error: No config file found at default paths (/usr/etc/supervisord.conf, /usr/supervisord.conf, supervisord.conf, etc/supervisord.conf, /etc/supervisord.conf); use the -c option to specify a config file at a different path
For help, use /usr/bin/supervisord -h
supervisord.confファイルのパス指定やファイル名が間違っていると、サービスは起動できません。COPY命令を修正し、イメージを再ビルドしてやり直す必要があります。続いて、次のようなエラーに遭遇することもあります。
# docker run -ti -p 22 -p 80 image-3:latest
/usr/lib/python2.7/site-packages/supervisor-3.1.3-py2.7.egg/
supervisor/options.py:296: UserWarning: Supervisord is running as root and it is searching for its configuration file in default locations (including its current working directory); you probably want to specify a "-c" argument specifying an absolute path to a configuration file for improved security.
'Supervisord is running as root and it is searching '
372 CRIT Supervisor running as root (no user in config file)
375 INFO supervisord started with pid 1
378 INFO spawned: 'httpd' with pid 9
381 INFO spawned: 'sshd' with pid 10
602 INFO exited: httpd (exit status 1; not expected)
606 INFO spawned: 'httpd' with pid 11
606 INFO success: sshd entered RUNNING state, process has stayed up for > than 1 seconds (startsecs)
671 INFO exited: httpd (exit status 1; not expected)
676 INFO spawned: 'httpd' with pid 12
742 INFO exited: httpd (exit status 1; not expected)
749 INFO spawned: 'httpd' with pid 13
825 INFO exited: httpd (exit status 1; not expected)
826 INFO gave up: httpd entered FATAL state, too many start retries too quickly
gave up: httpd entered FATAL state, too many start retries too quickly
ここで起きているのは、Apacheのプロセスが終了し、supervisordが何度も再起動を試みたものの、最終的に諦めてFATAL状態に陥っている状況です。このままではコンテナはほぼ使い物になりません。
解決策は、supervisord.confファイルを編集し、[program:httpd]セクションに追加のディレクティブを加えて、プロセスの起動をより柔軟に扱えるようにすることです。
[program:httpd]
startsecs = 0
autorestart = false
command=/bin/bash -c "exec /usr/sbin/httpd -DFOREGROUND"
startsecs = 0 と autorestart = false を追加しました。最初のディレクティブの意味は公式ドキュメントによると次のとおりです。
起動後にプログラムが「正常に起動した」とみなされるまでに、稼働し続ける必要のある秒数。プログラムが起動後この秒数以上稼働しなければ、たとえ期待される終了コードで終了した場合でも(exitcodes参照)、その起動は失敗とみなされます。
2つ目のディレクティブは、supervisordがApacheプロセスの再起動を管理しないことを意味します。再起動はWebサーバー自身が、HTTPリクエストの処理の一環として行うことになります。
false、unexpected、trueのいずれかを指定できます。falseの場合、プロセスは自動再起動されません。unexpectedの場合、このプロセス設定に関連付けられた終了コード以外(exitcodes参照)で終了したときに再起動されます。trueの場合、終了コードに関係なく、終了時に無条件に再起動されます。
これで、コンテナを再度実行してみましょう。元のガイドで遭遇した/run/httpdディレクトリの問題を覚えていますか? /runディレクトリが用意されていないと、次のようなメッセージが表示されます。
docker run -ti -p 22 -p 80 image-3:latest
/usr/lib/python2.7/site-packages/supervisor-3.1.3-py2.7.egg/
supervisor/options.py:296: UserWarning: Supervisord is running as root and it is searching for its configuration file in default locations (including its current working directory); you probably want to specify a "-c" argument specifying an absolute path to a configuration file for improved security.
'Supervisord is running as root and it is searching '
913 CRIT Supervisor running as root (no user in config file)
916 INFO supervisord started with pid 1
919 INFO spawned: 'httpd' with pid 8
921 INFO spawned: 'sshd' with pid 9
079 INFO success: httpd entered RUNNING state, process has stayed up for > than 0 seconds (startsecs)
105 INFO exited: httpd (exit status 0; expected)
120 INFO reaped unknown pid 10
122 INFO success: sshd entered RUNNING state, process has stayed up for > than 1 seconds (startsecs)
この段階では、コンテナに接続(attachするかexecでBASHシェルを起動)し、ログを確認しながら、なぜサービスが期待どおりに動作しないのかを調査する必要があります。
テスト成功
そして、すべての問題を解決できたときの様子がこちらです。supervisord経由でsshdとhttpdが安定して稼働し、コンテナが意図どおりに機能するようになりました。
まとめ
かなりマニアックなチュートリアルでしたが、これでツールキットにまた一つ便利な道具が加わりました。systemdのような大掛かりで複雑なフレームワークを導入することなく、コンテナ内のサービスを堅牢かつエレガントに制御できるようになったのです。あわせて、Dockerの操作方法やトラブルシューティングの勘所についても学ぶことができました。
Supervisordは必須というわけではありません。実際、sshdとhttpdはsupervisordなしでも動作させることができました。ただし、サービスの起動・再起動を頻繁に行う必要がある方には、この手法が好まれるかもしれません。いずれにしても、このユーティリティに慣れておくことは、Dockerの仕組みへの理解と自信を深めることにつながります。本ガイドが皆さんのお役に立てば幸いです。次に取り上げてほしいテーマのリクエストもお待ちしています。
それでは、また。
-
KVMのストレージ管理を徹底解説!ストレージプールとボリュームの作成チュートリアル
さて、先日、Kernel-based Virtual Machine(KVM)という技術をご紹介しました。KVMは無料かつオープンソースの仮想化ソリューションで、VirtualBoxやVMware製品の代わりとして、あるいはそれらと併用して使うこともできます。前回は基本的な管理操作を扱いましたが、ストレージとネットワークについては別のチュートリアルに回すことにしました。 今回は、KVMにおけるストレージ管理について、より踏み込んだガイドをお届けします。内容はVirtualBoxで行ったものと似ており、仮想ディスクの追加・縮小・拡張などが含まれます。さらに、NFSストレージやNTFSフォーマット
-
VirtualBoxでディスクをクローンする方法【VBoxManage活用チュートリアル】
仮想化を業務でも趣味でも利用している方なら、VirtualBoxという強力かつ多用途な無料ソリューションを目にしたことがあるかもしれません。VirtualBoxは、デスクトップユーザーに対して、あらゆる形でOSを展開できる大きな柔軟性を提供してくれます。さらに、単なる趣味として仮想化を楽しんでいるだけでなく、仮想化を通じて新しいOSを学ぼうとする熱心なソフトウェア愛好家の方であれば、次のような場面に必ず直面することでしょう。それは「大量の仮想マシンを展開する必要がある」というシナリオです。一台ずつインストール作業を行う時間的な余裕はないはずです。実際、大規模に環境を展開する際に手動で一つずつマ