EKSでCalicoを使ってみた[1.インストール編]

『IT自動化の力でビジネス加速を全ての企業に』

”IT自動化の専門会社”、リアルグローブ・オートメーティッド(RGA)の技術ブログ編集部の馬塚です。本日もRGAの技師がまとめた技術情報を読者の皆様にお届けしていきます!

前回、コンテナ技術を使うと「アプリケーションごとに環境を分離できる」ため、"より効率的で機動的なシステム運用が可能"になることをお伝えしましたが、その他に「環境を統一できる(開発環境・テスト環境・本番環境での差異を軽減できる)」ことや「軽量である(オーバーヘッドが少なく、起動も高速)」であることも、運用の効率化やスピードアップに寄与しています。

ビジネス加速には欠かせない、大変便利なコンテナ技術ですが、運用するコンテナの数が増えるとその管理が大変になるため、kubernetes等のコンテナオーケストレーションツールが必要になって来るわけですが、今回の記事はコンテナの増加に伴い増えるPodの運用に関わるネットワークモデルの構築に関してご案内いたします。

ディープな内容になっているので、複数編に分けてお届けいたします!

――――――――――――――――――――――――――――――――――

EKSでCalicoを使ってみた

今回は、Amazon EKS(Amazon Elastic Kubernetes Service、以下EKS)のCNIプラグインを、デフォルトの amazon-vpc-cni-k8s から calico に変更した際の手順とその検証結果について書きたいと思います。

※編集部注:CNI(Container Networking Interface)は、コンテナへのネットワーク接続を実現するための仕様です。

なぜCNIプラグインをCalicoに変更したかったのか

Kubernetesのネットワークモデルの実装方法は複数ありますが、EKSではEKSに特化したCNIプラグイン amazon-vpc-cni-k8s がデフォルトで採用されています。(Kubernetesのネットワークモデルについては公式ドキュメントを参照して下さい) 

EKSで amazon-vpc-cni-k8s を使うと次のようなメリット・デメリットがあります。

メリット

● EKSで唯一公式サポートされているCNIプラグインである。 https://docs.aws.amazon.com/ja_jp/eks/latest/userguide/alternate-cni-plugins.html
● (EKSで使うなら)最もシンプルで高パフォーマンスらしい。 https://aws.amazon.com/jp/blogs/opensource/networking-foundation-eks-aws-cni-calico/
● EKSを立ち上げたら最初から動いているので、色々余計なことを考えなくてよい。

デメリット

● 1ノードあたりのPod数が
   ENIの数 × (ENIあたりのセカンダリIPの数 - 1) + 2
   に制限される。
参考:各インスタンスでのPodの上限数
※例えば m5.large であれば、ENIの数が3個でENIあたりのセカンダリIPの数が10個なので、1ノードあたり、3 * (10 -1) + 2 = 29個しかPodがデプロイできません。これだと、小さいPodをたくさんデプロイしたいときなどは、ノードのCPUやメモリに空きがあっても、IPの数が足りなくてPodがデプロイできなくなります。

メリット・デメリットについては、以下の記事により詳細な情報が書かれています。
https://www.weave.works/blog/aws-and-kubernetes-networking-options-and-trade-offs-part-3

基本的には amazon-vpc-cni-k8s を使うのが良いですが、上記のPod数の制約が問題となる環境では他のネットワークモデルに変更する必要があります。今回は、AWSのサイトで「amazon-vpc-cni-k8s でどうしてもダメな場合はcalicoとかいいんじゃない?」と紹介されていましたので、calicoを試してみることにしました。

Calicoのインストール方法

基本的には公式サイトのインストール方法通りにやりましたが、少しクラスタの設定に気をつける必要がありました。
(amazon-vpc-cni-k8sを使いながらCalico network policyを使う方法も書いてありますが、今回はAmazon VPC Networking を Calico Networking に変更したいので、"Install EKS with Calico networking"の手順を参考にしました。)

クラスタを作成

ノードグループなしでクラスタを作成します。

$ eksctl create cluster \
 --name calico-cluster \
 --without-nodegroup

”aws-node” DaemonSetを削除

クラスタが作成できたら、コンテキストが正しいことを確認して次のコマンドを実行します。

$ kubectl delete daemonset -n kube-system aws-node

Calicoの設定をインストール

Calicoを導入するためのマニフェストファイルを適用します。

$ kubectl apply -f https://docs.projectcalico.org/manifests/calico-vxlan.yaml

ノードグループを作成

クラスタにノードグループを追加します。
このときに、--max-pods-per-node を十分に大きな値に設定することが重要です。amazon-vpc-cni-k8sプラグイン由来のPod数制限がなくなっても、eksctlのデフォルト設定でノードグループを作成すると、各ノードの割当制限としてamazon-vpc-cni-k8sプラグインを使用している場合の制限値が設定されてしまうため、この値を明示的に変更する必要があります。今回は1ノードあたりのPod数上限を「10」に設定してみました。

$ eksctl create nodegroup \
 --cluster calico-cluster \
 --node-type t3.nano \
 --nodes 2 \
 --node-ami auto \
 --max-pods-per-node 10

