taxin's notes

読書、勉強メモ etc.

Kubernetes the hard way (GCP版) #7 (etcdクラスターのブートストラップ)

Kubernetes the hard way (GCP版)の続きです。

前回の記事はこちら

taxintt.hatenablog.com

Chap7. Bootstrapping the etcd Cluster(etcdクラスターのブートストラップ)

このチャプターでは、Control Planeを構成するコンポーネントの一つであるetcdのクラスターのブートストラップを行います。

etcdバイナリのダウンロードとインストール

このチャプターでの作業はControl Planeの各ノードにsshでログインした上で行います。
(筆者はtmuxを使わずに、各ノードごとにターミナルのウィンドウを開いて作業をしました。)

最初にetcd のバイナリをダウンロードします。
(CLIツールであるetcdctlも含まれているので、別でインストールを行う必要はありません。)

wget -q --show-progress --https-only --timestamping \
  "https://github.com/etcd-io/etcd/releases/download/v3.4.0/etcd-v3.4.0-linux-amd64.tar.gz"


バイナリを解凍して、etcdの本体とetcdctl (CLIツール)を/usr/local/binに移動することでセットアップ前の準備は完了となります。

{
  tar -xvf etcd-v3.4.0-linux-amd64.tar.gz
  sudo mv etcd-v3.4.0-linux-amd64/etcd* /usr/local/bin/
}


etcdサーバーの設定

バイナリのダウンロードが完了したら、etcdサーバーの設定を行っていきます。

最初に、ノード内で必要なディレクトリ (/etc/etcd, /var/lib/etcd) を作成して、Chap4で作成したAPI Server用の証明書ファイル類を配置します。

taxintt.hatenablog.com

...@controller-0:~$ {
>   sudo mkdir -p /etc/etcd /var/lib/etcd
>   sudo cp ca.pem kubernetes-key.pem kubernetes.pem /etc/etcd/
> }


次に、Control Plane(インスタンス)のPrivate IPとホスト名を変数として取得します。

インスタンスメタデータに関しては、メタデータサーバーから取得できるようになっています。
インスタンスからメタデータサーバへのAPIアクセスに関しては、追加で認証処理を行うことなくメタデータを取得することが可能です。

cloud.google.com

