DACエンジニアブログ:アドテクゑびす界

DACのエンジニアやマーケター、アナリストが執筆するアドテクの技術系ブログです。

GCP上でCoreOSクラスタを作ってコンテナ起動をしてみた

Google Cloud Platform(GCP)上でCoreOS + etcd +  fleet + docker でコンテナ起動まで行ったので紹介したいと思います。

CoreOSの起動

CoreOSは、コンテナの実行環境を構築することに特化したLinuxディストリビューションです。 なお、この記事ではCoreOS 815.0.0 を利用しており、GCPのCloud SDKがインストール済みであることを前提にしてます。

GCPでの起動

CoreOSでは、cloud-configというファイルで初期設定をします。 例えば以下のような内容です。

[code]

cloud-config

coreos: update: reboot-strategy: off etcd2: discovery: <https://discovery.etcd.io/new?size=3 で取得した内容> initial-advertise-peer-urls: http://$private_ipv4:2380 listen-peer-urls: http://$private_ipv4:2380 listen-client-urls: http://0.0.0.0:2379,http://0.0.0.0:4001 advertise-client-urls: http://$private_ipv4:2379,http://$private_ipv4:4001 fleet: public_ip: $private_ipv4 etcd-servers: http://0.0.0.0:2379 units: - name: etcd2.service command: start - name: fleet.service command: start - name: docker.service command: start

[/code]

 

GCPでは、以下のようにインスタンスを起動します。

[bash] $ gcloud compute instances create <ホスト名> --image-project coreos-cloud --image <最新CoreOSのイメージ名> --boot-disk-size 200GB --machine-type g1-small --zone asia-east1-c --metadata-from-file user-data=<cloud-configファイル> [/bash]

CoreOSのイメージ名は以下のコマンドで取得してください。

[bash] $ gcloud compute images list [/bash]

インスタンス起動したら以下のコマンドでログインできます。

[bash] gcloud compute ssh <ホスト名> --zone asia-east1-c [/bash]

もしかすると、初回はprojectを設定するように促されるかもしれません。

また、GCPだとprojectに属するメンバーのssh鍵が予め登録されるみたいなのですが、登録されておらずログインできない場合はGCPコンソール画面からインスタンスへssh鍵を登録してください。

etcdクラスタ

etcd の状態

etcdクラスタの状態は以下のコマンドで確認できます

[bash] $ etcdctl cluster-health member 166142cf9d722824 is healthy: got healthy result from http://10.240.0.2:2379 member c6d31dfab88110de is healthy: got healthy result from http://10.240.0.3:2379 member df537aa4f51bc509 is healthy: got healthy result from http://10.240.0.4:2379 cluster is healthy [/bash]

etcdのメンバーは以下のコマンドで確認できます。

[bash] $ etcdctl member list 166142cf9d722824: name=0961a55a5c11f91b9604ab2e9e174b90 peerURLs=http://10.240.0.2:2380 clientURLs=http://10.240.0.2:2379,http://10.240.0.2:4001 c6d31dfab88110de: name=c7eeb70a321d94c46e03e5cc798a1ec0 peerURLs=http://10.240.0.3:2380 clientURLs=http://10.240.0.3:2379,http://10.240.0.3:4001 df537aa4f51bc509: name=0ddbef29e654d7f949a90256c0f92ece peerURLs=http://10.240.0.4:2380 clientURLs=http://10.240.0.4:2379,http://10.240.0.4:4001 [/bash]






bootstrap処理

ここでは、etcdクラスタの初期設定のことです。先ほどcloud-config内に以下のような内容を記述していました。

[code] discovery: <https://discovery.etcd.io/new?size=3 で取得した内容> [/code]

これは、

[code] https://discovery.etcd.io/new?size=3 [/code]

のようにアクセスすると

[code] https://discovery.etcd.io/729fd97bfee6537de4f26174d06c6582 [/code]

