Kubernetes install

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3680051/de2f4686-f153-8b47-ebf0-ad8b324eedfa.png)




## はじめに
昨今の機械学習環境で、Kubernetesが結構流行っている印象を受ける。私の周りの方々もを使っているので、それにならってインストール手順を連携する。

これを見た読者が安定的にKubernetes環境を構築できると嬉しい。

いきなり複数台のサーバでクラスタを構成してもいいが、私は1つ1つ確認しながら進めていった方がいいと思う。
なるべく、飛躍・伏線の内容にデプロイを進めていきたい。
(伏線とは、手順書通りではあるが目的のわからない設定を変更し、最後の方でその理由が分かるパターンである。)

## 参考文献

[Kubernetes document(日本語版)](https://kubernetes.io/ja/docs/home/)

公式ドキュメントからのスタート地点は、「はじめに」から以下の図のように進む。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3680051/806dbc3e-e9a7-da8e-f21a-adbf5c12bdb3.png)

## 前提条件
サーバ1台 ただし2コア

## インストール前の確認事項

### MACアドレスの確認

Kubernetesは通常、複数台のサーバ上で作動する。
その際、異なるサーバ間でNICのMACアドレスが被ってしまうと、Kubernetes本体がデバイスを識別できなくなってしまう。

現在は1台のサーバでデプロイしているが、ノードを追加する場合は確認しておかなければならない。

MACアドレスは、サーバのそれぞれのデバイスに割り当てられたアドレスである。サーバの中にはNICはdisk等様々なデバイスが存在し、その数だけアドレスも存在する。
```
[実行コマンド]
ip link

[結果]
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN mode DEFAULT group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
2: enp0s3: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP mode DEFAULT group default qlen 1000
    link/ether 08:00:27:b7:18:9c brd ff:ff:ff:ff:ff:ff
3: enp0s8: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP mode DEFAULT group default qlen 1000
    link/ether 08:00:27:ba:49:07 brd ff:ff:ff:ff:ff:ff

```
今回、NICはip linkコマンドで確認したところ2枚刺さっており、それぞれのMACアドレスが分かった。(08:00:27:b7:18:9c の部分)

### product_uuidの確認
product_uuidというのは、1つのサーバに1つだけ存在するidである。

これも、複数台のサーバを動かすことを前提としているKubernetesにとって、一意である必要がある。
今回は、1台のサーバでのみデプロイしているので本来であれば確認する必要はない。

しかし、今後の継続できなデプロイを行っていくためには確認しておいた方がいい。

product_uuidは、/sys/class/dmi/id/product_uuidに保存されている。
/sys は、システムのカーネルおよびハードウェアに関する情報や設定を提供する仮想ファイルシステムである。
そこに、uuidも保存されている。

```
[実行コマンド]
sudo cat /sys/class/dmi/id/product_uuid 

[結果]
628e8bb7-710f-8649-ace8-5b3b6c499196
```

### 必須ポートの確認

Kubernetesでは、6443が必須ポートとなる。
-vは、詳細モード(verbose mode)のことであり、コマンドの結果を詳細に表示する。
コマンドのインプットの内容が変わるわけではないので、つけなくてもいい。

```
[実行コマンド]
nc 127.0.0.1 6443 -v

[結果]
nc: connect to 127.0.0.1 port 6443 (tcp) failed: Connection refused
```
Connection refusedと出ているが、問題ない。
むしろここで、他のサービスが検出されてしまっていると、Kubernetesが6443ポートを扱えなくなってしまう。



## コンテナランタイムCRI-Oのインストール

今回利用するコンテナCRI-Oとする。
CRI-Oは、Kubernetesと相性の良いランタイムである。
というか、Kunernetes用に作られたランタイムである。

[CRI-O install](https://qiita.com/haru_yama/items/67241d0b202c76c1e350)

## kubeadm、kubelet、kubectlのインストール

ここから、kubernetesに必要なパッケージのインストールを行う。

### 1.aptのパッケージ一覧を更新し、Kubernetesのaptリポジトリーを利用するのに必要なパッケージをインストール

ドキュメントの以下の箇所を参考にする。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3680051/cc860486-9a58-fcea-d280-aa5785d59d3a.png)

