自分用：Bootstrapping Clusters with kubeadm #1

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

# インストール kubeadm
## 前提条件

- OS
    - Ubuntu 16.04+
    - Debian 9
    - CentOS 7
    - RHEL 7
    - Fedora 25/26 (best-effort)
    - HypriotOS v1.0.1+
    - Container Linux (tested with 1800.6.0)
- RAM
    - 2GB以上
- CPU
    - 2CPU以上
- クラスタ内の全マシン間でネットワーク接続が可能なこと
- ホスト名、MACアドレス：ノードごとに一意であること
    - 詳細は[こちら](#macアドレスとproduct_uuidが全てのノードで一意か確認する)
- Port
    - 詳細は[こちら](#必須port)
- Swap
    - **必ず無効にしなければならない**
    - kubeletが正しく機能するためにはswapを無効にしておかなければならない

## MACアドレスとproduct_uuidが全てのノードで一意か確認する

- `ip link`または`ifconfig -a`を利用してNetworkインターフェースのMACアドレスを取得できる
- コマンド：`sudo cat /sys/class/dmi/id/product_uuid`を利用してproduct_uuidを確認できる

ハードウェアデバイスは一意のアドレスを持つ可能性が非常に高いが、一部の仮想マシンは同じ値を持つ場合がある。Kubernetesはこれらの値を利用してノードを一意に識別する。もしこれらの値が各ノードで一意でなかった場合、インストールは失敗する可能性がある。

## Networkアダプターの確認
１つ以上のNetworkアダプターを持っており、Kubernetesコンポーネントがデフォルトルートに到達できない場合、Kubernetesクラスターアドレスが適切なアダプターを経由するようにIPルートを追加することを推奨する。

## 必須Port
###Master node(s)

|Protocol|方向|範囲|目的|利用対象|
|:--|:--|:--|:--|:--|
|TCP|受信|6443[^1]|Kubernetes API server|All|
|TCP|受信|2379-2380|etcd server client API|kube-apiserver, etcd|
|TCP|受信|10250|Kubelet API|Self, Control plane|
|TCP|受信|10251|kube-scheduler|Self|
|TCP|受信|10252|kube-controller-manager|Self|

###Worker node(s)

|Protocol|方向|範囲|目的|利用対象|
|:--|:--|:--|:--|:--|
|TCP|受信|10250|Kubelet API|Self, Control plane|
|TCP|受信|30000-32767|NodePortサービス[^2]|All|

etcd portはマスターノードに含まれているが、独自のetcdクラスターを外部またはカスタムportでホストすることもできる。

使用しているpodネットワークプラグイン（下記参照）も、特定のportを開く必要がある。
各podネットワークプラグインによって異なるので、それらが必要とするportについてはプラグインのドキュメントを参照すること。

[^1]: 上書き可能なPort番号なので、指定したカスタムPortもすべて開いていることを確認する必要がある
[^2]: NodePortサービスのデフォルトPort範囲

## ランタイムのインストール

V1.6.0以降、KubernetesはデフォルトでCRI(Container Runtime Interface)の使用を有効にした。
コンテナランタイムはデフォルトでDockerを使用し、`kubelet`内の組み込み`dockershim`CRIを通して有効にされる。

他のCRIベースのランタイムは次の通り：

- containerd (containerdに組み込まれたCRIプラグイン)
- cri-o
- frakti

詳しくは、[CRIのインストール手順](https://kubernetes.io/docs/setup/cri/)を参照。
”CentOS, RHEL 7.4+”のDockerインストールコマンド

```shell
# Install Docker CE
## Set up the repository
### Install required packages.
    yum install yum-utils device-mapper-persistent-data lvm2

### Add docker repository.
yum-config-manager \
    --add-repo \
    https://download.docker.com/linux/centos/docker-ce.repo

## Install docker ce.
yum update && yum install docker-ce-18.06.2.ce

## Create /etc/docker directory.
mkdir /etc/docker

# Setup daemon.
cat > /etc/docker/daemon.json <<EOF
{
  "exec-opts": ["native.cgroupdriver=systemd"],
  "log-driver": "json-file",
  "log-opts": {
    "max-size": "100m"
  },
  "storage-driver": "overlay2",
  "storage-opts": [
    "overlay2.override_kernel_check=true"
  ]
}
EOF

mkdir -p /etc/systemd/system/docker.service.d

# Restart docker.
systemctl daemon-reload
systemctl restart docker
```

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

これらのパッケージを全てのマシンにインストールする：

- `kubeadm`: クラスタをブートストラップするコマンド。
- `kubelet`: クラスタ内の全てのマシンで動作し、podやコンテナの起動などを行うコンポーネント。
- `kubectl`: クラスタと通信するためのコマンドラインユーティリティー。

kubeadmは`kubelet`や`kubectl`をインストールまたは管理**しない**ので、kubeadmにインストールしたいKubernetesコントロールプレーンのバージョンと確実に一致させる必要がある。
一致させなかった場合、バージョンのズレが生じ、予期せぬバグが発生する可能性がある。
ただし、kubeletとコントロールプレーン間は１つ以内のマイナーバージョンのズレはサポートされているが、kubeletのバージョンがAPIサーバーのバージョンを超えることはない。
例えば、1.7.0で動作しているkubeletは1.8.0のAPIサーバーと完全に互換性があるが、その逆はない。

**警告：　**これらの手順は、システムのアップグレードから全てのKubernetesパッケージを除外する。何故ならばこれは、kubeadmとKubernetesがアップグレードに特に注意を必要とするため。

バージョンのズレに関する詳細は以下を参照：

- Kubernetesのバージョンとバージョン不一致のポリシー
- Kubeadm固有のバージョン不一致のポリシー

”CentOS, RHEL or Fedora”のインストールコマンド

```shell
cat <<EOF > /etc/yum.repos.d/kubernetes.repo
[kubernetes]
name=Kubernetes
baseurl=https://packages.cloud.google.com/yum/repos/kubernetes-el7-x86_64
enabled=1
gpgcheck=1
repo_gpgcheck=1
gpgkey=https://packages.cloud.google.com/yum/doc/yum-key.gpg https://packages.cloud.google.com/yum/doc/rpm-package-key.gpg
exclude=kube*
EOF

# Set SELinux in permissive mode (effectively disabling it)
setenforce 0
sed -i 's/^SELINUX=enforcing$/SELINUX=permissive/' /etc/selinux/config

yum install -y kubelet kubeadm kubectl --disableexcludes=kubernetes

systemctl enable --now kubelet
```

**注意：　**

- `setenforce 0`と`sed ...`を実行してSELinuxをpermissiveモードにしなければならない。これはコンテナが、ホストファイルシステムにアクセスできるようにするために必要。これはポッドネットワークなどで必要。SELinuxサポートがkubeletで改善されるまで対処しなければならない。
- RHEL / CentOS 7の一部のユーザーは、iptablesがバイパスされているためにトラフィックが誤ってルーティングされるという問題を報告している。`sysctl`で`net.bridge.bridge-nf-call-iptables`が１に設定されていることを確認すること。

```shell
cat <<EOF >  /etc/sysctl.d/k8s.conf
net.bridge.bridge-nf-call-ip6tables = 1
net.bridge.bridge-nf-call-iptables = 1
EOF
sysctl --system
```

- このステップの前に`br_netfilter`モジュールがロードされていることを確認する。`lsmod | grep br_netfilter`を実行することで確認できる。`modprobe br_netfilter`で明示的に呼び出せる。

クラッシュループでkubeadmが処理するのを待つので、kubeletは数秒ごとに再起動する。

## Master node: kubeletが使用するcgroupドライバを設定する

Dockerを使用する場合、kubeadmは自動的にkubelet用のcgroupドライバを検出し、実行時に`/var/lib/kubelet/kubeadm-flags.env`ファイルに設定する。

別のCRIを使用している場合は、`/etc/default/kubelet`ファイルの`cgroup-driver`の値を次のように変更する必要がある：

```shell
KUBELET_EXTRA_ARGS=--cgroup-driver=<value>
```

このファイルは、`kubeadm init`と`kubeadm join`によって使用され、kubeletの追加のユーザー定義引数を取得する。

CRIのcgroupドライバが、`cgroupfs`ではない場合に**のみ**実行する必要があることに注意する。それがkubeletのデフォルト値であるため。

kubeletを再起動する必要がある：

```shell
systemctl daemon-reload
systemctl restart kubelet
```

## トラブルシューティング

kubeadmで問題が発生した場合は、トラブルシューティングのドキュメントを参照する。

## What's next

- kubeadmを使用してクラスタを作成する