k8s: calico の Pod が Pending ステータスから変わらない

TL;DR
--------------------
- まずNodeに`Taint`が付いてるかどうか確かめましょう(`kubectl describe nodes | grep Taints`)


参考資料
--------------------
[Quickstart for Calico on Kubernetes (projectcalico.org)](https://docs.projectcalico.org/v3.0/getting-started/kubernetes/)
[Installing Calico on Kubernetes (projectcalico.org)](https://docs.projectcalico.org/v3.0/getting-started/kubernetes/installation/)
[Calico Kubernetes Hosted Install (projectcalico.org)](https://docs.projectcalico.org/v3.0/getting-started/kubernetes/installation/hosted/)
[kubeadm Hosted Install (projectcalico.org)](https://docs.projectcalico.org/v3.0/getting-started/kubernetes/installation/hosted/kubeadm/)
[Taints and Tolerations (kubernetes.io)](https://kubernetes.io/docs/concepts/configuration/taint-and-toleration/)
[kubernetes admission.go  (github.com)](https://github.com/kubernetes/kubernetes/blob/master/plugin/pkg/admission/defaulttolerationseconds/admission.go)


前提条件 / 環境情報
--------------------
- k8s: v1.15.2
- CNI実装: calico
- CRI実装: Docker
- ホストOS(インフラ): Ubuntu 18.04
- Node構成: Single Node(Master Nodeのみ)


状況
--------------------

### `calico`のPodが`Pending`ステータスのまま

```
kubectl get pod -A

NAMESPACE     NAME                                       READY   STATUS              RESTARTS   AGE
kube-system   calico-etcd-djqmm                          0/1     Pending             0          4m12s
kube-system   calico-kube-controllers-66968c8b4c-g42mm   1/1     Running             5          7m18s
kube-system   calico-node-7vj6k                          0/2     Pending             0          4m12s
kube-system   coredns-5c98db65d4-bcz62                   0/1     ContainerCreating   0          102m
kube-system   coredns-5c98db65d4-zwk8g                   0/1     ContainerCreating   0          102m
...
```

`Pending`なので、何かの理由でPodをNodehスケジューリング出来ていないはず。

### PodがスケジューリングされるはずのNodeを見てみると`KubeletNotReady`が発生している

```
kubectl describe nodes

...
Conditions:
  Type             Status  LastHeartbeatTime                 LastTransitionTime                Reason                       Message
  ----             ------  -----------------                 ------------------                ------                       -------
  Ready            False   Thu, 08 Aug 2019 13:18:38 +0900   Thu, 08 Aug 2019 11:28:28 +0900   KubeletNotReady              runtime network not ready: NetworkReady=false reason:NetworkPluginNotReady message:docker: network plugin is not ready: cni config uninitialized
```

### `calico`の要件は？

`calico`の要件をチェックしてみる → [Installing Calico on Kubernetes (projectcalico.org)](https://docs.projectcalico.org/v3.0/getting-started/kubernetes/installation/)。

> The kubelet must be configured to use CNI network plugins (e.g --network-plugin=cni).
    The kube-proxy must be started in iptables proxy mode. This is the default as of Kubernetes v1.2.0.
    The kube-proxy must be started without the --masquerade-all flag, which conflicts with Calico policy.
    The Kubernetes NetworkPolicy API requires at least Kubernetes version v1.3.0.
    When RBAC is enabled, the proper accounts, roles, and bindings must be defined and utilized by the Calico components. Examples exist for both the etcd and kubernetes api datastores.

- `--network-plugin=cni`が`kubelet`で指定されてるか → はい。

```
systemctl status kubelet
● kubelet.service - kubelet: The Kubernetes Node Agent
...
   CGroup: /system.slice/kubelet.service
           └─13940 /usr/bin/kubelet 
--bootstrap-kubeconfig=/etc/kubernetes/bootstrap-kubelet.conf 
--kubeconfig=/etc/kubernetes/kubelet.conf 
--config=/var/lib/kubelet/config.yaml 
--cgroup-driver=cgroupfs 
--network-plugin=cni     ←これ
i -
...
```

- `kube-proxy`が`iptables`モードで動いているか → 不明

`--config=/var/lib/kube-proxy/config.conf`で指定されたファイルが見つからない。。
[kube-proxy Options (kubernetes.io)](https://kubernetes.io/docs/reference/command-line-tools-reference/kube-proxy/#options)には`--proxy-mode ProxyMode`というオプションがあるので、これの事らしいが。。

```
ps aux

...
root     15594  0.1  1.5 139284 32144 ?        Ssl  11:28   0:13 /usr/local/bin/kube-proxy --config=/var/lib/kube-proxy/config.conf --hostname-override=xubuntu
```

- `kube-proxy`が`--masquerade-all`無しで動いているか → 不明(前述のProxyModeと同じ理由により)

- k8sが`v1.3.0`以降であるか → はい。

- RBAC(Role Based Access Control)が有効であり → はい。
  - 適切なロールが設定されているか → 不明(能力不足)

```
kubectl cluster-info dump | grep RBAC

"--authorization-mode=Node,RBAC",
```

```
kubectl api-resources | grep Role

clusterrolebindings                            rbac.authorization.k8s.io      false        ClusterRoleBinding
clusterroles                                   rbac.authorization.k8s.io      false        ClusterRole
rolebindings                                   rbac.authorization.k8s.io      true         RoleBinding
roles                                          rbac.authorization.k8s.io      true         Role
```

### ダメだ、、もっと理解しよう

解決の糸口が見つからないので、一旦仕様を探してみます。
[Calico Kubernetes Hosted Install (projectcalico.org)](https://docs.projectcalico.org/v3.0/getting-started/kubernetes/installation/hosted/)
[kubeadm Hosted Install (projectcalico.org)](https://docs.projectcalico.org/v3.0/getting-started/kubernetes/installation/hosted/kubeadm/)

> Requirements
For Calico to be compatible with your kubeadm-created cluster:
    It must be running at least Kubernetes v1.7
    There should be no other CNI network configurations installed in /etc/cni/net.d (or equivalent directory)
    The kubeadm flag --pod-network-cidr must be set when creating the cluster with kubeadm init and the CIDR(s) specified with the flag must match Calico’s IP pools. The default IP pool configured in Calico’s manifests is 192.168.0.0/16
    The CIDR specified with the kubeadm flag --service-cidr must not overlap with Calico’s IP pools
        The default CIDR for --service-cidr is 10.96.0.0/12
        The default IP pool configured in Calico’s manifests is 192.168.0.0/16


- `It must be running at least Kubernetes v1.7` → はい。
- There should be no other CNI network configurations installed in /etc/cni/net.d (or equivalent directory) → はい。

```
ls -a /etc/cni/net.d/

.  ..
```
- The kubeadm flag --pod-network-cidr must be set when creating the cluster with kubeadm init and the CIDR(s) specified with the flag must match Calico’s IP pools. The default IP pool configured in Calico’s manifests is 192.168.0.0/16
→ いいえ。`192.168.122.0/24`でCIDR使ってます。。

### 

```
```


```
kubectl describe nodes

...
PodCIDR:                     192.168.0.0/24
```

-     The CIDR specified with the kubeadm flag --service-cidr must not overlap with Calico’s IP pools
        The default CIDR for --service-cidr is 10.96.0.0/12
        The default IP pool configured in Calico’s manifests is 192.168.0.0/16
→ はい。`--service-cidr`は使ってません


### 解決

情報を見る事が漏れており、思い込みがありました。。
Single Node環境で、Master Nodeに`Taint`が付いたままの状態でした。
(`flannel`を使っていた時には付いていなかった`Taint`だったので、`Taint`自体が必要と思い込んでいました)
「`calico`を動かそう」→「`calico`の仕様と実行環境を照合しよう」→「そもそも`calico`のPodがスケジューリング出来てないじゃないか」→「そういえばNodeに`Taint`付いてる」→「`calico`を動かしようが無い」
という思考経路でたどり着きました(矛盾していた)。。
遠回りしましたが、その分色々調べられたので、(自分としては)OKとしましょう。

```
kubectl describe pod -A

...
Events:
  Type     Reason            Age                  From               Message
  ----     ------            ----                 ----               -------
  Warning  FailedScheduling  48s (x6 over 4m24s)  default-scheduler  0/1 nodes are available: 1 node(s) had taints that the pod didn't tolerate.
```

```
kubectl describe nodes

...
Taints:             node.kubernetes.io/not-ready:NoSchedule
```

この`Taint`を外します。

```
kubectl taint node xubuntu node.kubernetes.io/not-ready:NoSchedule-

node/xubuntu untainted
```

来ました！`calico`が`Running`になりました。

```
kubectl get pods -A

NAMESPACE     NAME                                       READY   STATUS    RESTARTS   AGE
kube-system   calico-etcd-2fs7v                          1/1     Running   0          65s
kube-system   calico-kube-controllers-66968c8b4c-mrp8x   1/1     Running   2          9m14s
kube-system   calico-node-xm9wz                          2/2     Running   0          65s
```

何度か`Taint`を外す必要はありましたが、Master Nodeも`Ready`になりました。

```
kubectl describe nodes

...
  Ready            True    Thu, 08 Aug 2019 14:50:00 +0900   Thu, 08 Aug 2019 14:50:00 +0900   KubeletReady                 kubelet is posting ready status. AppArmor enabled
```

`flannel`を使ってる時はこんな`Taint`は無かったのになぁ・・・と思いつつ、
もっとk8sに関する仕様を理解しなきゃな、、と以下を調べてたのですが、
[Taints and Tolerations (kubernetes.io)](https://kubernetes.io/docs/concepts/configuration/taint-and-toleration/)
[kubernetes admission.go  (github.com)](https://github.com/kubernetes/kubernetes/blob/master/plugin/pkg/admission/defaulttolerationseconds/admission.go)
どんどん広がって行きそうなので、一旦中断としました。


まとめ
--------------------
- `flannel`を使う場合と違って、`calico`ではMaster Nodeに余分な`Taint`が付く場合がある
  - 追加調査していないので、原因は不明
  - (試してないので推測)Worker Nodeをクラスタへ参加させれば(`kubeadm join ...`)、Master Nodeの`Taint`は関係無いので`calico`はPodスケジューリングされるはず
- インストールが簡単になっている半面、仕様をざっとでも読んでおかないと障害調査がおぼつかない
  - 今時は公式サイトの仕様はきちんと書いてあるので、がんばって読むだけです。。


以上です。