```
[実行コマンド]
sudo apt-get update

[結果]
Hit:1 http://jp.archive.ubuntu.com/ubuntu jammy InRelease     
Get:2 http://jp.archive.ubuntu.com/ubuntu jammy-updates InRelease [128 kB]      
Get:3 http://download.opensuse.org/repositories/devel:/kubic:/libcontainers:/stable:/cri-o:/1.23/xUbuntu_22.04  InRelease [1,626 B]
Get:4 http://download.opensuse.org/repositories/devel:/kubic:/libcontainers:/stable/xUbuntu_20.04  InRelease [1,642 B]
Hit:5 http://jp.archive.ubuntu.com/ubuntu jammy-backports InRelease
Get:6 http://jp.archive.ubuntu.com/ubuntu jammy-security InRelease [129 kB]
Get:7 http://jp.archive.ubuntu.com/ubuntu jammy-updates/main amd64 Packages [1,790 kB]
Get:8 http://jp.archive.ubuntu.com/ubuntu jammy-updates/universe amd64 Packages [1,101 kB]
Get:9 http://jp.archive.ubuntu.com/ubuntu jammy-updates/universe Translation-en [255 kB]
Get:10 http://jp.archive.ubuntu.com/ubuntu jammy-security/main amd64 Packages [1,583 kB]
Get:11 http://jp.archive.ubuntu.com/ubuntu jammy-security/universe amd64 Packages [883 kB]
Fetched 5,873 kB in 4s (1,673 kB/s)                                  
Reading package lists... Done
```
続いて、HTTPS通信を行うためのパッケージを取得する。
ここでは、主にパッケージを取得するためのパッケージをインストールする。
例えばHTTPSで取得すツールや、証明書を発行・管理するツールなどである。

```
[実行コマンド]
sudo apt-get install -y apt-transport-https ca-certificates curl gpg

[結果]
Reading package lists... Done
Building dependency tree... Done
Reading state information... Done
ca-certificates is already the newest version (20230311ubuntu0.22.04.1).
ca-certificates set to manually installed.
curl is already the newest version (7.81.0-1ubuntu1.16).
curl set to manually installed.
gpg is already the newest version (2.2.27-3ubuntu2.1).
gpg set to manually installed.
(続く)
```
パッケージインストールは完了した。

### 2.Kubernetesパッケージリポジトリーの公開署名キーをダウンロード

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3680051/96ce01c1-d2c3-9958-c493-f310fcf392de.png)


まずは、URLが正しいか確認する。
```
[実行コマンド]
curl -fsSL https://pkgs.k8s.io/core:/stable:/v1.30/deb/Release.key

[結果]
-----BEGIN PGP PUBLIC KEY BLOCK-----
Version: GnuPG v2.0.15 (GNU/Linux)

mQENBGMHoXcBCADukGOEQyleViOgtkMVa7hKifP6POCTh+98xNW4TfHK/nBJN2sm
u4XaiUmtB9UuGt9jl8VxQg4hOMRf40coIwHsNwtSrc2R9v5Kgpvcv537QVIigVHH
(続く)
```
URLが正しいことが分かった。
次にgpg --dearmorで、GPGキーをバイナリ形式に変換して保存する。

```
[実行コマンド]
curl -fsSL https://pkgs.k8s.io/core:/stable:/v1.30/deb/Release.key | sudo gpg --dearmor -o /etc/apt/keyrings/kubernetes-apt-keyring.gpg

[確認コマンド]
ll /etc/apt/keyrings/

[結果]
total 12
drwxr-xr-x 2 root root 4096 Jul  9 11:33 ./
drwxr-xr-x 8 root root 4096 Jul  7 05:50 ../
-rw-r--r-- 1 root root 1200 Jul  9 11:33 kubernetes-apt-keyring.gpg
```
kubernetes-apt-keyring.gpgが作成されていることが確認できた。
ちなみにcatで表示するとバイナリの文字が出てくる。

### 3.aptリポジトリを登録する
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3680051/b2e36d9d-2b12-7647-7b80-0a797ee0c130.png)

