よく使っているkubeadmを使ったKubernetes検証環境の構築

# 概要
私がKubernetes環境での検証用途でよく利用しているkubeadmの構築方法についてまとめてみました。
Kubernetes系の記事を書いた際にも参考用として再利用もできると思い、整理を行ってみた次第です。

## 本記事の対象
* kubernetesを触り始めた方
* kubeadmでKubernetesを構築してみたい方
* 複数台のノードでのKubernetesを構築してみたい方

## kubeadmについて
個人的には比較的簡単にUbuntuなどの環境上にKubernetes環境を構築できるツールとして利用しています。
セットアップはkubeadm init、クラスタへの参加はkubeadm joinなどでどれも簡単に実施できます。
[公式ドキュメント](https://kubernetes.io/ja/docs/reference/setup-tools/kubeadm/)

# 構築手順
## 構成図
今回は3台のUbuntuマシンを用いてMaster1台とWorker2台の構成で作成していきます。
マシンのスペック基準は以下公式ドキュメントに記載があるため、そちらに準拠していれば問題ございません。
[公式ドキュメント](https://kubernetes.io/ja/docs/setup/production-environment/tools/kubeadm/install-kubeadm/)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/406495/9c6e82d3-807e-5e0f-6c86-f71f0689be14.png)

## 全マシン共通設定
まずはMasterとWorkerで共通の設定をしていきます。

### swap領域の無効化
kubeletを利用する前提条件としてswap領域がオフである必要があるため無効にします。
※マシン再起動後も永続的に無効にする場合は/etc/fstab内のswapfileの記載をコメントアウト
```shell
sudo swapoff –a

# 永続的なswap領域無効化
sudo vi /etc/fstab
```

### Firewallの無効化
検証用途などで利用するため、一旦Firewallは全て無効にしておきます。
```shell
sudo systemctl stop ufw
sudo systemctl disable ufw
```

### apt-transport-httpsをインストール
aptパッケージのダウンロードをhttpsでも可能にするためのパッケージをインストールします
```shell
sudo apt-get install apt-transport-https
```

### Kubernetesのリポジトリの登録
Kubernetes関連のパッケージをダウンロードのためにリポジトリの登録をします。
```shell
curl -s https://packages.cloud.google.com/apt/doc/apt-key.gpg | sudo apt-key add -
sudo tee /etc/apt/sources.list.d/kubernetes.list << EOF >/dev/null
deb http://apt.kubernetes.io/ kubernetes-xenial main
EOF
sudo apt update
```

### Kubernetes関連パッケージのインストール
kubeadmの稼働に必要なKubernetes関連のパッケージをインストールしていきます。
以下ではバージョンをそれぞれ指定しておりますが、指定無しで最新版もしくは各々の環境に合わせてバージョンを指定して下さい。
```shell
sudo apt-get install -y kubelet=1.24.3-00 kubeadm=1.24.3-00 kubectl=1.24.3-00 docker.io=20.10.12-0ubuntu2~20.04.1
```

参考としてUbuntuの場合は以下のようなコマンドでダウンロードできるパッケージを確認できます。
```shell
apt-cache show kubelet | grep Version
```

### オーバーレイネットワークの設定
Kubernetesで使うオーバーレイネットワークのためにカーネルのパラメータを変更します。
```shell
sudo sysctl net.bridge.bridge-nf-call-iptables=1
```

以上が全台共通の最低限の設定が完了です。

## MasterNode用マシンのセットアップ
ここからMasterNode側でのセットアップを進めていきます。

### kubeadm initの実行
kubeadm initコマンドでKubernetesのセットアップを行います。
kubeadm initではkubeletの起動や証明書の作成などを行っているようです。
※pod-network-cidrでは今回CNIに使うFlannelの要件に準拠して「10.244.90.0/16」を指定しています。
```shell
sudo kubeadm init --pod-network-cidr=10.244.0.0/16
```

kubeadm initを実行しますと出力の最後に以下のようなコマンドの記載があります。
こちらは後程WorkerNodeの設定の際に利用するため、メモをしておいてください。
```shell
kubeadm join 172.22.18.211:6443 --token (以降省略)
```

### kubeconfigの設定
kubectlコマンドを実行できるようにkubeconfigの設定をしておきます。
```
mkdir -p $HOME/.kube
sudo cp /etc/kubernetes/admin.conf $HOME/.kube/config
sudo chown $(id -u):$(id -g) $HOME/.kube/config
export KUBECONFIG=$HOME/.kube/config
```

### Flannel（CNI）のデプロイ
Pod間通信などで利用するCNIとしてFlannelをデプロイします。
公式のgithub上にマニフェストも置いてありますので、そのまま利用しています。
[Flannel github](https://github.com/flannel-io/flannel)
```shell
kubectl apply -f https://raw.githubusercontent.com/flannel-io/flannel/v0.19.1/Documentation/kube-flannel.yml
```

以上でMasterNode側のセットアップが完了です。

## WorkerNode用マシンのセットアップ
WorkerNodeのセットアップを進めていきますが、ここでは先程のMasterNodeのクラスタに参加するという1手順のみとなります。

### Kubernetesクラスタに参加
先程MasterNodeのセットアップの際に **kubeadm init**で出力されたコマンドをメモいただいたかと思います。
そのコマンドを各WorkerNodeで実行いただく形になります。
```shell
# IPアドレス等は環境に合わせて変更ください
kubeadm join 172.22.18.211:6443 --token (以降省略)

#出力
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.
```
問題なくKubernetesクラスタに参加が出来ましたら、WorkerNode側の最低限の設定は完了です。

### クラスタの参加Nodeの確認
MasterNodeに戻り以下コマンドでWorkerNodeがクラスタに参加できているか確認しておきます。
STATUSがReadyになっていれば問題ないです。
```shell
kubectl get nodes

NAME             STATUS   ROLES           AGE     VERSION
ubuntu-kube11    Ready    control-plane   3h19m   v1.24.3
ubuntu-kube12    Ready    <none>          3h4m    v1.24.3
ubuntu-kube13    Ready    <none>          177m    v1.24.3
```

以上がkubeadmを使ったKubernetesの構築なります。

## nginxをデプロイしてみる
せっかくなので動作確認も兼ねて構築したKubernetes環境上でnginxのPodでも構築してみます。

### nginxのデプロイ
以下マニフェストファイルでnginxをデプロイしてみます。
```deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx
  labels:
   app: nginx
spec:
  selector:
    matchLabels:
      app: nginx
  replicas: 2
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx
        ports:
        - containerPort: 80
```
```shell
kubectl apply -f deployment.yaml
```

### 作成されたPodの動作確認
作成したPodのIPを確認して、curlコマンドでhtmlが返ってくるか見てみます。

```
kubectl get pods -o wide

#出力
NAME                     READY   STATUS    RESTARTS   AGE   IP           NODE             NOMINATED NODE   READINESS GATES
nginx-6c8b449b8f-62zhh   1/1     Running   0          16s   10.244.2.3   ubuntu-kube13    <none>           <none>
nginx-6c8b449b8f-zrgpc   1/1     Running   0          16s   10.244.1.2   ubuntu-kube12    <none>           <none>    
```
今回はマニフェストでreplicasを2に指定したため、2台Podが作成されています。
また、出力のNode列を見てみるとPodは2つのWorkerNodeにそれぞれ作成されている様子も確認できます。
それではどちらかのIPにcurlを投げてみます。
```shell
curl 10.244.2.3

# 出力
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
~~
省略
~~
</html>
```
nginxのWelcomeページの情報が返ってきたことが確認でき、無事にnginxが動作していることが確認できました。

## nginxの外部公開
前述までで最終的にcurlで動作していることはわかりましたが、実際にブラウザで確認もしてみたいため、
外部公開のLBのセットアップもしてみます。
今回はLBとしてMetallbを用いてみます。

### Metallbのデプロイ
Metallbのデプロイを行います。
Flannelの時と同様にgihub上にマニフェストが置いてあるため、そのまま利用します。
[metallb github](https://github.com/metallb/metallb)
```shell
kubectl apply -f https://raw.githubusercontent.com/metallb/metallb/v0.10.1/manifests/namespace.yaml
kubectl apply -f https://raw.githubusercontent.com/metallb/metallb/v0.10.1/manifests/metallb.yaml
```

### configmapのデプロイ
Metallbで使うプロトコルやクラスタの外向けのIPアドレスプールなどを定義するため、
以下マニフェストのconfigmapをデプロイします。
※addressesのIPプールはご利用の環境で空いているアドレスをご記載ください。
```configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  namespace: metallb-system
  name: config
data:
  config: |
    address-pools:
    - name: default
      protocol: layer2
      addresses:
      - 172.22.18.216-172.22.18.220
```
用意したマニフェストでデプロイ
```
kubectl apply -f configmap.yaml
```

### nginx podのLBをデプロイ
ここまでの手順でMetallbを利用する準備が出来たため、最後にnginx用のserviceをデプロイします。
serviceが前述で展開したnginxのpodへの入り口になります。
マニフェストの参考例は以下です。
```service.yaml
apiVersion: v1
kind: Service
metadata:
  labels:
    app: nginx-lb
  name: nginx-lb
spec:
  ports:
  - port: 8080
    protocol: TCP
    targetPort: 80
  selector:
    app: nginx
  type: LoadBalancer
```
用意したマニフェストでデプロイ
```shell
kubectl apply -f service.yaml
```

デプロイしたserviceを確認すると、EXTERNAL-IPを確認することができます。
このEXTERNAL-IPがクラスタの外向けのIPアドレスになります。
```shell
kubectl get svc nginx-lb

#出力
NAME       TYPE           CLUSTER-IP       EXTERNAL-IP     PORT(S)          AGE
nginx-lb   LoadBalancer   10.102.105.222   172.22.18.216   8080:30333/TCP   43s
```

確認したIPアドレスと同じネットワーク領域にある環境のブラウザにて、
IPアドレス：ポート番号（8080）で接続をすると以下のようにブラウザ上でも確認ができました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/406495/7ac46d4e-1286-3123-f2fa-147a92461c0e.png)


# 最後に
今回はkubeadmを使ったkubernetesの構築についてまとめてみました。
Kuberneteを手軽に利用できる環境としては、AKSやGKEなどが非常に便利だと思います。
一方でもし仮想マシンなどでマシンを複数用意できる環境がある場合などは、
こちらも手軽に用意はできるため初めて触るという方にもおすすめかなと思います。