kubeadmでFedora CoreOSにKubernetes1.18

[kubeadmでFedora CoreOSにKubernetes1.17を入れる場合はこちら](https://qiita.com/rururu_kenken/items/25ef311e379c3be6bd95)

# メモ

・Fedora CoreOSは、CoreOS Container Linuxと同様にデフォルトで自動アップデートが有効なので、新しい安定版が出ると自動でアップデートします。

・Calicoのデプロイや設定を変えた時(kubectl apply -f calico.yaml)にすべてのノードの再起動(sudo systemctl reboot)しないとRedisにserviceでアクセスできなかった。

# 環境

#### Master Node

|    EC2　　 |    OS         | Kubernetes | Docker    |
|:----------:|:-------------:|:----------:|:---------:|
| t3.medium   |Fedora CoreOS stable 31.20200310.3.0 | 1.18.0|18.09.8 |

Fedora CoreOS preview AMI のユーザー名は core です

Master Nodeは、2CPU、メモリ2GB以下の場合、kubeadm init実行時にエラーになります。
ディスクサイズは12G

Master NodeとWorker Nodeは同じVPC
Master NodeのIPアドレスは172.31.20.100

#### Worker Node

|    EC2　　 |    OS         | Kubernetes | Docker    |
|:----------:|:-------------:|:----------:|:---------:|
| t3.small|Fedora CoreOS stable 31.20200310.3.0 |1.18.0|18.09.8 |

Fedora CoreOS preview AMI のユーザー名は core です

Master NodeとWorker Nodeは同じVPC
Master NodeのIPアドレスは172.31.27.67
ディスクサイズは12G

# Podman確認

```sh
podman -v

# 実行結果
podman version 1.8.1
```

# CPUの数

[CoreOS incorrectly reports CPU info via /proc/cpuinfo #413](https://github.com/coreos/fedora-coreos-tracker/issues/413)
**Google翻訳**
>（AWS上の）Fedora CoreOSの最新の安定リリースを実行していて、/ proc / cpuinfoの内容が正しくない。
>
>[core@ip-10-36-176-20 ~]$ rpm-ostree status ・・・
>2つのCPUを備えたt3.smallは1を示します。4を備えたt3.xlargeは2を示します。これは、Kubernetes（正確にはcadvisor）が/ proc / cpuinfoを使用して容量用のCPUの数を決定するため、問題を引き起こします。 これにより、ノードの容量が必要な半分になると報告されます。
>
> Fedora CoreOS: [core@ip-10-36-176-20 ~]$ cat /proc/cpuinfo ・・・

>@jlebon
>FCOSが必要に応じてSMTを無効にしている可能性があります ： https : //github.com/coreos/fedora-coreos-tracker/blob/master/Design.md#automatically-disable-smt-when-needed-to-address-vulnerabilities 。 EC2インスタンスタイプで引用されているvCPU数はハイパースレッディングを想定していると思います。
>
>@ cyrus-mc
>それはそれのようです。 迅速な対応に感謝します。
>
>を使用してカーネルオプションを更新しました
>
> rpm-ostree kargs --replace="mitigations=auto" 
>
>nosmtを削除します。

[Fedora CoreOSで/proc/cpuinfoの内容をEC2インスタンスのvCPU数と同じにする設定する場合はこちらを参照してください](https://qiita.com/rururu_kenken/items/2d7a2f50190940d99ac2)

```sh
# CPU ごとのコア数
grep cpu.cores /proc/cpuinfo

# 実行結果
cpu cores	: 1
```

# .bashrc編集など

```sh
vi .bashrc

# 以下の設定を追加
export PATH=$PATH:/opt/bin

# 設定反映
source ~/.bashrc

# sudoの権限を設定
sudo visudo

# :/opt/bin を追加
Defaults    secure_path = /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/opt/bin
```

# SELinux設定無効

```sh
# 現在の状態確認
#・Enforcing ･･･ SELinuxは有効で、アクセス制限も有効。
#・Permissive ･･･ SELinuxは有効だが、アクセス制限は行わず警告を出力。
#・Disabled ･･･ SELinux機能は無効。
getenforce

# 実行結果
Enforcing

# Disabled への変更
sudo sed -i --follow-symlinks 's/SELINUX=enforcing/SELINUX=disabled/g' /etc/sysconfig/selinux

# 再起動
# 再起動後にsshで再接続
sudo systemctl reboot

getenforce

# 実行結果
Disabled
```

# swap確認

```
# ある場合はswapoff -a
free

# 実行結果
              total        used        free      shared  buff/cache   available
Mem:        1990120       95560     1687952         608      206608     1751980
Swap:             0           0           0
```

# Docker設定

```sh
docker -v

# 実行結果
Docker version 18.09.8, build 0dd43dd

# Dockerの自動起動有効
sudo systemctl enable docker

# ログインしているユーザーがdockerグループの追加されているか確認
# デフォルトでは設定されていない
cat /etc/group | grep docker

# 実行結果
docker:x:982:

# ログインしているユーザーをdockerグループに追加
sudo usermod -a -G docker $USER

# 確認コマンド
cat /etc/group | grep docker

# 実行結果
docker:x:993:core

# ログアウト
# すぐにsshで再接続
exit
```

# Docker の設定例

cgroupdriverを「systemd」
log-driverを「json-file」。max-size「100m」
insecure-registryに「hogehoge:5000」


[Control Docker with systemd](https://docs.docker.com/config/daemon/systemd/)
[systemd と Docker の管理・設定](http://docs.docker.jp/engine/articles/systemd.html)
[docker18.09.0にあげたらdocker.serviceが起動しなくなった](https://qiita.com/aoi1/items/7602ec6530eaab29aeee)

```sh
sudo mkdir -p /etc/systemd/system/docker.service.d

# Fedora CoreOSのDockerは18.09なので dockerdのうしろに「-H fd://」は付けないこと
sudo tee /etc/systemd/system/docker.service.d/docker.conf <<EOF
[Service]
ExecStart=
ExecStart=/usr/bin/dockerd --exec-opt native.cgroupdriver=systemd --log-driver=json-file \
          --log-opt max-size=100m \
          --insecure-registry=hogehoge:5000
EOF

# "daemon-reload"は「Unitファイルに加えた変更を読み込む」ためのものです
sudo systemctl daemon-reload
sudo systemctl restart docker
```

# sysctlでネットワークをブリッジできるようする

https://kubernetes.io/docs/concepts/extend-kubernetes/compute-storage-net/network-plugins/#network-plugin-requirements
>By default if no kubelet network plugin is specified, 
>the noop plugin is used, which sets 
>net/bridge/bridge-nf-call-iptables=1 to ensure simple >configurations (like Docker with a bridge) work correctly >with the iptables proxy.

```sh

sudo tee /etc/sysctl.d/k8s.conf <<EOF
net.bridge.bridge-nf-call-iptables  = 1
net.ipv4.ip_forward                 = 1
net.bridge.bridge-nf-call-ip6tables = 1
EOF

sudo sysctl --system
```

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

```sh
CNI_VERSION="v0.8.5"
sudo mkdir -p /opt/cni/bin
curl -L "https://github.com/containernetworking/plugins/releases/download/${CNI_VERSION}/cni-plugins-linux-amd64-${CNI_VERSION}.tgz" | sudo tar -C /opt/cni/bin -xz

CRICTL_VERSION="v1.17.0"
sudo mkdir -p /opt/bin
curl -L "https://github.com/kubernetes-incubator/cri-tools/releases/download/${CRICTL_VERSION}/crictl-${CRICTL_VERSION}-linux-amd64.tar.gz" | sudo tar -C /opt/bin -xz

# 1.17.0の場合はv1.17.0を指定してください
RELEASE="v1.18.0"
sudo mkdir -p /opt/bin
cd /opt/bin
sudo curl -L --remote-name-all https://storage.googleapis.com/kubernetes-release/release/${RELEASE}/bin/linux/amd64/{kubeadm,kubelet,kubectl}
sudo chmod +x {kubeadm,kubelet,kubectl}

# k8s 1.18.0のkubelet.serviceと10-kubeadm.confがなかったので
# k8s 1.17.4のファイルを使用する。
RELEASE="v1.17.4"
cd
curl -sSL "https://raw.githubusercontent.com/kubernetes/kubernetes/${RELEASE}/build/debs/kubelet.service" | sed "s:/usr/bin:/opt/bin:g" > ./kubelet.service
sudo mv ./kubelet.service /etc/systemd/system/

sudo mkdir -p /etc/systemd/system/kubelet.service.d
curl -sSL "https://raw.githubusercontent.com/kubernetes/kubernetes/${RELEASE}/build/debs/10-kubeadm.conf" | sed "s:/usr/bin:/opt/bin:g" > ./10-kubeadm.conf
sudo mv 10-kubeadm.conf /etc/systemd/system/kubelet.service.d
```

# kubelet 起動 & 自動起動

```sh
sudo systemctl enable --now kubelet
```

# Masterノードのセットアップ

Fedore CoreOSの場合、kubeadm init時にconfigファイルを用意する必要があります。詳細は以下のissuesを見てください。

[failed to join the cluster with /usr/libexec/kubernetes: read-only file system #88210](https://github.com/kubernetes/kubernetes/issues/88210)
[add workarounds for Fedora Coreos's R/O /usr/libexec/ #2031](https://github.com/kubernetes/kubeadm/issues/2031)

```sh
# kubeadm init実行で
#「[WARNING FileExisting-ethtool]: 
# ethtool not found in system path」
# と
# [ERROR FileExisting-conntrack]: 
# conntrack not found in system path
# が出るためインストール
sudo rpm-ostree install ethtool conntrack -r

# 再起動後にsshで再接続

# Calicoの場合、「podSubnet」に「192.168.0.0/16」を指定
# Flannelの場合、「podSubnet」に「10.244.0.0/16」を指定
# 例) Calico用のファイル作成
cat <<EOF > ./kubeadm-config.yaml
apiVersion: kubeadm.k8s.io/v1beta2
kind: InitConfiguration
nodeRegistration:
  kubeletExtraArgs:
    volume-plugin-dir: "/opt/libexec/kubernetes/kubelet-plugins/volume/exec/"
---
apiVersion: kubeadm.k8s.io/v1beta2
kind: ClusterConfiguration
controllerManager:
  extraArgs:
    flex-volume-plugin-dir: "/opt/libexec/kubernetes/kubelet-plugins/volume/exec/"
networking:
  podSubnet: 192.168.0.0/16
EOF

# CPU2つ(AWS EC2の場合、t3.smallやt3.medium)のままで、
#「sudo kubeadm init --config kubeadm-config.yaml」を
# 実行する場合は、うしろに「--ignore-preflight-errors=NumCPU」を付けて
# 実行してください。
sudo kubeadm init --config kubeadm-config.yaml --ignore-preflight-errors=NumCPU
```

## kubectl 設定

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

## 確認

```sh
kubectl get po -A

# 実行結果
NAMESPACE     NAME                                       READY   STATUS    RESTARTS   AGE
kube-system   coredns-66bff467f8-85pdl                   1/1     Running   0          50s
kube-system   coredns-66bff467f8-x6bs2                   1/1     Running   0          50s
kube-system   etcd-ip-172-31-19-137                      1/1     Running   0          65s
kube-system   kube-apiserver-ip-172-31-19-137            1/1     Running   0          65s
kube-system   kube-controller-manager-ip-172-31-19-137   1/1     Running   0          65s
kube-system   kube-proxy-z92wh                           1/1     Running   0          49s
kube-system   kube-scheduler-ip-172-31-19-137            1/1     Running   0          65s

kubectl get node

# 実行結果
NAME               STATUS   ROLES    AGE   VERSION
ip-172-31-19-137   Ready    master   74s   v1.18.0
```

Calicoデプロイ

```sh
curl -L -O https://docs.projectcalico.org/v3.13/manifests/calico.yaml

# Calico 3.8 fails to install under CoreOS stable #2712
# https://github.com/projectcalico/calico/issues/2712
# flexvol-driver-host の path を修正
sed -i -e "s?/usr/libexec/kubernetes/kubelet-plugins/volume/exec/nodeagent~uds?/opt/libexec/kubernetes/kubelet-plugins/volume/exec/nodeagent~uds?g" calico.yaml

# name: calico-nodeのenvに以下の設定を追加
#
# IP_AUTODETECTION_METHODは、WorkerNodeのJoin後に
# calico-nodeのPodのREADYが「0/1」になったので追加。
vi calico.yaml

- name: IP_AUTODETECTION_METHOD
  value: "interface=eth.*"
- name: IP6_AUTODETECTION_METHOD
  value: "interface=eth.*"

kubectl apply -f calico.yaml 

# 確認 
kubectl get po -A

# 実行結果
NAMESPACE     NAME                                       READY   STATUS    RESTARTS   AGE
kube-system   calico-kube-controllers-5b8b769fcd-n8tjv   1/1     Running   0          15s
kube-system   calico-node-xp7rr                          1/1     Running   0          15s
kube-system   coredns-66bff467f8-85pdl                   1/1     Running   0          93s
kube-system   coredns-66bff467f8-x6bs2                   1/1     Running   0          93s
kube-system   etcd-ip-172-31-19-137                      1/1     Running   0          108s
kube-system   kube-apiserver-ip-172-31-19-137            1/1     Running   0          108s
kube-system   kube-controller-manager-ip-172-31-19-137   1/1     Running   0          108s
kube-system   kube-proxy-z92wh                           1/1     Running   0          92s
kube-system   kube-scheduler-ip-172-31-19-137            1/1     Running   0          108s

kubectl get node

# 実行結果
NAME               STATUS   ROLES    AGE    VERSION
ip-172-31-19-137   Ready    master   117s   v1.18.0
```

# WorkerNodeを構築する場合

以下はMaster Nodeの手順を参照
・.bashrc編集など
・SELinux設定無効
・swap確認
・Docker設定
・sysctlでネットワークをブリッジできるようする
・kubelet、kubeadm、kubectlインストール
・kubelet 起動

クラスタに参加

Fedore CoreOSの場合、Joinする時にconfigファイルを用意する必要があります。詳細は以下のissueを見てください。
[failed to join the cluster with /usr/libexec/kubernetes: read-only file system #88210](https://github.com/kubernetes/kubernetes/issues/88210)
[add workarounds for Fedora Coreos's R/O /usr/libexec/ #2031](https://github.com/kubernetes/kubeadm/issues/2031)
[kubeadm: add TS guide note about CoreOS read-only /usr #19166](https://github.com/kubernetes/website/pull/19166)

「kubeadm join・・・」実行時の「WARNING: JoinControlPane.controlPlane settings will be ignored when control-plane flag is not set.」については、以下のissueを見てください。
[kubeadm cannot join control plane node via --config flag](https://github.com/kubernetes/kubernetes/issues/89499)
[misleading warning on control-plane join #206](https://github.com/kubernetes/kubeadm/issues/2065)

```sh
# kubeadm join実行で
#「[WARNING FileExisting-ethtool]: 
# ethtool not found in system path」
# と
# [ERROR FileExisting-conntrack]: 
# conntrack not found in system path
# が出るためインストール
sudo rpm-ostree install ethtool conntrack -r

# sshで再接続後に
# Master Nodeで実行
kubeadm token create --print-join-command

# configファイル作成
vi node-join-config.yaml

apiVersion: kubeadm.k8s.io/v1beta2
kind: JoinConfiguration
discovery:
  bootstrapToken:
    token: "kubeadm joinコマンドのトークンの値を指定"
    caCertHashes:
    - "kubeadm joinコマンドのdiscovery-token-ca-cert-hashを指定"
    apiServerEndpoint: "マスターノードのIPアドレスを指定:6443"
nodeRegistration:
  kubeletExtraArgs:
    volume-plugin-dir: "/opt/libexec/kubernetes/kubelet-plugins/volume/exec/"

# WorkerNodeで生成されたコマンドに先頭に「sudo 」をつけて実行
sudo kubeadm join マスターノードのIPアドレスを指定:6443 --config=node-join-config.yaml

0327 16:38:15.418644    3946 join.go:346] [preflight] WARNING: JoinControlPane.controlPlane settings will be ignored when control-plane flag is not set.
[preflight] Running pre-flight checks
[preflight] Reading configuration from the cluster...
[preflight] FYI: You can look at this config file with 'kubectl -n kube-system get cm kubeadm-config -oyaml'
[kubelet-start] Downloading configuration for the kubelet from the "kubelet-config-1.18" ConfigMap in the kube-system namespace
[kubelet-start] Writing kubelet configuration to file "/var/lib/kubelet/config.yaml"
[kubelet-start] Writing kubelet environment file with flags to file "/var/lib/kubelet/kubeadm-flags.env"
[kubelet-start] Starting the kubelet
[kubelet-start] Waiting for the kubelet to perform the TLS Bootstrap...

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.
```

## Nodeの状態確認

Master Nodeで作業

```sh
kubectl get po -A

# 実行結果
NAMESPACE     NAME                                       READY   STATUS    RESTARTS   AGE
kube-system   calico-kube-controllers-5b8b769fcd-n8tjv   1/1     Running   0          103s
kube-system   calico-node-xp7rr                          1/1     Running   0          103s
kube-system   calico-node-xx9wq                          1/1     Running   0          19s
kube-system   coredns-66bff467f8-85pdl                   1/1     Running   0          3m1s
kube-system   coredns-66bff467f8-x6bs2                   1/1     Running   0          3m1s
kube-system   etcd-ip-172-31-19-137                      1/1     Running   0          3m16s
kube-system   kube-apiserver-ip-172-31-19-137            1/1     Running   0          3m16s
kube-system   kube-controller-manager-ip-172-31-19-137   1/1     Running   0          3m16s
kube-system   kube-proxy-vrtwn                           1/1     Running   0          19s
kube-system   kube-proxy-z92wh                           1/1     Running   0          3m
kube-system   kube-scheduler-ip-172-31-19-137            1/1     Running   0          3m16s
```

## MasterNodeとWorkerNodeの再起動

MasterNode

```sh
# 再起動
# 再起動後にsshで再接続
sudo systemctl reboot
```

WorkerNode

```sh
# 再起動
# 再起動後にsshで再接続
sudo systemctl reboot
```

## Redisデプロイ・動作確認

Master Nodeで作業

```
vi redis.yaml
```

```redis.yaml
apiVersion: v1
kind: Service
metadata:
  name: redis-svc
spec:
  ports:
    - port: 6379
      targetPort: 6379
  selector:
    app: redis
  clusterIP: None
---
apiVersion: v1
kind: ConfigMap
metadata:
  name: redis.config
data:
  redis.conf: |
    requirepass password
    bind 0.0.0.0
---
apiVersion: apps/v1
kind: Deployment
metadata:
  # Deploymentの名前。Namespace内ではユニークである必要があります
  name: redis
spec:
  selector:
    matchLabels:
      app: redis
  # レプリカ数の指定
  replicas: 1
  # Podのテンプレート(PodTemplate)
  template:
    metadata:
      labels:
        # ラベル指定は必須
        app: redis
    spec:
      containers:
        - name: redis
          image: redis:5.0.8
          command: 
            - "redis-server"
            - "/redis-master/redis.conf"
          ports:
            - name: redis
              containerPort: 6379
          volumeMounts:
            - name: data
              mountPath: /redis-master-data
            - name: config
              mountPath: /redis-master
      volumes:
        - name: data
          emptyDir: {}
        - name: config
          configMap:
            name: redis.config
```

```shell-session
kubectl apply -f redis.yaml
kubectl run -it redis-cli --rm --image redis:5.0.8 --restart=Never -- bash
If you don't see a command prompt, try pressing enter.
root@redis-cli:/data# redis-cli -c -h redis-svc -p 6379 -a password
Warning: Using a password with '-a' or '-u' option on the command line interface may not be safe.
redis-svc:6379> set a 1
OK
redis-svc:6379> get a
"1"
redis-svc:6379> exit
root@redis-cli:/data# exit
```