```
[実行コマンド]
echo 'deb [signed-by=/etc/apt/keyrings/kubernetes-apt-keyring.gpg] https://pkgs.k8s.io/core:/stable:/v1.30/deb/ /' | sudo tee /etc/apt/sources.list.d/kubernetes.list

[結果]
deb [signed-by=/etc/apt/keyrings/kubernetes-apt-keyring.gpg] https://pkgs.k8s.io/core:/stable:/v1.30/deb/ /

[確認コマンド]
cat /etc/apt/sources.list.d/kubernetes.list

[結果]
deb [signed-by=/etc/apt/keyrings/kubernetes-apt-keyring.gpg] https://pkgs.k8s.io/core:/stable:/v1.30/deb/ /
```
リポジトリが登録されたのを確認できた。

### 4.kubelet kubeadm kubectlのインストール
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3680051/20fe5e96-db30-319a-182e-0412ffb0295c.png)


```
[実行コマンド]
sudo apt update

[結果]
Hit:2 http://jp.archive.ubuntu.com/ubuntu jammy InRelease                           
Hit:3 http://jp.archive.ubuntu.com/ubuntu jammy-updates InRelease                                      
Get:1 https://prod-cdn.packages.k8s.io/repositories/isv:/kubernetes:/core:/stable:/v1.30/deb  InRelease [1,186 B]
Hit:4 http://jp.archive.ubuntu.com/ubuntu jammy-backports InRelease
(続く)
```
次にインストールを行う。
```
[実行コマンド]
sudo apt-get install -y kubelet kubeadm kubectl

[結果]
Reading package lists... Done
Building dependency tree... Done
Reading state information... Done
(続く)
```
次に、バージョンを固定する。
```
[実行コマンド]
sudo apt-mark hold kubelet kubeadm kubectl

[結果]
kubelet set on hold.
kubeadm set on hold.
kubectl set on hold.
```

## cgroupドライバーの設定

以下の部分を参考にして、cgroup ドライバーを設定する。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3680051/7eb8e8d3-6964-ad82-31d8-2ada3ca46c0c.png)

cgroup（control group）は、Linuxカーネルの機能で、プロセスやリソースをグループ化し、そのグループごとにリソース制御や管理を行うためのもの。

cgroupドライバーは、このcgroupを操作・管理するためのソフトウェアコンポーネントである。

Kubernetesでは、kubeletとCRI（Container Runtime Interface）で使用されるcgroupドライバーを一致させることが重要。

```
[実行コマンド]
sudo vi /etc/default/kubelet

[結果]
KUBELET_EXTRA_ARGS=--cgroup-driver=cgroupfs
```
設定が完了しているか、確認する。

```
[実行コマンド]
cat /etc/default/kubelet

[結果]
KUBELET_EXTRA_ARGS=--cgroup-driver=cgroupfs
```
問題無く設定が完了していることが分かった。


### kubeletの再起動

```
[実行コマンド]
systemctl daemon-reload

[結果]
==== AUTHENTICATION COMPLETE ===
```

```
[実行コマンド]
systemctl restart kubelet

[結果]
==== AUTHENTICATION COMPLETE ===
```

kubeletの起動状況を確認する。
```
[実行コマンド]
sudo systemctl status kubelet

[結果]
● kubelet.service - kubelet: The Kubernetes Node Agent
     Loaded: loaded (/lib/systemd/system/kubelet.service; enabled; vendor preset: enabled)
    Drop-In: /usr/lib/systemd/system/kubelet.service.d
             └─10-kubeadm.conf
     Active: activating (auto-restart) (Result: exit-code) since Tue 2024-07-09 12:06:13 UTC; 6s ago
```
定期的に再起動がかかっている。
しかし、これは問題ないらしいので、引き続きkubeadm initにてクラスタ構築を行う。

## kubedam init 実行

一旦kubeletを停止する。
```
[実行コマンド]
sudo systemctl stop kubelet

[確認コマンド]
...
Active: inactive (dead) (Result: exit-code) since Tue 2024-07-09 12:18:16 UTC; 56s ago
...
```
そのうえで、kubeadm initを行う。

まず、swap領域をオフにする。

```
[実行コマンド]
sudo swapoff -a
```
次に、IPフォワーディング(ネットワークインターフェースに受信したIPパケットを、他のネットワークインターフェースへ転送する機能)を有効にする。
net.ipv4.ip_forwardはIPフォワーディングの設定を管理するパラメータで、1を設定することでIPフォワーディングを有効にする。

