Ubuntu に Kubernetesクラスタを構築

今回構築する環境と必要なモノ

構築手順の確認と検証のためとなるので、下記が必要なものとなります。
 ・ESXi
 ・Ubuntu
これだけですね。

ESXiに3つの仮想マシンを作成します。
それらは全てUbuntu。
ひとつがコントロールプレーンと呼ばれるMasterノード。
他2つがWorkerノードとなります。

ESXi:仮想マシン(Ubuntu)の用意

とにもかくにもESXi上に仮想マシンとしてUbuntuを乗せる

Ubuntuのインストール過程は省略。
インストールには多少の時間がかかるので、3台を一度に作成してインストールを開始させてしばらく放置。(とはいえ、サーバがTM200でもそんなに時間はかからなかったかな)

<注意事項>
 ・vCPUは2以上
 ・メモリは2GB以上
ここはデフォルトから手動で変更しないと下回ってるので要変更。
しかもメモリ2GBはアプリが使える領域がほとんどないそうなので、少し増やしておくと良いかも。
また、Ubuntuインストール中にネットワーク設定でDHCPからManualに変更してIPを固定しよう。

仮想マシンの作成
Ubuntuインストール中 ネットワーク設定の変更を忘れずに

全てのUbuntu:全ノードで共通の作業

iptablesの設定

参考URL:https://kubernetes.io/ja/docs/setup/production-environment/tools/kubeadm/install-kubeadm/

br_netfilter モジュールがロードされているか確認。
ついでにoverlayについても見ておく。

$ sudo lsmod | grep br_netfilter
$ sudo lsmod | grep overlay

うちはロードされていなかったので、下記のようにしてロードしておく。

$ sudo modprobe br_netfilter
$ sudo modprobe overlay

続いて /etc/sysctl.d/k8s.conf ファイルを作成し、内容を下記の通りに。

net.bridge.bridge-nf-call-ip6tables = 1
net.bridge.bridge-nf-call-iptables = 1
net.ipv4.ip_forward = 1

/etc/modules-load.d/modules.conf も下記の2分を追加する。

overlay
br_netfilter

編集が終わったら、構成ファイルを反映させる。

$ sudo sysctl --system

今回使用したUbuntuでは問題なかったけど、iptables が nftables API を使う iptables-nft に設定されているとDockerが外部と通信出来ないので、iptables-legacy になっているか確認。

ls -al /etc/alternatives/iptables
lrwxrwxrwx 1 root root 25 Feb 23 08:55 /etc/alternatives/iptables -> /usr/sbin/iptables-legacy

もし、legacy になっていなかったら、下記のコマンドを打って、legacy となっている番号を選び、変更しておく。

$ sudo update-alternatives --config iptables
There are 2 choices for the alternative iptables (providing /usr/sbin/iptables).
  Selection    Path                      Priority    Status
------------------------------------------------------------
* 0            /usr/sbin/iptables-legacy   20        auto mode
  1            /usr/sbin/iptables-legacy   20        manual mode
  2            /usr/sbin/iptables-nft      10        manual mode

Press <Enter> to keep the current choice[*], or type selection number:

入ってなかったパッケージのインストール

$ sudo apt install apt-transport-https

Dockerのインストールと設定の変更、サービスの有効化

Dockerのインストール

$ sudo apt install docker.io

設定ファイルの変更。
/etc/systemd/system/multi-user.target.wants/docker.service
このファイルの「ExecStart」の末尾に「–exec-opt native.cgroupdriver=systemd」を追加。
(Dockerがsystemdを使うようにしないとダメらしい。最初、これでハマった・・・)

<修正前>
ExecStart=/usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock

<修正後>
ExecStart=/usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock --exec-opt native.cgroupdriver=systemd

Dockerサービスの有効化(サーバ再起動時にDockerサービスが自動的に起動するようにする)

$ sudo systemctl enable docker.service

その他、チョイチョイ設定

Kubernetesのリポジトリ キーを取得して追加。

$ curl -s https://packages.cloud.google.com/apt/doc/apt-key.gpg | sudo apt-key add

Kubernetesリポジトリを追加。

$ sudo apt-add-repository "deb http://apt.kubernetes.io/ kubernetes-xenial main"

swapの無効化

いろいろなサイトに下記コマンドを打つよう記載があるけど、これ意味なくね?
だって、一時的な変更で、サーバー再起動でまた有効になるから・・・

swapoff -a

なので、/etc/fstab を編集するべきでしょう。
このファイルの最後の方にあるswapに関する記述を#でコメントアウト。

#/swap.img      none     swap      sw      0      0

サーバの再起動

$ sudo reboot

kubernetes のインストール

kubelet はMasterサーバだけで良い?という記載もどこかで見かけたけど、とりあえず、全ノードにインストールする。

$ sudo apt install kubeadm kubectl kubelet

Masterノードでの作業:kubernetes クラスタ構築

Kubernetesクラスタの初期化

「kubeadm init」といったコマンドを打つけど、その際に「kubeadm config images pull」もやってね、というメッセージが出ていたので、予め実行しておく。

$ sudo kubeadm config images pull

続いてkubernetesクラスタの初期化。
–node-name は不要かも知れないけど、自ホスト名を明示した。
–apiserver-advertise-address は複数NICを持っているなら書かなきゃダメ。
–pod-network-cidr は後でflannelというネットワークプラグインを使うためのアドレス

$ sudo kubeadm init --node-name k8s-master --apiserver-advertise-address=192.168.1.1 --pod-network-cidr=10.244.0.0/16