以上でcalicoのインストールは完了です。

動作確認

次に、本当に1ノードあたりのPod数制限が変更されているのか確認します。t3.nano のノードを2つ作ったので、デフォルトCNIでは {2 * (2-1) + 2} * 2 = 8個のPodしかデプロイできないノードグループになるはずです。
しかし、Calico Networking を採用し、--max-pods-per-node を「10」に設定したので、クラスタ全体で20個のPodが動かせるようになっているはずです。

Node情報の確認

Node情報を確認して、Nodeに割当可能なPod数が「10」になっているか確認します。

$ kubectl get nodes -o json | jq '.items[].status.allocatable'
{
 "attachable-volumes-aws-ebs": "25",
 "cpu": "1930m",
 "ephemeral-storage": "18242267924",
 "hugepages-1Gi": "0",
 "hugepages-2Mi": "0",
 "memory": "106612Ki",
 "pods": "10"
}
{
 "attachable-volumes-aws-ebs": "25",
 "cpu": "1930m",
 "ephemeral-storage": "18242267924",
 "hugepages-1Gi": "0",
 "hugepages-2Mi": "0",
 "memory": "106612Ki",
 "pods": "10"
}

ちゃんと各ノードの pods の値が「10」になっています。

サンプルPodをデプロイする

予め、すでに立ち上がっているPodの数を確認しておきます。

$ kubectl get pods --all-namespaces
NAMESPACE     NAME                                       READY   STATUS    RESTARTS   AGE
kube-system   calico-kube-controllers-77d6cbc65f-wjl7b   1/1     Running   0          9m14s
kube-system   calico-node-lxpl8                          1/1     Running   0          10m
kube-system   calico-node-zjlql                          1/1     Running   0          10m
kube-system   coredns-cdd78ff87-6p6lj                    1/1     Running   0          9m14s
kube-system   coredns-cdd78ff87-sv97r                    1/1     Running   0          9m13s
kube-system   kube-proxy-c8v2z                           1/1     Running   0          10m
kube-system   kube-proxy-vtwhv                           1/1     Running   0          10m

すでに7個のPodが立ち上がっているため、サンプルPodを14個立ち上げて1個だけ Pending になるか確認します。

まず1個デプロイしてみます。

$ kubectl apply -f - <<EOF
apiVersion: apps/v1
kind: Deployment
metadata:
 name: sample
 namespace: default
spec:
 replicas: 1
 selector:
   matchLabels:
     app: sample-app
 template:
   metadata:
     labels:
       app: sample-app
   spec:
     containers:
     - name: nginx
       image: nginx:latest
EOF

次にレプリカ数を「14」にします。

$ kubectl scale deployment sample --replicas=14

Podの状況を確認します。

$ kubectl get pods -n default
NAME                      READY   STATUS    RESTARTS   AGE
sample-74996797fd-6z2h7   0/1     Pending   0          14m
sample-74996797fd-84b7p   1/1     Running   0          14m
sample-74996797fd-8s4jg   1/1     Running   0          14m
sample-74996797fd-frbbq   1/1     Running   0          14m
sample-74996797fd-gv9s8   1/1     Running   0          14m
sample-74996797fd-hx27n   1/1     Running   0          14m
sample-74996797fd-jczhq   1/1     Running   0          14m
sample-74996797fd-pt97j   1/1     Running   0          14m
sample-74996797fd-r2bk5   1/1     Running   1          34m
sample-74996797fd-sxzrr   1/1     Running   0          14m
sample-74996797fd-ts2sl   1/1     Running   1          48m
sample-74996797fd-v7zpg   1/1     Running   0          14m
sample-74996797fd-wz582   1/1     Running   0          14m
sample-74996797fd-zx7zr   1/1     Running   0          14m

想定通り、20個のPodが Runnnig になり、余った1個が Pending になったので成功です。

追加検証

amazon-vpc-cni-k8sを使用しながら --max-pods-per-node の値だけ大きくしたらどうなるのか?

試しにやってみました。

$ kubectl get pods --all-namespaces
NAMESPACE     NAME                      READY   STATUS              RESTARTS   AGE
default       sample-74996797fd-2pmff   0/1     ContainerCreating   0          35m
default       sample-74996797fd-jsl8h   0/1     ContainerCreating   0          35m
default       sample-74996797fd-l58qt   1/1     Running             3          90m
kube-system   aws-node-dhw2q            1/1     Running             0          27m
kube-system   aws-node-g6rxl            1/1     Running             0          27m
kube-system   coredns-cdd78ff87-hmqpk   1/1     Running             0          35m
kube-system   coredns-cdd78ff87-w8wv8   1/1     Running             0          35m
kube-system   kube-proxy-kc5gd          1/1     Running             0          27m
kube-system   kube-proxy-tjg2p          1/1     Running             0          27m

STATUSは Pending ではなく ContainerCreating になります。そして待っていても Running にはなりません。

ContainerCreating になっているPodのEventsを確認してみます。

