涅槃を目指す in はてな

人生に迷う様を書きます

Kubernetes The Hard Way On VirtualBox 6日目

Kubernetesを雰囲気で使わないための修行Kubernetes The Hard Way On VirtualBoxの6日目。

今回はKubernetes のControl Planeを作成します。

いよいよそれっぽくなってきました。

Bootstrapping the Kubernetes Control Plane

今回は高可用性のために2つのインスタンスにControl Planeを設定します。また、Kubernetes API Serverをリモートクライアントに公開するためのロードバランサも作成します。

以下のコンポーネントが2つのノードにインストールされます

Prerequisites

今回の作業は maste-1 master-2 両方に行います

Provision the Kubernetes Control Plane

設定用のディレクトリ作成

sudo mkdir -p /etc/kubernetes/config

Download and Install the Kubernetes Controller Binaries

公式のバイナリをダウンロードします。公式手順だと v1.13.0 なんですけど流石に古いので、執筆時点で最新の v1.22.0 に変えてます。

リリース情報は https://kubernetes.io/docs/setup/release/#server-binaries から確認できます。

wget -q --show-progress --https-only --timestamping \
  "https://storage.googleapis.com/kubernetes-release/release/v1.22.0/bin/linux/amd64/kube-apiserver" \
  "https://storage.googleapis.com/kubernetes-release/release/v1.22.0/bin/linux/amd64/kube-controller-manager" \
  "https://storage.googleapis.com/kubernetes-release/release/v1.22.0/bin/linux/amd64/kube-scheduler" \
  "https://storage.googleapis.com/kubernetes-release/release/v1.22.0/bin/linux/amd64/kubectl"

バイナリをインストールします。

{
  chmod +x kube-apiserver kube-controller-manager kube-scheduler kubectl
  sudo mv kube-apiserver kube-controller-manager kube-scheduler kubectl /usr/local/bin/
}

Configure the Kubernetes API Server

証明書と暗号化に関するファイルを配置します。

{
  sudo mkdir -p /var/lib/kubernetes/

  sudo cp ca.crt ca.key kube-apiserver.crt kube-apiserver.key \
    service-account.key service-account.crt \
    etcd-server.key etcd-server.crt \
    encryption-config.yaml /var/lib/kubernetes/
}

インスタンスの内部IPアドレスAPIサーバをクラスターメンバにする際のアドバタイズに使われます。

現在の内部IPアドレスを取得しておきます。

INTERNAL_IP=$(ip addr show enp0s8 | grep "inet " | awk '{print $2}' | cut -d / -f 1)

確認します。

echo $INTERNAL_IP

kube-apiserver.service という、systemdのunitファイルを作成します。

cat <<EOF | sudo tee /etc/systemd/system/kube-apiserver.service
[Unit]
Description=Kubernetes API Server
Documentation=https://github.com/kubernetes/kubernetes

[Service]
ExecStart=/usr/local/bin/kube-apiserver \\
  --advertise-address=${INTERNAL_IP} \\
  --allow-privileged=true \\
  --apiserver-count=2 \\
  --audit-log-maxage=30 \\
  --audit-log-maxbackup=3 \\
  --audit-log-maxsize=100 \\
  --audit-log-path=/var/log/audit.log \\
  --authorization-mode=Node,RBAC \\
  --bind-address=0.0.0.0 \\
  --client-ca-file=/var/lib/kubernetes/ca.crt \\
  --enable-admission-plugins=NodeRestriction,ServiceAccount \\
  --enable-swagger-ui=true \\
  --enable-bootstrap-token-auth=true \\
  --etcd-cafile=/var/lib/kubernetes/ca.crt \\
  --etcd-certfile=/var/lib/kubernetes/etcd-server.crt \\
  --etcd-keyfile=/var/lib/kubernetes/etcd-server.key \\
  --etcd-servers=https://192.168.5.11:2379,https://192.168.5.12:2379 \\
  --event-ttl=1h \\
  --encryption-provider-config=/var/lib/kubernetes/encryption-config.yaml \\
  --kubelet-certificate-authority=/var/lib/kubernetes/ca.crt \\
  --kubelet-client-certificate=/var/lib/kubernetes/kube-apiserver.crt \\
  --kubelet-client-key=/var/lib/kubernetes/kube-apiserver.key \\
  --kubelet-https=true \\
  --runtime-config=api/all=true \\
  --service-account-key-file=/var/lib/kubernetes/service-account.crt \\
  --service-cluster-ip-range=10.96.0.0/24 \\
  --service-node-port-range=30000-32767 \\
  --tls-cert-file=/var/lib/kubernetes/kube-apiserver.crt \\
  --tls-private-key-file=/var/lib/kubernetes/kube-apiserver.key \\
  --v=2
Restart=on-failure
RestartSec=5

[Install]
WantedBy=multi-user.target
EOF