のように返ってくるので、これをcloud-configに記載します。

今回discovery:で https://discovery.etcd.io/ のサービスを利用しましたが、自前で別に立てたクラスタ用のetcdとは別のetcdで同じように作成することもできます。また、etcdのクラスタサイズとして"new=3"として作成していますので、4台目以降のetcdはプロキシモードで動作します。なお、3台etcdが参加するまでetcdクラスタとしては正常に動作しませんので注意が必要です。

上記とは別に静的にetcdクラスタを構成することもできます。1台目は以下のようにcloud-configへ記載します。

[code] coreos: etcd2: name : master listen-client-urls: http://0.0.0.0:2379,http://0.0.0.0:4001 advertise-client-urls: http://$private_ipv4:2379,http://$private_ipv4:4001 initial-cluster-token: testetcd listen-peer-urls: http://$private_ipv4:2380,http://$private_ipv4:7001 initial-advertise-peer-urls: http://$private_ipv4:2380 initial-cluster: master=http://$private_ipv4:2380 initial-cluster-state: new [/code]




2台目以降は以下のように書くとetcdクラスタに参加できます。こちらもプロキシモードでの参加です。IPアドレスが事前にわかっていれば、プロキシモードで無くとも参加できます。

[code] coreos: etcd2: listen-client-urls: http://0.0.0.0:2379,http://0.0.0.0:4001 advertise-client-urls: http://0.0.0.0:2379,http://0.0.0.0:4001 initial-cluster: master=http://のip>:2380 proxy: on [/code]






メンバーの追加

etcdクラスタへメンバーを追加することが出来ます。etcdクラスタは、その利用している"Raft"というアルゴリズムがあまり大規模なクラスタには不向きであるらしく、5~9メンバーが適切なサイズと言われています。3メンバーだと1メンバーダウン時の挙動が不安定になることがあったため、5メンバーいると良いと思います。

メンバー追加は以下のように行います。

まず、追加するCoreOSで以下のコマンドを実行します

[bash] $ cat /etc/machine-id [/bash]

次に、既存のクラスタメンバーで以下のコマンドを実行します。

[bash] $ etcdctl member add http://<追加するメンバーのIPアドレス>:2380 [/bash]

すると、以下のような出力がでます

[bash] $ etcdctl member add 0b54ddfcc16f6595d15dd6fbb75da153 http://10.240.0.5:2380 Added member named 0b54ddfcc16f6595d15dd6fbb75da153 with ID 1aea5ee2f7aaddac to cluster ETCD_NAME="0b54ddfcc16f6595d15dd6fbb75da153" ETCD_INITIAL_CLUSTER="0961a55a5c11f91b9604ab2e9e174b90=http://10.240.0.2:2380,0b54ddfcc16f6595d15dd6fbb75da153=http://10.240.0.5:2380,c7eeb70a321d94c46e03e5cc798a1ec0=http://10.240.0.3:2380,0ddbef29e654d7f949a90256c0f92ece=http://10.240.0.4:2380" ETCD_INITIAL_CLUSTER_STATE="existing" [/bash]

ここでの出力結果を追加するメンバーで利用します。

追加するメンバーの/etc/systemd/system/etcd2.service.d/50-join-cluster.confに以下の内容記載します。

[code] [Service] Environment="ETCD_NAME=0b54ddfcc16f6595d15dd6fbb75da153" Environment="ETCD_INITIAL_CLUSTER=0961a55a5c11f91b9604ab2e9e174b90=http://10.240.0.2:2380,0b54ddfcc16f6595d15dd6fbb75da153=http://10.240.0.5:2380,c7eeb70a321d94c46e03e5cc798a1ec0=http://10.240.0.3:2380,0ddbef29e654d7f949a90256c0f92ece=http://10.240.0.4:2380" Environment="ETCD_INITIAL_CLUSTER_STATE=existing" Environment="ETCD_LISTEN_CLIENT_URLS=http://0.0.0.0:2379,http://0.0.0.0:4001" Environment="ETCD_LISTEN_PEER_URLS=http://10.240.0.5:2380" Environment="ETCD_ADVERTISE_CLIENT_URLS=http://10.240.0.5:2379,http://10.240.0.5:4001" [/code]

