KubernetesのPod間通信にCalicoを使ってみる


概要

複数のノード(マシン)でKubernetesによるコンテナオーケストレーションをする際に、異なるノードに配置されたPodをつなぐためのネットワーク構築が必要となる。Pod間のネットワークを構築するツールはFlannelをはじめとして多くあるが、今回Calicoを使ってみたら結構便利だったのでご紹介する。

例えばVirtualBoxのVMがノードに含まれていたりすると、ネットワークインターフェースが特殊なために、マニュアルや書籍に書かれている通りにやっても上手く行かないことが多い。Flannelのサンプルyamlファイルを適切に修正することでホストOSのネットワークが複雑な場合でも対応はできるのだが、ネットワークインターフェース名を追記したり、ノードにラベルをつけてラベル毎の条件をマニフェストに反映したりする必要がある。マニフェストの書き方に関する知識もそれなりに必要で、一年ほど前にKubernetes初心者だった筆者はかなり手こずった…。

しかし改めて同じことをCalicoでやってみたら、サンプルのマニフェストを2行ほど修正するだけで、Pod間通信をあっさりと実現できたので、ここで共有する。

試した構成

下図のように、WindowsのVirtualBox上にLinuxの仮想マシンをインストールしており、ブリッジ接続でVirtualBoxの外のネットワークからも直接アクセス可能な状態になっている。さらにもう一つ、同じネットワーク上にLinuxOSのPCが繋がっている状態。

上の構成において、VirtualBoxのLinux仮想マシンとLinuxPCにそれぞれKubernetesをインストールして、MasterノードとWorkerノード、およびPod間ネットワークが下図の状態になるようにしたい。

ちなみにVirtualBoxのLinux仮想マシンについては、ネットワークインターフェースが下記のように複数あり、後でノードのネットワークを構築する際に注意が必要。

$ ip a
...
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> ...
    ...
    inet 10.0.2.15/24 brd 10.0.2.255 ...
    ...
3: eth1: <BROADCAST,MULTICAST,UP,LOWER_UP> ...
    ...
    inet 192.168.1.3/24 brd 192.168.1.255 ...
    ...

必要なツール

  • Docker等のコンテナ構築ツール
  • kubeadm(Kubernetes環境を簡単に構築するためのツール)

    • 基本的には公式サイトの手順にしたがってインストールすればOK。
    • ただしVirtualBoxの仮想マシンに関しては、何も設定しないとKubernetesのノードをeth0のIPアドレス(10.0.2.15/24)と関連づけてしまうので、/etc/default/kubelet(CentOS、RHEL、Fedoraでは/etc/sysconfig/kubelet)を作成して、下記のようにeth1のIPアドレス(192.168.1.3/24)をノードIPとするように指定する必要あり。今回に限らず、ネットワークインターフェースが複数あるマシンには意図しないIPアドレスにノードが紐付けられてしまう可能性があるので(おそらく優先順位が最も高いネットワークのIPとなる?)、念のため以下を設定していた方が良いはず。
    /etc/default/kubelet
    KUBELET_EXTRA_ARGS=--node-ip=192.168.1.3
    

Kubernetesノードの作成

  • マスターノード(VirtualBoxの仮想マシン)でkubeadm initコマンドを実行

    • 引数にPod間ネットワークのサブネット192.168.2.0/24が必要(今回の構成例での設定値であり、各ネットワーク構成に応じて任意の値を指定可能)。また、KubernetesのAPIサーバのアドレスとして192.168.1.3(VirtualBoxの仮想マシンのIPアドレス)を指定する必要があることに注意。
    $ sudo kubeadm init \
      --pod-network-cidr=192.168.2.0/24 \
      --apiserver-advertise-address=192.168.1.3
    
    • 最後に下記のようなメッセージが出てきたら成功
    ...
    To start using your cluster, you need to run the following as a regular user:
    
      mkdir -p $HOME/.kube
      sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
      sudo chown $(id -u):$(id -g) $HOME/.kube/config
    
    You should now deploy a pod network to the cluster.
    Run "kubectl apply -f [podnetwork].yaml" with one of the options listed at:
      https://kubernetes.io/docs/concepts/cluster-administration/addons/
    
    Then you can join any number of worker nodes by running the following on each as root:
    
    kubeadm join 192.168.1.3:6443 --token xxxxxxxx... \
        --discovery-token-ca-cert-hash sha256:yyyyyyyy...
    
    • 出力結果にも書かれているように、下記コマンドで設定ファイルをユーザディレクトリにコピーして、Kubernetesのクラスターにユーザ権限でアクセスできるようにする。
    $ mkdir -p $HOME/.kube
    $ sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
    $ sudo chown $(id -u):$(id -g) $HOME/.kube/config
    
    • 余談だが、マスターノードにもPodなどのリソースを作れるようにするには、下記コマンドでmaster:NoScheduleのtaint(痕跡?)を外してあげる必要あり。
    $ kubectl taint nodes $(hostname) node-role.kubernetes.io/master:NoSchedule-
    
  • ワーカーノード(LinuxOSの物理マシン)でkubeadm joinコマンドを実行

    • マスターノードでkubeadm joinした時に出力されたコマンドを素直に実行する。
    $ sudo kubeadm join 192.168.1.3:6443 --token xxxxxxxx... \
        --discovery-token-ca-cert-hash sha256:yyyyyyyy...
    
    • マスターノード(VirtualBoxの仮想マシン)で、以下のように2つのノードが表示されたらOK(以下の出力は全設定が既に完了してから出力したものなので、実際にこの時点で確認したらSTATUSがReadyにはなっていなかったかも…)
    $ kubectl get node
    NAME         STATUS   ROLES    AGE    VERSION
    virtualbox   Ready    master   3d1h   v1.18.8
    linux-pc     Ready    <none>   3d1h   v1.18.8
    

