Project CalicoをKubernetesで使ってみる:構築編

2018年7月25日(水)
安座間 勇二(あざま ゆうじ)

今回は実際に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 を指定しています。

k8s-master~$ sudo kubeadm init --pod-network-cidr=192.168.0.0/16 --ignore-preflight-errors=Swap
[init] Using Kubernetes version: v1.9.4
[init] Using Authorization modes: [Node RBAC]
[preflight] Running pre-flight checks.
        [WARNING SystemVerification]: docker version is greater than the most recently validated version. Docker version: 17.12.1-ce. Max validated version: 17.03
        [WARNING Swap]: running with swap on is not supported. Please disable swap
        [WARNING FileExisting-crictl]: crictl not found in system path
[preflight] Starting the kubelet service
[certificates] Generated ca certificate and key.
[certificates] Generated apiserver certificate and key.
[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]
[certificates] Generated apiserver-kubelet-client certificate and key.
[certificates] Generated sa key and public key.
[certificates] Generated front-proxy-ca certificate and key.
[certificates] Generated front-proxy-client certificate and key.
[certificates] Valid certificates and keys now exist in "/etc/kubernetes/pki"
[kubeconfig] Wrote KubeConfig file to disk: "admin.conf"
[kubeconfig] Wrote KubeConfig file to disk: "kubelet.conf"
[kubeconfig] Wrote KubeConfig file to disk: "controller-manager.conf"
[kubeconfig] Wrote KubeConfig file to disk: "scheduler.conf"
[controlplane] Wrote Static Pod manifest for component kube-apiserver to "/etc/kubernetes/manifests/kube-apiserver.yaml"
[controlplane] Wrote Static Pod manifest for component kube-controller-manager to "/etc/kubernetes/manifests/kube-controller-manager.yaml"
[controlplane] Wrote Static Pod manifest for component kube-scheduler to "/etc/kubernetes/manifests/kube-scheduler.yaml"
[etcd] Wrote Static Pod manifest for a local etcd instance to "/etc/kubernetes/manifests/etcd.yaml"
[init] Waiting for the kubelet to boot up the control plane as Static Pods from directory "/etc/kubernetes/manifests".
[init] This might take a minute or longer if the control plane images have to be pulled.
[apiclient] All control plane components are healthy after 48.001818 seconds
[uploadconfig]?Storing the configuration used in ConfigMap "kubeadm-config" in the "kube-system" Namespace
[markmaster] Will mark node k8s-master as master by adding a label and a taint
[markmaster] Master k8s-master tainted and labelled with key/value: node-role.kubernetes.io/master=""
[bootstraptoken] Using token: 658fea.b67a9ffdaced182a
[bootstraptoken] Configured RBAC rules to allow Node Bootstrap tokens to post CSRs in order for nodes to get long term certificate credentials
[bootstraptoken] Configured RBAC rules to allow the csrapprover controller automatically approve CSRs from a Node Bootstrap Token
[bootstraptoken] Configured RBAC rules to allow certificate rotation for all node client certificates in the cluster
[bootstraptoken] Creating the "cluster-info" ConfigMap in the "kube-public" namespace
[addons] Applied essential addon: kube-dns
[addons] Applied essential addon: kube-proxy

Your Kubernetes master has initialized successfully!

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/

You can now join any number of machines by running the following on each node
as root:

  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というディレクトリに移動し、ファイルの所有権を変更します。

k8s-master~$ mkdir -p $HOME/.kube
k8s-master~$ sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
k8s-master~$ sudo chown $(id -u):$(id -g) $HOME/.kube/config

これでkubectlコマンドが使用できるようになりました。ノードの状態を確認してみます。以下のようにノードの状態が取得できれば成功です。

k8s-master~$ kubectl get nodes
NAME         STATUS    ROLES     AGE       VERSION
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に全て記載されているので必要に応じて修正します。今回はサンプルのまま設定します。インストール方法は以下のようにサンプルの設定ファイルを適用するだけです。

k8s-master~$ kubectl apply -f https://docs.projectcalico.org/v3.0/getting-started/kubernetes/installation/hosted/kubeadm/1.7/calico.yaml

