Contents
Overview
Kubernetes クラスターを構築します。本稿の特徴は以下のとおりです。
- 本稿の Kubernetes クラスターは、Master ノード x1、Worker ノード x1 の構成ですが、controlPlaneEndpoint でロードバランサー (HAProxy) の VIP を指定しており、これにより Master ノード (API) を冗長構成とすることができます。この VIP を指定して Master/Worker ノードをクラスターに Join させることができ、柔軟なスケールができます。本稿の例では VIP に FQDN を使用しています。
- 本稿の Kubernetes クラスターは、IPv4/IPv6 DualStack を前提としているため、通常と比較して若干複雑になっています。特に IPv6 のサイズは Kubernetes, CNI ともに制約があり、試しながら適切なサイズをアサインする必要があります(明確な情報はあまり公開されていませんがサイズに問題があればエラーが出ます)。IPv6 が不要なら、各マニフェストから IPv6 の要素を除くだけで問題ありません。
- 本稿では、Kube-proxy のバックエンドに IPVS を使用しています。デフォルトでは iptables を使用しますが、IPVS はロードバランシング専用に設計されており、効率的なデータ構造(ハッシュテーブル)を使用するため、クラスター内のサービスロードバランシングのスケーラビリティを大幅に向上させます。これにより、Kubernetes クラスタが大規模なワークロードを効率的に処理できるようになります。エンタープライズレベルでは IPVS を前提とした方が良いと考えています。
- CNI には Calico を採用しています。Calico は CNI としてデファクトスタンダードに近く、多くのマネージド Kubernetes でも採用されています。他には、flannel や Kube-OVN などの CNI が存在しています。Calico は BGP でも動作しますが、本稿では使用していません。
前提条件
- こちらを参考に containerd の環境構築が完了していること。
- こちらを参考に「Kubernetes クラスター構築の事前準備」が完了していること。
- 本稿では、Kubernetes クラスターの構築までを説明しており、これ以降の Kubernetes の使用に関してはこちらを参照して下さい。
- Kubernetes クラスターの構築は、Master ノード、Worker ノードのそれぞれで操作が必要になるため、各手順にどちらで実施する操作であるかを記載しています。
- ステータスの出力情報はサンプルであり、名前などの一貫性がない場合があります。
kubeadm init
Master ノード: ${HOME}/work/k8s/kubeadm-config.yaml
を作成します。
myadmin@ubuntu-22-04:~$ tee ${HOME}/work/k8s/kubeadm-config.yaml <<"EOF"
apiVersion: kubeadm.k8s.io/v1beta3
kind: ClusterConfiguration
clusterName: s00-int-k8s-cluster-n001.si1230.com
networking:
podSubnet: 10.129.0.0/21,fd02::/64
serviceSubnet: 10.129.32.0/21,fd03::/108
controlPlaneEndpoint: s00-int-k8s-cluster-n001.si1230.com:6443
---
apiVersion: kubeadm.k8s.io/v1beta3
kind: InitConfiguration
localAPIEndpoint:
advertiseAddress: 10.1.0.180
bindPort: 6443
nodeRegistration:
kubeletExtraArgs:
node-ip: 10.1.0.180,fd00::a01:b4
---
apiVersion: kubelet.config.k8s.io/v1beta1
kind: KubeletConfiguration
cgroupDriver: systemd
---
apiVersion: kubeproxy.config.k8s.io/v1alpha1
kind: KubeProxyConfiguration
mode: "ipvs"
# MetalLB L2 mode only
ipvs:
strictARP: true
EOF
- ClusterConfiguration:
apiVersion: kubeadm.k8s.io/v1beta3
: 使用している API バージョン。kind: ClusterConfiguration
: このリソースの種類を示します。clusterName
: クラスターの名前。networking
: ネットワーキングに関連する設定を含みます。podSubnet
: Pod が使用するサブネットを指定します。ここでは IPv4 と IPv6 のアドレス範囲が指定されています。serviceSubnet
: Kubernetes サービスが使用するサブネット。IPv4 と IPv6 の範囲も指定されています。
controlPlaneEndpoint
: コントロールプレーンのエンドポイントをs00-int-k8s-cluster-n001.si1230.com:6443
に設定します。追加のノードはエンドポイントを指定して参加します。これは HAProxy などのロードバランサーのアドレスを指定します。
- InitConfiguration:
apiVersion: kubeadm.k8s.io/v1beta3
: 使用している API バージョン。kind: InitConfiguration
: このリソースの種類を示します。localAPIEndpoint
: API サーバーのエンドポイント設定。advertiseAddress
: クラスタ内の他のコンポーネントがこの Master ノードを見つけるために使用する IP アドレス。bindPort
: Kubernetes API サーバーがリッスンするポート(通常は 6443)。
nodeRegistration
: ノード登録時の追加設定。kubeletExtraArgs
: kubelet の追加コマンドライン引数。node-ip
: ノードに割り当てられた IP アドレス。IPv4 と IPv6 のアドレスが指定されています。
- KubeletConfiguration:
apiVersion: kubelet.config.k8s.io/v1beta1
: Kubelet 設定の API バージョン。kind: KubeletConfiguration
: このリソースの種類を示します。cgroupDriver
: Kubernetes が使用する cgroup ドライバー。ここではsystemd
を指定しており、この設定は containerd の設定と合わせる必要があります。
- KubeProxyConfiguration:
apiVersion: kubeproxy.config.k8s.io/v1alpha1
: Kube-proxy 設定の API バージョン。kind: KubeProxyConfiguration
: このリソースの種類を示します。mode "ipvs"
: ipvs モードを使用します。IPVS は、iptables と比較して高いパフォーマンスとスケーラビリティを提供します。ipvs
: MetalLB で L2 モードを使用する場合にのみ設定します。strictARP
: MetalLB で L2 モードを使用する場合にのみ設定します。
Master ノード: kubeadm init
を実行し、クラスターを作成します。
myadmin@ubuntu-22-04:~$ sudo kubeadm init --config=${HOME}/work/k8s/kubeadm-config.yaml --upload-certs
成功すると以下のように出力されます。この出力には以降の手順で使用する情報(ハイライトの箇所)が含まれます。control-plane node(Master ノード)の追加コマンドの出力は、controlPlaneEndpoint
の指定がない場合は出力されません。
I0520 22:06:52.020398 13521 version.go:256] remote version is much newer: v1.30.1; falling back to: stable-1.29
[init] Using Kubernetes version: v1.29.5
[preflight] Running pre-flight checks
[preflight] Pulling images required for setting up a Kubernetes cluster
[preflight] This might take a minute or two, depending on the speed of your internet connection
[preflight] You can also perform this action in beforehand using 'kubeadm config images pull'
W0520 22:06:52.685971 13521 checks.go:835] detected that the sandbox image "registry.k8s.io/pause:3.8" of the container runtime is inconsistent with that used by kubeadm. It is recommended that using "registry.k8s.io/pause:3.9" as the CRI sandbox image.
[certs] Using certificateDir folder "/etc/kubernetes/pki"
[certs] Generating "ca" certificate and key
[certs] Generating "apiserver" certificate and key
[certs] apiserver serving cert is signed for DNS names [kubernetes kubernetes.default kubernetes.default.svc kubernetes.default.svc.cluster.local s00-int-k8s-cluster-n001.si1230.com s00-int-k8s-master-v001] and IPs [10.129.32.1 10.1.0.180]
[certs] Generating "apiserver-kubelet-client" certificate and key
[certs] Generating "front-proxy-ca" certificate and key
[certs] Generating "front-proxy-client" certificate and key
[certs] Generating "etcd/ca" certificate and key
[certs] Generating "etcd/server" certificate and key
[certs] etcd/server serving cert is signed for DNS names [localhost s00-int-k8s-master-v001] and IPs [10.1.0.180 127.0.0.1 ::1]
[certs] Generating "etcd/peer" certificate and key
[certs] etcd/peer serving cert is signed for DNS names [localhost s00-int-k8s-master-v001] and IPs [10.1.0.180 127.0.0.1 ::1]
[certs] Generating "etcd/healthcheck-client" certificate and key
[certs] Generating "apiserver-etcd-client" certificate and key
[certs] Generating "sa" key and public key
[kubeconfig] Using kubeconfig folder "/etc/kubernetes"
[kubeconfig] Writing "admin.conf" kubeconfig file
[kubeconfig] Writing "super-admin.conf" kubeconfig file
[kubeconfig] Writing "kubelet.conf" kubeconfig file
[kubeconfig] Writing "controller-manager.conf" kubeconfig file
[kubeconfig] Writing "scheduler.conf" kubeconfig file
[etcd] Creating static Pod manifest for local etcd in "/etc/kubernetes/manifests"
[control-plane] Using manifest folder "/etc/kubernetes/manifests"
[control-plane] Creating static Pod manifest for "kube-apiserver"
[control-plane] Creating static Pod manifest for "kube-controller-manager"
[control-plane] Creating static Pod manifest for "kube-scheduler"
[kubelet-start] Writing kubelet environment file with flags to file "/var/lib/kubelet/kubeadm-flags.env"
[kubelet-start] Writing kubelet configuration to file "/var/lib/kubelet/config.yaml"
[kubelet-start] Starting the kubelet
[wait-control-plane] Waiting for the kubelet to boot up the control plane as static Pods from directory "/etc/kubernetes/manifests". This can take up to 4m0s
[apiclient] All control plane components are healthy after 4.024414 seconds
[upload-config] Storing the configuration used in ConfigMap "kubeadm-config" in the "kube-system" Namespace
[kubelet] Creating a ConfigMap "kubelet-config" in namespace kube-system with the configuration for the kubelets in the cluster
[upload-certs] Storing the certificates in Secret "kubeadm-certs" in the "kube-system" Namespace
[upload-certs] Using certificate key:
e5f5e4c5903a64eebb5fbaf13e301e37bb1169a53a0364713d1667f3b4ae3af7
[mark-control-plane] Marking the node s00-int-k8s-master-v001 as control-plane by adding the labels: [node-role.kubernetes.io/control-plane node.kubernetes.io/exclude-from-external-load-balancers]
[mark-control-plane] Marking the node s00-int-k8s-master-v001 as control-plane by adding the taints [node-role.kubernetes.io/control-plane:NoSchedule]
[bootstrap-token] Using token: p6hx1h.38roeyfwyka0mkfe
[bootstrap-token] Configuring bootstrap tokens, cluster-info ConfigMap, RBAC Roles
[bootstrap-token] Configured RBAC rules to allow Node Bootstrap tokens to get nodes
[bootstrap-token] Configured RBAC rules to allow Node Bootstrap tokens to post CSRs in order for nodes to get long term certificate credentials
[bootstrap-token] Configured RBAC rules to allow the csrapprover controller automatically approve CSRs from a Node Bootstrap Token
[bootstrap-token] Configured RBAC rules to allow certificate rotation for all node client certificates in the cluster
[bootstrap-token] Creating the "cluster-info" ConfigMap in the "kube-public" namespace
[kubelet-finalize] Updating "/etc/kubernetes/kubelet.conf" to point to a rotatable kubelet client certificate and key
[addons] Applied essential addon: CoreDNS
[addons] Applied essential addon: kube-proxy
Your Kubernetes control-plane has initialized successfully!
To start using your cluster, you need to run the following as a regular user:
mkdir -p $HOME/.kube
sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
sudo chown $(id -u):$(id -g) $HOME/.kube/config
Alternatively, if you are the root user, you can run:
export KUBECONFIG=/etc/kubernetes/admin.conf
You should now deploy a pod network to the cluster.
Run "kubectl apply -f [podnetwork].yaml" with one of the options listed at:
https://kubernetes.io/docs/concepts/cluster-administration/addons/
You can now join any number of the control-plane node running the following command on each as root:
kubeadm join s00-int-k8s-cluster-n001.si1230.com:6443 --token p6hx1h.38roeyfwyka0mkfe \
--discovery-token-ca-cert-hash sha256:903bf0263a878d364112455ddfbe8c2b5a9f672faf6bd2aba61ce3372c40bdd4 \
--control-plane --certificate-key e5f5e4c5903a64eebb5fbaf13e301e37bb1169a53a0364713d1667f3b4ae3af7
Please note that the certificate-key gives access to cluster sensitive data, keep it secret!
As a safeguard, uploaded-certs will be deleted in two hours; If necessary, you can use
"kubeadm init phase upload-certs --upload-certs" to reload certs afterward.
Then you can join any number of worker nodes by running the following on each as root:
kubeadm join s00-int-k8s-cluster-n001.si1230.com:6443 --token p6hx1h.38roeyfwyka0mkfe \
--discovery-token-ca-cert-hash sha256:903bf0263a878d364112455ddfbe8c2b5a9f672faf6bd2aba61ce3372c40bdd4
Master ノード: kubeadm init
が成功した際の出力にも記載されていますが、以下のようにクレデンシャルファイルを設定します。これにより、Master ノードから kubectl
コマンドを実行できるようになります。
myadmin@ubuntu-22-04:~$ mkdir -p ${HOME}/.kube && sudo cp /etc/kubernetes/admin.conf ${HOME}/.kube/config && sudo chown $(id -u):$(id -g) ${HOME}/.kube/config
Master ノード: kubectl get node
でノードの状態を確認します。CNI が存在しない状態では NotReady
になります。
NAME STATUS ROLES AGE VERSION
s00-int-k8s-master-v001 NotReady control-plane 2m42s v1.29.5
Master ノード: kubectl get pods -A
で Pod の状態を確認します。CNI が存在しない状態では coredns が起動しません。
NAMESPACE NAME READY STATUS RESTARTS AGE
kube-system coredns-76f75df574-b8w2f 0/1 ContainerCreating 0 4m20s
kube-system coredns-76f75df574-fbd99 0/1 ContainerCreating 0 4m20s
kube-system etcd-s00-int-k8s-master-v001 1/1 Running 6 4m34s
kube-system kube-apiserver-s00-int-k8s-master-v001 1/1 Running 1 4m34s
kube-system kube-controller-manager-s00-int-k8s-master-v001 1/1 Running 4 4m34s
kube-system kube-proxy-xsscq 1/1 Running 0 4m21s
kube-system kube-scheduler-s00-int-k8s-master-v001 1/1 Running 4 4m34s
CNI のインストール
Master ノード: CNI (Container Network Interface) をインストールします。本稿では Calico を使用します。
myadmin@ubuntu-22-04:~$ kubectl create -f https://raw.githubusercontent.com/projectcalico/calico/v3.27.0/manifests/tigera-operator.yaml
Master ノード: Calico を設定します。問題なければ、この時点で各 Pod の状態が正常になります。
myadmin@ubuntu-22-04:~$ cat <<EOF | kubectl create -f -
apiVersion: operator.tigera.io/v1
kind: Installation
metadata:
name: default
spec:
calicoNetwork:
ipPools:
- blockSize: 24
cidr: 10.129.0.0/21
encapsulation: None
natOutgoing: Enabled
nodeSelector: all()
- blockSize: 116
cidr: fd02::/64
encapsulation: None
natOutgoing: Enabled
nodeSelector: all()
EOF
- Installation:
apiVersion: operator.tigera.io/v1
: 使用している API バージョン。kind: Installation
: このリソースの種類を示します。Calico のインストールを行う設定です。metadata
:name: default
: この設定の名前。デフォルトの設定として適用されます。
spec
:calicoNetwork
:ipPools
: 使用する IP プールの設定。blockSize: 24
: IPv4 アドレスプールのブロックサイズ。サブネットマスクのビット数を示します。cidr: 10.129.0.0/21
: Pod に割り当てられる IPv4 アドレスの範囲。encapsulation: None
: IP パケットのカプセル化を行わない設定です。パフォーマンスを最適化するために、オーバーレイネットワークを使用しません。natOutgoing: Enabled
: NAT を有効にし、クラスター内のプライベートアドレスから外部への通信時にノードの IP アドレスを使用します。nodeSelector: all()
: この IP プールをクラスター内のすべてのノードで使用する設定です。
blockSize: 116
: IPv6 アドレスプールのブロックサイズ。cidr: fd02::/64
: Pod に割り当てられる IPv6 アドレスの範囲。encapsulation: None
: IPv6 においてもカプセル化は行わず、オーバーレイネットワークを使用しません。natOutgoing: Enabled
: IPv6 アドレスに対しても NAT を有効にし、外部通信を可能にします。nodeSelector: all()
: この IPv6 アドレスプールもクラスター内の全ノードで使用します。
Master ノード: kubectl get node
でノードの状態を確認します。CNI をインストールすることで Ready
になります。
NAME STATUS ROLES AGE VERSION
s00-int-k8s-master-v001 Ready control-plane 9m58s v1.29.5
Master ノード: kubectl get pods -A
で Pod の状態を確認します。CNI をインストールすることで coredns が起動します。
NAMESPACE NAME READY STATUS RESTARTS AGE
calico-system calico-kube-controllers-c45bddc79-qwkr2 1/1 Running 0 64s
calico-system calico-node-4wnfj 1/1 Running 0 64s
calico-system calico-typha-9f64f5f44-4trst 1/1 Running 0 64s
calico-system csi-node-driver-q6q4l 2/2 Running 0 64s
kube-system coredns-76f75df574-b8w2f 1/1 Running 0 10m
kube-system coredns-76f75df574-fbd99 1/1 Running 0 10m
kube-system etcd-s00-int-k8s-master-v001 1/1 Running 6 10m
kube-system kube-apiserver-s00-int-k8s-master-v001 1/1 Running 1 10m
kube-system kube-controller-manager-s00-int-k8s-master-v001 1/1 Running 4 10m
kube-system kube-proxy-xsscq 1/1 Running 0 10m
kube-system kube-scheduler-s00-int-k8s-master-v001 1/1 Running 4 10m
tigera-operator tigera-operator-55585899bf-7mjds 1/1 Running 0 97s
Worker ノードの追加
Master ノード: Worker ノードの追加に必要となるトークンを出力させます。この情報は kubeadm init
の出力で得られる情報と同じです。
myadmin@ubuntu-22-04:~$ kubeadm token create --print-join-command
Worker ノード: kubeadm join
で Kubernetes クラスターに参加します。
myadmin@ubuntu-22-04:~$ sudo sudo kubeadm join 10.1.0.180:6443 --token [token] --discovery-token-ca-cert-hash [discovery-token-ca-cert-hash]
Master ノード: kubectl get node
でノードの状態を確認します。Worker ノードが追加されたことを確認できます。
NAME STATUS ROLES AGE VERSION
s00-int-k8s-master-v001 Ready control-plane 21m v1.29.5
s00-int-k8s-worker-v001 Ready <none> 78s v1.29.5
Master ノード: kubectl get pods -A
で Pod の状態を確認します。calico-node が増えたことが確認できます。
NAMESPACE NAME READY STATUS RESTARTS AGE
calico-system calico-kube-controllers-c45bddc79-qwkr2 1/1 Running 0 12m
calico-system calico-node-4wnfj 1/1 Running 0 12m
calico-system calico-node-89bj2 1/1 Running 0 99s
calico-system calico-typha-9f64f5f44-4trst 1/1 Running 0 12m
calico-system csi-node-driver-22kq6 2/2 Running 0 99s
calico-system csi-node-driver-q6q4l 2/2 Running 0 12m
kube-system coredns-76f75df574-b8w2f 1/1 Running 0 21m
kube-system coredns-76f75df574-fbd99 1/1 Running 0 21m
kube-system etcd-s00-int-k8s-master-v001 1/1 Running 6 21m
kube-system kube-apiserver-s00-int-k8s-master-v001 1/1 Running 1 21m
kube-system kube-controller-manager-s00-int-k8s-master-v001 1/1 Running 4 21m
kube-system kube-proxy-kv6zd 1/1 Running 0 99s
kube-system kube-proxy-xsscq 1/1 Running 0 21m
kube-system kube-scheduler-s00-int-k8s-master-v001 1/1 Running 4 21m
tigera-operator tigera-operator-55585899bf-7mjds 1/1 Running 0 12m
Master ノードの追加
Master ノード: 前述と同様に、Master ノードの追加に必要となるトークンを出力させます。
myadmin@ubuntu-22-04:~$ kubeadm token create --print-join-command
Master ノード: 加えて、Master ノードの追加には、certificate-key の情報が必要です。このコマンドでは内部の証明書の情報が変わりますが、全体的に変更されるため、既存に影響はありません。
myadmin@ubuntu-22-04:~$ sudo kubeadm init phase upload-certs --upload-certs
Master ノード: Master ノードの追加します。追加する Master ノード上で実行します。これには以下のように kubeadm init
の出力の内容を実行します。Worker ノードの追加と比較し、--control-plane --certificate-key [certificate-key]
が追加で必要となります。
myadmin@ubuntu-22-04:~$ sudo kubeadm join s00-int-k8s-cluster-n001.si1230.com:6443 --token [token] --discovery-token-ca-cert-hash [discovery-token-ca-cert-hash] --control-plane --certificate-key [certificate-key]
クラスターの初期化(参考)
ここまでの手順は、おそらく「慣れるまで」または「意図した設計にできるまで」、何度もやり直すことになると思います。その際、0 から作り直すは大変なので、kubeadm
ではリセット機能が用意されています。
まず、既にクラスターに参加しているノードが存在している場合、Master ノードで以下のように実行し、ノードを切り離し、削除します。以下の例では s00-int-k8s-worker-v001
を削除しています。
myadmin@ubuntu-22-04:~$ kubectl drain s00-int-k8s-worker-v001 --delete-local-data --force --ignore-daemonsets
myadmin@ubuntu-22-04:~$ kubectl delete node s00-int-k8s-worker-v001
次に、各ノードで以下のようにリセットし、システムを再起動します。特に順序性は問わないようではありますが、経験上、Master ノードを最後に実行する方が適切な気がしています。
myadmin@ubuntu-22-04:~$ sudo kubeadm reset -f
myadmin@ubuntu-22-04:~$ sudo systemctl reboot
参考
- https://kubernetes.io/blog/2018/07/09/ipvs-based-in-cluster-load-balancing-deep-dive
- https://metallb.universe.tf/installation/