KubernetesはPod用のネットワークとしてFlannelを採用されることが多いと思います。 JujuでデプロイできるKubernetesの構成でも、多くのBundleではFlannelが指定されています。
しかしこのFlannel、VXLANやGREなどを利用してL2ネットワークを構築するため、クラウド環境を構築する際に悩ましいMTUの問題が発生するのです。ネットワーク機器がジャンボフレームに対応していればこの問題は回避可能ですが、事情があってMTUを変えられないときは頭が痛いのです。そこで、今回はCalicoをつかってKubernetesを構築することにしました。
Calicoについてはこちらをご覧ください。
thinkit.co.jp techblog.yahoo.co.jp
構築に利用したJuju Bundleは「Kubernetes Calico #118」です。 デフォルトのテンプレートのままだと9つのマシンが必要になるため、以下のように書き換えてデプロイしてみました。いつものようにJuju CloudとしてMAASを使っています。Juju MachineはMAASで管理している物理サーバーを利用しています。
このBundleは2台の物理サーバーにKubernetes環境を構築するように書き換えてあります。後々workerノードを追加することを考慮して、kubeapi-load-balancerもあらかじめデプロイしています。
# canonical-kubernetes-206 base description: A 2-machine Kubernetes cluster, appropriate for PoC. Includes a 1 Kubernetes worker nodes. machines: '0': series: xenial constraints: "arch=amd64 tags=blade" '1': series: xenial constraints: "arch=amd64 tags=gpu" services: easyrsa: annotations: gui-x: '450' gui-y: '550' charm: cs:~containers/easyrsa-44 num_units: 1 to: - '0' etcd: annotations: gui-x: '800' gui-y: '550' charm: cs:~containers/etcd-87 num_units: 1 options: channel: 3.2/stable to: - '0' calico: annotations: gui-x: '450' gui-y: '750' charm: cs:~containers/calico-39 kubeapi-load-balancer: annotations: gui-x: '450' gui-y: '250' charm: cs:~containers/kubeapi-load-balancer-62 expose: true num_units: 1 options: proxy_read_timeout: 360 to: - '0' kubernetes-master: annotations: gui-x: '800' gui-y: '850' charm: cs:~containers/kubernetes-master-113 num_units: 1 options: channel: 1.10/stable enable-nvidia-plugin: auto to: - '0' kubernetes-worker: annotations: gui-x: '100' gui-y: '850' charm: cs:~containers/kubernetes-worker-128 expose: true num_units: 1 options: channel: 1.10/stable to: - '1' relations: - - kubernetes-master:kube-api-endpoint - kubeapi-load-balancer:apiserver - - kubernetes-master:loadbalancer - kubeapi-load-balancer:loadbalancer - - kubernetes-master:kube-control - kubernetes-worker:kube-control - - kubernetes-master:certificates - easyrsa:client - - etcd:certificates - easyrsa:client - - kubernetes-master:etcd - etcd:db - - kubernetes-worker:certificates - easyrsa:client - - kubernetes-worker:kube-api-endpoint - kubeapi-load-balancer:website - - kubeapi-load-balancer:certificates - easyrsa:client - - calico:etcd - etcd:db - - calico:cni - kubernetes-master:cni - - calico:cni - kubernetes-worker:cni
Jujuについては昨日アップロードした次の資料などを参考にしてください。
www.slideshare.net
あとはjuju deploy
コマンドを実行して、待つだけです。
% juju deploy calico-k8s.yaml
このBundleの構成でも、WorkerノードにNVIDIA GPUを接続した状態でデプロイしした場合もKubernetesのPodでGPUを参照可能でした。他のKubernetes Bundleと同様に、自動的に必要なコンポーネントであるCUDA Driver、GPU Driver、NVIDIA DockerやDockerのプラグイン、Docker CEのインストールなどを行ってくれます。案外すんなり動くことに驚きました。
これまではFlannelを使ってKubernetesを構成することが多かったのですが、上流にVXLANを使ったスイッチがいたりするとMTU問題が発生したり、Jujuでデプロイ中にいくつかエラーが発生することがあり、構築をなんども行うといったことがありました。
また過去には、Jujuのスクリプトの問題でホスト名に大文字が含まれると、Flannelと偶然同じネットワークアドレス帯を設定しているグローバル上のホストに対して名前解決をみにいってしまうという問題が発生して頭を悩ませました。この問題は現在のJuju CharmおよびBundleですでに修正されています。
一方、JujuでCalicoを使ったKubernetes環境をデプロイする際は特に大きなトラブルなく、すぐに試すことができる環境を構築できてあっけに取られました。
Jujuによるアプリケーションのデプロイ中はJuju GUIやjuju debug-log
コマンド、juju status
コマンドでデプロイの状況を確認します。うまくいくと、Juju GUIに次のように表示されます。
いつものように、Podを作ってみます。DockerイメージはあらかじめBusyboxを仕込んだ自分で作ったものを使っています。
% cat first-pod.yml apiVersion: v1 kind: Pod metadata: name: ubuntu spec: containers: - name: ubuntu image: ytooyama/ubuntu-redis:latest tty: true % kubectl create -f first-pod.yml pod "ubuntu" created % kubectl get -f first-pod.yml NAME READY STATUS RESTARTS AGE ubuntu 0/1 ContainerCreating 0 4s % kubectl get -f first-pod.yml NAME READY STATUS RESTARTS AGE ubuntu 1/1 Running 0 14s
起動したようなので、Pod内のコンテナーにアクセスしてみます。 Flannel構成ではPodの中のコンテナーのデバイスはMTU 1450となっていましたが、Calico構成ではMTU 1500でリンクしています。
きちんとグローバルアクセスもできることが確認できます。
% kubectl exec -it ubuntu -- busybox ip a 1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue qlen 1 link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00 inet 127.0.0.1/8 scope host lo valid_lft forever preferred_lft forever 3: eth0@if39: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue link/ether 1a:d2:85:0a:85:fc brd ff:ff:ff:ff:ff:ff inet 192.168.44.33/32 scope global eth0 valid_lft forever preferred_lft forever % kubectl exec -it ubuntu -- busybox ip r default via 169.254.1.1 dev eth0 169.254.1.1 dev eth0 % kubectl exec -it ubuntu -- busybox ping -c1 virtualtech.jp PING virtualtech.jp (124.35.85.83): 56 data bytes 64 bytes from 124.35.85.83: seq=0 ttl=61 time=3.468 ms --- virtualtech.jp ping statistics --- 1 packets transmitted, 1 packets received, 0% packet loss round-trip min/avg/max = 3.468/3.468/3.468 ms
コンテナーでGPUが参照できるかも確認してみましょう。別のイメージを設定したYAMLファイルを書いて、同じようにPodを作ってみましょう。
% cat cuda.yml apiVersion: v1 kind: Pod metadata: name: testpod-cuda91 spec: containers: - name: testpod-cuda91 image: nvidia/cuda:9.1-base tty: true resources: limits: nvidia.com/gpu: 1 % kubectl create -f cuda.yml % kubectl exec -it testpod-cuda91 -- nvidia-smi -q ==============NVSMI LOG============== Timestamp : Fri Jun 15 02:52:33 2018 Driver Version : 396.26 Attached GPUs : 1 GPU 00000000:03:00.0 ... (nvidia-smiコマンドに対して応答があった)
...というわけで、割とすんなり動かすことができました。次回の後編ではWorkerノードを一台増やして、Podのノード間通信を試してみたいと思います。
後編に続きます。