Calico the hard wayの作業ログ

2019-11-12に作成

KubernetesのCNIプラグインにCalicoというものがあって、いま自分が運用に関わっているシステムはそれを使っているんだけど、今までちゃんとCalicoについて勉強したことがなかったので、ちょっとチュートリアルをやってみようと思う。今回はCalico the hard wayというやつ。
これはCalicoのチュートリアルではあるんだけど、いわゆるハローワールドみたいなものとは違って、Calicoの機能やCalicoを支えるコンポーネントも網羅してハンズオンするみたいな感じ。というわけで、Calicoについて勉強するには適切な題材となっている。
ただ、hard wayとあるように、ややボリュームが多いので、数日にわたって行うことになる。というわけで、せっかくだし、Crieitのボード機能を使って作業ログを残してみようと思う。

所有者限定モードのためこのボードには投稿できません ボードとは?

Day4: Follow up

だいぶ間が空いてしまったけど、前回言っていたように、Day4の内容の解説を行う。

まず前提としてCalicoはKubernetesのNetwork Pluginなので、Kubernetesと通信する必要がある。そして、KubernetesのAPIとの通信には認証が必要である。ということで、最初にやることは、認証用の鍵を作成して署名すること。

以下のコマンドで認証用の鍵を作成している。

$ openssl req -newkey rsa:4096 \  # 鍵を4096bitのRSA暗号で作成する
           -keyout cni.key \      # 鍵の出力先ファイル名
           -nodes \               # 鍵の中身を暗号化しない
           -out cni.csr \         #  CSRの出力先ファイル名
           -subj "/CN=calico-cni" # 証明書のサブジェクトのdistinguish nameを設定する

これをKubernetesのCA(認証局)に署名してもらう。

$ sudo openssl x509 -req -in cni.csr \  # CSRが入力であり(--req)、CSRの場所は cni.csrである(--in)
                  -CA /etc/kubernetes/pki/ca.crt \  # KubernetesのCA証明書の場所
                  -CAkey /etc/kubernetes/pki/ca.key \  # KubernetesのCA鍵の場所
                  -CAcreateserial \  # シリアル番号がなければ番号を生成する
                  -out cni.crt \     # 署名された証明書の出力先ファイル名
                  -days 365         # 署名された証明書の有効期限
sudo chown ubuntu:ubuntu cni.crt

これでKubernetesにアクセスするための証明書が作成されたことになる。次に、ここで作成した証明書を使うように設定する。つまり、(Kubernetesをサーバーだと見立てた場合に)クライアント側の設定を行う。

# KubernetesのAPIサーバーのIPアドレスを取得する
$ APISERVER=$(kubectl config view -o jsonpath='{.clusters[0].cluster.server}')

$ kubectl config set-cluster kubernetes \  # kubeconfigに"kubernetes"という名前でクラスターエントリを設定する
    --certificate-authority=/etc/kubernetes/pki/ca.crt \  # CA証明書の位置。クライアント証明書を検証するために必要
    --embed-certs=true \  # kubeconfigの中に証明書を埋め込むかどうか
    --server=$APISERVER \  # KubernetesのAPIサーバーのIPアドレスの指定
    --kubeconfig=cni.kubeconfig  # 設定を保存するkubeconfigのファイルの場所

$ kubectl config set-credentials calico-cni \  # kubeconfigに"calico-cni"という名前でユーザーエントリを設定する
    --client-certificate=cni.crt \  # CAに署名してもらった証明書の場所
    --client-key=cni.key \  # 証明書に対応する鍵
    --embed-certs=true \  # kubeconfigの中に証明書を埋め込むかどうか
    --kubeconfig=cni.kubeconfig  # 設定を保存するkubeconfigのファイルの場所

$ kubectl config set-context default \  # kubeconfigに"default"というコンテキストエントリを設定する
    --cluster=kubernetes \  # "default"というコンテキストに対応するクラスターの名前
    --user=calico-cni \  # "default"というコンテキストに対応するユーザーの名前
    --kubeconfig=cni.kubeconfig  # 設定を保存するkubeconfigのファイルの場所

# 設定した"default"コンテキストを指定する。読み込む設定ファイルはcni.kubeconfigとする
$ kubectl config use-context default --kubeconfig=cni.kubeconfig

これはCalicoが使う設定ファイルなので、Calicoノードに配布しておく必要がある。

ここまで見たように、1つ1つのステップがCalicoがKubernetesのAPIサーバーと通信するために必要な準備作業であることがわかる。

では、ここまで完了したら後はCalicoがKubernetesと協調的に動くようになるかと言うとそうでもなくて、Calicoに限らず、Kubernetesのリソース(DeploymentとかPodとか)を扱うときにはRoleを割り当てなければならない。

というわけで、作成するRoleが以下のようになる

$ kubectl apply -f - <<EOF
kind: ClusterRole
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  name: calico-cni
rules:
  # The CNI plugin needs to get pods, nodes, and namespaces.
  - apiGroups: [""]
    resources:
      - pods
      - nodes
      - namespaces
    verbs:
      - get
  # The CNI plugin patches pods/status.
  - apiGroups: [""]
    resources:
      - pods/status
    verbs:
      - patch
 # These permissions are required for Calico CNI to perform IPAM allocations.
  - apiGroups: ["crd.projectcalico.org"]
    resources:
      - blockaffinities
      - ipamblocks
      - ipamhandles
    verbs:
      - get
      - list
      - create
      - update
      - delete
  - apiGroups: ["crd.projectcalico.org"]
    resources:
      - ipamconfigs
      - clusterinformations
      - ippools
    verbs:
      - get
      - list
EOF

上について細かい説明は省略するというか、追々わかってくると思うのでここでは一旦"オマジナイ"的なものとしてコピペしておくにとどめておいて良いと思う。強いて言うなら、verbsはHTTPのメソッド的なやつだというぐらいの認識で良いと思う。

あとはCalicoのバイナリをダウンロードして所定の位置に配置するだけなので割愛。Day4のフォローアップはここまでにして、次はDay5をやる。