コマンドが問題なく終了したら、Podの状態を確認します。 kubectl get pods --all-namespaces で全てのPodのSTATUSがRunningになっていることを確認します。Kubernetes本体のPodやCalicoのPodはkube-systemというネームスペースで起動されますので、 --all-namespace-n kube-system というオプションを指定する必要があります。

NAMESPACE     NAME                                       READY     STATUS    RESTARTS   AGE
kube-system   calico-etcd-dxb8s                          1/1       Running   0          3m
kube-system   calico-kube-controllers-559b575f97-29m7j   1/1       Running   0          3m
kube-system   calico-node-bggsx                          2/2       Running   0          3m
kube-system   etcd-k8s-master                            1/1       Running   0          4m
kube-system   kube-apiserver-k8s-master                  1/1       Running   0          3m
kube-system   kube-controller-manager-k8s-master         1/1       Running   0          3m
kube-system   kube-dns-6f4fd4bdf-8xwwz                   3/3       Running   0          4m
kube-system   kube-proxy-f5mpg                           1/1       Running   0          4m
kube-system   kube-scheduler-k8s-master                  1/1       Running   0          3m

すべて正常に起動できると、ノードのSTATUSがReadyになっているのが確認できます。

k8s-master~$ kubectl get nodes
NAME         STATUS    ROLES     AGE       VERSION
k8s-master   Ready     master    5m        v1.9.4

以上でマスターの構築は完了です。

ノードの追加

マスターが構築できたので、続いてノードを追加していきます。ノードにも事前にkubeadmなどのパッケージをインストールしておいてください。

マスターの構築時にメモしたノードを追加するコマンドを用意してください。ノードにログインし、メモしたコマンドを実行します。

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
[preflight] Running pre-flight checks.
        [WARNING SystemVerification]: docker version is greater than the most recently validated version. Docker version: 17.12.1-ce. Max validated version: 17.03
        [WARNING Swap]: running with swap on is not supported. Please disable swap
        [WARNING FileExisting-crictl]: crictl not found in system path
[preflight] Starting the kubelet service
[discovery] Trying to connect to API Server "172.16.0.10:6443"
[discovery] Created cluster-info discovery client, requesting info from "https://172.16.0.10:6443"
[discovery] Requesting info from "https://172.16.0.10:6443" again to validate TLS against the pinned public key
[discovery] Cluster info signature and contents are valid and TLS certificate validates against pinned roots, will use API Server "172.16.0.10:6443"
[discovery] Successfully established connection with API Server "172.16.0.10:6443"

This node has joined the cluster:
* Certificate signing request was sent to master and a response
  was received.
* The Kubelet was informed of the new secure connection details.

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クラスタの構築は完了です。

k8s-master~$ kubectl get nodes
NAME          STATUS    ROLES     AGE       VERSION
k8s-master    Ready     master    9m        v1.9.4
k8s-node-01   Ready     <none>    3m        v1.9.4
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の情報を取得します。

k8s-master~$ kubectl get pods -n kube-system -o wide
NAME                                       READY     STATUS    RESTARTS   AGE       IP                NODE
calico-etcd-dxb8s                          1/1       Running   0          9m        172.16.0.10       k8s-master
calico-kube-controllers-559b575f97-29m7j   1/1       Running   0          9m        172.16.0.10       k8s-master
calico-node-2mttf                          2/2       Running   0          3m        172.16.0.11       k8s-node-01
calico-node-6snck                          2/2       Running   1          1m        172.16.0.12       k8s-node-02
calico-node-bggsx                          2/2       Running   0          9m        172.16.0.10       k8s-master
etcd-k8s-master                            1/1       Running   0          9m        172.16.0.10       k8s-master
kube-apiserver-k8s-master                  1/1       Running   0          9m        172.16.0.10       k8s-master
kube-controller-manager-k8s-master         1/1       Running   0          9m        172.16.0.10       k8s-master
kube-dns-6f4fd4bdf-8xwwz                   3/3       Running   0          9m        192.168.235.193   k8s-master
kube-proxy-22gs4                           1/1       Running   0          1m        172.16.0.12       k8s-node-02
kube-proxy-f5mpg                           1/1       Running   0          9m        172.16.0.10       k8s-master
kube-proxy-tc24n                           1/1       Running   0          3m        172.16.0.11       k8s-node-01
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 CLI Tool

