仮想化通信

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

Ubuntu 18.04LTSベースでJuju/MAASを使ってオンプレ環境でKubernetesをデプロイする方法(後編)

後編を進める前に前編を確認してください。

tech.virtualtech.jp

Jujuによるアプリケーションのデプロイを実行する前に、JujuとCloud、Model、Charms、Bundleについて理解する必要があります。 詳細はJujuやMAASの公式ドキュメントをご確認いただくとして、次のような資料をアップロードしていますので参考にしてください。

www.slideshare.net

JujuとMAAS Cloudについて

JujuでMAAS Cloudを使ってアプリケーションをデプロイするには、事前に以下のような設定が必要です。公式ドキュメントを参考に設定してください。

Juju CharmもしくはBundleはJuju Charms Storeに公開されています。

今回はここからKubernetes + Calicoの構成のBundleを利用してセットアップします。

Juju Charms Storeに公開されているサンプルを用いることでJujuでKubernetesをデプロイできますが、正直、Kubernetesで永続ストレージを使いたいので、手頃に使えるNFSをBundleに追加して「kubernetes calico + NFS」な環境を自動でセットアップするBundleにしてみます。

NFSのJuju Charmはこちらを使います。

Bundle YAMLについて

Bundle YAMLについて少々解説します。

machinesにJujuでアプリケーションをデプロイするためのマシンを定義します。 machinesの下の数字はJuju Machineの番号です。0から始めます。この番号をservicesの展開先として後ほどtoの項に記述します。

seriesはOSをコードネームで示しています。Ubuntu 18.04のコードネームはBionic Beaverなので、ここではbionicを指定しています。

constraintsはマシンを識別するための項目です。今回はJuju+MAASの構成なので、amd64アーキテクチャーのサーバーでかつMAAS tagとして設定したtagを列挙します。指定できるconstraintsは"Cloud"によって異なります。詳細は次のドキュメントを確認してください。

上記を考慮した上で、Juju Charms Siteで公開されているKubernetes Calicoをベースに追加、加筆してみたものが次のYAMLです。

3台のマシンにデプロイするのでJuju Machinesに3台のノードを定義し、servicesの展開先としてJuju Machinesで定義したマシンを各種割り当てています。

# Kubernetes Calico 273 base
description: 3-machine Kubernetes cluster, appropriate for PoC. Includes a 2 Kubernetes worker nodes.
machines:
  '0':
    series: bionic
    constraints: "arch=amd64 tags=vm1" 
  '1':
    series: bionic
    constraints: "arch=amd64 tags=vm2"
  '2':
    series: bionic
    constraints: "arch=amd64 tags=vm3"

series: bionic
services:
  calico:
    annotations:
      gui-x: '450'
      gui-y: '750'
    charm: cs:~containers/calico-526
    options:
      docker-opts: '--bip=10.0.0.1/16'
  easyrsa:
    annotations:
      gui-x: '450'
      gui-y: '550'
    charm: cs:~containers/easyrsa-195
    num_units: 1
    to: 
    - 0
  etcd:
    annotations:
      gui-x: '800'
      gui-y: '550'
    charm: cs:~containers/etcd-338
    num_units: 1
    options:
      channel: 3.2/stable
    to:
    - 0
  kubeapi-load-balancer:
    annotations:
      gui-x: '450'
      gui-y: '250'
    charm: cs:~containers/kubeapi-load-balancer-525
    expose: true
    num_units: 1
    options:
      proxy_read_timeout: 6000
    to:
    - 0
  kubernetes-master:
    annotations:
      gui-x: '800'
      gui-y: '850'
    charm: cs:~containers/kubernetes-master-542
    num_units: 1
    options:
      channel: 1.13/stable
      enable-nvidia-plugin: auto
      allow-privileged: "true"
    to:
    - 0
  kubernetes-worker:
    annotations:
      gui-x: '100'
      gui-y: '850'
    charm: cs:~containers/kubernetes-worker-398
    expose: true
    num_units: 2
    options:
      channel: 1.13/stable
      docker_runtime: auto
      docker-opts: '--bip=10.0.0.1/16'
    to:
    - 1
    - 2
  nfs:
    charm: 'cs:nfs-7'
    num_units: 1
    series: bionic
    annotations:
      gui-x: '104'
      gui-y: '544'
    to:
    - 0
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
- - nfs:nfs
  - kubernetes-worker:nfs

もし、CNIとしてCalicoではなくFlannelを使いたい場合は上記のYAMLのCalicoの部分を次のように変更してください。 relationsの変更もお忘れなく。

  flannel:
    annotations:
      gui-x: '450'
      gui-y: '750'
    charm: cs:~containers/flannel-351
...
- - flannel:etcd
  - etcd:db
- - flannel:cni
  - kubernetes-master:cni
- - flannel:cni
  - kubernetes-worker:cni

必要な情報や環境は揃いましたので早速デプロイしましょう。「juju add-model k8s」などのようにコマンドを実行してModelを作り、そのモデルにアプリケーションを登録します。 この後の流れについては以前の投稿をご覧いただき、デプロイを行なってください。

Kubernetesを早速使ってみる

次の流れでJujuを使ってデプロイした Kubernetesを、早速使ってみましょう。

1. クレデンシャルファイルをコピーしてくる

% mkdir ~/.kube && touch ~/.kube/config
% juju scp kubernetes-master/0:config ~/.kube/config

2. クライアントにkubectlをインストールする

Ubuntuクライアントの場合

% sudo snap install kubectl --channel=stable --classic

macOSの場合(Homebrewが必要)

% brew install kubectl

3. 確認

クレデンシャルとkubectlコマンドの導入がうまくいったことを確認してみます。 次のような感じで出力されれば、Kubernetes Masterノード、Workerノードともに正常に動いていることが確認できます。

