話題の記事

CoreOS on EC2でDockerコンテナをクラスタリングする

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

はじめに

ここ最近の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を使いました。

Amazon_EC2

 

すると通常の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

EC2_Management_Console

 

セキュリティグループはこのような感じで、同一グループ内での4001/tcpと7001/tcpの通信を許可しておきます。

VPC_Management_Console

今回は全く同じ設定で、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台でサービスが起動していることが分かります。

doc1

$ 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にサービスが移っています!

doc2

$ 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はなかなか奥が深そうなのでもっと調べたいです。