$ kubectl describe pods sample-74996797fd-2pmff -n default
(省略)
Events:                                                                                                                                                                                                           
 Type     Reason                  Age                    From                                                       Message                                                                                      
 ----     ------                  ----                   ----                                                       -------                                                                                      
 Warning  FailedScheduling        33m (x4 over 34m)      default-scheduler                                          0/2 nodes are available: 2 node(s) were unschedulable.
 Warning  FailedScheduling        33m (x3 over 33m)      default-scheduler                                          0/1 nodes are available: 1 node(s) were unschedulable.
 Warning  FailedScheduling        27m (x6 over 32m)      default-scheduler                                          no nodes available to schedule pods
 Warning  FailedScheduling        26m                    default-scheduler                                          0/1 nodes are available: 1 node(s) had taints that the pod didn't tolerate.
 Warning  FailedScheduling        26m (x2 over 26m)      default-scheduler                                          0/2 nodes are available: 2 node(s) had taints that the pod didn't tolerate.
 Normal   Scheduled               25m                    default-scheduler                                          Successfully assigned default/sample-74996797fd-2pmff to ip-192-168-68-97.ap-northeast-1.comp
ute.internal
 Warning  FailedCreatePodSandBox  25m                    kubelet, ip-192-168-68-97.ap-northeast-1.compute.internal  Failed create pod sandbox: rpc error: code = Unknown desc = failed to set up sandbox containe
r "926c546742d4e2c199cb0b57a06b48a45d8b1bd7f4b34929a9de2a9ed276ba1a" network for pod "sample-74996797fd-2pmff": networkPlugin cni failed to set up pod "sample-74996797fd-2pmff_default" network: add cmd: failed 
to assign an IP address to container
(...一部省略)
 Warning  FailedCreatePodSandBox  24m                    kubelet, ip-192-168-68-97.ap-northeast-1.compute.internal  Failed create pod sandbox: rpc error: code = Unknown desc = failed to set up sandbox containe
r "2b83c2e58d35536007d8216c82ecb6a2b239700f95032f87f46285e8b715093a" network for pod "sample-74996797fd-2pmff": networkPlugin cni failed to set up pod "sample-74996797fd-2pmff_default" network: add cmd: failed 
to assign an IP address to container
 Normal   SandboxChanged          15m (x86 over 25m)     kubelet, ip-192-168-68-97.ap-northeast-1.compute.internal  Pod sandbox changed, it will be killed and re-created.
 Warning  FailedCreatePodSandBox  5m36s (x118 over 24m)  kubelet, ip-192-168-68-97.ap-northeast-1.compute.internal  (combined from similar events): Failed create pod sandbox: rpc error: code = Unknown desc = f
ailed to set up sandbox container "23277d1da24d3c2757c39c61a69dfa08f7bee6a9de7cb7df21c78b7939d1eacd" network for pod "sample-74996797fd-2pmff": networkPlugin cni failed to set up pod "sample-74996797fd-2pmff_de
fault" network: add cmd: failed to assign an IP address to container

予想通りCNIプラグインがエラーを吐いてます。そして、理由はわかりませんがNodeが NotReady になってしまいました。

$ kubectl get nodes                
NAME                                                STATUS     ROLES    AGE   VERSION
ip-192-168-45-205.ap-northeast-1.compute.internal   NotReady   <none>   32m   v1.16.8-eks-e16311
ip-192-168-68-97.ap-northeast-1.compute.internal    NotReady   <none>   32m   v1.16.8-eks-e16311

結果

amazon-vpc-cni-k8sを使っているときは、--max-pods-per-node の値を変えただけでは1ノード辺りのPod数の上限値は増えないことがわかりました。
そしておそらくこの設定が原因で、Nodeも NotReady になってしまいました。
CNIプラグインもちゃんと別のものに変えないといけないということですね。
Calico独自の機能や動作検証の結果については、またの機会に書こうと思います。

執筆者:株式会社リアルグローブ・オートメーティッド技師 青島――――――――――――――――――――――――――――――――――

執筆者プロフィール:青島 秀治
株式会社リアルグローブ・オートメーティッド 技師
九州大学大学院理学府博士課程中退。
大学院では理論天文学が専門。数値計算プログラム開発の傍ら、研究用の計算機郡や学内システムの開発・運用を経験。
2019年よりAnsibleを用いた運用作業自動化や自社サービスのKubernetes移行、OpenShiftのインフラCI実装などの業務に従事。

【ご案内】
ITシステム開発やITインフラ運用の効率化、高速化、品質向上、その他、情シス部門の働き方改革など、IT自動化導入がもたらすメリットは様々ございます。
IT業務の自動化にご興味・ご関心ございましたら、まずは一度、IT自動化の専門家リアルグローブ・オートメーティッド(RGA)にご相談ください!

お問合せは以下の窓口までお願いいたします。

【お問い合わせ窓口】
株式会社リアルグローブ・オートメーティッド
代表窓口:info@rg-automated.jp
URL: https://rg-automated.jp

画像1

(編集:馬塚勇介/校正:水谷裕一)