[Service]からの上3行は、先ほどのコマンドの出力結果です。下3行はetcdクラスタ通信のための設定です。IPアドレスは追加するメンバーのIPアドレスを記載してください。

ファイルを書き込んだら、systemdからetcdを起動します。

[bash] $ sudo systemctl start etcd2 [/bash]

起動したらクラスタの状態を見てみます。

[bash] $ etcdctl cluster-health member 166142cf9d722824 is healthy: got healthy result from http://10.240.0.2:2379 member 1aea5ee2f7aaddac is healthy: got healthy result from http://10.240.0.5:2379 member c6d31dfab88110de is healthy: got healthy result from http://10.240.0.3:2379 member df537aa4f51bc509 is healthy: got healthy result from http://10.240.0.4:2379 cluster is healthy [/bash]

クラスタにメンバーを追加できていることがわかります。

メンバーの削除

メンバーを削除するときは、削除するメンバーのetcd上のIDを指定して以下のコマンドを実行します。

まず、IDを確認します。

[bash] $ etcdctl member list 166142cf9d722824: name=0961a55a5c11f91b9604ab2e9e174b90 peerURLs=http://10.240.0.2:2380 clientURLs=http://10.240.0.2:2379,http://10.240.0.2:4001 1aea5ee2f7aaddac: name=0b54ddfcc16f6595d15dd6fbb75da153 peerURLs=http://10.240.0.5:2380 clientURLs=http://10.240.0.5:2379,http://10.240.0.5:4001 c6d31dfab88110de: name=c7eeb70a321d94c46e03e5cc798a1ec0 peerURLs=http://10.240.0.3:2380 clientURLs=http://10.240.0.3:2379,http://10.240.0.3:4001 df537aa4f51bc509: name=0ddbef29e654d7f949a90256c0f92ece peerURLs=http://10.240.0.4:2380 clientURLs=http://10.240.0.4:2379,http://10.240.0.4:4001 [/bash]

今回は、先ほどメンバーに追加したname=0b54ddfcc16f6595d15dd6fbb75da153をクラスタから削除しましょう。行先頭の文字列がIDです。

[bash] $ etcdctl member remove [/bash]

今回の例では以下のようになります

[bash] $ etcdctl member remove 1aea5ee2f7aaddac Removed member 1aea5ee2f7aaddac from cluster [/bash]

上記のコマンドを実行すると、削除されたメンバーのetcdがそれを検知してetcdが停止します。クラスタに復帰するときは、再度メンバー追加を行う必要があります。再度参加させるときは、/var/lib/etcd2/member/を削除しておく必要があるので注意が必要です。

最後にクラスタメンバーが削除されたことを確認してみます。

[bash] $ etcdctl member list 166142cf9d722824: name=0961a55a5c11f91b9604ab2e9e174b90 peerURLs=http://10.240.0.2:2380 clientURLs=http://10.240.0.2:2379,http://10.240.0.2:4001 c6d31dfab88110de: name=c7eeb70a321d94c46e03e5cc798a1ec0 peerURLs=http://10.240.0.3:2380 clientURLs=http://10.240.0.3:2379,http://10.240.0.3:4001 df537aa4f51bc509: name=0ddbef [/bash]

 

コンテナ起動

etcdクラスタも動いたところで、dockerコンテナを動かしてみたいと思います。今回は、コンテナとしてmackerel-agentを動かしてみたいと思います。

fleetを利用したコンテナ起動

まずは、fleetの管理下にあるマシンを見てみます