Configure the Kubernetes Controller Manager

kube-controller-manager のkubeconfigを配置します

sudo cp kube-controller-manager.kubeconfig /var/lib/kubernetes/

kube-controller-manager.service という、systemdのunitファイルを作成します。

cat <<EOF | sudo tee /etc/systemd/system/kube-controller-manager.service
[Unit]
Description=Kubernetes Controller Manager
Documentation=https://github.com/kubernetes/kubernetes

[Service]
ExecStart=/usr/local/bin/kube-controller-manager \\
  --address=0.0.0.0 \\
  --cluster-cidr=192.168.5.0/24 \\
  --cluster-name=kubernetes \\
  --cluster-signing-cert-file=/var/lib/kubernetes/ca.crt \\
  --cluster-signing-key-file=/var/lib/kubernetes/ca.key \\
  --kubeconfig=/var/lib/kubernetes/kube-controller-manager.kubeconfig \\
  --leader-elect=true \\
  --root-ca-file=/var/lib/kubernetes/ca.crt \\
  --service-account-private-key-file=/var/lib/kubernetes/service-account.key \\
  --service-cluster-ip-range=10.96.0.0/24 \\
  --use-service-account-credentials=true \\
  --v=2
Restart=on-failure
RestartSec=5

[Install]
WantedBy=multi-user.target
EOF

Configure the Kubernetes Scheduler

kube-scheduler のkubeconfigを配置します

sudo cp kube-scheduler.kubeconfig /var/lib/kubernetes/

kube-scheduler.service という、systemdのunitファイルを作成します。

cat <<EOF | sudo tee /etc/systemd/system/kube-scheduler.service
[Unit]
Description=Kubernetes Scheduler
Documentation=https://github.com/kubernetes/kubernetes

[Service]
ExecStart=/usr/local/bin/kube-scheduler \\
  --kubeconfig=/var/lib/kubernetes/kube-scheduler.kubeconfig \\
  --address=127.0.0.1 \\
  --leader-elect=true \\
  --v=2
Restart=on-failure
RestartSec=5

[Install]
WantedBy=multi-user.target
EOF

Start the Controller Services

作成したサービスの自動起動設定と、起動をします

{
  sudo systemctl daemon-reload
  sudo systemctl enable kube-apiserver kube-controller-manager kube-scheduler
  sudo systemctl start kube-apiserver kube-controller-manager kube-scheduler
}

確認しましょう

kubectl get componentstatuses --kubeconfig admin.kubeconfig

ここでトラブル!

vagrant@master-1:~$ kubectl get componentstatuses --kubeconfig admin.kubeconfig
The connection to the server 127.0.0.1:6443 was refused - did you specify the right host or port?

ほうほう。なんで?