Calicoノードの状態の確認や様々な設定を行ったりするために、Calico CLI Toolと呼ばれるクライアントツールが用意されています。Calico CLI Toolを使用するには、ソースコードからビルドするかGitHubからバイナリファイルをダウンロードして実行権限を付与します。

k8s-master~$ wget https://github.com/projectcalico/calicoctl/releases/download/v2.0.1/calicoctl
k8s-master~$ chmod +x calicoctl

calicoctlを実行するにはetcdエンドポイントなどの値をcalicoctl.cfgという設定ファイルか環境変数でコマンドに渡す必要があります。ここではcalicoctl.cfgを使用します。

まず、calicoctl.cfgのファイルを置くディレクトリを作成します。calicoctlはデフォルトで /etc/calico/ を参照するようになっているので、このディレクトリを作成します。

k8s-master~$ sudo mkdir /etc/calico

calicoctl.cfgを作成します。

k8s-master~$ sudo vim /etc/calico/calicoctl.cfg

以下のようにYamlで記述し保存してください。etcdEndopointsはcalico.yamlの17行目に定義されているIPアドレスを設定します。etcdが冗長化され複数台ある場合には、カンマで区切って複数のIPアドレスを設定します。

apiVersion: projectcalico.org/v3
kind: CalicoAPIConfig
metadata:
spec:
  datastoreType: "etcdv3"
  etcdEndpoints: "http://10.96.232.136:6666"

これでcalicoctlを使用する準備が整いましたので、実際にコマンドを実行してCalicoノードを取得してみます。以下のように、Calicoノードの情報が取得できれば正しく動作しています。

k8s-master~$ ./calicoctl get node -o wide
NAME          ASN         IPV4             IPV6
k8s-master    (unknown)   172.16.0.10/16
k8s-node-01   (unknown)   172.16.0.11/16
k8s-node-02   (unknown)   172.16.0.12/16

--helpオプションを使用すれば様々な使い方を知ることができます。ぜひ色々見て使いこなしてください。

Usage:
  calicoctl [options] <command> [<args>...]

    create    Create a resource by filename or stdin.
    replace   Replace a resource by filename or stdin.
    apply     Apply a resource by filename or stdin.  This creates a resource
              if it does not exist, and replaces a resource if it does exists.
    delete    Delete a resource identified by file, stdin or resource type and
              name.
    get       Get a resource identified by file, stdin or resource type and
              name.
    convert   Convert config files between different API versions.
    ipam      IP address management.
    node      Calico node management.
    version   Display the version of calicoctl.

Options:
  -h --help               Show this screen.
  -l --log-level=<level>  Set the log level (one of panic, fatal, error,
                          warn, info, debug) [default: panic]

Description:
  The calicoctl command line tool is used to manage Calico network and security
  policy, to view and manage endpoint configuration, and to manage a Calico
  node instance.

  See 'calicoctl <command> --help' to read about a specific subcommand.

アプリケーションのデプロイと疎通確認

Nginxアプリケーションのデプロイ

KubernetesとCalicoの環境が構築できたので実際にNginxのアプリケーションをデプロイしてみます。KubernetesのマスターにログインしてNginxのPodを起動します。--replicas=2とすることでNginxのPodを2つ起動しています。

k8s-master~$ kubectl run my-nginx --image=nginx --replicas=2 --port=80
deployment "my-nginx" created

Podが起動できたか確認します。

k8s-master~$ kubectl get pods
NAME                       READY     STATUS    RESTARTS   AGE
my-nginx-9d5677d94-48pmz   1/1       Running   0          31s
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が確認できます。

k8s-master~$ kubectl get pods -o wide
NAME                       READY     STATUS    RESTARTS   AGE       IP                NODE
my-nginx-9d5677d94-48pmz   1/1       Running   0          1m        192.168.154.193   k8s-node-01
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宛にリクエストします。

