varu3/techBlog

IT infrastructure technology memo.

Kopsでcalico-nodeがCrashLoopBackOffになる事象

ちょくちょくとKubernetes関連の記事を上げていっています。今回もちょっとしたトラブルの覚書です。

事象

Kopsでcalicoを使っていると、Node立ち上げ時にcalico-nodeがCrashLoopBackOffになることがある。エラーが出たcalico-nodeと同じnodeのpodから外部への接続が一切できなくなってしまいました。(ping, 名前解決ともにできなくなる。)

2018-MM-DD HH:MM:SS.207 [INFO][9] startup.go 467: Using autodetected IPv4 address on interface eth0: XX.XX.XX.XX/24
2018-MM-DD HH:MM:SS.207 [INFO][9] startup.go 338: Node IPv4 changed, will check for conflicts
2018-MM-DD HH:MM:SS.626[WARNING][9] startup.go 718: Calico node '<ホスト名>' is already using the IPv4 address XX.XX.XX.XX.
2018-MM-DD HH:MM:SS.626 [WARNING][9] startup.go 915: Terminating
Calico node failed to start

ログをみてみると、Calico node '[ホスト名]' is already using the IPv4 address <IP Addresess>.というエラーが出力されていました。

原因

前提としてKubernetesのMasterにはETCDというKVSがバックエンドとして存在していて、そこにノードの情報などが格納されています。

$ kubectl exec -it etcd-server-ip-XX-XX-XX-XX.XX.compute.internal -n kube-system -- /bin/sh
/ # etcdctl ls /calico/v1/host
/calico/v1/host/<ホスト名>
...

こんな感じで。どうやらNodeが削除されてもここのKVが残り続け、新規で立ち上げたNodeとIPアドレスが被ってしまった場合、上記のエラーが出力されるようです。

解決方法

Nodeが削除される時に同時にETCDからも削除されれば解決しそうです。調べてみると、calico-nodeを管理するcalico-kube-controllersにNode controllerという機能がありました。Node controllreNode削除時にetcdのホスト情報を一緒に削除してくれるというもので、これを使えば解決しそうですね。この機能はデフォルトでは無効化されているので、有効化する手順をまとめます。

$ kops version
Version 1.8.1 (git-94ef202)

まず、deploymentのcalico-kube-controllersにENABLED_CONTROLLERSという環境変数を設定します。

$ kubectl get deployment -n kube-system
NAME                       DESIRED   CURRENT   UP-TO-DATE   AVAILABLE   AGE
calico-kube-controllers    1         1         1            1           20d
$ kubectl edit deployment calico-kube-controllers -n kube-system
  ....
    spec:
      containers:
      - env:
      + - name: ENABLED_CONTROLLERS
      +   value: policy,profile,workloadendpoint,node
        - name: ETCD_ENDPOINTS
          valueFrom:
            configMapKeyRef:
              key: etcd_endpoints
              name: calico-config
        image: quay.io/calico/kube-controllers:v1.0.3
        imagePullPolicy: IfNotPresent
        name: calico-kube-controllers
        resources:
          requests:
            cpu: 10m
        terminationMessagePath: /dev/termination-log
        terminationMessagePolicy: File
  .....

続いてcalico-nodeのdaemonsetにCALICO_K8S_NODE_REFという環境変数を設定します。

$ kubectl get daemonset -n kube-system
NAME          DESIRED   CURRENT   READY     UP-TO-DATE   AVAILABLE   NODE SELECTOR   AGE
calico-node   2         2         2         1            2           <none>          20d

$ kubectl edit daemonset calico-node -n kube-system 
  ....
    spec:
      containers:
      - env:
        - name: ETCD_ENDPOINTS
          valueFrom:
            configMapKeyRef:
              key: etcd_endpoints
              name: calico-config
        - name: CALICO_NETWORKING_BACKEND
          valueFrom:
            configMapKeyRef:
              key: calico_backend
              name: calico-config
        - name: CALICO_IPV4POOL_CIDR
          value: XX.XX.XX.XX/11
        - name: CALICO_IPV4POOL_IPIP
          value: cross-subnet
        - name: CLUSTER_TYPE
          value: kops,bgp
        - name: CALICO_DISABLE_FILE_LOGGING
          value: "true"
        - name: IP
        - name: FELIX_IPV6SUPPORT
          value: "false"
        - name: FELIX_LOGSEVERITYSCREEN
          value: info
        - name: FELIX_HEALTHENABLED
          value: "true"
      + - name: CALICO_K8S_NODE_REF
      +   valueFrom:
      +     fieldRef:
      +       apiVersion: v1
      +       fieldPath: spec.nodeName
        image: quay.io/calico/node:v2.6.6
  ....

これでNode controllerが有効化されました。

確認

実際に確認してみます。Masterのetcd serverに入ってetcdctlコマンドで確認します。

nodesを増やす前

# etcdctl ls /calico/v1/host | wc -l
2

nodesを増やしてみる。その後

# etcdctl ls /calico/v1/host | wc -l
5

nodesを消した後

# etcdctl ls /calico/v1/host | wc -l
2

とノードの数と合わせてcalicoのホストも増減していることがわかります。

既存のホストはどうするか

これでノードの増減とcalicoのホストも合わせて増減することができましたが、calico-node-controllerを有効化する前にできた余分なホストは削除してくれないので、これは自分で削除する必要があります。手動でちまちまと消していくのはとてもダルイのでRubyスクリプトを書きましたが、そこまで数が多いのなら作り直してしまった方が早いかもしれません。

ということで、こんな感じの簡単な備忘録でした。