Calicoをデプロイ

ようやく本題のCalicoの話。
まずは以下コマンドで、Calicoのマニフェストをダウンロード

$ wget https://docs.projectcalico.org/manifests/calico.yaml

ダウンロードしたcalico.yamlで、下記の行(3674行目あたり)の#を外して、value:192.168.2.0/24kubeadm init で指定した引数--pod-network-cidrと同じもの)を指定。

calico.yaml
             (省略)
             # - name: CALICO_IPV4POOL_CIDR
             #   value: "192.168.0.0/16" # -> "192.168.2.0/24"に変更
             (省略)

※Calicoの場合は上の二行を修正するだけでOKだが、Flannelで同じことをやろうとすると相当に面倒くさい…。(その話はここでは割愛)

Calicoのリソースを下記コマンドで作成

$ kubectl apply -f calico.yaml

数分程度待って、Calicoを含めた各Podが動いていることを確認

$ kubectl get pods -n kube-system -o wide
NAME                                       READY   STATUS    RESTARTS   AGE    IP             NODE          NOMINATED NODE   READINESS GATES
calico-kube-controllers-5bc4fc6f5f-gvtzq   1/1     Running   0          6m9s   10.244.1.4     linux-pc     <none>           <none>
calico-node-57f6n                          1/1     Running   0          6m9s   192.168.1.23   linux-pc     <none>           <none>
calico-node-8kjzb                          1/1     Running   0          6m9s   192.168.1.3    virtualbox   <none>           <none>
coredns-f9fd979d6-7rrvh                    1/1     Running   0          22m    10.244.1.2     linux-pc     <none>           <none>
coredns-f9fd979d6-tlb82                    1/1     Running   0          22m    10.244.1.3     linux-pc     <none>           <none>
etcd-kube-master                           1/1     Running   0          22m    192.168.1.3    virtualbox   <none>           <none>
kube-apiserver-kube-master                 1/1     Running   0          22m    192.168.1.3    virtualbox   <none>           <none>
kube-controller-manager-virtualbox         1/1     Running   0          22m    192.168.1.3    virtualbox   <none>           <none>
kube-proxy-dtcsk                           1/1     Running   0          19m    192.168.1.4    linux-pc     <none>           <none>
kube-proxy-htk75                           1/1     Running   0          22m    192.168.1.3    virtualbox   <none>           <none>
kube-scheduler-kube-master                 1/1     Running   0          22m    192.168.1.3    virtualbox   <none>           <none>

Pod間ネットワークの疎通確認

試しに、nginxのコンテナをレプリカ3の冗長構成で動かしてみる

$ kubectl create deployment nginx --image=nginx --replicas=3

起動後しばらくして確認すると、事前に定義したPodネットワーク192.168.2.0/24内で動いていることを確認

$ kubectl get pods -o wide
NAME                     READY   STATUS    RESTARTS   AGE   IP              NODE          NOMINATED NODE   READINESS GATES
nginx-6799fc88d8-8jjl9   1/1     Running   0          11s   192.168.2.194   virtualbox    <none>           <none>
nginx-6799fc88d8-fzg2h   1/1     Running   0          11s   192.168.2.131   linux-pc      <none>           <none>
nginx-6799fc88d8-kj44h   1/1     Running   0          11s   192.168.2.132   linux-pc      <none>           <none>

あるPodからcurlを実行し、他のPodのwebサーバにアクセスできることを確認!

$ kubectl exec nginx-6799fc88d8-8jjl9 -- curl 192.168.2.131
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
(以後の出力省略)