: O. Yuanying

etcd3 on CoreOS

とりとめもなく、etcd3を CoreOS で使ってハマったことなどを。

Kubernetes 1.6 がリリース された。 早速使ってみようと思ったのだが、 どうやら 1.6 からストレージのバックエンドが etcd3 になったらしい。

それはいいのだが、CoreOS のドキュメントを見るに、 etcdcloud-config で起動する方法etcd2 のものばかりで、 etcd3 をどうやって起動すればいいのやら。 そもそも CoreOS に etcd3バイナリが含まれてなくないかい

いくらかウェブを彷徨った末に、etcd3flannel などと同じように、 コンテナとして起動するようになったということに気づく。 service の名前が etcd-member とやらになってたせいで若干わかりづらい。

なにはともあれ、CoreOS 1298.6.0 における etcd-member の Unit ファイルを確認する。

[Unit]
Description=etcd (System Application Container)
Documentation=https://github.com/coreos/etcd
Wants=network.target
Conflicts=etcd.service
Conflicts=etcd2.service

[Service]
Type=notify
Restart=on-failure
RestartSec=10s
TimeoutStartSec=0
LimitNOFILE=40000

Environment="ETCD_IMAGE_TAG=v3.0.10"
Environment="ETCD_NAME=%m"
Environment="ETCD_USER=etcd"
Environment="ETCD_DATA_DIR=/var/lib/etcd"
Environment="RKT_RUN_ARGS=--uuid-file-save=/var/lib/coreos/etcd-member-wrapper.uuid"

ExecStartPre=/usr/bin/mkdir --parents /var/lib/coreos
ExecStartPre=-/usr/bin/rkt rm --uuid-file=/var/lib/coreos/etcd-member-wrapper.uuid
ExecStart=/usr/lib/coreos/etcd-wrapper $ETCD_OPTS
ExecStop=-/usr/bin/rkt stop --uuid-file=/var/lib/coreos/etcd-member-wrapper.uuid

[Install]
WantedBy=multi-user.target

これだけ見ると etcd-wrapper に起動オプションとして $ETCD_OPTS を環境変数として渡せばいいだけに見える。

が、自分は TLS クライアント認証を有効化して利用したいので、 どうにかして etcd-wrapperから起動されるコンテナに、 証明書を保存しているディレクトリをマウントさせなければならない。 その場合、$ETCD_OPTS にオプションを渡すだけでは無理だろうと想像できる。

ちらっと、etcd-wrapper のソースをのぞいて見ると、 $ETCD_SSL_DIR という環境変数が目に見える。 そこで思考停止して drop-ins などで Environment="ETCD_SSL_DIR=/etc/kubernetes/ssl" などとしてやると (ホスト上の /etc/kubernetes/ssl に証明書を置いておいたので。) 当然動かない。

デフォルトで ETCD_SSL_DIR/etc/ssl/certs を指していて、 etcd が利用するデフォルトの CA の証明書ディレクトリとして利用されているっぽい。 これを変なところに変更してやると、 ディスカバリ URL として使ってる、 https://discovery.etcd.io/ の証明書が invalid であると怒られる羽目となる。 そりゃそうだ、CA の証明書が無いんだから。

最終的には https://discovery.etcd.io/ を使っている限り、 ETCD_SSL_DIR を変更するのはあまり良い方法では無いということがわかった。

そうすると解決する方法としては、

  1. オレオレ証明書を /etc/ssl/certs に保存する。
  2. どうにかして /etc/kubernetes/ssl をマウントする。

の二案ということになる。

案1は、元の CA の証明書は /usr/share/ca-certificates にあってシンボリックリンクになっているだけとはいえ、 システムにインストールされた証明書と同じ場所にオレオレ証明書をインストールするのはなんとなく憚られたため、 案2とすることにした。

結論を言ってしまうと、$RKT_RUN_ARGS という環境変数があるのでそれに渡してやればいい、 ということになる。

最終的には以下のような cloud-config になった。

...
  units:
    - name: etcd-member.service
      command: start
      drop-ins:
      - name: 00-override.conf
        content: |
          [Service]
          Environment="RKT_RUN_ARGS=--uuid-file-save=/var/lib/coreos/etcd-member-wrapper.uuid \
                                    --volume etc-ssl-k8s-certs,kind=host,source=/etc/kubernetes/ssl,readOnly=true \
                                    --mount volume=etc-ssl-k8s-certs,target=/etc/kubernetes/ssl"
          Environment="ETCD_IMAGE_TAG=v3.1.2"
          Environment="ETCD_NAME=master01"
          Environment="ETCD_DISCOVERY=https://discovery.etcd.io/XXXXXXXXXXXXXXXXXXXXXXXXXXXX"
          Environment="ETCD_ADVERTISE_CLIENT_URLS=https://192.168.1.111:2379"
          Environment="ETCD_INITIAL_ADVERTISE_PEER_URLS=https://192.168.1.111:2380"
          Environment="ETCD_LISTEN_CLIENT_URLS=https://192.168.1.111:2379,http://127.0.0.1:2379"
          Environment="ETCD_LISTEN_PEER_URLS=https://192.168.1.111:2380"
          Environment="ETCD_CLIENT_CERT_AUTH=true"
          Environment="ETCD_CERT_FILE=/etc/kubernetes/ssl/apiserver.pem"
          Environment="ETCD_KEY_FILE=/etc/kubernetes/ssl/apiserver-key.pem"
          Environment="ETCD_TRUSTED_CA_FILE=/etc/kubernetes/ssl/ca.pem"
          Environment="ETCD_PEER_CLIENT_CERT_AUTH=true"
          Environment="ETCD_PEER_CERT_FILE=/etc/kubernetes/ssl/apiserver.pem"
          Environment="ETCD_PEER_KEY_FILE=/etc/kubernetes/ssl/apiserver-key.pem"
          Environment="ETCD_PEER_TRUSTED_CA_FILE=/etc/kubernetes/ssl/ca.pem"
          Environment="ETCD_PEER_CA_FILE=/etc/kubernetes/ssl/ca.pem"
...

drop-insRKT_RUN_ARGS を上書きするのは良いんだけど、 デフォルトの RKT_RUN_ARGS もあるのでちょっと気持ち悪い。

Environment="RKT_RUN_ARGS=${RKT_RUN_ARGS} --volume etc-ssl-k8s-certs,kind=host,source=/etc/kubernetes/ssl,readOnly=true --mount volume=etc-ssl-k8s-certs,target=/etc/kubernetes/ssl"

みたいにできれば良いのだが…。