vagrant@master-1:~$ systemctl status kube-apiserver
● kube-apiserver.service - Kubernetes API Server
   Loaded: loaded (/etc/systemd/system/kube-apiserver.service; enabled; vendor preset: enabled
   Active: activating (auto-restart) (Result: exit-code) since Wed 2021-10-06 22:30:20 UTC; 3s
     Docs: https://github.com/kubernetes/kubernetes
  Process: 7337 ExecStart=/usr/local/bin/kube-apiserver --advertise-address=192.168.5.11 --all
 Main PID: 7337 (code=exited, status=1/FAILURE)

どうもkube-apiserver が動いてない。sudo 付けてもう一度起動させてみる。

vagrant@master-1:~$ sudo systemctl start kube-apiserver
vagrant@master-1:~$ sudo systemctl status kube-apiserver
● kube-apiserver.service - Kubernetes API Server
   Loaded: loaded (/etc/systemd/system/kube-apiserver.service; enabled; vendor preset: enabled
   Active: activating (auto-restart) (Result: exit-code) since Sat 2021-10-09 04:35:15 UTC; 2s
     Docs: https://github.com/kubernetes/kubernetes
  Process: 30902 ExecStart=/usr/local/bin/kube-apiserver --advertise-address=192.168.5.11 --al
 Main PID: 30902 (code=exited, status=1/FAILURE)

Oct 09 04:35:15 master-1 systemd[1]: kube-apiserver.service: Main process exited, code=exited,
Oct 09 04:35:15 master-1 systemd[1]: kube-apiserver.service: Failed with result 'exit-code'.

やっぱダメ

syslog見ると

Oct  9 04:35:57 master-1 systemd[1]: Started Kubernetes API Server.
Oct  9 04:35:57 master-1 kube-apiserver[31144]: Error: unknown flag: --kubelet-https
Oct  9 04:35:57 master-1 systemd[1]: kube-apiserver.service: Main process exited, code=exited, status=1/FAILURE
Oct  9 04:35:57 master-1 systemd[1]: kube-apiserver.service: Failed with result 'exit-code'.

https://kubernetes.io/docs/reference/command-line-tools-reference/kube-apiserver/ みてもそんな--kubelet-httpsというフラグはないなあ。廃止になったのかな?

--kubelet-httpsを消して起動させると、今度はこんなログが

Oct  9 04:53:32 master-1 kube-apiserver[4894]: Error: [service-account-issuer is a required flag, --service-account-signing-key-file and --service-account-issuer are required flags]
Oct  9 04:53:32 master-1 systemd[1]: kube-apiserver.service: Main process exited, code=exited, status=1/FAILURE
Oct  9 04:53:32 master-1 systemd[1]: kube-apiserver.service: Failed with result 'exit-code'.

やれやれだぜ。一難去ってまた一難

service-account-issuerservice-account-signing-key-file が必須と来たか。k8s 1.18以降では、ServiceAccountIssuerDiscoveryというOIDC DiscoveryやJWKsのエンドポイントを提供する機能が追加されて、認証用トークン作成のために鍵が必要らしい。

ここでissueが上がってるな

https://github.com/kelseyhightower/kubernetes-the-hard-way/issues/626

秘密鍵を作成

openssl genrsa -out service-account.key 2048
openssl req -new -key service-account.key -subj "/CN=service-accounts" -out service-account.csr
openssl x509 -req -in service-account.csr -CA ca.crt -CAkey ca.key -CAcreateserial  -out service-account.crt -days 1000

/etc/systemd/system/kube-apiserver.serviceに以下を追記

  --service-account-key-file=/var/lib/kubernetes/service-account-key.pem \
  --service-account-signing-key-file=/var/lib/kubernetes/service-account-key.pem \
  --service-account-issuer=api \

もう1回起動

sudo systemctl daemon-reload
sudo systemctl start kube-apiserver
vagrant@master-1:~$ sudo systemctl status kube-apiserver
● kube-apiserver.service - Kubernetes API Server
   Loaded: loaded (/etc/systemd/system/kube-apiserver.service; enabled; vendor preset: enabled
   Active: active (running) since Sun 2021-10-10 21:34:46 UTC; 1min 36s ago
     Docs: https://github.com/kubernetes/kubernetes
 Main PID: 30706 (kube-apiserver)
    Tasks: 9 (limit: 2360)
   CGroup: /system.slice/kube-apiserver.service
           └─30706 /usr/local/bin/kube-apiserver --advertise-address=192.168.5.11 --allow-priv

よしよし。kubectlでも確認

kubectl get componentstatuses --kubeconfig admin.kubeconfig
vagrant@master-1:~$ kubectl get componentstatuses --kubeconfig admin.kubeconfig
Warning: v1 ComponentStatus is deprecated in v1.19+
NAME                 STATUS    MESSAGE                         ERROR
scheduler            Healthy   ok                              
etcd-1               Healthy   {"health":"true","reason":""}   
controller-manager   Healthy   ok                              
etcd-0               Healthy   {"health":"true","reason":""} 

master-2 に鍵を転送して確認

vagrant@master-2:~$ kubectl get componentstatuses --kubeconfig admin.kubeconfig
Warning: v1 ComponentStatus is deprecated in v1.19+
NAME                 STATUS    MESSAGE                         ERROR
etcd-1               Healthy   {"health":"true","reason":""}   
etcd-0               Healthy   {"health":"true","reason":""}   
controller-manager   Healthy   ok                              
scheduler            Healthy   ok    

OKOK!

The Kubernetes Frontend Load Balancer

ここではKubernetes API Server用の外部向けロードバランサを作成します。

ロードバランサのインスタンスSSH接続します。

vagrant ssh loadbalancer

haproxyをインストールします。

sudo apt-get update && sudo apt-get install -y haproxy

/etc/haproxy/haproxy.cfg に設定をします。

cat <<EOF | sudo tee /etc/haproxy/haproxy.cfg 
frontend kubernetes
    bind 192.168.5.30:6443
    option tcplog
    mode tcp
    default_backend kubernetes-master-nodes

backend kubernetes-master-nodes
    mode tcp
    balance roundrobin
    option tcp-check
    server master-1 192.168.5.11:6443 check fall 3 rise 2
    server master-2 192.168.5.12:6443 check fall 3 rise 2
EOF
sudo service haproxy restart

HTTTPリクエストをして動作確認

curl  https://192.168.5.30:6443/version -k

以下のように返ってくればOK

{
  "major": "1",
  "minor": "22",
  "gitVersion": "v1.22.0",
  "gitCommit": "c2b5237ccd9c0f1d600d3072634ca66cefdf272f",
  "gitTreeState": "clean",
  "buildDate": "2021-08-04T17:57:25Z",
  "goVersion": "go1.16.6",
  "compiler": "gc",
  "platform": "linux/amd64"
}

今回はここまで。エラー出たときはびっくりした。

お読みいただきありがとうございました。