% kubectl get po --namespace=kube-system 
NAME                                              READY   STATUS    RESTARTS   AGE
calico-policy-controller-5974f46875-6h8tp         1/1     Running   0          110m
heapster-v1.6.0-beta.1-58774bcb4d-fgwf8           4/4     Running   0          107m
kube-dns-8f7866879-rfx5p                          3/3     Running   1          112m
kubernetes-dashboard-654cfb4879-5sc9m             1/1     Running   2          112m
metrics-server-v0.3.1-54b884db75-46dbh            2/2     Running   0          109m
monitoring-influxdb-grafana-v4-5866497777-g2xnq   2/2     Running   0          112m

% kubectl get no
NAME   STATUS   ROLES    AGE    VERSION
vm2    Ready    <none>   112m   v1.13.1
vm3    Ready    <none>   112m   v1.13.1

4. Kubernetes YAMLを用意する

今回はKubernetes 1.13をデプロイしたため、次のようなYAMLを用意すればNFSボリュームをPodに割り当てることができます。Kubernetes 1.10以降はいきなりPVCから要求してもうまくいくようになったようです。

---
kind: PersistentVolumeClaim
apiVersion: v1
metadata:
  name: nginxapp3-claim
spec:
  storageClassName: default
  accessModes:
    - ReadWriteMany
  resources:
    requests:
      storage: 1Gi
---
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
  name: nginxapp3
spec:
  replicas: 2
  template:
    metadata:
      labels:
        app: nginxapp3
    spec:
      containers:
      - name: nginxapp3
        image: nginx:alpine
        ports:
        - containerPort: 80
        volumeMounts:
        - mountPath: "/usr/share/nginx/html/"
          name: nginxapp3
      volumes:
      - name: nginxapp3
        persistentVolumeClaim:
          claimName: nginxapp3-claim
---
apiVersion: v1
kind: Service
metadata:
  name: nginxapp3-nodeport
  labels:
    app: nginxapp3
spec:
  type: NodePort
  ports:
  - port: 80
    targetPort: 80
  selector:
    app: nginxapp3

5. Kubernetesでアプリケーションをデプロイする

デプロイ
% kubectl apply -f nfs-storage-default.yml
persistentvolumeclaim/nginxapp3-claim created
deployment.extensions/nginxapp3 created
service/nginxapp3-nodeport created
状況の確認
% kubectl get -f nfs-storage-default.yml
NAME                                                          STATUS  VOLUME                                         CAPACITY   ACCESS MODES   STORAGECLASS   AGE
persistentvolumeclaim/nginxapp3-claim   Bound     pvc-23b2a893-130d-11e9-88fb-525400dd100b   1Gi        RWX            default        73s

NAME                              READY   UP-TO-DATE   AVAILABLE   AGE
deployment.extensions/nginxapp3   2/2     2            2           73s

NAME                         TYPE       CLUSTER-IP      EXTERNAL-IP   PORT(S)        AGE
service/nginxapp3-nodeport   NodePort   10.152.183.65   <none>        80:31061/TCP   73s
アプリケーションへのアクセス
1. Podにログインしてみる

replicas: 2を指定していたため、2つPodが稼働中であることが確認できます。一方のPodにアクセスしてみます。

% kubectl get po|grep nginxapp3
nginxapp3-75dcf8dbdb-7gz8z               1/1     Running   0          41m
nginxapp3-75dcf8dbdb-svr8s               1/1     Running   0          41m

% kubectl exec -it nginxapp3-75dcf8dbdb-7gz8z  -- ash 
/ # df -h
...
172.17.28.57:/srv/data/kubernetes-worker/default-nginxapp3-claim-pvc-23b2a893-130d-11e9-88fb-525400dd100b
                         39.1G      7.7G     29.4G  21% /usr/share/nginx/html
2. コンテナーの内容を編集してみる

一方のPod内でHTMLコンテンツを作ってみます。

/ # echo "hello k8s world" >> /usr/share/nginx/html/index.htm
/ # exit
...
% kubectl get svc|grep nginxapp3-nodeport
nginxapp3-nodeport   NodePort    10.152.183.65   <none>        80:31061/TCP   8m38s

NGINXサーバーにアクセスしてみます。同じNFS共有ボリュームをマウントするので、同じ内容が出力されます。

% kubectl get no -o wide
NAME   STATUS   ROLES    AGE    VERSION   INTERNAL-IP    EXTERNAL-IP   OS-IMAGE             KERNEL-VERSION      CONTAINER-RUNTIME
vm2    Ready    <none>   125m   v1.13.1   172.17.28.58   <none>        Ubuntu 18.04.1 LTS   4.15.0-43-generic   docker://18.6.1
vm3    Ready    <none>   125m   v1.13.1   172.17.28.66   <none>        Ubuntu 18.04.1 LTS   4.15.0-43-generic   docker://18.6.1
% curl http://172.17.28.58:31061
hello k8s world
% curl http://172.17.28.66:31061
hello k8s world

kubeapi-load-balancerからアクセスしてみます。

% curl http://172.17.28.57:31061
hello k8s world
ちなみに

NFSサーバーをセットアップしたJuju Machineにアクセスすると、先ほど作成したindex.htmを見つけることができます。

ubuntu@vm1:~$ ls -R /srv/data/
/srv/data/:
kubernetes-worker

/srv/data/kubernetes-worker:
default-nginxapp3-claim-pvc-23b2a893-130d-11e9-88fb-525400dd100b

/srv/data/kubernetes-worker/default-nginxapp3-claim-pvc-23b2a893-130d-11e9-88fb-525400dd100b:
index.htm

以上です。