仮想化通信

日本仮想化技術株式会社の公式エンジニアブログ

JujuでCalicoを使ったKubernetes環境を構築する(前編)

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に次のように表示されます。

f:id:virtualtech:20180615111704p:plain

いつものように、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のノード間通信を試してみたいと思います。

後編に続きます。

tech.virtualtech.jp