Kubernetes the hard way (GCP版)の続きです。
前回の記事はこちら
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用の証明書ファイル類を配置します。
...@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アクセスに関しては、追加で認証処理を行うことなくメタデータを取得することが可能です。
...@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
上記の設定項目に関する説明は下記のリンクに記載されています。
...@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コマンドを実行してからサービスを起動します。
{
sudo systemctl daemon-reload
sudo systemctl enable etcd
sudo systemctl start etcd
}
注意点として、etcdのメンバーを単独で起動するとサービスの起動は失敗します。
サービスのステータス確認時にfailedの状態になった場合は、systemctl reset-failedコマンドで異常状態のリセットを行います。
...@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)
...@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) については関連リンクだけ記載しておきます。