k8s-master~$ kubectl run curl --image=radial/busyboxplus:curl -i --tty --rm
If you don't see a command prompt, try pressing enter.
[ root@curl-545bbf5f9c-4bxsq:/ ]$ curl 192.168.154.193
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
    body {
        width: 35em;
        margin: 0 auto;
        font-family: Tahoma, Verdana, Arial, sans-serif;
    }
</style>
</head>
<body>
<h2>Welcome to nginx!</h2>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p>

<p>For online documentation and support please refer to
<a href="http://nginx.org/">nginx.org</a>.<br/>
Commercial support is available at
<a href="http://nginx.com/">nginx.com</a>.</p>

<p><em>Thank you for using nginx.</em></p>
</body>
</html>

同じようにk8s-node-02上の192.168.44.193にもリクエストしてNginxからレスポンスが返ってくればCalicoによるクラスターネットワークが正常に動作しています。

[ root@curl-545bbf5f9c-4bxsq:/ ]$ curl 192.168.44.193
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
    body {
        width: 35em;
        margin: 0 auto;
        font-family: Tahoma, Verdana, Arial, sans-serif;
    }
</style>
</head>
<body>
<h2>Welcome to nginx!</h2>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p>

<p>For online documentation and support please refer to
<a href="http://nginx.org/">nginx.org</a>.<br/>
Commercial support is available at
<a href="http://nginx.com/">nginx.com</a>.</p>

<p><em>Thank you for using nginx.</em></p>
</body>
</html>

最後にPodへの経路情報を確認してみましょう。まず、マスターからcalicoctlコマンドを使用してPodの名前、IPアドレス、インターフェース名の紐付きを確認します。CalicoではPodのインターフェースのことをワークロードエンドポイントと呼んでおり、取得するリソース名としてworkloadEndpointを指定しています。取得できる情報が多いので-oオプションを使用して表示するカラムを整形しています。

k8s-master~$ ./calicoctl get workloadEndpoint -o custom-columns=NODE,WORKLOAD,NETWORKS,INTERFACE
NODE          WORKLOAD                   NETWORKS             INTERFACE
k8s-node-01   my-nginx-9d5677d94-48pmz   192.168.154.193/32   calieafb5bf2e52
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というインターフェースにホストルーティングされていることが確認できます。

k8s-node-01~$ route
Kernel IP routing table
Destination     Gateway         Genmask         Flags Metric Ref    Use Iface
default         172.16.0.1      0.0.0.0         UG    0      0        0 enp0s3
172.16.0.0      *               255.255.0.0     U     0      0        0 enp0s3
172.17.0.0      *               255.255.0.0     U     0      0        0 docker0
192.168.44.192  172.16.0.12     255.255.255.192 UG    0      0        0 tunl0
192.168.154.192 *               255.255.255.192 U     0      0        0 *
192.168.154.193 *               255.255.255.255 UH    0      0        0 calieafb5bf2e52
192.168.235.192 172.16.0.10     255.255.255.192 UG    0      0        0 tunl0

以上でCalicoおよびKubernetesの動作確認は終了です。

今回はCalicoとKubernetesの環境を構築し実際にNginxのアプリケーションを起動して疎通確認まで行いました。これでネットワークプラグインとしてのCalicoの振る舞いやコンテナネットワークのイメージができたと思います。次回は今回構築した環境を使用して、Calicoの代表的なセキュリティ機能であるネットワークポリシーを使用してみます。

著者
安座間 勇二(あざま ゆうじ)
NECソリューションイノベータ株式会社
1991年、沖縄県生まれ。2014年の入社以来、ソフトウェアエンジニアとしてOpenStackでのSFC(Service Function Chaining)やOpenDaylightを使ったSDN/NFVを中心とした開発や検証などに携わる。OpenStack Neutronを中心にコントリビューションしており、OpenStack Summit Tokyo 2015においてSFCのR&Dについて発表。

連載バックナンバー

Think ITメルマガ会員登録受付中

Think ITでは、技術情報が詰まったメールマガジン「Think IT Weekly」の配信サービスを提供しています。メルマガ会員登録を済ませれば、メルマガだけでなく、さまざまな限定特典を入手できるようになります。

Think ITメルマガ会員のサービス内容を見る

他にもこの記事が読まれています