今回は実際にCalicoを使用してKubernetesのネットワークを構築します。Kubernetesはコンテナオーケストレーションツールとして非常に盛り上がりを見せています。CalicoはKubernetesとの統合も活発に進められており、以前に紹介したようにセキュリティポリシーにも対応していることから、コンテナのネットワークおよびセキュリティとして使用される場面が多くなってくると思われます。
Kubernetesとは
Kubernetesはコンテナ化されたアプリケーションの自動デプロイやオートスケーリング、管理を行うオープンソースソフトウェアです。元々はGoogleがデータセンターでコンテナを管理するために開発したBorgというソフトウェアをOSS化したものになります。Kubernetesではネットワークの管理やデプロイを各ネットワークプラグインに任せており、Container Networking Interface(CNI)として実装されます。CNIプラグインの一つとしてCalicoが提供されているため、Kubernetesのコンテナネットワークとして動作させることを可能としています。
構築する環境について
バージョン情報
今回構築する環境では以下のバージョンを使用しています。
バージョン
Calico
v3.0
Calico CLI Tool
v2.0.1
Kubernetes
v1.9.4
Docker
17.12.1-ce
kubeadm
v1.9.4
クラスタ構成
今回構築するKubernetes環境は、1台のマスターと2台のノード、合計3台で構成するシンプルなKubernetesクラスタになります。Kubernetesは最小1台で構成できますが、せっかくCalicoを使ってルーティングネットワークを組むので3台構成にしています。筆者の環境ではUbuntu16.04をインストールした物理サーバー上にKVMで仮想マシンを3台立てており、1つのLinux Bridgeに接続してL2で通信できるようにしています。仮想マシンのOSとしてもUbuntu16.04をインストールしています。
Kubernetes構築
Kubeadmのインストール
今回は構築にkubeadmというツールを使用しました。kubeadmはKubernetesのアップストリームで開発されているKubernetes構築ツールです。kubeadm自体のインストール手順はInstalling kubeadmに詳しく書かれているので割愛します。
Kubernetesクラスタの構築
Masterの構築
まず始めにマスターの構築から行います。 kubeadm init
コマンドによりマスターを初期化します。コマンド実行時にさまざまなオプションを渡すことができますが、ここではCalicoによって管理されるPodに割り当てられるIPアドレスのCIDRに 192.168.0.0/16
を指定しています。
01 | k8s-master~$ sudo kubeadm init --pod-network-cidr=192.168.0.0/16 --ignore-preflight-errors=Swap |
02 | [init] Using Kubernetes version: v1.9.4 |
03 | [init] Using Authorization modes: [Node RBAC] |
04 | [preflight] Running pre-flight checks. |
05 | [WARNING SystemVerification]: docker version is greater than the most recently validated version. Docker version: 17.12.1-ce. Max validated version: 17.03 |
06 | [WARNING Swap]: running with swap on is not supported. Please disable swap |
07 | [WARNING FileExisting-crictl]: crictl not found in system path |
08 | [preflight] Starting the kubelet service |
09 | [certificates] Generated ca certificate and key. |
10 | [certificates] Generated apiserver certificate and key. |
11 | [certificates] apiserver serving cert is signed for DNS names [k8s-master kubernetes kubernetes.default kubernetes.default.svc kubernetes.default.svc.cluster.local] and IPs [10.96.0.1 172.16.0.10] |
12 | [certificates] Generated apiserver-kubelet-client certificate and key. |
13 | [certificates] Generated sa key and public key. |
14 | [certificates] Generated front-proxy-ca certificate and key. |
15 | [certificates] Generated front-proxy-client certificate and key. |
16 | [certificates] Valid certificates and keys now exist in "/etc/kubernetes/pki" |
17 | [kubeconfig] Wrote KubeConfig file to disk: "admin.conf" |
18 | [kubeconfig] Wrote KubeConfig file to disk: "kubelet.conf" |
19 | [kubeconfig] Wrote KubeConfig file to disk: "controller-manager.conf" |
20 | [kubeconfig] Wrote KubeConfig file to disk: "scheduler.conf" |
21 | [controlplane] Wrote Static Pod manifest for component kube-apiserver to "/etc/kubernetes/manifests/kube-apiserver.yaml" |
22 | [controlplane] Wrote Static Pod manifest for component kube-controller-manager to "/etc/kubernetes/manifests/kube-controller-manager.yaml" |
23 | [controlplane] Wrote Static Pod manifest for component kube-scheduler to "/etc/kubernetes/manifests/kube-scheduler.yaml" |
24 | [etcd] Wrote Static Pod manifest for a local etcd instance to "/etc/kubernetes/manifests/etcd.yaml" |
25 | [init] Waiting for the kubelet to boot up the control plane as Static Pods from directory "/etc/kubernetes/manifests". |
26 | [init] This might take a minute or longer if the control plane images have to be pulled. |
27 | [apiclient] All control plane components are healthy after 48.001818 seconds |
28 | [uploadconfig]?Storing the configuration used in ConfigMap "kubeadm-config" in the "kube-system" Namespace |
29 | [markmaster] Will mark node k8s-master as master by adding a label and a taint |
30 | [markmaster] Master k8s-master tainted and labelled with key/value: node-role.kubernetes.io/master="" |
31 | [bootstraptoken] Using token: 658fea.b67a9ffdaced182a |
32 | [bootstraptoken] Configured RBAC rules to allow Node Bootstrap tokens to post CSRs in order for nodes to get long term certificate credentials |
33 | [bootstraptoken] Configured RBAC rules to allow the csrapprover controller automatically approve CSRs from a Node Bootstrap Token |
34 | [bootstraptoken] Configured RBAC rules to allow certificate rotation for all node client certificates in the cluster |
35 | [bootstraptoken] Creating the "cluster-info" ConfigMap in the "kube-public" namespace |
36 | [addons] Applied essential addon: kube-dns |
37 | [addons] Applied essential addon: kube-proxy |
39 | Your Kubernetes master has initialized successfully! |
41 | To start using your cluster, you need to run the following as a regular user: |
44 | sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config |
45 | sudo chown $(id -u):$(id -g) $HOME/.kube/config |
47 | You should now deploy a pod network to the cluster. |
48 | Run "kubectl apply -f [podnetwork].yaml" with one of the options listed at: |
51 | You can now join any number of machines by running the following on each node |
54 | kubeadm join --token 77d3cb.a4344218b6afb535 172.16.0.10:6443 --discovery-token-ca-cert-hash sha256:d87774ddd2e342e86cf9092d294f9fedb85639a1812629f5f6b2c079ff4b67fc |
初期化処理が完了すると「Your Kubernetes master has initialized successfully!」というメッセージとともに、kubectlを使用するための設定方法とノードを追加するためのコマンドが出力されます。これはノードの構築時に使用するのでメモしておいてください。
kubectlを使うための設定としてadmin.confが作成されているので、ホームディレクトリの.kubeというディレクトリに移動し、ファイルの所有権を変更します。
1 | k8s-master~$ mkdir -p $HOME/.kube |
2 | k8s-master~$ sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config |
3 | k8s-master~$ sudo chown $(id -u):$(id -g) $HOME/.kube/config |
これでkubectlコマンドが使用できるようになりました。ノードの状態を確認してみます。以下のようにノードの状態が取得できれば成功です。
1 | k8s-master~$ kubectl get nodes |
2 | NAME STATUS ROLES AGE VERSION |
3 | k8s-master NotReady master 2m v1.9.4 |
この時点ではネットワークプラグインをインストールしていないのでノードのSTATUSがNotReadyとなっています。
それでは、ネットワークプラグインをインストールします。通常、Podネットワークはクラスタごとに1つのCNIプラグインが必要になりますのでCalicoを選択します。Project Calicoのドキュメントで サンプル の設定が用意されているので、ここではそのサンプルを使いたいと思います。
マスターの構築時に --pod-network-cider=192.168.0.0/16 を指定しました。これは、calico.yamlの220行目のCALICO_IPV4POOL_CIDRの値と揃えています。その他のCalicoノードの設定パラメータは[ドキュメントのConfiguring calico/nodeに全て記載されているので必要に応じて修正します。今回はサンプルのまま設定します。インストール方法は以下のようにサンプルの設定ファイルを適用するだけです。
コマンドが問題なく終了したら、Podの状態を確認します。 kubectl get pods --all-namespaces
で全てのPodのSTATUSがRunningになっていることを確認します。Kubernetes本体のPodやCalicoのPodはkube-systemというネームスペースで起動されますので、 --all-namespace
か -n kube-system
というオプションを指定する必要があります。
01 | NAMESPACE NAME READY STATUS RESTARTS AGE |
02 | kube-system calico-etcd-dxb8s 1/1 Running 0 3m |
03 | kube-system calico-kube-controllers-559b575f97-29m7j 1/1 Running 0 3m |
04 | kube-system calico-node-bggsx 2/2 Running 0 3m |
05 | kube-system etcd-k8s-master 1/1 Running 0 4m |
06 | kube-system kube-apiserver-k8s-master 1/1 Running 0 3m |
07 | kube-system kube-controller-manager-k8s-master 1/1 Running 0 3m |
08 | kube-system kube-dns-6f4fd4bdf-8xwwz 3/3 Running 0 4m |
09 | kube-system kube-proxy-f5mpg 1/1 Running 0 4m |
10 | kube-system kube-scheduler-k8s-master 1/1 Running 0 3m |
すべて正常に起動できると、ノードのSTATUSがReadyになっているのが確認できます。
1 | k8s-master~$ kubectl get nodes |
2 | NAME STATUS ROLES AGE VERSION |
3 | k8s-master Ready master 5m v1.9.4 |
以上でマスターの構築は完了です。
ノードの追加
マスターが構築できたので、続いてノードを追加していきます。ノードにも事前にkubeadmなどのパッケージをインストールしておいてください。
マスターの構築時にメモしたノードを追加するコマンドを用意してください。ノードにログインし、メモしたコマンドを実行します。
01 | k8s-node-01~$ sudo kubeadm join --token 77d3cb.a4344218b6afb535 172.16.0.10:6443 --discovery-token-ca-cert-hash sha256:d87774ddd2e342e86cf9092d294f9fedb85639a1812629f5f6b2c079ff4b67fc --ignore-preflight-errors=Swap |
02 | [preflight] Running pre-flight checks. |
03 | [WARNING SystemVerification]: docker version is greater than the most recently validated version. Docker version: 17.12.1-ce. Max validated version: 17.03 |
04 | [WARNING Swap]: running with swap on is not supported. Please disable swap |
05 | [WARNING FileExisting-crictl]: crictl not found in system path |
06 | [preflight] Starting the kubelet service |
07 | [discovery] Trying to connect to API Server "172.16.0.10:6443" |
10 | [discovery] Cluster info signature and contents are valid and TLS certificate validates against pinned roots, will use API Server "172.16.0.10:6443" |
11 | [discovery] Successfully established connection with API Server "172.16.0.10:6443" |
13 | This node has joined the cluster: |
14 | * Certificate signing request was sent to master and a response |
16 | * The Kubelet was informed of the new secure connection details. |
18 | Run 'kubectl get nodes' on the master to see this node join the cluster. |
マスターで kubectl get pods --all-namespaces
を実行して、全てのPodが起動できたらノードの構築が完了です。もう1台のノードk8s-node-02でも同じようにコマンドを実行し、全てのPodが起動できたらノードのSTATUSがReadyになっておりKubernetesクラスタの構築は完了です。
1 | k8s-master~$ kubectl get nodes |
2 | NAME STATUS ROLES AGE VERSION |
3 | k8s-master Ready master 9m v1.9.4 |
4 | k8s-node-01 Ready <none> 3m v1.9.4 |
5 | k8s-node-02 Ready <none> 1m v1.9.4 |
動作の確認
CNIプラグインとしてCalicoを指定しました。Calicoを使用している場合、実際にはどのようなPodが動作しているのか見ていきます。
CalicoのコンポーネントとしてFelixやBIRD、etcdなどがありますが、これらはKubernetesのPodとしてkube-systemというネームスペースで起動します。CalicoのPodを確認するにはkube-systemというネームスペースを指定してPodの情報を取得します。
01 | k8s-master~$ kubectl get pods -n kube-system -o wide |
02 | NAME READY STATUS RESTARTS AGE IP NODE |
03 | calico-etcd-dxb8s 1/1 Running 0 9m 172.16.0.10 k8s-master |
04 | calico-kube-controllers-559b575f97-29m7j 1/1 Running 0 9m 172.16.0.10 k8s-master |
05 | calico-node-2mttf 2/2 Running 0 3m 172.16.0.11 k8s-node-01 |
06 | calico-node-6snck 2/2 Running 1 1m 172.16.0.12 k8s-node-02 |
07 | calico-node-bggsx 2/2 Running 0 9m 172.16.0.10 k8s-master |
08 | etcd-k8s-master 1/1 Running 0 9m 172.16.0.10 k8s-master |
09 | kube-apiserver-k8s-master 1/1 Running 0 9m 172.16.0.10 k8s-master |
10 | kube-controller-manager-k8s-master 1/1 Running 0 9m 172.16.0.10 k8s-master |
11 | kube-dns-6f4fd4bdf-8xwwz 3/3 Running 0 9m 192.168.235.193 k8s-master |
12 | kube-proxy-22gs4 1/1 Running 0 1m 172.16.0.12 k8s-node-02 |
13 | kube-proxy-f5mpg 1/1 Running 0 9m 172.16.0.10 k8s-master |
14 | kube-proxy-tc24n 1/1 Running 0 3m 172.16.0.11 k8s-node-01 |
15 | kube-scheduler-k8s-master 1/1 Running 0 9m 172.16.0.10 k8s-master |
CalicoのPodが5つ動作しているのがわかります。Calicoが使用するcalico-etcdがマスターで動作しています。calico-kube-controllersはkubernetesのネットワークポリシーやネームスペース、ラベルなどを監視し、etcdに書き込みます。そして、calico-nodeというPod内でFelixやBIRDといったプロセスが各ノードで動作しており、calico-etcdの情報をノードの設定に反映します。
Calicoノードの状態の確認や様々な設定を行ったりするために、Calico CLI Toolと呼ばれるクライアントツールが用意されています。Calico CLI Toolを使用するには、ソースコードからビルドするかGitHubからバイナリファイルをダウンロードして実行権限を付与します。
2 | k8s-master~$ chmod +x calicoctl |
calicoctlを実行するにはetcdエンドポイントなどの値をcalicoctl.cfgという設定ファイルか環境変数でコマンドに渡す必要があります。ここではcalicoctl.cfgを使用します。
まず、calicoctl.cfgのファイルを置くディレクトリを作成します。calicoctlはデフォルトで /etc/calico/
を参照するようになっているので、このディレクトリを作成します。
1 | k8s-master~$ sudo mkdir /etc/calico |
calicoctl.cfgを作成します。
1 | k8s-master~$ sudo vim /etc/calico/calicoctl.cfg |
以下のようにYamlで記述し保存してください。etcdEndopointsはcalico.yamlの17行目に定義されているIPアドレスを設定します。etcdが冗長化され複数台ある場合には、カンマで区切って複数のIPアドレスを設定します。
1 | apiVersion: projectcalico.org/v3 |
5 | datastoreType: "etcdv3" |
これでcalicoctlを使用する準備が整いましたので、実際にコマンドを実行してCalicoノードを取得してみます。以下のように、Calicoノードの情報が取得できれば正しく動作しています。
1 | k8s-master~$ ./calicoctl get node -o wide |
3 | k8s-master (unknown) 172.16.0.10/16 |
4 | k8s-node-01 (unknown) 172.16.0.11/16 |
5 | k8s-node-02 (unknown) 172.16.0.12/16 |
--helpオプションを使用すれば様々な使い方を知ることができます。ぜひ色々見て使いこなしてください。
02 | calicoctl [options] <command> [<args>...] |
04 | create Create a resource by filename or stdin. |
05 | replace Replace a resource by filename or stdin. |
06 | apply Apply a resource by filename or stdin. This creates a resource |
07 | if it does not exist, and replaces a resource if it does exists. |
08 | delete Delete a resource identified by file, stdin or resource type and |
10 | get Get a resource identified by file, stdin or resource type and |
12 | convert Convert config files between different API versions. |
13 | ipam IP address management. |
14 | node Calico node management. |
15 | version Display the version of calicoctl. |
18 | -h --help Show this screen. |
19 | -l --log-level=<level> Set the log level (one of panic, fatal, error, |
20 | warn, info, debug) [default: panic] |
23 | The calicoctl command line tool is used to manage Calico network and security |
24 | policy, to view and manage endpoint configuration, and to manage a Calico |
27 | See 'calicoctl <command> --help' to read about a specific subcommand. |
アプリケーションのデプロイと疎通確認
Nginxアプリケーションのデプロイ
KubernetesとCalicoの環境が構築できたので実際にNginxのアプリケーションをデプロイしてみます。KubernetesのマスターにログインしてNginxのPodを起動します。--replicas=2とすることでNginxのPodを2つ起動しています。
1 | k8s-master~$ kubectl run my-nginx --image=nginx --replicas=2 --port=80 |
2 | deployment "my-nginx" created |
Podが起動できたか確認します。
1 | k8s-master~$ kubectl get pods |
2 | NAME READY STATUS RESTARTS AGE |
3 | my-nginx-9d5677d94-48pmz 1/1 Running 0 31s |
4 | my-nginx-9d5677d94-z655m 1/1 Running 0 32s |
STATUSがRunningになっていれば正しく起動できています。
疎通確認
NginxのPodがデプロイできたので、クラスター内部からアクセスできることを確認してみます。cURLがインストールされているPodを新たに起動して、NginxのPod IP宛にリクエストしてみます。まず、NginxのPod IPを確認します。--replicas=2を指定したので2つのPod IPが確認できます。
1 | k8s-master~$ kubectl get pods -o wide |
2 | NAME READY STATUS RESTARTS AGE IP NODE |
3 | my-nginx-9d5677d94-48pmz 1/1 Running 0 1m 192.168.154.193 k8s-node-01 |
4 | my-nginx-9d5677d94-z655m 1/1 Running 0 1m 192.168.44.193 k8s-node-02 |
cURLがインストールされているPodを立ち上げます。起動と同時にPod内のプロンプトに入ることができます。--rmオプションを指定することで、プロンプトからCtrl+Cで抜けると同時にこのPodは削除されます。
それではNginxのPod IPにcurlでリクエストを投げてみます。まず、k8s-node-01上の192.168.154.193宛にリクエストします。
01 | k8s-master~$ kubectl run curl --image=radial/busyboxplus:curl -i --tty --rm |
02 | If you don't see a command prompt, try pressing enter. |
03 | [ root@curl-545bbf5f9c-4bxsq:/ ]$ curl 192.168.154.193 |
07 | <title>Welcome to nginx!</title> |
12 | font-family: Tahoma, Verdana, Arial, sans-serif; |
17 | <h2>Welcome to nginx!</h2> |
18 | <p>If you see this page, the nginx web server is successfully installed and |
19 | working. Further configuration is required.</p> |
21 | <p>For online documentation and support please refer to |
23 | Commercial support is available at |
26 | <p><em>Thank you for using nginx.</em></p> |
同じようにk8s-node-02上の192.168.44.193にもリクエストしてNginxからレスポンスが返ってくればCalicoによるクラスターネットワークが正常に動作しています。
01 | [ root@curl-545bbf5f9c-4bxsq:/ ]$ curl 192.168.44.193 |
05 | <title>Welcome to nginx!</title> |
10 | font-family: Tahoma, Verdana, Arial, sans-serif; |
15 | <h2>Welcome to nginx!</h2> |
16 | <p>If you see this page, the nginx web server is successfully installed and |
17 | working. Further configuration is required.</p> |
19 | <p>For online documentation and support please refer to |
21 | Commercial support is available at |
24 | <p><em>Thank you for using nginx.</em></p> |
最後にPodへの経路情報を確認してみましょう。まず、マスターからcalicoctlコマンドを使用してPodの名前、IPアドレス、インターフェース名の紐付きを確認します。CalicoではPodのインターフェースのことをワークロードエンドポイントと呼んでおり、取得するリソース名としてworkloadEndpointを指定しています。取得できる情報が多いので-oオプションを使用して表示するカラムを整形しています。
1 | k8s-master~$ ./calicoctl get workloadEndpoint -o custom-columns=NODE,WORKLOAD,NETWORKS,INTERFACE |
2 | NODE WORKLOAD NETWORKS INTERFACE |
3 | k8s-node-01 my-nginx-9d5677d94-48pmz 192.168.154.193/32 calieafb5bf2e52 |
4 | k8s-node-02 my-nginx-9d5677d94-z655m 192.168.44.193/32 calie29c2d4b309 |
my-nginx-9d5677d94-48pmzというNginxのPodがIPアドレス192.168.154.193が割り当てられてk8s-node-01上で動作しています。
k8s-node-01にログインしてPodへのルーティングを見てみましょう。NginxのPod宛である192.168.154.193への通信がcalieafb5bf2e52というインターフェースにホストルーティングされていることが確認できます。
02 | Kernel IP routing table |
03 | Destination Gateway Genmask Flags Metric Ref Use Iface |
04 | default 172.16.0.1 0.0.0.0 UG 0 0 0 enp0s3 |
05 | 172.16.0.0 * 255.255.0.0 U 0 0 0 enp0s3 |
06 | 172.17.0.0 * 255.255.0.0 U 0 0 0 docker0 |
07 | 192.168.44.192 172.16.0.12 255.255.255.192 UG 0 0 0 tunl0 |
08 | 192.168.154.192 * 255.255.255.192 U 0 0 0 * |
09 | 192.168.154.193 * 255.255.255.255 UH 0 0 0 calieafb5bf2e52 |
10 | 192.168.235.192 172.16.0.10 255.255.255.192 UG 0 0 0 tunl0 |
以上でCalicoおよびKubernetesの動作確認は終了です。
今回はCalicoとKubernetesの環境を構築し実際にNginxのアプリケーションを起動して疎通確認まで行いました。これでネットワークプラグインとしてのCalicoの振る舞いやコンテナネットワークのイメージができたと思います。次回は今回構築した環境を使用して、Calicoの代表的なセキュリティ機能であるネットワークポリシーを使用してみます。