Ubuntu で K8S クラスタ構築

## はじめに
今更ながらマネジメントサービスじゃなく手動でk8sクラスタ環境構築してみる。

[Kubernetes Setup](https://kubernetes.io/docs/setup/independent/install-kubeadm/#)

## k8s コンポーネント
| 名前 | 概要 |
| --- | --- |
| kubeadm | k8s環境構築ツール | 
| kubectl | 操作用CLI |
| kube-apiserver | k8s APIを提供する |
| kube-scheduler | 起動するポッドをノードに割り当て |
| kube-controller-manager | 様々なコントローラを実行する |
| kubelet | コンテナランタイムと連携して実際にコンテナを制御する |
| kube-proxy | Serviceリソースが作られた際にClusterIP や NodePort宛のトラフィックをPodに転送する |
| kube-dns(CoreDNS) | k8sクラスタ内の名前解決やサービスディスカバリに利用される |
| etcd | k8s内の全ての情報が保存されるKVS |

## Requirements
* 2GB以上のメモリ
* 2CPU以上
* クラスタ内の各ノードが相互に通信できること
* hostname、MACaddress、product_uuid がユニークであること
* 必要なポートが空いていること
* スワップ無効(kueletが正しく動かない)

## 環境
| 役割 | OS |
| --- | --- |
| Master | Ubuntu 16.04.5 LTS |
| Node01 | Ubuntu 16.04.5 LTS |
| Node02 | Ubuntu 16.04.5 LTS |

## 必要なポート
### Master-Node
| Protocol | Direction | Port Range | Purpose | Used By |
| --- | --- | --- | --- | --- |
| TCP | Inbound | 6443* | Kubernetes API server | All |
| TCP | Inbound | 2379-2380 | etcd server client API | kube-apiserver, etcd |
| TCP | Inbound | 10250 | Kubelet API | Self, Control plane |
| TCP | Inbound | 10251| kube-scheduler | Self |
| TCP | Inbound | 10252| kube-controller-manager | Self |

### Worker-Node
| Protocol | Direction | Port Range | Purpose | Used By |
| --- | --- | --- | --- | --- |
| TCP | Inbound | 10250 | Kubelet API | Self, Control plane |
| TCP | Inbound | 30000-32767 | NodePort Services** | All |

### Dockerインストール(最新)
```
$ apt-get update
$ apt-get install -y docker.io
```

### Dockerインストール(バージョン指定)
最新の18.09だとエラーが出てしまうので18.06を指定。

```
$ apt-get update
$ apt-get install -y apt-transport-https ca-certificates curl software-properties-common
$ curl -fsSL https://download.docker.com/linux/ubuntu/gpg | apt-key add -
$ add-apt-repository "deb https://download.docker.com/linux/$(. /etc/os-release; echo "$ID") (lsb_release -cs) stable"
$ apt-get update && apt-get install -y docker-ce=$(apt-cache madison docker-ce | grep 18.06 | head -1 | awk '{print $3}')
```

### k8sコンポーネントインストール

```
$ apt-get update && apt-get install -y apt-transport-https curl
$ curl -s https://packages.cloud.google.com/apt/doc/apt-key.gpg | apt-key add -
$ cat <<EOF >/etc/apt/sources.list.d/kubernetes.list
deb http://apt.kubernetes.io/ kubernetes-xenial main
EOF
$ apt-get update
$ apt-get install -y kubelet kubeadm kubectl
$ apt-mark hold kubelet kubeadm kubectl
```

ここでインストールされるのは3つ。

* kubeadm
* kubelet
* kubectl

### kubeadm実行

kubeadmでk8sクラスタを作ります。

swapを無効化

```
$ swapoff -a
```

### k8s クラスタを初期化

`kubeadm init`のみでクラスタを構成するとネットワークが構成されず、
ノードのステータスがNotReadyとなりました。

後追いでネットワーク周りを調整するのは面倒だったので
大人しくkubeadm init時にCalicoを考慮したオプションを指定。

```
$ kubeadm init --pod-network-cidr=192.168.0.0/16
```

ログが流れていきますがその中でk8sコンポーネントが作成されます。

```
[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"
・
・
・
[addons] Applied essential addon: CoreDNS
[addons] Applied essential addon: kube-proxy
```

```

Your Kubernetes master 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

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 machines by running the following on each node
as root:

  kubeadm join 172.31.39.215:6443 --token iqk2c6.xmg85ojpn2iv9gz8 --discovery-token-ca-cert-hash sha256:34ce2b3c0d7946630d0928a20f7a8728df7a9379cd644e421acf6eeb456d68fa

```

最後の`kubeadm join ～`をWorker-Nodeで実行する事でk8sクラスタに参加する事ができます。

下記は初期化後に実行。

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

### Calicoのインストール

[Quickstart for Calico on Kubernetes](https://docs.projectcalico.org/getting-started/kubernetes/quickstart) を参考にします。

```
$ kubectl apply -f https://docs.projectcalico.org/manifests/calico.yaml
```

podが正常に起動してくることを確認

```
$ kubectl get pod -A | grep calico
kube-system   calico-kube-controllers-789f6df884-jv9rw   1/1     Running   0          143m
kube-system   calico-node-5sldv                          1/1     Running   0          143m
kube-system   calico-node-kvk6h                          1/1     Running   0          143m
kube-system   calico-node-vqtpr                          1/1     Running   0          143m
kube-system   calico-node-xpt4z                          1/1     Running   0          143m
```


### ワーカーノードをクラスタに追加

ワーカーノードで先ほどの `kubeadm join *` を実行してK8Sに追加。
マスターでノード情報を取得します。

```
$ kubectl get nodes
NAME               STATUS  ROLES    AGE    VERSION
ip-172-31-33-209   Ready   <none>   104s   v1.18.3
ip-172-31-39-215   Ready   master   21m    v1.18.3
ip-172-31-47-222   Ready   <none>   14m    v1.18.3
```

### Calicoの疏通確認
[Kubernetes policy, basic tutorial](https://docs.projectcalico.org/security/tutorials/kubernetes-policy-basic) を参考にします。

テスト用のNameSpaceを作成して疏通確認用のnginxのdeploymentを作成。

```
$ kubectl create ns policy-demo

$ kubectl create deployment --namespace=policy-demo nginx --image=nginx

$ kubectl expose --namespace=policy-demo deployment nginx --port=80
```

busyboxをデプロイしてnginxの名前でアクセス。

```
$ kubectl run --namespace=policy-demo access --rm -ti --image busybox /bin/sh

/ #

/ # wget -q nginx -O -
```

下記のようにnginxの応答があればOK。

```
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
    body {
        width: 35em;
        margin: 0 auto;
        font-family: Tahoma, Verdana, Arial, sans-serif;
    }
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p>

<p>For online documentation and support please refer to
<a href="http://nginx.org/">nginx.org</a>.<br/>
Commercial support is available at
<a href="http://nginx.com/">nginx.com</a>.</p>

<p><em>Thank you for using nginx.</em></p>
</body>
</html>
```