しばらく待つと・・・

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/

Then you can join any number of worker nodes by running the following on each as root:

kubeadm join 192.168.1.1:6443 --token oviwhw.tj7hsu26h6hdjnd7 \
    --discovery-token-ca-cert-hash sha256:9ac9be65d23342b4296f940e4d4cb709677a43b184b5300c7404c7ddd3a132a9

「Your Kubernetes control-plane has initialized successfully!」
という表示が現れれば、初期化に成功。
ここまでがけっこう大変かも。

その後は、メッセージに指示されている通り、下記コマンドを実行。

$ mkdir -p $HOME/.kube
$ sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
$ sudo chown $(id -u):$(id -g) $HOME/.kube/config
$ export KUBECONFIG=$HOME/.kube/config

同様にPOD に必要なネットワーク構成をインストール。

kubectl apply -f https://raw.githubusercontent.com/coreos/flannel/master/Documentation/kube-flannel.yml

上手く初期化が行えない場合、

どこかで設定を間違えたか何か作業が抜けているはず。
それらを見直してもう一度「kubeadm init」をするわけだけど、その前にはリセットした方がいい。

# sudo kubeadm reset

んで、その見直した方がいい、という箇所。

ip link で flannel.1 といったNICが残っていたら ip link delete flannel.1 で削除する。
同じくcni0 も削除。
また、/etc/cni/net.d/ 内のファイルも全て削除する。
$home/.kube/config これも削除。

Masterノードのステータス確認

ここまで来れば、Masterノードがきちんと動作しているはず・・・

$ kubectl get nodes
NAME         STATUS   ROLES                  AGE    VERSION
k8s-master   Ready    control-plane,master   4m     v1.23.4

STATUSがReadyになっているのでOKですね。

Workerノードでの作業:kubernetes クラスタ構築(クラスタへの参加)

Workerノードの追加

Masterノードで「kubeadm init」を実行した際、
Then you can join any number of worker nodes by running the following on each as root:
というメッセージに続くコマンドがあった。
これがWorkerノードを追加するコマンドなので、それをWorkerノードで実行する。

$ sudo kubeadm join 192.168.1.1:6443 --token [ここにtokenを入力] --discovery-token-ca-cert-hash sha256:[ここにhashを入力]

ちょっぴし待つと・・・

This node has joined the cluster:
* Certificate signing request was sent to apiserver and a response was received.
* The Kubelet was informed of the new secure connection details.
Run 'kubectl get nodes' on the control-plane to see this node join the cluster.

と表示されてクラスタへ参加出来たことがわかる。

Run ‘kubectl get nodes’ on the control-plane to see this node join the cluster.
という表示もあるので、Masterノード(control-plane)でも確認してみる。

$ kubectl get nodes
NAME         STATUS   ROLES                  AGE    VERSION
k8s-master   Ready    control-plane,master   14m     v1.23.4
k8s-worker1  NotReady <none>                 17s     v1.23.4

NotReadyになっているのはネットワークプラグイン(flannel)のインストールを忘れてたから・・・

2台目のWorkerノードも同様にしてクラスタへ参加させる。
(この時はネットワークプラグインのインストールを済ませた)

$ kubectl get nodes
NAME         STATUS   ROLES                  AGE    VERSION
k8s-master   Ready    control-plane,master   27m     v1.23.4
k8s-worker1  Ready    <none>                 30m     v1.23.4
k8s-worker2  NotReady <none>                 10s     v1.23.4

worker1がReadyなのに対してworker2がNotReadyなのはkubectlが早すぎたから。
1分ほど待ってもう一度実行すると無事worker2もReadyになりましたとさ。

Workerノードが追加出来ないとき

iptablesで6443ポートが開放されていない。
iptablesの設定が難解だから、ということでufwを有効化していると見落としがち。
sudo ufw allow 6443 でポートを開放してあげよう。

tokenは24時間でなくなる

クラスタ構築が完了し、後日、ノードを追加したい場合、「kubeadm join」を行うけれど、tokenは24時間で無効になる。

なので、tokenを再作成しなければならない。

が、まずはtokenが生きているか確認。

$ kubeadm token list

tokenが表示されればまだ使える。
TTLで寿命がわかるので、確認しておこう。

もし何も表示されず、tokenがなくなっていたら下記のようにして再作成。

$ sudo kubeadm token create

hashは下記のようにして確認。

$ openssl x509 -pubkey -in /etc/kubernetes/pki/ca.crt | openssl rsa -pubin -outform der 2>/dev/null | openssl dgst -sha256 -hex | sed 's/^.* //'

これでいつでも参加出来るようになりました。

Podを作成してコンテナを実行する

現在の状況を確認してみる。

$ kubectl get pods
No resources found in default namespace.

まだ何も作ってないので空っぽ。

みんなが試すnginx。
yamlファイルを下記のように書いてみる。

apiVersion: v1
kind: Pod
metadata:
  name: nginx
spec:
  containers:
  -  image: nginx:1.13
     name: nginx
     - containerPort: 80

そして、kubectl でデプロイ。

kubectl apply -f nginx.yaml

正常にデプロイされたか確認。

$ kubectl get pods
NAME   READY  STATUS    RESTARTS  AGE
nginx  0/1    Running   0         1m4s

STATUS が Running となっているのでとりあえずはOK。

よく使うコマンド

全てのpodの状態を見る

$ kubectl get pods --all-namespaces

全てのpodのログを見る

$ kubectl describe pods --all-namespaces

この記事にコメントしてみる