SystemdによるCloud DI実装を考えてみた
はじめに
藤本です。
みなさん、CDP(Cloud Design Pattern)をご存知でしょうか。私はつい先日知りました。インフラエンジニアが一度はぶつかる問題に対して、AWSによるベストプラクティス、ノウハウ集となります。 素晴らしいです。
私は中でもCloud DIパターンに感銘を受けました。
OSに依存しない外部パラメータで環境の差分を吸収できるなんて素敵すぎる! 前職でこの考え方を知っていれば。。。ってことはさておき。
概要
Systemd
について書こうとしたら既に当ブログで紹介されていました。 systemd超入門
Systemdからサービス、プロセスの取り扱いが大きく変わりました。SysVinitやUpstartのようにスクリプトによりプロセスを操作する考えではなく、設定ファイルとcgroupでプロセスのライフサイクルを管理する考えとなりました。
そこでSysVinitやUpstartではサービス起動スクリプト内で実装していたCloud DIの実装をどうすればSystemdで実現できるのか考えてみましたのでご紹介します。 もっとシンプルに実装可能な方法があればフィードバックください。
Amazon Linux、RHEL6/CentOS6(SysVinitやUpstart)の実装方法は以下のエントリーをご覧ください。 実践Cloud DIパターン – 環境ごとにApache設定ファイルを読み分ける
環境
OS : CentOS 7 AMI : CentOS 7 x86_64 (2014_09_29) (ami-89634988) Systemd : systemd-208-20.el7_1.5.x86_64 Apache : httpd-2.4.6-31.el7.centos.x86_64
想定ケースは以前のエントリーと同じ、環境に応じてEC2インスタンスのタグを割り当て、ApacheのVirtualHostを分けることとします。
# cat /etc/httpd/conf/httpd.conf (略) Include conf.modules.d/*.conf Include conf.d/virtualhost/${HTTPD_ENVIRONMENT}.conf (略) DocumentRoot "/var/www/html" (略) # cat /etc/httpd/conf.d/virtualhost/dev.conf DocumentRoot /var/www/html/dev/ # cat /etc/httpd/conf.d/virtualhost/prod.conf DocumentRoot /var/www/html/prod/ # cat /var/www/html/index.html index page # cat /var/www/html/dev/index.html development page # cat /var/www/html/prod/index.html production page
やってみた
一言で言うと、PreScriptでEnvironmentFileの書き換えを行うことでhttpdに動的な環境変数を渡すことでき、実現できました。 EnvironmentFileの評価がExecStartPreよりも後だということがポイントとなりました。 (サービス起動のシーケンスはまだ追えていませんが、、)
それではやってみましょう。
- EnvironmentFile書き換えスクリプト作成 httpdサービスはデフォルトでEnvironmentFileに/etc/sysconfig/httpdを指定しています。 EnvironmentFileは複数指定可能ですので、今回は新しく指定するファイルを作成します。 作成したファイルに環境変数を追記するスクリプトを作成します。
# touch /etc/sysconfig/httpd-env # vi /usr/local/sbin/httpd-env.sh 〜〜〜 #!/bin/sh ENV_FILE=/etc/sysconfig/httpd-env INSTANCE_ID=$(curl -s http://169.254.169.254/latest/meta-data/instance-id) ENV_TAG=$(aws ec2 describe-tags \ --filters "Name=resource-id,Values=$INSTANCE_ID" "Name=key,Values=Environment" \ --query "Tags[].Value" --output text) echo $ENV_TAG > $ENV_FILE 〜〜〜 # chmod 744 /usr/local/sbin/httpd-env.sh
- Unitファイルに設定追加 UnitファイルにExecStartPre、EnvironmentFileを追加します。 Unitファイルを修正する場合、/usr/lib/systemd/system/配下のファイルを/etc/systemd/system/配下にコピーした上で修正しましょう。 /etc/systemd/system/配下が優先的に読み込まれます。
# cp -a /usr/lib/systemd/system/httpd.service /etc/systemd/system/ # vi /etc/systemd/system/httpd.service 〜〜〜 [Unit] Description=The Apache HTTP Server After=network.target remote-fs.target nss-lookup.target [Service] Type=notify EnvironmentFile=/etc/sysconfig/httpd EnvironmentFile=/etc/sysconfig/httpd-env (追記) ExecStartPre=/usr/local/sbin/httpd-env.sh (追記) ExecStart=/usr/sbin/httpd $OPTIONS -DFOREGROUND ExecReload=/usr/sbin/httpd $OPTIONS -k graceful ExecStop=/bin/kill -WINCH ${MAINPID} # We want systemd to give httpd some time to finish gracefully, but still want # it to kill httpd after TimeoutStopSec if something went wrong during the # graceful stop. Normally, Systemd sends SIGTERM signal right after the # ExecStop, which would kill httpd. We are sending useless SIGCONT here to give # httpd time to finish. KillSignal=SIGCONT PrivateTmp=true [Install] WantedBy=multi-user.target 〜〜〜
- Unitファイルのリロード Unitファイルを作成、変更した際はSystemdの依存関係を再構成する必要があります。
# systemctl daemon-reload
httpdサービスを起動します。
# systemctl start httpd
HTTPアクセスします。
# curl http://localhost/ development page
/etc/httpd/conf.d/virtualhost/dev.confに記述したVirtualHostが適用されていますね。
httpdサービスを再起動します。
# systemctl stop httpd # systemctl start httpd
HTTPアクセスします。
# curl http://localhost/ production page
こちらも/etc/httpd/conf.d/virtualhost/prod.confに記述したVirtualHostが適用されていますね。
まとめ
いかがでしたでしょうか? 環境が変わっても同じAMIからデプロイしたEC2インスタンスを設定し直すことなく(OSにログインする必要なく)、システムを作ることができます。 仮想化ならではと言った感じではないでしょうか。
SysVinit、Upstart世代の私はまだまだSystemdの機能を追えておらず、今はまだ融通がきかないイメージが強いです。 ただSystemdは今年の4月にDebian、Ubuntuでも採用され、ほとんどのLinuxディストリビューションのデフォルトのシステム管理デーモンとなり、あまり悠長なことは言っていられない状況となりました。 Amazon Linuxに採用されるまでにはある程度使えるようになっておきたいところですね。
ちなみに色々なパターンを試してみたけどダメだったことも記載しておきます。
- Unitファイル内のEnvironmentにコマンドを利用できない
- ExecStartPreにexportやsourceが使えない(/から始まる必要がある)
- ExecStartPreに/bin/shでラップして、環境変数にコマンド結果をセットしてexportしても値を取り出せず
- 同じくExceStartを/bin/shでラップして、環境変数にコマンド結果をセットしてexportすると環境変数は適用され、プロセスは起動したが数分後にプロセスが落ちる