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

     - ネットワーク  


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

CoreOSの起動

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

GCPでの起動

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

#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

 

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

 $ 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ファイル>
 

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

 $ gcloud compute images list

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

gcloud compute ssh <ホスト名> --zone asia-east1-c

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

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

etcdクラスタ

etcd の状態

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

$ 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

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

$ 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

bootstrap処理

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

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

これは、


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

のようにアクセスすると


https://discovery.etcd.io/729fd97bfee6537de4f26174d06c6582

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

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

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

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

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

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://<masterのip>:2380
     proxy: on

メンバーの追加

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

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

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

 $ cat /etc/machine-id

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

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

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

 $ 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"

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

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

 [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"

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

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

 $ sudo systemctl start etcd2

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

 $ 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

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

メンバーの削除

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

まず、IDを確認します。

 $ 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

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

 $ etcdctl member remove

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

 $ etcdctl member remove 1aea5ee2f7aaddac
 Removed member 1aea5ee2f7aaddac from cluster

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

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

 $ 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

 

コンテナ起動

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

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

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

 $ 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      -

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

 $ fleetctl list-unit-files
 UNIT    HASH    DSTATE  STATE   TARGET
 $ fleetctl list-units
 UNIT    MACHINE ACTIVE  SUB

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

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

 [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 &quot;/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=<code>/usr/bin/etcdctl get /mackerel/apikey</code> mackerel/mackerel-agent&quot;
 ExecStop=/usr/bin/docker stop mackerel-agent
[X-Fleet]
 Global=true

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

 [X-Fleet]
 Global=true

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

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

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

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

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

 $ 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

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

 $ 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

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

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

参考

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


DACエンジニア採用情報

  関連記事

aws
AWSのcredentialsを注意して取り扱う話

はじめに 最近ではオンプレミスでサーバを自前で用意する他に、クラウドサーバを使う機会が増えているかと思います。 弊社では、Amazon Web Services (AWS)を利用しており、多くの処理をAWS上で行っています。 AWSを利用していくにあたっては、アクセス情報(credentials)を …

no image
AnsibleでJunosのバージョン情報を取得

インフラ開発部 松田です。 今回は弊社で検証中のAnsibleについて書きます。 Ansibleを使ったサーバ構築の記事は最近よく見かけますが、私が触る機会の多いネットワーク機器も操作できる(Ansibleはエージェントレス)ということで、Ansible+NW機器について色々書いていきます。 初回は …