Kubernetes the hard way を初学者目線で解説する ~ #7 Workerノードの設定


はじめに

30代未経験からエンジニアを目指して勉強中のYNと申します。
インフラ初学者の私ですが、Kubernetes the hard wayを進めるにあたって、インフラに関する基本的な知識を体系的に学ぶことができました。
そこで、初学者目線での学びなどを本記事にまとめておきたいと思います。

目次

こちらをご覧ください

Workerノードを設定する

ここではWorkerノードにkubeletkube-proxyをインストールします。

kubeletのサーバー/クライアント証明書を生成

下図の通り、TLS証明書をつくります。

worker-1.node
master-1$ cat > openssl-worker-1.cnf <<EOF
[req]
req_extensions = v3_req
distinguished_name = req_distinguished_name
[req_distinguished_name]
[ v3_req ]
basicConstraints = CA:FALSE
keyUsage = nonRepudiation, digitalSignature, keyEncipherment
subjectAltName = @alt_names
[alt_names]
DNS.1 = worker-1
IP.1 = 192.168.5.21
EOF
worker-1.node
openssl genrsa -out worker-1.key 2048
openssl req -new -key worker-1.key -subj "/CN=system:node:worker-1/O=system:nodes" -out worker-1.csr -config openssl-worker-1.cnf
openssl x509 -req -in worker-1.csr -CA ca.crt -CAkey ca.key -CAcreateserial  -out worker-1.crt -extensions v3_req -extfile openssl-worker-1.cnf -days 1000

kubelet Configuration ファイルを生成する

ここで、クラスター内外からのkube-apiserverへのリクエストにおける認証について整理しておくと、こちらに規定されている通り、API-serverへリクエストを送るに当たってクライアント認証の方法は4つのモードがあります。

  • Node
  • ABAC
  • RBAC
  • Webhook

その中でも、Nodeモードはkubeletにのみ許された特権的な権限で、様々なAPI操作権限を有します。このNodeモードを使って認証するため、後述のkubeconfigファイルにsystem:node:worker-1を設定する必要があります。

ここから、kubeletの設定ファイルを作っていきます。

LBのIPをshell変数にメモする

master-1.node
LOADBALANCER_ADDRESS=192.168.5.30

worker-1.kubeconfigファイルを生成する

master-1.node
{
  kubectl config set-cluster kubernetes-the-hard-way \
    --certificate-authority=ca.crt \
    --embed-certs=true \
    --server=https://${LOADBALANCER_ADDRESS}:6443 \
    --kubeconfig=worker-1.kubeconfig

  kubectl config set-credentials system:node:worker-1 \
    --client-certificate=worker-1.crt \
    --client-key=worker-1.key \
    --embed-certs=true \
    --kubeconfig=worker-1.kubeconfig

  kubectl config set-context default \
    --cluster=kubernetes-the-hard-way \
    --user=system:node:worker-1 \
    --kubeconfig=worker-1.kubeconfig

  kubectl config use-context default --kubeconfig=worker-1.kubeconfig
}

作ったconfigファイルをworker-1ノードに移動する

master-1.node
scp ca.crt worker-1.crt worker-1.key worker-1.kubeconfig worker-1:~/

worker-1ノードの設定

ここから、worker-1ノードの設定をしていきます。

worker-1ノードににkubelet/kube-proxy/kubekubectlをインストール

worker-1.node
wget -q --show-progress --https-only --timestamping \
  https://storage.googleapis.com/kubernetes-release/release/v1.13.0/bin/linux/amd64/kubectl \
  https://storage.googleapis.com/kubernetes-release/release/v1.13.0/bin/linux/amd64/kube-proxy \
  https://storage.googleapis.com/kubernetes-release/release/v1.13.0/bin/linux/amd64/kubelet

適切なディレクトリを作成

worker-1.node
sudo mkdir -p \
  /etc/cni/net.d \
  /opt/cni/bin \
  /var/lib/kubelet \
  /var/lib/kube-proxy \
  /var/lib/kubernetes \
  /var/run/kubernetes

実行権限を付与してディレクトリ移動

worker-1.node
{
  chmod +x kubectl kube-proxy kubelet
  sudo mv kubectl kube-proxy kubelet /usr/local/bin/
}

kubeletの設定

必要なデータを適切なディレクトリに移動する

worker-1.node
{
  sudo mv ${HOSTNAME}.key ${HOSTNAME}.crt /var/lib/kubelet/
  sudo mv ${HOSTNAME}.kubeconfig /var/lib/kubelet/kubeconfig
  sudo mv ca.crt /var/lib/kubernetes/
}

kubelet-config.yamlをつくる

worker-1.node
cat <<EOF | sudo tee /var/lib/kubelet/kubelet-config.yaml
kind: KubeletConfiguration
apiVersion: kubelet.config.k8s.io/v1beta1
authentication: 
  anonymous: #(1)
    enabled: false
  webhook: #(2)
    enabled: true
  x509: #(3)
    clientCAFile: "/var/lib/kubernetes/ca.crt"
authorization:
  mode: Webhook #(4)
clusterDomain: "cluster.local"
clusterDNS:
  - "10.96.0.10"
resolvConf: "/run/systemd/resolve/resolv.conf" #(5)
runtimeRequestTimeout: "15m" #(6)
EOF