```
[実行コマンド]
sudo sysctl -w net.ipv4.ip_forward=1

[結果]
net.ipv4.ip_forward=1
```
デーモンをリロードする。
```
[実行コマンド]
systemctl daemon-reload
```
最後にkubeadm initを実行する。
```
[実行コマンド]
sudo kubeadm init

[結果]
[init] Using Kubernetes version: v1.30.2
[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'
W0709 12:24:58.778191   29048 checks.go:844] detected that the sandbox image "registry.k8s.io/pause:3.6" of the container runtime is inconsistent with that used by kubeadm.It is recommended to use "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 [kube-controller01 kubernetes kubernetes.default kubernetes.default.svc kubernetes.default.svc.cluster.local] and IPs [10.96.0.1 10.0.2.15]
[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 [kube-controller01 localhost] and IPs [10.0.2.15 127.0.0.1 ::1]
[certs] Generating "etcd/peer" certificate and key
[certs] etcd/peer serving cert is signed for DNS names [kube-controller01 localhost] and IPs [10.0.2.15 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"
[kubelet-check] Waiting for a healthy kubelet. This can take up to 4m0s
[kubelet-check] The kubelet is healthy after 501.194996ms
[api-check] Waiting for a healthy API server. This can take up to 4m0s
[api-check] The API server is healthy after 7.501992559s
[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] Skipping phase. Please see --upload-certs
[mark-control-plane] Marking the node kube-controller01 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 kube-controller01 as control-plane by adding the taints [node-role.kubernetes.io/control-plane:NoSchedule]
[bootstrap-token] Using token: 14t6wj.zni6a9skfyc94gej
[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/

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

kubeadm join 10.0.2.15:6443 --token 14t6wj.zni6a9skfyc94gej \
        --discovery-token-ca-cert-hash sha256:427292283adab313e03559d91265bfe64c0fcccb031a455040f479851662a095
```

initが完了した。
kubeletのステータスを確認する。

```
[実行コマンド]
sudo systemctl status kubelet

[結果]
Active: active (running) since Tue 2024-07-09 12:25:43 UTC; 1min 17s ago
```
activeになっていることが確認できた。

## kubectlをrootユーザ以外でも実行可能にする

公式ドキュメントの以下を参照する。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3680051/3c0140c5-b1af-978d-ad60-d7958134c52c.png)



root権限を持つユーザの場合、init後に以下を実施する。
```
export KUBECONFIG=/etc/kubernetes/admin.conf

sudo chown mainte:mainte /etc/kubernetes/admin.conf
```
`KUBECONFIG`という環境変数は、`kubectl`コマンドなどを実行する際に利用される変数である。
これが設定されていないと、kubectl getコマンドなどでノードの情報などが参照できないため、コマンドが失敗する。

## Kubernetes動作確認
```
mainte@kube-controller01:~$ kubectl get pod
No resources found in default namespace.
mainte@kube-controller01:~$ kubectl get ns
NAME              STATUS   AGE
default           Active   20m
kube-node-lease   Active   20m
kube-public       Active   20m
kube-system       Active   20m
```
でた！嬉しい！

```
kubectl -n kube-system get pod
NAME                                        READY   STATUS    RESTARTS   AGE
coredns-7db6d8ff4d-58mm5                    0/1     Pending   0          20m
coredns-7db6d8ff4d-g5rkv                    0/1     Pending   0          20m
etcd-kube-controller01                      1/1     Running   2          20m
kube-apiserver-kube-controller01            1/1     Running   1          20m
kube-controller-manager-kube-controller01   1/1     Running   0          20m
kube-proxy-94xnx                            1/1     Running   0          20m
kube-scheduler-kube-controller01            1/1     Running   1          20m
```

```
kubectl get node
NAME                STATUS     ROLES           AGE   VERSION
kube-controller01   NotReady   control-plane   23m   v1.30.2
```
POD CIDR確認
```
kubectl describe node kube-controller01 | less
PodCIDR:                      192.168.0.0/24
PodCIDRs:                     192.168.0.0/24
```

## 次にやること

今回、基本的なKubernetes環境を構築した。
しかし、今後はpod間の連携を行いたい場合、podが利用するネットワークを指定する必要がる。

そのため次は、コンテナネットワークインターフェースのCalicoをインストールする。
[Calico install](https://qiita.com/haru_yama/items/30e96adde58ef197238d)