CoreOS on EC2でDockerコンテナをクラスタリングする
はじめに
ここ最近のDockerムーブメントの中で、キーワードとして良く取り上げられるようになったものの一つにCoreOSがあります。つい先日もGoogle Compute EngineがCoreOSを正式にサポートしたことが大きな話題となっていました。
CoreOSはLinuxディストリビューションの一つです。細かい説明については、外部サイトになりますがCoreOS 入門 - Qiitaという記事が非常に参考になりますのでご一読下さい。
ざっくり書くと、仮想化コンテナを大規模に運用することに特化したLinuxOSです。etcdという分散KVSとfleetという分散システムによるクラスタリング機能を標準的に持っています。
そこで今回は、Amazon EC2上でCoreOSを導入し、更にfleetを使ってDockerコンテナをクラスタリングして起動させる、ということをやってみました。
やったこと
CoreOSでEC2をLaunchする
まず最初に、etcdを分散KVSとして使用するためには、クラスタノードを管理するリーダーノードを構築する必要があります。しかし、CoreOSでその機能を代行しててくれるサービスがありますので、今回はそちらを使います。https://discovery.etcd.io/newにアクセスすると、一意のトークン番号を出力してくれるので、そのトークン番号をメモしておきます。
それではEC2のLaunchを行います。CoreOSのWebサイトにあるRunning CoreOS on EC2というページから、LaunchしたいAMIをクリックします。今回は東京リージョンのAMIを使いました。
すると通常のEC2のLaunch画面になります。各設定は通常通りで構いませんが、一点だけ、UserDataを以下のように設定します。これで今回の環境に必要なetcd、fleet、dockerが起動します。
#cloud-config coreos: etcd: discovery: https://discovery.etcd.io/<払い出しされたトークン番号> addr: $private_ipv4:4001 peer-addr: $private_ipv4:7001 units: - name: etcd.service command: start - name: fleet.service command: start - name: docker.service command: start
セキュリティグループはこのような感じで、同一グループ内での4001/tcpと7001/tcpの通信を許可しておきます。
今回は全く同じ設定で、t1.microのEC2インスタンスを3台起動しました。起動したらSSHで接続します。このときに指定するユーザ名はcoreです。
$ ssh -i ./.ssh/key.pem -l core 54.178.212.XXX CoreOS (beta) $
さて、ではサービス状態を確認します。UserDataに記述した通り、etcd、fleet、dockerがサービス起動しています。
$ systemctl status etcd ● etcd.service - etcd Loaded: loaded (/usr/lib64/systemd/system/etcd.service; disabled) Drop-In: /run/systemd/system/etcd.service.d └─10-oem.conf, 20-cloudinit.conf Active: active (running) since Tue 2014-05-27 02:26:47 UTC; 4min 10s ago Main PID: 3819 (etcd) CGroup: /system.slice/etcd.service └─3819 /usr/bin/etcd $ systemctl status fleet ● fleet.service - fleet Loaded: loaded (/usr/lib64/systemd/system/fleet.service; disabled) Active: active (running) since Tue 2014-05-27 02:26:47 UTC; 4min 23s ago Main PID: 3884 (fleet) CGroup: /system.slice/fleet.service └─3884 /usr/bin/fleet $ systemctl status docker -l ● docker.service - Docker Application Container Engine Loaded: loaded (/usr/lib64/systemd/system/docker.service; disabled) Active: active (running) since Tue 2014-05-27 02:26:47 UTC; 4min 30s ago Docs: http://docs.docker.io Main PID: 3892 (docker) CGroup: /system.slice/docker.service └─3892 /usr/bin/docker -d -s=btrfs -r=false -H fd://
なお、etcdの起動オプションは以下のファイルに記述されていますので、上手く動作しない場合は確認してみると良いでしょう。
$ cat /run/systemd/system/etcd.service.d/20-cloudinit.conf [Service] Environment="ETCD_DISCOVERY=https://discovery.etcd.io/<トークン番号>" Environment="ETCD_ADDR=172.31.14.203:4001" Environment="ETCD_PEER_ADDR=172.31.14.203:7001" Environment="ETCD_NAME=2a8f721c072b4bc4a95b5a8e7afc59e7"
etcdの動作確認
ではまず、etcdがちゃんと分散KVSとして動作しているか確認してみましょう。
1台目のEC2で、以下コマンドを実行してメッセージをセットしてみます。
$ etcdctl set /message HelloWorld HelloWorld
次に2台目のEC2で、以下コマンドを実行してメッセージをゲットしてみます。
$ etcdctl get /message HelloWorld
ちゃんとゲット出来ましたね!
fleetでDockerコンテナをクラスタリングする
では本題です。今回登録するサービスはLaunching Containers with fleet - CoreOSを参考にしています。
まず、Apacheが起動するサービス定義ファイルを2つ作成します。
### 1つ目のサービス $ sudo vi /etc/systemd/system/apache.1.service [Unit] Description=My Apache Frontend After=docker.service Requires=docker.service [Service] ExecStart=/usr/bin/docker run --name apache -p 80:80 coreos/apache /usr/sbin/apache2ctl -D FOREGROUND ExecStop=/usr/bin/docker stop apache [X-Fleet] X-Conflicts=apache.*.service ### 2つ目のサービス $ sudo vi /etc/systemd/system/apache.2.service [Unit] Description=My Apache Frontend After=docker.service Requires=docker.service [Service] ExecStart=/usr/bin/docker run --name apache -p 80:80 coreos/apache /usr/sbin/apache2ctl -D FOREGROUND ExecStop=/usr/bin/docker stop apache [X-Fleet] X-Conflicts=apache.*.service
この2つのサービスをfleetに登録して起動します。
$ fleetctl start apache.1.service Job apache.1.service scheduled to 98930432.../172.31.14.202 $ fleetctl start apache.2.service Job apache.2.service scheduled to 61be18b7.../172.31.14.203
以下のコマンドでサービス状態を確認出来ます。3台のEC2のうち2台でサービスが起動していることが分かります。
$ fleetctl list-units UNIT LOAD ACTIVE SUB DESC MACHINE apache.1.service loaded active running My Apache Frontend 98930432.../172.31.14.202 apache.2.service loaded active running My Apache Frontend 61be18b7.../172.31.14.203
このとき、別のEC2でも、同じようにサービス状態が確認出来ます。
$ fleetctl list-units UNIT LOAD ACTIVE SUB DESC MACHINE apache.1.service loaded active running My Apache Frontend 98930432.../172.31.14.202 apache.2.service loaded active running My Apache Frontend 61be18b7.../172.31.14.203
実際にサービス起動対象となったEC2(上記例だと172.31.14.202と172.31.14.203)では、80/tcpがLISTENとなり、Webサーバが起動しています。
$ netstat -an | grep 80 | grep LISTEN tcp6 0 0 :::80 :::* LISTEN
それではここで、サービス起動しているEC2を停止してみます。そうすると、サービスが起動していなかったEC2にサービスが移っています!
$ fleetctl list-units UNIT LOAD ACTIVE SUB DESC MACHINE apache.1.service loaded active running My Apache Frontend 98930432.../172.31.14.202 apache.2.service loaded active running My Apache Frontend 3595aa64.../172.31.14.201
ちゃんとクラスタリング動作になっています!
なお、fleetに登録されたサービスを停止する場合はstopを使います。
$ fleetctl stop apache.1.service Requested Job apache.1.service stop
またfleetからサービスを削除する場合はdestroyを使います。
$ fleetctl destroy apache.1.service Destroyed Job apache.1.service $ fleetctl list-units UNIT LOAD ACTIVE SUB DESC MACHINE apache.2.service loaded active running My Apache Frontend 3595aa64.../172.31.14.201
まとめ
コンテナをデプロイしてサービスリリース、かつクラスタリングというのがこんなに簡易に出来るというのはとても便利ですね。etcdとfleetはなかなか奥が深そうなのでもっと調べたいです。