KubeletConfigurationの詳細はこちらにありますが、上記を解説してみます。

  • (1) kubeletへの(podなどからの)リクエストは全て認証を必要とさせます。

    Enables anonymous requests to the Kubelet server. Requests that are not rejected by another authentication method are treated as anonymous requests. Anonymous requests have a username of system:anonymous, and a group name of system:unauthenticated.

  • (2) kubeletの認証モードをwebhookに設定します。
    Webhookとは

    Webhook - A WebHook is an HTTP callback: an HTTP POST that occurs when something happens; a simple event-notification via HTTP POST. A web application implementing WebHooks will POST a message to a URL when certain things happen.

  • (3) kubeletがサーバーとして働く際に、利用するルート認証局の証明書の場所を指定します。

    File containing x509 Certificate used for serving HTTPS (with intermediate certs, if any, concatenated after server cert).

  • (4) kubeletによるリソースへのアクセス制御モードをwebhookにします。

    Authorization mode for Kubelet server. Valid options are AlwaysAllow or Webhook.

  • (5) コンテナのDNS解決の設定ファイルの場所。後述するkubelet.serviceunitが使用してるubuntuネームサーバーの設定ファイルを指定します。

    Resolver configuration file used as the basis for the container DNS resolution configuration.

  • (6) コンテナ操作に時間がかかる場合のタイムアウト設定を指定します。

    Timeout of all runtime requests except long running request - pull, logs, exec and attach. When timeout exceeded, kubelet will cancel the request, throw out an error and retry later.

kubelet.serviceファイルを設定する

このserviceをenableにすることで、ノード起動と共にkubeletが起動します。
workerノードには既にdockerがインストール済で、依存関係にdocker.serviceが入っていることに注目します。

worker-1.node
cat <<EOF | sudo tee /etc/systemd/system/kubelet.service
[Unit]
Description=Kubernetes Kubelet
Documentation=https://github.com/kubernetes/kubernetes
After=docker.service
Requires=docker.service

[Service]
ExecStart=/usr/local/bin/kubelet \\
  --config=/var/lib/kubelet/kubelet-config.yaml \\
  --image-pull-progress-deadline=2m \\
  --kubeconfig=/var/lib/kubelet/kubeconfig \\
  --tls-cert-file=/var/lib/kubelet/${HOSTNAME}.crt \\
  --tls-private-key-file=/var/lib/kubelet/${HOSTNAME}.key \\
  --network-plugin=cni \\
  --register-node=true \\
  --v=2
Restart=on-failure
RestartSec=5

[Install]
WantedBy=multi-user.target
EOF

kube-proxyの設定

以前に生成したkube-proxy.kubeconfigを使ってkube-proxy-config.yamlをつくります。

必要なデータを適切なディレクトリに移動する

worker-1.node
sudo mv kube-proxy.kubeconfig /var/lib/kube-proxy/kubeconfig

kube-proxy-config.yamlをつくる

worker-1.node
cat <<EOF | sudo tee /var/lib/kube-proxy/kube-proxy-config.yaml
kind: KubeProxyConfiguration
apiVersion: kubeproxy.config.k8s.io/v1alpha1
clientConnection:
  kubeconfig: "/var/lib/kube-proxy/kubeconfig"
mode: "iptables" #(1)
clusterCIDR: "192.168.5.0/24"
EOF

(1) proxy modeを規定します。各modeにおけるkube-proxyの挙動についてはこちらを参照ください。

  • Which proxy mode to use: 'userspace' (older) or 'iptables' (faster) or 'ipvs' or 'kernelspace' (windows). If blank, use the best-available proxy (currently iptables). If the iptables proxy is selected, regardless of how, but the system's kernel or iptables versions are insufficient, this always falls back to the userspace proxy.
  • デフォルトでは、iptablesモードにおけるkube-proxyはバックエンドPodをランダムで選択します。
  • トラフィックのハンドリングのためにiptablesを使用すると、システムのオーバーヘッドが少なくなります。
  • kube-proxyがiptablesモードで稼働し、最初に選択されたPodが応答しない場合、そのコネクションは失敗します。

KubeProxyConfigurationの詳細はこちらを参照ください。
kube-proxyはKubernetesクラスタ内で非常に大事な役割を果たしています。下図のようにユーザーおよびPodがノードを意識せず通信できるのはkube-proxyとCNIがうまく機能しているからであり、ここがKubernetesクラスタのミソだと思います。

kubelet.serviceファイルを設定する

このserviceをenableにすることで、ノード起動と共にkube-proxyが起動します。

worker-1.node
cat <<EOF | sudo tee /etc/systemd/system/kube-proxy.service
[Unit]
Description=Kubernetes Kube Proxy
Documentation=https://github.com/kubernetes/kubernetes

[Service]
ExecStart=/usr/local/bin/kube-proxy \\
  --config=/var/lib/kube-proxy/kube-proxy-config.yaml
Restart=on-failure
RestartSec=5

[Install]
WantedBy=multi-user.target

kubeletkube-proxyを起動する

worker-1.node
{
  sudo systemctl daemon-reload
  sudo systemctl enable kubelet kube-proxy
  sudo systemctl start kubelet kube-proxy
}

動作確認

master-1.node
kubectl get nodes
NAME       STATUS     ROLES    AGE   VERSION
worker-1   NotReady   <none>   93s   v1.13.0