...@controller-0:~$ INTERNAL_IP=$(curl -s -H "Metadata-Flavor: Google" \
>   http://metadata.google.internal/computeMetadata/v1/instance/network-interfaces/0/ip)
...@controller-0:~$ echo $INTERNAL_IP
10.240.0.10

...@controller-0:~$ hostname -s
controller-0
...@controller-0:~$ ETCD_NAME=$(hostname -s)


最後にetcdをサービスとして登録するために、etcdのサービスファイル (etcd.service) を作成します。
先ほど取得したノードのPrivate IPとホスト名はここで利用します。

他にも下記のような項目が設定されています。

  • --client-cert-auth: etcdへの通信時TLSクライアント認証を有効化する
  • --peer-client-cert-auth: ピア同士の通信時にTLSクライアント認証を有効化する
  • --cert-file / --key-file: etcdへの通信時に利用するTLS証明書ファイル・秘密鍵ファイル
  • --peer-cert-file / --peer-key-file: ピア同士の通信に利用されるTLS証明書ファイル・秘密鍵ファイル
  • --listen-client-urls (port: 2379) : etcdへの通信時に接続を受け付けるURL
  • --listen-peer-urls (port: 2380) : ピア同士の通信時に接続を受け付けるURL
  • --advertise-client-urls (port: 2379) : etcdへの通信時に外部に広告するURL
  • --initial-advertise-peer-urls (port: 2380) : ピア同士の通信時に全てのピアに広告するURL

上記の設定項目に関する説明は下記のリンクに記載されています。

github.com

...@controller-0:~$ cat <<EOF | sudo tee /etc/systemd/system/etcd.service
> [Unit]
> Description=etcd
> Documentation=https://github.com/coreos
>
> [Service]
> Type=notify
> ExecStart=/usr/local/bin/etcd \\
>   --name ${ETCD_NAME} \\
>   --cert-file=/etc/etcd/kubernetes.pem \\
>   --key-file=/etc/etcd/kubernetes-key.pem \\
>   --peer-cert-file=/etc/etcd/kubernetes.pem \\
>   --peer-key-file=/etc/etcd/kubernetes-key.pem \\
>   --trusted-ca-file=/etc/etcd/ca.pem \\
>   --peer-trusted-ca-file=/etc/etcd/ca.pem \\
>   --peer-client-cert-auth \\
>   --client-cert-auth \\
>   --initial-advertise-peer-urls https://${INTERNAL_IP}:2380 \\
>   --listen-peer-urls https://${INTERNAL_IP}:2380 \\
>   --listen-client-urls https://${INTERNAL_IP}:2379,https://127.0.0.1:2379 \\
>   --advertise-client-urls https://${INTERNAL_IP}:2379 \\
>   --initial-cluster-token etcd-cluster-0 \\
>   --initial-cluster controller-0=https://10.240.0.10:2380,controller-1=https://10.240.0.11:2380,controller-2=https://10.240.0.12:2380 \\
>   --initial-cluster-state new \\
>   --data-dir=/var/lib/etcd
> Restart=on-failure
> RestartSec=5
>
> [Install]
> WantedBy=multi-user.target
> EOF
[Unit]
Description=etcd
Documentation=https://github.com/coreos

[Service]
Type=notify
...
RestartSec=5

[Install]
WantedBy=multi-user.target

etcdサーバーの起動

サービスファイルの作成が完了したら、systemctlコマンドでetcdのサービスを起動します。
作成したサービスファイルをsystemdに反映させるために、daemon-reloadコマンドを実行してからサービスを起動します。

enakai00.hatenablog.com

{
  sudo systemctl daemon-reload
  sudo systemctl enable etcd
  sudo systemctl start etcd
}


注意点として、etcdのメンバーを単独で起動するとサービスの起動は失敗します。
サービスのステータス確認時にfailedの状態になった場合は、systemctl reset-failedコマンドで異常状態のリセットを行います。

dev.classmethod.jp

...@controller-0:~$ {
>   sudo systemctl daemon-reload
>   sudo systemctl enable etcd
>   sudo systemctl start etcd
> }
Created symlink /etc/systemd/system/multi-user.target.wants/etcd.service → /etc/systemd/system/etcd.service.

Job for etcd.service failed because a timeout was exceeded.
See "systemctl status etcd.service" and "journalctl -xe" for details.

...@controller-0:~$ journalctl -xe
Feb 29 03:58:45 controller-0 etcd[3667]: raft2020/02/29 03:58:45 INFO: f98dc20bce6225a0 became candidate at term 85
Feb 29 03:58:45 controller-0 etcd[3667]: raft2020/02/29 03:58:45 INFO: f98dc20bce6225a0 received MsgVoteResp from f98dc20bce6225a0 at term 85
Feb 29 03:58:45 controller-0 etcd[3667]: raft2020/02/29 03:58:45 INFO: f98dc20bce6225a0 [logterm: 1, index: 3] sent MsgVote request to 3a57933972cb5131 at term 85
Feb 29 03:58:45 controller-0 etcd[3667]: raft2020/02/29 03:58:45 INFO: f98dc20bce6225a0 [logterm: 1, index: 3] sent MsgVote request to ffed16798470cab5 at term 85
Feb 29 03:58:47 controller-0 etcd[3667]: raft2020/02/29 03:58:47 INFO: f98dc20bce6225a0 is starting a new election at term 85
Feb 29 03:58:47 controller-0 etcd[3667]: raft2020/02/29 03:58:47 INFO: f98dc20bce6225a0 became candidate at term 86
Feb 29 03:58:47 controller-0 etcd[3667]: raft2020/02/29 03:58:47 INFO: f98dc20bce6225a0 received MsgVoteResp from f98dc20bce6225a0 at term 86
Feb 29 03:58:47 controller-0 etcd[3667]: raft2020/02/29 03:58:47 INFO: f98dc20bce6225a0 [logterm: 1, index: 3] sent MsgVote request to 3a57933972cb5131 at term 86
Feb 29 03:58:47 controller-0 etcd[3667]: raft2020/02/29 03:58:47 INFO: f98dc20bce6225a0 [logterm: 1, index: 3] sent MsgVote request to ffed16798470cab5 at term 86
Feb 29 03:58:48 controller-0 etcd[3667]: raft2020/02/29 03:58:48 INFO: f98dc20bce6225a0 is starting a new election at term 86
Feb 29 03:58:48 controller-0 etcd[3667]: raft2020/02/29 03:58:48 INFO: f98dc20bce6225a0 became candidate at term 87
Feb 29 03:58:48 controller-0 etcd[3667]: raft2020/02/29 03:58:48 INFO: f98dc20bce6225a0 received MsgVoteResp from f98dc20bce6225a0 at term 87
Feb 29 03:58:48 controller-0 etcd[3667]: raft2020/02/29 03:58:48 INFO: f98dc20bce6225a0 [logterm: 1, index: 3] sent MsgVote request to 3a57933972cb5131 at term 87
Feb 29 03:58:48 controller-0 etcd[3667]: raft2020/02/29 03:58:48 INFO: f98dc20bce6225a0 [logterm: 1, index: 3] sent MsgVote request to ffed16798470cab5 at term 87

// 単独でサービスを起動しているため、他のメンバーへの通信に失敗する
Feb 29 03:58:49 controller-0 etcd[3667]: health check for peer 3a57933972cb5131 could not connect: dial tcp 10.240.0.12:2380: connect: connection refused
Feb 29 03:58:49 controller-0 etcd[3667]: health check for peer ffed16798470cab5 could not connect: dial tcp 10.240.0.11:2380: connect: connection refused
Feb 29 03:58:49 controller-0 etcd[3667]: health check for peer ffed16798470cab5 could not connect: dial tcp 10.240.0.11:2380: connect: connection refused
Feb 29 03:58:49 controller-0 etcd[3667]: health check for peer 3a57933972cb5131 could not connect: dial tcp 10.240.0.12:2380: connect: connection refused

検証

全てのControl Planeでetcdのセットアップを実行してから、正常にクラスターが構成されているか検証を行います。
検証では、etcdctlを利用してetcdクラスターのメンバー一覧を取得します。

導入したetcdのバージョンがv3.4.0以下の場合は、環境変数をセットする必要があります。(ETCDCTL_API=3)

github.com

...@controller-1:~$ sudo ETCDCTL_API=3 etcdctl member list \
>   --endpoints=https://127.0.0.1:2379 \
>   --cacert=/etc/etcd/ca.pem \
>   --cert=/etc/etcd/kubernetes.pem \
>   --key=/etc/etcd/kubernetes-key.pem
3a57933972cb5131, started, controller-2, https://10.240.0.12:2380, https://10.240.0.12:2379, false
f98dc20bce6225a0, started, controller-0, https://10.240.0.10:2380, https://10.240.0.10:2379, false
ffed16798470cab5, started, controller-1, https://10.240.0.11:2380, https://10.240.0.11:2379, false


正常にetcdクラスターのメンバー一覧を取得できたので、etcdクラスタのセットアップは完了となります。

今回は、Chap7の内容をまとめました。
etcdで利用されている分散合意アルゴリズム (Raft) については関連リンクだけ記載しておきます。

qiita.com

Raft(分散合意アルゴリズム)について · GitHub