[bash] $ fleetctl list-machines MACHINE         IP              METADATA 0961a55a...     10.240.0.2      - 0b54ddfc...     10.240.0.5      - 0ddbef29...     10.240.0.4      - c7eeb70a...     10.240.0.3      - [/bash]

先ほど作成したetcdクラスタの4台がいることがわかります。

[bash] $ fleetctl list-unit-files UNIT    HASH    DSTATE  STATE   TARGET $ fleetctl list-units UNIT    MACHINE ACTIVE  SUB [/bash]

まだ、fleet上ではまだ何も動いていません。

それでは、fleetでコンテナを起動するために、unitファイルを作成します。fleet用のunitファイルは、systemd用のunitファイルに非常に似ています。以下のファイルmackerel-agent.serviceを 適当な場所に置きます。

[code] [Unit] Description=Mackerel Agent After=docker.service Requires=docker.service [Service] ExecStartPre=-/usr/bin/docker kill mackerel-agent ExecStartPre=-/usr/bin/docker rm mackerel-agent ExecStartPre=/usr/bin/docker pull mackerel/mackerel-agent ExecStart=/usr/bin/sh -c "/usr/bin/docker run --log-driver=journald --privileged --name mackerel-agent -h %H -v /var/run/docker.sock:/var/run/docker.sock -v /var/lib/mackerel-agent/:/var/lib/mackerel-agent/ -v /proc/mounts:/host/proc/mounts:ro -v /sys/fs/cgroup/:/host/sys/fs/cgroup:ro -e apikey=/usr/bin/etcdctl get /mackerel/apikey mackerel/mackerel-agent" ExecStop=/usr/bin/docker stop mackerel-agent [X-Fleet] Global=true [/code]

最後の[X-Fleet]がfleetに対してどこでコンテナを動かすかを指示する内容になります。

[code] [X-Fleet] Global=true [/code]

と書くことでetcdクラスタすべてのホストでコンテナを起動する事ができます。

今回mackerel-agent起動時にapikeyをetcd経由で取得しているので、

[code] $ etcdctl set /mackerel/apikey <your-api-key> [/code]

のようにapikeyを登録して置く必要があります。

etcdにapikeyを登録したら、以下のコマンドでfleetからコンテナを起動します

[bash] $ fleetctl submit mackerel-agent.service Unit mackerel-agent.service $ fleetctl load mackerel-agent.service Triggered global unit mackerel-agent.service load $ fleetctl start mackerel-agent.service Triggered global unit mackerel-agent.service start [/bash]

最初にsubmitでfleetにファイルの内容を登録します。その後、loadstartでfleet登録した内容を起動します。コンテナの起動を確認してみます。

[bash] $ fleetctl list-unit-files UNIT                    HASH    DSTATE          STATE   TARGET mackerel-agent.service  668bf63 launched        -       global $ fleetctl list-units UNIT                    MACHINE                 ACTIVE  SUB mackerel-agent.service  0961a55a.../10.240.0.2  active  running mackerel-agent.service  0b54ddfc.../10.240.0.5  active  running mackerel-agent.service  0ddbef29.../10.240.0.4  active  running mackerel-agent.service  c7eeb70a.../10.240.0.3  active  running $ docker ps CONTAINER ID        IMAGE                     COMMAND             CREATED             STATUS              PORTS               NAMES 4c03a9571b74        mackerel/mackerel-agent   "/startup.sh"       2 seconds ago       Up 1 seconds                            mackerel-agent [/bash]

CoreOSが動いているすべてのホストでコンテナが起動していることが確認できました。

執筆時点のmackerel-agent 0.23.0では、CoreOS上のdockerの状態を取ることは出来ません。https://github.com/mackerelio/docker-mackerel-agent を少し細工をして利用する必要があります。

参考

CoreOSを使ってDockerコンテナを動かす——15分でできるCoreOSクラスタの作り方 Monitoring Docker with Mackerel