仮想化通信

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

仮想化通信をHTTPS化いたしました

仮想化通信をHTTPS化いたしました。本日の今現在より、HTTP URLでアクセスした場合もHTTPSのアドレスにリダイレクトされるようになっています。

以下のブラウザーで動作することを確認しています。

  • IE11
  • Firefox 60
  • Safari 11

はてなブログでは、はてな所有のドメインはCOMODOの証明書が、このサイトのように独自ドメインを利用している場合はLet's Encryptの証明書が使われるようです。

HTTPS化にあたり問題は発生しないと思われますが、何かお気づきの点がございましたらブログコメントをいただければ幸いです。

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

前編はこちらです。

tech.virtualtech.jp

前編ではKubernetes MasterとWorkerの2台構成の環境を作りました。後編ではまずWorkerノードを増やしてみます。 Jujuでアプリケーションを構築した場合、ノードを追加してスケールするのは簡単にできます。

前編と同様、Juju CloudとしてMAASを使った場合を例とします。

スケールの拡大(ノードの追加)

ノードを増やすにはGUIで行う方法と、コマンドラインで行う方法があります。 次のようなコマンドを実行するだけです。

一行目では、MAASのノードに「node2」というタグを振ったノードを新たなJuju machineとして追加しています。 juju add-machineコマンドを実行するとMAAS API経由で該当のノードの電源を入れて、Ubuntuをデプロイします。鍵認証でログインできるようにするため、公開鍵を該当のノードに転送します(~/.local/share/juju/ssh/にあるキーペアを利用します)。

二行目では、Juju Machine 2にkubernetes-workerを2つ目のユニットとして 追加しています。

すでにあるユニットを拡大するにはjuju deployコマンドではなく、juju add-unitコマンドを実行します。 実行するまえにJuju Machine番号を確認しておいてください。

% juju add-machine --constraints "arch=amd64 tags=node2"
% juju machines
Machine  State    DNS            Inst id  Series  AZ       Message
0        started  172.17.28.110  cnep3s   xenial  default  Deployed
1        started  172.17.28.104  6gchhg   xenial  default  Deployed
2        started  172.17.28.105  e3ye8t   xenial  default  Deployed

% juju add-unit kubernetes-worker --to 2

デプロイの状況はjuju debug-logコマンドやjuju statusコマンドを確認します。 デプロイが完了すると、Kubernetes Dashboardに新たなノードとして追加されます。

f:id:virtualtech:20180615163358p:plain

ラベルの確認

Kubernetesというよりクラウド全般はどこのノードでコンテナーないし仮想マシンが動いているかは意識する必要はありません。 外部からアクセスする手段があれば、なんとかなるからです。

今回はあえてコンテナーを動かすホストを固定して、ホストまたぎのPod間通信を確認するためにKubernetes Workerノードに定義されたラベルを確認します。これらのラベルはいくつかビルトインのものが定義されます。任意のラベルを設定することもできます。

次のようなコマンドでKubernetesノードのラベルを確認します。 kubernetes.io/hostnameがノードの識別に使えそうであることがわかります。

% kubectl get no --show-labels
NAME         STATUS    ROLES     AGE       VERSION   LABELS
110gen9      Ready     <none>    1d        v1.10.4   beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,cuda=true,gpu=true,juju-application=kubernetes-worker,kubernetes.io/hostname=110gen9
bl460cg7n6   Ready     <none>    12m       v1.10.4   beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,juju-application=kubernetes-worker,kubernetes.io/hostname=bl460cg7n6

Pod作成のためのYAMLの準備

各WorkerノードにPodを作るため、nodeSelectorを使います。次のようなYAMLを用意します。 前編で作ったYAMLにnodeSelectorを追加しただけのYAMLです。

% cat pod1.yml
apiVersion: v1
kind: Pod
metadata:
  name: ubuntu
spec:
  containers:
    - name: ubuntu
      image: ytooyama/ubuntu-redis:latest
      tty: true

  nodeSelector:
    kubernetes.io/hostname: 110gen9

% cat pod2.yml
apiVersion: v1
kind: Pod
metadata:
  name: ubuntu2
spec:
  containers:
    - name: ubuntu2
      image: ytooyama/ubuntu-redis:latest
      tty: true

  nodeSelector:
    kubernetes.io/hostname: bl460cg7n6

Podの起動

Podを起動してみます。

% kubectl create -f pod1.yml
% kubectl create -f pod2.yml

IPアドレスを確認してみます。 別々のネットワークのIPアドレスを取得していることがわかります。

% kubectl exec -it ubuntu -- busybox ip a|grep eth0
3: eth0@if42: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue
    inet 192.168.44.36/32 scope global eth0
% kubectl exec -it ubuntu2 -- busybox ip a|grep eth0
3: eth0@if15: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue
    inet 192.168.129.131/32 scope global eth0

pingとtracerouteによる疎通確認

ubuntuのPodからubuntu2にPingを飛ばしてみます。 パケロスする事なく、Pingが通りました。

% kubectl exec -it ubuntu -- busybox ping -c1 192.168.129.131
PING 192.168.129.131 (192.168.129.131): 56 data bytes
64 bytes from 192.168.129.131: seq=0 ttl=62 time=0.503 ms

--- 192.168.129.131 ping statistics ---
1 packets transmitted, 1 packets received, 0% packet loss
round-trip min/avg/max = 0.503/0.503/0.503 ms

簡易的ながら、経路をtracerouteで追ってみました。

% kubectl exec -it ubuntu -- busybox ip a|grep eth0
3: eth0@if42: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue
    inet 192.168.44.36/32 scope global eth0

% kubectl exec -it ubuntu -- busybox traceroute -I 192.168.129.131
traceroute to 192.168.129.131 (192.168.129.131), 30 hops max, 46 byte packets
 1  110gen9.maas (172.17.28.104)  0.010 ms  0.006 ms  0.004 ms
 2  bl460cg7n6.maas (172.17.28.105)  0.286 ms  0.291 ms  0.220 ms
 3  192.168.129.131 (192.168.129.131)  0.278 ms  0.252 ms  0.214 ms

このことから、ubuntuコンテナーのIPアドレス(192.168.44.36)からコンテナーが起動しているKubernetes-workerノード0のホスト(172.17.28.104)から、Kubernetes-workerノード1のホスト(172.17.28.105)を経由して、ubuntu2コンテナーのIPアドレス(192.168.129.131)に到達していることがわかります。

iperf3を使ったベンチマーク

iperf3を使ってスループット値を計測してみます。 まずはiperf3のインストールから。

% kubectl exec -it ubuntu -- apt update -qq
% kubectl exec -it ubuntu -- apt install iperf3 -y -qq

% kubectl exec -it ubuntu2 -- apt update -qq
% kubectl exec -it ubuntu2 -- apt install iperf3 -y -qq

ubuntu2コンテナーをサーバーにして、ubuntuコンテナーから計測するため、次のようにコマンドを実行します。 計測を実行すると、ubuntu2の方にも出力がされますが、今回は省略します。

サーバーは1GbEで接続されています。これだけスループットがでれば良いでしょう。 リトライは発生していますが、TCP/IPによる通信なので特に問題はありません。

% kubectl exec -it ubuntu2 -- iperf3 -s
-----------------------------------------------------------
Server listening on 5201
-----------------------------------------------------------
...

% kubectl exec -it ubuntu -- iperf3 -c 192.168.129.134
Connecting to host 192.168.129.134, port 5201
[  4] local 192.168.44.37 port 40694 connected to 192.168.129.134 port 5201
[ ID] Interval           Transfer     Bandwidth       Retr  Cwnd
[  4]   0.00-1.00   sec   114 MBytes   960 Mbits/sec   10   2.28 MBytes
[  4]   1.00-2.00   sec   111 MBytes   933 Mbits/sec    0   2.48 MBytes
[  4]   2.00-3.00   sec   112 MBytes   944 Mbits/sec   11   1.28 MBytes
[  4]   3.00-4.00   sec   111 MBytes   933 Mbits/sec    8    529 KBytes
[  4]   4.00-5.00   sec   112 MBytes   944 Mbits/sec    0    676 KBytes
[  4]   5.00-6.00   sec   111 MBytes   933 Mbits/sec    6    592 KBytes
[  4]   6.00-7.00   sec   111 MBytes   933 Mbits/sec    2    721 KBytes
[  4]   7.00-8.00   sec   111 MBytes   933 Mbits/sec    9    611 KBytes
[  4]   8.00-9.00   sec   112 MBytes   943 Mbits/sec    0    738 KBytes
[  4]   9.00-10.00  sec   111 MBytes   933 Mbits/sec    0    847 KBytes
- - - - - - - - - - - - - - - - - - - - - - - - -
[ ID] Interval           Transfer     Bandwidth       Retr
[  4]   0.00-10.00  sec  1.09 GBytes   939 Mbits/sec   46             sender
[  4]   0.00-10.00  sec  1.09 GBytes   937 Mbits/sec                  receiver

iperf Done.

iptablesを確認してみる

また次のように実行すると、Workerノードのiptablesにforwardingのルールが記述されていることがわかります。 grepコマンドを外せば全体のルールを確認できます。

% juju status calico
...
Unit                  Workload  Agent  Machine  Public address  Ports           Message
easyrsa/0*            active    idle   0        172.17.28.110                   Certificate Authority connected.
kubernetes-master/0*  active    idle   0        172.17.28.110   6443/tcp        Kubernetes master running.
  calico/0*           active    idle            172.17.28.110                   Calico is active
kubernetes-worker/0*  active    idle   1        172.17.28.104   80/tcp,443/tcp  Kubernetes worker running.
  calico/1            active    idle            172.17.28.104                   Calico is active
kubernetes-worker/1   active    idle   2        172.17.28.105   80/tcp,443/tcp  Kubernetes worker running.
  calico/2            active    idle            172.17.28.105                   Calico is active

% juju ssh calico/0 sudo iptables -L|grep 192.168.
Connection to 172.17.28.110 closed.

% juju ssh calico/1 sudo iptables -L|grep 192.168.
ACCEPT     all  --  192.168.0.0/16       anywhere             /* kubernetes forwarding conntrack pod source rule */ ctstate RELATED,ESTABLISHED
ACCEPT     all  --  anywhere             192.168.0.0/16       /* kubernetes forwarding conntrack pod destination rule */ ctstate RELATED,ESTABLISHED
Connection to 172.17.28.104 closed.

% juju ssh calico/2 sudo iptables -L|grep 192.168.
ACCEPT     all  --  192.168.0.0/16       anywhere             /* kubernetes forwarding conntrack pod source rule */ ctstate RELATED,ESTABLISHED
ACCEPT     all  --  anywhere             192.168.0.0/16       /* kubernetes forwarding conntrack pod destination rule */ ctstate RELATED,ESTABLISHED
Connection to 172.17.28.105 closed.

Jujuを使えばKubernetesをお試しする環境がすぐに作れます。 標準的に使われるFlannel構成のほか、Calicoを使った構成も簡単です。

以上、「JujuでCalicoを使ったKubernetes環境を構築する」の話題でした。

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

Kubernetesと永続ストレージの使い方

Kubernetesは現在、バックエンドエンジンとしてDockerを利用しています。 Podの作成はYAML形式でエディターで書いて、kubectl createコマンドで簡単に作成できます。

作成したPodはkubectl execコマンドを使って、bashシェルなどにログインすれば仮想マシンにアクセスする様に環境にログインして操作できます。

ただ、何も特別な設定をしていない状態でPodを作成すると、非永続のストレージしか利用できません。従ってPod内のコンテナーで再起動が走ってしまうとデータが消去されてしまいます。

たとえば次のようなYAMLファイルでPodを作成したとします。

kind: Pod
apiVersion: v1
metadata:
  name: mywebpod
spec:
  containers:
    - name: myfrontend
      image: nginx:latest
      ports:
      - containerPort: 80
        hostPort: 50080

NGINXのDockerイメージでは、Web rootは/usr/share/nginx/htmlがデフォルト設定になっています。確認のため、ここに任意のindex.htmlを作成してみましょう。

$ kubectl exec -it mywebpod bash
root@mywebpod:/# ls /usr/share/nginx/html
50x.html  index.html
(Web rootを確認)

root@mywebpod:/# echo "<html><h1>hello world</h1></html>" > /usr/share/nginx/html/index.html
(適当な内容で上書き)

root@mywebpod:/# cat /usr/share/nginx/html/index.html
<html><h1>hello world</h1></html>
(ファイルを確認)

ではこのコンテナーのプロセスを再起動してみましょう。一旦シェルから抜けて、docker stopdocker startコマンドでコンテナーを再起動してみます。一度プロセスが終了されたため、index.htmlはデフォルトのページに戻ってしまいます。

~$ docker ps |grep mywebpod
b1fb6d922358        nginx@sha256:0fb320e2a1b1620b4905facb3447e3d84ad36da0b2c8aa8fe3a5a81d1187b884                                 "nginx -g 'daemon ..."   9 minutes ago       Up 9 minutes                            k8s_myfrontend_mywebpod_default_f827a307-6235-11e8-babe-984be167d804_0
150426c756a4        k8s.gcr.io/pause-amd64:3.1                                                                                    "/pause"                 9 minutes ago       Up 9 minutes                            k8s_POD_mywebpod_default_f827a307-6235-11e8-babe-984be167d804_0

~$ docker stop b1fb6d922358
b1fb6d922358
~$ docker start b1fb6d922358
b1fb6d922358
(コンテナーを再起動)

$ kubectl exec -it mywebpod bash
(Podのシェルにログイン)

root@mywebpod:/# cat /usr/share/nginx/html/index.html
(初期ページに戻ってしまった)

<!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>
<h1>Welcome to nginx!</h1>
<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>

と、いうわけでデータを永続して持っておきたい場合、永続ストレージが必要であるという事がわかります。

Kubernetesと永続ストレージ

本当はこの辺りを書きたかったのですが、Kubernetes公式のドキュメントやRed Hat社のドキュメントが纏まっていたので、リンクだけ貼り付けておきます。

Kubernetesと永続ストレージについては公式のドキュメントを参照して欲しいのですが、色々ある用語のうち、特に重要なキーワードは次の二つです。

Persistent Volumes

ざっくりいうと、永続ストレージを定義するためのものです。

PersistentVolumeClaims

ざっくりいうと、Podに紐づけるストレージを要求するためのものです。

Kubernetesで利用できるストレージはStorage Classesに纏まっています。今回はその中からNFS、Redis、Cephの使い方についてまとめます。

NFS共有ボリュームをPodにマウントする

NFS共有ボリュームをPodにマウントするにはNFSサービスと共用ボリュームがあらかじめ必要です。 まず、次のようなYAMLを記述して、PVとPVCについて定義します。

この中で重要なのは「persistentVolumeReclaimPolicy」です。この設定はデフォルトはRecycleが設定されており、簡易的なクリーンアップが施された上で新たに割り当てられます。データを保持したい場合は「Retain」に設定する必要があります。

apiVersion: v1
kind: PersistentVolume
metadata:
  name: pv1
  labels:
    volume: my-volume1
spec:
  capacity:
    storage: 10Gi
  volumeMode: Filesystem
  accessModes:
    - ReadWriteOnce                                       #ストレージのアクセスモード
  persistentVolumeReclaimPolicy: Retain    #保持オプション
  storageClassName: slow
  mountOptions:              #NFSマウントオプション
    - hard
    - nfsvers=3
  nfs:
    path: "/dist-volume"   #NFS共有ボリュームパス
    server: 172.17.14.100      #NFSサーバーのIPアドレス
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: pvc1
spec:
  accessModes:
    - ReadWriteOnce
  volumeMode: Filesystem
  resources:
    requests:
      storage: 2Gi
  storageClassName: slow
  selector:
    matchLabels:
      volume: my-volume1

pv1にmy-volume1と言う名前のラベルを定義して、PVCでmy-volume1のボリュームを要求しています。 このPVCにはpvc1という名前を設定しています。

あとは、Podを作成するときにpersistentVolumeClaimを指定することで、定義ずみのPVから要求したボリュームをPodに割り当てる事ができます。以下、PodのYAMLの例です。

本例はmynfspodと言う名前のPodにpvc1を割り当てる例です。

apiVersion: v1
kind: Pod
metadata:
  name: mynfspod
spec:
  containers:
    - name: myfrontend
      image: nginx:latest
      ports:
      - containerPort: 80
        hostPort: 51080

      volumeMounts:
      - mountPath: "/usr/share/nginx/html"
        name: mynfspod
  volumes:
    - name: mynfspod
      persistentVolumeClaim:
        claimName: pvc1

次のように実行すると、PodにNFS共有ボリュームがマウントされている事が確認できます。

% kubectl exec -it mynfspod -- df -hT
Filesystem               Type   Size  Used Avail Use% Mounted on
none                     aufs   275G   12G  250G   5% /
tmpfs                    tmpfs   24G     0   24G   0% /dev
tmpfs                    tmpfs   24G     0   24G   0% /sys/fs/cgroup
/dev/sda1                ext4   275G   12G  250G   5% /etc/hosts
shm                      tmpfs   64M     0   64M   0% /dev/shm
172.17.14.100:/dist-volume nfs     27G  1.2G   26G   5% /usr/share/nginx/html
tmpfs                    tmpfs   24G   12K   24G   1% /run/secrets/kubernetes.io/serviceaccount
tmpfs                    tmpfs   24G     0   24G   0% /sys/firmware

Redisを永続ボリューム用途でPodにマウントする

次にRedisをPodで使う方法を説明します。RedisはいわゆるNoSQLデータベースのことで、オンメモリーのストレージとしても使うことができます。DockerやKubernetesでRedisを使うには、公式のDockerイメージを使ってコンテナーを起動するだけで利用できます。

このDockerイメージの実態は、redis-serverデーモンによって特定のディレクトリーのデータを永続化しているだけです。各Podの中でredis-serverを動作させます。特定の外部サーバー(NFS,iSCSIといった)が必要ないために手軽に利用できる反面、オンメモリストレージなので大きいデータのやり取りは不向きかもしれません。というより要注意です。

以下は公式のRedisイメージを使ってPodを起動するYAMLの例です。

apiVersion: v1
kind: Pod
metadata:
  name: redis
spec:
  containers:
  - name: redis
    image: redis
    volumeMounts:
    - name: redis-storage
      mountPath: /data/redis
  volumes:
  - name: redis-storage
    emptyDir: {}

上記の内容のYAMLでPodを起動すると、ディレクトリー/data/redisがマウントされるのが確認できます。

% kubectl exec -it redis bash
root@redis:/data# ls -F
redis/
(起動したPodに/data/redisがある事が確認できる)

root@redis:/data# echo "TEST File" > /data/redis/test.data
(適当に書きこむ)

%  docker stop 5c61f8fdb56f
5c61f8fdb56f
%  docker start 5c61f8fdb56f
(workerノードでコンテナーのプロセスを終了し、再開する)

% kubectl exec -it redis bash
(シェルに再ログインして)

root@redis:/data# cat /data/redis/test.data
TEST File
(書き込んだデータはまだ残っていた)

Redisの公式イメージはDebian版とAlpine Linux版が存在します。試しにUbuntuでRedisを使うためのイメージを作ってみましたので、次のようなYAMLファイルを書けばUbuntu 16.04でRedisを使うことができます。イメージをベースとして設定を変えて使うこともできます。役立ちそうでしたらご利用ください。

apiVersion: v1
kind: Pod
metadata:
  name: redis
spec:
  containers:
  - name: redis
    image: ytooyama/ubuntu-redis
    tty: true
    volumeMounts:
    - name: redis-storage
      mountPath: /var/lib/redis
  volumes:
  - name: redis-storage
    emptyDir: {}

CephをPodにマウントする

CephをKubernetesで使うにはRookを使うと簡単です。 まず、ソースをダウンロードします。2018年6月14日時点は0.7.1が最新です。

% wget https://github.com/rook/rook/archive/v0.7.1.zip
% unzip v0.7.1.zip
% cd ~/rook-0.7.1/cluster/examples/kubernetes

次に三つのコマンドを実行すると利用することができます。

% kubectl create -f rook-operator.yaml
% kubectl create -f rook-cluster.yaml
% kubectl create -f rook-storageclass.yaml

デフォルトではrook-cluster.yamlで定義している「dataDirHostPath」のパスが共有領域として使われます。

ポイントとして、ホスト上の物理デバイスをKubernetesからアクセスするため、Kubernetesの各ノード(masterとworker)が特権モードで動作している必要があるようです。Jujuの場合はこちらの設定をtrueにする必要があります。

f:id:virtualtech:20180528195759p:plain:w360

rookはrookとrook-systemと言う名前のネームスペースを作り、その中で動作します。デプロイ中のログやPodの状況を確認するには、Kubernetesのダッシュボードを表示して確認する他、コマンドで確認することもできます。

次のように全てのネームスペース上のPodを確認して、kubectl logsコマンドでそれぞれ個別のログを確認できます。

% kubectl get pods --all-namespaces
% kubectl logs rook-operator-5c89ff9496-kjq8m --namespace=rook-system

準備ができたら、次のようなYAMLファイルを用意して、Podを作成してみましょう。

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: myclaim
  labels:
    app: myclaim
spec:
  storageClassName: rook-block
  accessModes:
  - ReadWriteOnce
  resources:
    requests:
      storage: 2Gi
---
kind: Pod
apiVersion: v1
metadata:
  name: mypod
spec:
  containers:
    - name: myfrontend
      image: nginx:latest
      volumeMounts:
      - mountPath: "/usr/share/nginx/html/"
        name: mypod-nginxroot
  volumes:
    - name: mypod-nginxroot
      persistentVolumeClaim:
        claimName: myclaim

うまくいくと、次の例と同じようにPVとPVCを表示できるはずです。

% kubectl create -f test-pvcpod.yml
persistentvolumeclaim "myclaim" created
pod "mypod" created
(Podを作成)

% kubectl get pv,pvc
NAME                                                        CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS    CLAIM             STORAGECLASS   REASON    AGE
persistentvolume/pvc-f64ee657-6267-11e8-85de-984be167d804   2Gi        RWO            Delete           Bound     default/myclaim   rook-block               1m

NAME                            STATUS    VOLUME                                     CAPACITY   ACCESS MODES   STORAGECLASS   AGE
persistentvolumeclaim/myclaim   Bound     pvc-f64ee657-6267-11e8-85de-984be167d804   2Gi        RWO            rook-block     1m
(PVとPVCを表示)

$ kubectl get -f test-pvcpod.yml
NAME                            STATUS    VOLUME                                     CAPACITY   ACCESS MODES   STORAGECLASS   AGE
persistentvolumeclaim/myclaim   Bound     pvc-f64ee657-6267-11e8-85de-984be167d804   2Gi        RWO            rook-block     24s
(Podの状態を確認)

NAME        READY     STATUS    RESTARTS   AGE
pod/mypod   1/1       Running   0          24s

% kubectl exec -it mypod -- df -h
Filesystem      Size  Used Avail Use% Mounted on
none            275G   14G  248G   6% /
tmpfs            24G     0   24G   0% /dev
tmpfs            24G     0   24G   0% /sys/fs/cgroup
/dev/sda1       275G   14G  248G   6% /etc/hosts
shm              64M     0   64M   0% /dev/shm
/dev/rbd0       2.0G  3.0M  1.8G   1% /usr/share/nginx/html
tmpfs            24G   12K   24G   1% /run/secrets/kubernetes.io/serviceaccount
tmpfs            24G     0   24G   0% /sys/firmware
(マウントされていることを確認)

と言うわけで、今回はKubernetesの永続ストレージの使い方まとめでした。

Jujuで構築するKubernetesでGPUを使うには(2)手書き文字解析編

tech.virtualtech.jp

今回は前回構築したKubernetes GPU環境でMNISTを動かしてみます。 MNISTは手書き文字を解析するサンプルプログラムです。

これを実現する方法はいくつかありますが、前回予告した通り、Chainerを使って実行してみます。

Podを作成するにあたって、Docker Hubに上げられたChainerイメージを使います。

Python2ベースのイメージとして「chainer/chainer:latest-python2」、Python3ベースのイメージとして「chainer/chainer:latest-python3」が存在します。今回はPython3ベースのイメージを使いますが、必要に応じて好きな方を設定してください。

YAMLは次のように記述したものを使います。

apiVersion: v1
kind: Pod
metadata:
  name: chainer
spec:
  restartPolicy: OnFailure
  containers:
    - name: chainer
      image: chainer/chainer:latest-python3
      tty: true

      resources:
        limits:
          nvidia.com/gpu: 1

次のように実行して、Podを作成します。

$ kubectl create -f chainer-gpupod.yml
pod "chainer" created
(Podを作成)

$ kubectl get -f chainer-gpupod.yml
NAME      READY     STATUS              RESTARTS   AGE
chainer   0/1       ContainerCreating   0          5s

$ kubectl get -w -f chainer-gpupod.yml
NAME      READY     STATUS              RESTARTS   AGE
chainer   0/1       ContainerCreating   0          11s
chainer   1/1       Running   0         25s
^C
(ステータスを確認)

シェルにログインしてみます。後で必要なので、wgetパッケージをインストールしておきます。

$ kubectl exec -it chainer bash
root@chainer:/#
(シェルにログインできた)

root@chainer:/# apt update && apt install wget
(wgetパッケージのインストール)

Pythonモジュールがインストールされていることを確認しましょう。Python 2版の場合はpip2、Python 3版の場合はpip3コマンドでlistを出力してみます。

root@chainer:~# pip3 list
chainer (5.0.0a1)
cupy-cuda80 (5.0.0a1)
fastrlock (0.3)
filelock (3.0.4)
numpy (1.14.3)
pip (8.1.1)
protobuf (3.5.2.post1)
setuptools (20.7.0)
six (1.11.0)
wheel (0.29.0)

念のため、現在インストールされているバージョンと同じソースコードをダウンロードしてみます。

root@chainer:~# wget https://github.com/chainer/chainer/archive/v5.0.0a1.tar.gz
root@chainer:~# tar zvxf v5.0.0a1.tar.gz

まずは次のように実行して、CPUモードで画像解析を実行してみます。

root@chainer:~# python3 chainer-5.0.0a1/examples/mnist/train_mnist.py
GPU: -1
# unit: 1000
# Minibatch-size: 100
# epoch: 20

Downloading from http://yann.lecun.com/exdb/mnist/train-images-idx3-ubyte.gz...
Downloading from http://yann.lecun.com/exdb/mnist/train-labels-idx1-ubyte.gz...
Downloading from http://yann.lecun.com/exdb/mnist/t10k-images-idx3-ubyte.gz...
Downloading from http://yann.lecun.com/exdb/mnist/t10k-labels-idx1-ubyte.gz...
/usr/local/lib/python3.5/dist-packages/chainer/training/extensions/plot_report.py:25: UserWarning: matplotlib is not installed on your environment, so nothing will be plotted at this time. Please install matplotlib to plot figures.

  $ pip install matplotlib

  warnings.warn('matplotlib is not installed on your environment, '
epoch       main/loss   validation/main/loss  main/accuracy  validation/main/accuracy  elapsed_time
     total [##................................................]  4.17%
this epoch [#########################################.........] 83.33%
       500 iter, 0 epoch / 20 epochs
    40.105 iters/sec. Estimated time to finish: 0:05:07.333278.
...
epoch       main/loss   validation/main/loss  main/accuracy  validation/main/accuracy  elapsed_time
1           0.192088    0.104656              0.942283       0.9655                    15.9014
2           0.0761355   0.083492              0.976633       0.9748                    34.297
3           0.0481078   0.0801713             0.984583       0.9774                    53.7614
4           0.0363545   0.0682803             0.988733       0.9803                    73.6677
5           0.0281913   0.0679281             0.990517       0.9819                    95.086
6           0.0233321   0.0992965             0.99245        0.9767                    116.134
7           0.0247206   0.0955383             0.992033       0.9757                    136.834
8           0.0157767   0.0864075             0.99495        0.9811                    158.071
9           0.0165213   0.0684731             0.995          0.983                     179.839
10          0.0147778   0.0693633             0.994833       0.9853                    202.334
11          0.0119251   0.0902634             0.995933       0.9821                    225.362
12          0.0139303   0.0877024             0.995683       0.9818                    248.44
13          0.0111728   0.0823854             0.996633       0.9838                    272.442
14          0.0146516   0.0914885             0.995267       0.9821                    297
15          0.00734373  0.0916999             0.997867       0.9829                    322.92
16          0.00987204  0.116907              0.997133       0.9797                    351.075
17          0.0141462   0.117645              0.995867       0.9775                    377.785
18          0.0121944   0.0804133             0.996233       0.985                     405.164
19          0.00477812  0.0914235             0.99845        0.9846                    433.902
20          0.0133259   0.123587              0.9963         0.9789                    463.388

CPUモードでは解析に要する時間は当然ながら、CPUの性能に依存します。5分程度かかりそうと予測されています。 では次に、GPUを使って解析をしてみます。

root@chainer:~# python3 chainer-5.0.0a1/examples/mnist/train_mnist.py -g0
...
Estimated time to finish: 0:00:56.929975.
...
epoch       main/loss   validation/main/loss  main/accuracy  validation/main/accuracy  elapsed_time
1           0.187311    0.0982425             0.943567       0.9681                    13.1751
2           0.0729037   0.0750831             0.977232       0.9768                    16.2432
3           0.0483815   0.0741541             0.984315       0.9775                    19.2818
4           0.0348181   0.0726876             0.988632       0.9792                    22.3202
5           0.0310322   0.0824915             0.989898       0.9777                    25.5088
6           0.0235344   0.0737441             0.991981       0.9814                    28.4955
7           0.0192432   0.0733679             0.993332       0.9824                    31.5288
8           0.0189031   0.0744087             0.993933       0.9831                    34.5434
9           0.016433    0.0905501             0.994599       0.9788                    37.5528
10          0.0141957   0.0850642             0.995566       0.9817                    40.6166
11          0.0151095   0.0771753             0.995232       0.9826                    43.6603
12          0.0112923   0.0848214             0.996215       0.9812                    46.7101
13          0.0148123   0.0836868             0.995183       0.9825                    49.7578
14          0.00946035  0.0908514             0.996815       0.9837                    52.992
15          0.0118137   0.103228              0.996298       0.9798                    56.034
16          0.0105525   0.100688              0.996932       0.9814                    59.044
17          0.00669109  0.105021              0.998333       0.9819                    62.0895
18          0.0142701   0.0929249             0.996015       0.9833                    65.0944
19          0.00628928  0.0943469             0.997999       0.9837                    68.124
20          0.00698401  0.0944361             0.997782       0.9826                    71.1269

手元の環境では1分以下、つまりCPUで行ったときの1/5の時間で解析できることがわかります。 GPUを使う事でデータ解析を短縮できることが確認できました。

Jujuを使えばKubernetesの環境の構築や、KubernetesでGPUを使う構成も簡単です。 ぜひお試しください。また、お手伝いできる事があればお問い合わせください。

KubernetesクラスタへSpinnakerを構築

Kubernetesはコンテナアプリケーションのオーケストレーターです。

yamlによるサービス構築がkubectlコマンドで実行できますが、 さらに自動化されたデプロイ環境が欲しくなってくるのではないでしょうか。

そこで前回構築したKubernetesにContinuous Delivery Platformである 「Spinnaker」を動作させ、パイプラインによる自動デプロイを行いました。

筆者: コムシス情報システム株式会社 山本 聡(やまもと さとる)

Kubernetesクラスタ環境の用意

まずはKubernetesクラスタを用意します。

以前当ブログにおいてJUJU+MAASでの環境構築を行っていますので、以下のエントリーを参考ください。

http://tech.virtualtech.jp/entry/2018/03/29/104216

Kubernetes永続ボリューム設定

SpinnakerをKubernetes上にデプロイするにあたって、ポッドが永続ボリューム要求を出します。

これを処理するため、ブロックストレージ等によるバックエンドの構築を行い、Kubernetesにストレージクラスを設定します。

永続ボリューム用のストレージ選定

Kubernetesの永続ボリュームに使用できるストレージはいくつかありますが、今回はCephを選びました。

中でもKubernetes対応のCephストレージソフトウェアである「ROOK」を使用します。

https://rook.io

Kubernetesの特権モードを有効化

ROOKを構築するにはKubernetesの特権モードを有効化しておく必要があります。

JUJUを使用している場合、MasterとWorkerのconfigureからallo-privileged=trueに設定します。

f:id:virtualtech:20180523133945p:plain

ROOKのダウンロード

ROOKをGithubからクローンでダウンロードします。

$ git clone https://github.com/rook/rook.git
$ cd rook/cluster/examples/kubernetes/

ROOK Operatorのデプロイ

始めにROOK Operatorをデプロイします。

kubectl create -f rook-operator.yaml

正常にデプロイできたかをポッドの一覧から確認します。

$ kubectl -n rook-system get pod
NAME                             READY     STATUS    RESTARTS   AGE
rook-agent-4ljgl                 1/1       Running   0          1m
rook-agent-988kd                 1/1       Running   0          1m
rook-operator-7cdfdb4bdc-ksg4b   1/1       Running   0          1m

ROOK Clusterのデプロイ

次にROOK Clusterをデプロイします。

kubectl create -f rook-cluster.yaml

こちらも正常にデプロイできたかをポッドの一覧から確認します。 ceph-osdやceph-monがworker数分作成されています。

$ kubectl -n rook get pod
NAME                              READY     STATUS    RESTARTS   AGE
rook-api-7f9df6fdfd-ph96w         1/1       Running   0          1m
rook-ceph-mgr0-67df677685-mzxvd   1/1       Running   0          1m
rook-ceph-mon0-5c66f              1/1       Running   0          1m
rook-ceph-mon1-qfn6h              1/1       Running   0          1m
rook-ceph-osd-pj4wk               1/1       Running   0          1m
rook-ceph-osd-q4xp7               1/1       Running   0          1m

ROOK Storage Class設定

ここまででバックエンドストレージが出来上がっていますので、最後にストレージクラスをKubernetesに設定します。

$ kubectl create -f rook-storageclass.yaml

作成確認します。

$ kubectl get storageclass
NAME                   PROVISIONER     AGE
rook-block (default)   rook.io/block   1m

規定のストレージクラス設定

Kubernetesでは永続ボリューム要求をする際にストレージクラスを指定します。

例えば以下のように

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: mysql-pv-claim
  labels:
    app: wordpress
spec:
  storageClassName: rook-block
  accessModes:
  - ReadWriteOnce
  resources:
    requests:
      storage: 20Gi

ところがyamlファイルの作りによってはstorageClassNameを指定していないものもあります。

後述するhelmによるspinnakerのデプロイもその一つでした。

したがって、明示的なストレージの指定がない場合の動作を規定しておく必要があります。

$ kubectl get storageclass
NAME         PROVISIONER     AGE
rook-block   rook.io/block   1m

$ kubectl patch storageclass rook-block -p '{"metadata": {"annotations":{"storageclass.kubernetes.io/is-default-class":"true"}}}'

$ kubectl get storageclass
NAME                   PROVISIONER     AGE
rook-block (default)   rook.io/block   3m

ストレージクラス名の横に(default)が付与されていればOKです。

Spinnakerのデプロイ

helmインストール

Spinnakerのデプロイにはkubernetesパッケージマネージャーhelmを使用して行います。

コマンド単体で公開されているので、PATHが通っている場所に展開します。

$ wget https://storage.googleapis.com/kubernetes-helm/helm-v2.8.2-linux-amd64.tar.gz
$ tar zxvf helm-v2.8.2-linux-amd64.tar.gz
$ sudo cp linux-amd64/helm /bin/

helm初期化

helmを初期化します

$ helm init

deploymentsにtiller-deployが作成されているかを確認します。

kubectl get deployments --namespace=kube-system
NAME                             DESIRED   CURRENT   UP-TO-DATE   AVAILABLE   AGE
heapster-v1.5.2                  1         1         1            1           10d
kube-dns                         1         1         1            1           10d
kubernetes-dashboard             1         1         1            1           10d
metrics-server-v0.2.1            1         1         1            1           10d
monitoring-influxdb-grafana-v4   1         1         1            1           10d
tiller-deploy                    1         1         1            1           10d

helmリポジトリアップデート

helmのリポジトリをアップデートします。

アップデートしない場合のstable/spinnaker CHART VERSIONは0.4.0になっており、

当該バージョンではデプロイに失敗していました。

当方の環境ではCHART VERSION 0.4.1でデプロイと動作確認しています。

$ helm search spinnaker
NAME                CHART VERSION   APP VERSION DESCRIPTION                                       
stable/spinnaker    0.4.0           1.6.0       Open source, multi-cloud continuous delivery pl...

$ helm repo update
Hang tight while we grab the latest from your chart repositories...
...Skip local chart repository
...Successfully got an update from the "stable" chart repository
Update Complete. ⎈ Happy Helming!⎈ 

$ helm search spinnaker
NAME                CHART VERSION   APP VERSION DESCRIPTION                                       
stable/spinnaker    0.4.1           1.6.0       Open source, multi-cloud continuous delivery pl...

Spinnakerデプロイ

helmコマンドでspinnakerをデプロイします。

$ helm install stable/spinnaker

プロンプトが返却されるのに時間がかかりますので、しばらく待ちます。

WEB UI への接続

デプロイしたSpinnakerのWEB UIにアクセスします。

方法は様々ですが、一番容易な方法としてローカルPCへkubectlをインストールし、port-forwardで接続することにしました。

ローカルPCはmacにて作業しています。

$ curl -LO https://storage.googleapis.com/kubernetes-release/release/$(curl -s https://storage.googleapis.com/kubernetes-release/release/stable.txt)/bin/darwin/amd64/kubectl
$ chmod 755 kubectl
$ mkdir .kube

kubectlがkubernetesクラスタへ接続するために、.kubeディレクトリ内へconfigという名前のコンフィグファイルを、既にkubectlが動作している環境(Masterノード等)からコピーしてください。

$ pwd
/Users/user/.kube

$ ls -l
total 8
-rw-r--r--   1 user  user  1961  5 11 17:29 config

kubectlが実行可能か、ポッドの一覧を取得して確認します。

$ ./kubectl get pod
NAME                                                   READY     STATUS      RESTARTS   AGE
default-http-backend-2wz6k                             1/1       Running     0          10d
nginx-ingress-kubernetes-worker-controller-6jr2k       1/1       Running     0          10d
nginx-ingress-kubernetes-worker-controller-twgsw       1/1       Running     0          10d
wishing-camel-create-bucket-hl5d7                      0/1       Completed   2          6d
wishing-camel-jenkins-6f7c98bf8f-xg2nx                 1/1       Running     0          5d
wishing-camel-minio-6cffcc6db8-vz4tw                   1/1       Running     0          6d
wishing-camel-redis-67968d58bf-9tnkm                   1/1       Running     0          6d
wishing-camel-spinnaker-clouddriver-6849758946-tnlgt   1/1       Running     0          6d
wishing-camel-spinnaker-deck-94bd44446-gllp7           1/1       Running     0          6d
wishing-camel-spinnaker-echo-6c8d594b58-d9g5l          1/1       Running     0          6d
wishing-camel-spinnaker-front50-5c96c6fb8-sxfsz        1/1       Running     0          6d
wishing-camel-spinnaker-gate-5bbb8f5f44-4g8vc          1/1       Running     0          6d
wishing-camel-spinnaker-igor-76f485774f-x5fjd          1/1       Running     0          6d
wishing-camel-spinnaker-orca-5d55699b75-p4vl7          1/1       Running     0          6d
wishing-camel-spinnaker-rosco-fbb775b59-z7pqf          1/1       Running     0          6d
wishing-camel-upload-build-image-dx295                 0/1       Completed   0          6d
wishing-camel-upload-run-pipeline-z8lpf                0/1       Completed   0          6d
wishing-camel-upload-run-script-bdllh                  0/1       Completed   0          6d

spinnaker-deck というポッドにport-forwardします。

$ ./kubectl port-forward wistful-crab-spinnaker-deck-74976bbcf9-x48dc 9000

WEBブラウザを開き、ポートフォワードしたローカルホストに対し接続します。

f:id:virtualtech:20180523134012p:plain

今回はひとまずここまで!

次回はSpinnakerのパイプライン設定を行い、Kubernetesへの自動デプロイを実行していきます。

JUJU + MAAS を使用したOpenstack構築 + 監視設定

JUJU + MAASによるOpenstackの構築と、 Gnocchi Grafanaを使用したリソース監視の作成に挑戦しました。

今回の筆者は コムシス情報システム株式会社 山本 聡(やまもと さとる)です。 以前のエントリーでKubernetesの構築について書かせていただきました。 http://tech.virtualtech.jp/entry/2018/03/29/104216

実行環境

構成はk8s構築で使用した物理サーバを流用します。 また、Openstack外部接続用のネットワークを追加しました。

f:id:virtualtech:20180424130921p:plain

MAASのインストール

MAAS、Ubuntuのインストールを実施します。

以下の設定でUbuntu Serverをインストール

  • インストールモード:Install Ubuntu Server(通常のインストール)

  • Language:日本語

  • Timezone:日本

  • Keyboard:Japanese

  • ソフトウェアの選択:OpenSSH Server

ネットワーク設定からMAAS+JUJUのインストール

JUJUのインストールまで以前のエントリーと同様です。 http://tech.virtualtech.jp/entry/2018/03/29/104216

MAASで認識された各サーバにタグを付与

Openstackのデプロイ用にMAAS上の各ノードにタグを付与します。

  • node01

 コントローラーノードとして設定

  • node02

 コンピュート及びcephノードとして設定

  • node03

 コンピュート及びcephノードとして設定

Openstackデプロイ

Openstackデプロイ用yamlファイルの作成

Openstack自動構築用のyamlファイルを用意します。 "tags="で記述される箇所がMAASのタグと一致するよう注意してください。

$ vim openstack-telemetry.yaml
machines:
  '0':
    series: xenial
    constraints: "arch=amd64 tags=node01"
  '1':
    series: xenial
    constraints: "arch=amd64 tags=node02"
  '2':
    series: xenial
    constraints: "arch=amd64 tags=node03"
relations:
- - nova-compute:amqp
  - rabbitmq-server:amqp
- - neutron-gateway:amqp
  - rabbitmq-server:amqp
- - keystone:shared-db
  - mysql:shared-db
- - nova-cloud-controller:identity-service
  - keystone:identity-service
- - glance:identity-service
  - keystone:identity-service
- - neutron-api:identity-service
  - keystone:identity-service
- - neutron-openvswitch:neutron-plugin-api
  - neutron-api:neutron-plugin-api
- - neutron-api:shared-db
  - mysql:shared-db
- - neutron-api:amqp
  - rabbitmq-server:amqp
- - neutron-gateway:neutron-plugin-api
  - neutron-api:neutron-plugin-api
- - glance:shared-db
  - mysql:shared-db
- - glance:amqp
  - rabbitmq-server:amqp
- - nova-cloud-controller:image-service
  - glance:image-service
- - nova-compute:image-service
  - glance:image-service
- - nova-cloud-controller:cloud-compute
  - nova-compute:cloud-compute
- - nova-cloud-controller:amqp
  - rabbitmq-server:amqp
- - nova-cloud-controller:quantum-network-service
  - neutron-gateway:quantum-network-service
- - nova-compute:neutron-plugin
  - neutron-openvswitch:neutron-plugin
- - neutron-openvswitch:amqp
  - rabbitmq-server:amqp
- - openstack-dashboard:identity-service
  - keystone:identity-service
- - nova-cloud-controller:shared-db
  - mysql:shared-db
- - nova-cloud-controller:neutron-api
  - neutron-api:neutron-api
- - cinder:image-service
  - glance:image-service
- - cinder:amqp
  - rabbitmq-server:amqp
- - cinder:identity-service
  - keystone:identity-service
- - cinder:cinder-volume-service
  - nova-cloud-controller:cinder-volume-service
- - cinder-ceph:storage-backend
  - cinder:storage-backend
- - ceph-mon:client
  - nova-compute:ceph
- - nova-compute:ceph-access
  - cinder-ceph:ceph-access
- - cinder:shared-db
  - mysql:shared-db
- - ceph-mon:client
  - cinder-ceph:ceph
- - ceph-mon:client
  - glance:ceph
- - ceph-osd:mon
  - ceph-mon:osd
- - ntp:juju-info
  - nova-compute:juju-info
- - ntp:juju-info
  - neutron-gateway:juju-info
- - ceph-radosgw:mon
  - ceph-mon:radosgw
- - ceph-radosgw:identity-service
  - keystone:identity-service
- - ceilometer:amqp
  - rabbitmq-server:amqp
- - ceilometer-agent:ceilometer-service
  - ceilometer:ceilometer-service
- - ceilometer:identity-notifications
  - keystone:identity-notifications
- - ceilometer-agent:nova-ceilometer
  - nova-compute:nova-ceilometer
- - aodh:shared-db
  - mysql:shared-db
- - aodh:identity-service
  - keystone:identity-service
- - aodh:amqp
  - rabbitmq-server:amqp
- - gnocchi:storage-ceph
  - ceph-mon:client
- - gnocchi:shared-db
  - mysql:shared-db
- - gnocchi:amqp
  - rabbitmq-server:amqp
- - gnocchi:coordinator-memcached
  - memcached:cache
- - gnocchi:metric-service
  - ceilometer:metric-service
- - gnocchi:identity-service
  - keystone:identity-service
- - ceilometer:identity-credentials
  - keystone:identity-credentials

series: xenial
services:
  aodh:
    annotations:
      gui-x: '1500'
      gui-y: '0'
    charm: cs:aodh-12
    num_units: 1
    options:
      openstack-origin: cloud:xenial-queens
    to:
    - lxd:0
  ceilometer:
    annotations:
      gui-x: '1250'
      gui-y: '0'
    charm: cs:ceilometer-252
    num_units: 1
    options:
      openstack-origin: cloud:xenial-queens
    to:
    - lxd:2
  ceilometer-agent:
    annotations:
      gui-x: '1250'
      gui-y: '500'
    charm: cs:ceilometer-agent-243
    num_units: 0
  ceph-mon:
    annotations:
      gui-x: '750'
      gui-y: '500'
    charm: cs:ceph-mon-23
    num_units: 2
    options:
      expected-osd-count: 2
      monitor-count: 2
      source: cloud:xenial-queens
    to:
    - lxd:1
    - lxd:2
  ceph-osd:
    annotations:
      gui-x: '1000'
      gui-y: '500'
    charm: cs:ceph-osd-257
    num_units: 2
    options:
      osd-devices: /dev/sdb
      osd-reformat: 'yes'
      source: cloud:xenial-queens
    to:
    - '1'
    - '2'
  ceph-radosgw:
    annotations:
      gui-x: '1000'
      gui-y: '250'
    charm: cs:ceph-radosgw-256
    num_units: 1
    options:
      source: cloud:xenial-queens
    to:
    - lxd:1
  cinder:
    annotations:
      gui-x: '750'
      gui-y: '0'
    charm: cs:cinder-268
    num_units: 1
    options:
      block-device: None
      glance-api-version: 2
      openstack-origin: cloud:xenial-queens
      worker-multiplier: 0.25
    to:
    - lxd:2
  cinder-ceph:
    annotations:
      gui-x: '750'
      gui-y: '250'
    charm: cs:cinder-ceph-231
    num_units: 0
  glance:
    annotations:
      gui-x: '250'
      gui-y: '0'
    charm: cs:glance-263
    num_units: 1
    options:
      openstack-origin: cloud:xenial-queens
      worker-multiplier: 0.25
    to:
    - lxd:2
  gnocchi:
    annotations:
      gui-x: '1500'
      gui-y: '250'
    charm: cs:gnocchi-7
    num_units: 1
    options:
      openstack-origin: cloud:xenial-queens
    to:
    - lxd:0
  keystone:
    annotations:
      gui-x: '500'
      gui-y: '0'
    charm: cs:keystone-275
    num_units: 1
    options:
      admin-password: openstack
      openstack-origin: cloud:xenial-queens
      worker-multiplier: 0.25
    to:
    - lxd:1
  memcached:
    annotations:
      gui-x: '1500'
      gui-y: '500'
    charm: cs:memcached-18
    num_units: 1
    to:
    - lxd:2
  mysql:
    annotations:
      gui-x: '0'
      gui-y: '250'
    charm: cs:percona-cluster-259
    num_units: 1
    options:
      innodb-buffer-pool-size: 256M
      max-connections: 1000
    to:
    - lxd:2
  neutron-api:
    annotations:
      gui-x: '500'
      gui-y: '500'
    charm: cs:neutron-api-258
    num_units: 1
    options:
      flat-network-providers: physnet1
      neutron-security-groups: true
      openstack-origin: cloud:xenial-queens
      worker-multiplier: 0.25
    to:
    - lxd:2
  neutron-gateway:
    annotations:
      gui-x: '0'
      gui-y: '0'
    charm: cs:neutron-gateway-247
    num_units: 1
    options:
      bridge-mappings: physnet1:br-ex
      data-port: br-ex:eno2
      openstack-origin: cloud:xenial-queens
      worker-multiplier: 0.25
    to:
    - '0'
  neutron-openvswitch:
    annotations:
      gui-x: '250'
      gui-y: '500'
    charm: cs:neutron-openvswitch-249
    num_units: 0
  nova-cloud-controller:
    annotations:
      gui-x: '0'
      gui-y: '500'
    charm: cs:nova-cloud-controller-306
    num_units: 1
    options:
      network-manager: Neutron
      openstack-origin: cloud:xenial-queens
      worker-multiplier: 0.25
    to:
    - lxd:0
  nova-compute:
    annotations:
      gui-x: '250'
      gui-y: '250'
    charm: cs:nova-compute-282
    num_units: 2
    options:
      config-flags: default_ephemeral_format=ext4
      enable-live-migration: true
      enable-resize: true
      migration-auth-type: ssh
      openstack-origin: cloud:xenial-queens
    to:
    - '1'
    - '2'
  ntp:
    annotations:
      gui-x: '1000'
      gui-y: '0'
    charm: cs:ntp-24
    num_units: 0
  openstack-dashboard:
    annotations:
      gui-x: '500'
      gui-y: '-250'
    charm: cs:openstack-dashboard-257
    num_units: 1
    options:
      openstack-origin: cloud:xenial-queens
    to:
    - lxd:0
  rabbitmq-server:
    annotations:
      gui-x: '500'
      gui-y: '250'
    charm: cs:rabbitmq-server-72
    num_units: 1
    to:
    - lxd:0
  grafana:
    charm: "cs:xenial/grafana-9"
    num_units: 1
    options:
      install_method: apt
      admin_password: password5656
    annotations:
      gui-x: '132.75'
      gui-y: '1066'
    to:
      - lxd:1

設定値のポイント解説

  • osd-devices: /dev/sdb

ceph-osdが設定されるサーバはディスクが2つ設定されている必要があります。

  • bridge-mappings: physnet1:br-ex
  • data-port: br-ex:eno2

サーバが認識するネットワークポートと一致させる必要があります。

  • config-flags: default_ephemeral_format=ext4

今回はext4で構成しますが、異なるファイルシステムも使用することが出来ます。

juju deploy を実行

$ juju deploy openstack-telemetry.yaml

openstackclientをインストール

Openstackを操作するためのクライアントをインストールします。

$ sudo apt install python-openstackclient

novarc_autoファイルの作成

Openstackクライアントの動作に必要なrcファイルを作成します

$ vim novarc_auto
_OS_PARAMS=$(env | awk 'BEGIN {FS="="} /^OS_/ {print $1;}' | paste -sd ' ')
for param in $_OS_PARAMS; do
    unset $param
done
unset _OS_PARAMS

keystone_unit=$(juju status keystone|grep -i workload -A1|tail -n1|awk '{print $1}'|tr -d '*')
echo Keystone unit: ${keystone_unit}
if ! curl -qs `juju run --unit ${keystone_unit} "unit-get private-address"`:5000/v3 | grep 404 ;
then
echo Using keystone v3 api
export OS_AUTH_URL=${OS_AUTH_PROTOCOL:-http}://`juju run --unit ${keystone_unit} "unit-get private-address"`:5000/v3
export OS_USERNAME=admin
export OS_PASSWORD=openstack
export OS_DOMAIN_NAME=admin_domain
export OS_USER_DOMAIN_NAME=admin_domain
export OS_PROJECT_DOMAIN_NAME=admin_domain
export OS_PROJECT_NAME=admin
export OS_REGION_NAME=RegionOne
export OS_IDENTITY_API_VERSION=3
# Swift needs this:
export OS_AUTH_VERSION=3
else
echo Using keystone v2 api
export OS_USERNAME=admin
export OS_PASSWORD=openstack
export OS_TENANT_NAME=admin
export OS_REGION_NAME=RegionOne
export OS_AUTH_URL=${OS_AUTH_PROTOCOL:-http}://`juju run --unit ${keystone_unit} "unit-get private-address"`:5000/v2.0

rcファイルの読み込み

$ source novarc_auto

監視確認

Openstack状態の確認

デプロイがすべて完了したことをjuju statusコマンドで確認後、 実際にOpenstackが操作できるかをコマンドで打ってみましょう。

$ openstack service list

+----------------------------------+-----------+--------------+
| ID                               | Name      | Type         |
+----------------------------------+-----------+--------------+
| 0a6aac12ae71496494a3b0748e17021b | aodh      | alarming     |
| 2447939369d74795a0ee65bda1bfe3a1 | swift     | object-store |
| 4a1d931905fd43c3bf3403eb25a96bd4 | placement | placement    |
| 4a40e8739f9046d7978422e5331c8383 | gnocchi   | metric       |
| 5586181aad80426392ee40c41ab9b19a | keystone  | identity     |
| 56608d839340422a8b02af265de70ce9 | neutron   | network      |
| 5e1abf112ca44857a347ba0bd471720e | nova      | compute      |
| 671b147f8d06417fa1b9ff14475d0f40 | glance    | image        |
| 9820e33afcf3467da93a7138632ea917 | cinderv3  | volumev3     |
| bfb458d163314bdeaefd1e867de2ead9 | cinderv2  | volumev2     |
+----------------------------------+-----------+--------------+

上記のような応答があれば成功です。

Ceilometerを有効化

今回の構成のようにCeilometerとGnocchiを連携する場合、 以下のコマンドで有効化する必要があります。

$ juju run-action ceilometer/0 ceilometer-upgrade

Dashboardにアクセス

Dashboardにアクセスします。 juju statusコマンドでopenstack-dashboardのIPアドレスを確認し、 http://xx.xx.xx.xx/horizon のURLでブラウザからアクセスしてください。 yamlファイルに認証の変更を加えていなければ、以下の情報でログインできます。

  • ドメイン:admin_domain
  • ユーザ名:admin
  • パスワード:openstack

インスタンスの作成

監視データの蓄積をするため、監視対象となるインスタンスの作成を行います。 jujuで構築したOpenstackは初期状態においてインスタンス作成に必要な下記項目が設定されていないので、 Dashboardから設定を行ってください。

  • イメージの登録
  • ルーターの作成
  • 内部ネットワークの作成
  • 内部ネットワークサブネットの作成
  • フレーバーの作成

CirrOS等の軽量イメージを使用してインスタンスを稼働しましょう。

メトリックデータの取得

実際に監視データが取得できているかを確認します。 まずはリソースの一覧から表示してみましょう。

$ openstack metric resource list

+--------------------------------------+----------------------------+----------------------------------+----------------------------------+-----------------------------------------------------------------------+----------------------------------+----------+----------------------------------+--------------+-------------------------------------------------------------------+
| id                                   | type                       | project_id                       | user_id                          | original_resource_id                                                  | started_at                       | ended_at | revision_start                   | revision_end | creator                                                           |
+--------------------------------------+----------------------------+----------------------------------+----------------------------------+-----------------------------------------------------------------------+----------------------------------+----------+----------------------------------+--------------+-------------------------------------------------------------------+
| 579ef430-4278-51ca-ad28-4edd6897fee6 | instance_network_interface | d948eedc6f1047bfaf9539e6526dd919 | 8981ef1a6dcb4683b97b82925fd87a9f | instance-00000001-bd7f158f-369c-41dc-81b1-84487a583c6e-tap91c4a8f8-9d | 2018-04-24T01:12:48.853092+00:00 | None     | 2018-04-24T01:12:48.853151+00:00 | None         | 1cf01d45402749e286c098b89caf5eaf:5f5d5bfecb944273a00697e59eafc436 |
| b39ba0c5-860f-598a-b0f4-82ab5afb5c50 | instance_disk              | d948eedc6f1047bfaf9539e6526dd919 | 8981ef1a6dcb4683b97b82925fd87a9f | bd7f158f-369c-41dc-81b1-84487a583c6e-vdb                              | 2018-04-24T01:12:48.941122+00:00 | None     | 2018-04-24T01:12:48.941142+00:00 | None         | 1cf01d45402749e286c098b89caf5eaf:5f5d5bfecb944273a00697e59eafc436 |
| 3f830f79-7cf9-5060-affd-5e4d43196ffc | instance_disk              | d948eedc6f1047bfaf9539e6526dd919 | 8981ef1a6dcb4683b97b82925fd87a9f | bd7f158f-369c-41dc-81b1-84487a583c6e-vda                              | 2018-04-24T01:12:49.119669+00:00 | None     | 2018-04-24T01:12:49.119688+00:00 | None         | 1cf01d45402749e286c098b89caf5eaf:5f5d5bfecb944273a00697e59eafc436 |
| bd7f158f-369c-41dc-81b1-84487a583c6e | instance                   | d948eedc6f1047bfaf9539e6526dd919 | 8981ef1a6dcb4683b97b82925fd87a9f | bd7f158f-369c-41dc-81b1-84487a583c6e                                  | 2018-04-24T01:17:48.346622+00:00 | None     | 2018-04-24T01:17:48.346641+00:00 | None         | 1cf01d45402749e286c098b89caf5eaf:5f5d5bfecb944273a00697e59eafc436 |
+--------------------------------------+----------------------------+----------------------------------+----------------------------------+-----------------------------------------------------------------------+----------------------------------+----------+----------------------------------+--------------+-------------------------------------------------------------------+

次にリソースの詳細です、instanceの詳細を表示してみます。

$ openstack metric resource show bd7f158f-369c-41dc-81b1-84487a583c6e

+-----------------------+---------------------------------------------------------------------+
| Field                 | Value                                                               |
+-----------------------+---------------------------------------------------------------------+
| created_by_project_id | 5f5d5bfecb944273a00697e59eafc436                                    |
| created_by_user_id    | 1cf01d45402749e286c098b89caf5eaf                                    |
| creator               | 1cf01d45402749e286c098b89caf5eaf:5f5d5bfecb944273a00697e59eafc436   |
| ended_at              | None                                                                |
| id                    | bd7f158f-369c-41dc-81b1-84487a583c6e                                |
| metrics               | compute.instance.booting.time: 41aa5d18-772c-49ef-b1f6-26ce117d9290 |
|                       | cpu.delta: f76b4f69-8a30-4565-95af-bbf5f080cb85                     |
|                       | cpu: f9e7437c-6346-49d1-bd93-e82320afad90                           |
|                       | cpu_l3_cache: fbbb5723-f24a-4376-8253-c9b69768022c                  |
|                       | cpu_util: 5c22865d-6727-4c6c-ba3d-37a6d8ee6f4c                      |
|                       | disk.allocation: cb44a188-0d14-443e-aa4b-f85cc502d021               |
|                       | disk.capacity: 8fae7b4d-43f7-4357-8250-e7644e93cd3c                 |
|                       | disk.ephemeral.size: 07eb3f61-6faa-481d-aa4a-6d2e66591b05           |
|                       | disk.iops: 62c81e4c-fb7d-4d96-8657-9e9884dc3aef                     |
|                       | disk.latency: 17f8f246-36c4-4096-8901-c32d5a0ecf42                  |
|                       | disk.read.bytes.rate: 7a7776a4-abe9-4c81-8981-d2c560f52f12          |
|                       | disk.read.bytes: bbe8c0a0-a7bc-4c67-9c62-b500f20fa7d2               |
|                       | disk.read.requests.rate: 4508526a-af1c-4289-b340-0255f012c042       |
|                       | disk.read.requests: 36e36446-fc08-4e20-8d1e-ffaa5c8543c5            |
|                       | disk.root.size: 504a2693-5083-4c2b-9653-1394ad3ed415                |
|                       | disk.usage: 8afdfafe-e499-4c8a-b6e8-c9b60fb61504                    |
|                       | disk.write.bytes.rate: 422f0e51-1fca-4762-b418-c6de634601f7         |
|                       | disk.write.bytes: d21bd9f7-c441-4f95-ad0f-1e29fc799231              |
|                       | disk.write.requests.rate: 114edd3e-ce8e-4fd7-b96e-5fe2808de96e      |
|                       | disk.write.requests: 6e15ee6b-965d-46e7-82a7-bd869464c956           |
|                       | memory.bandwidth.local: a05a8117-2364-47a1-8eb8-4335227b89f2        |
|                       | memory.bandwidth.total: 6ea4ed00-bcca-49bc-96a7-a089577f08aa        |
|                       | memory.resident: 72564fd4-e3df-46f2-b2a5-0da106e749ce               |
|                       | memory.swap.in: 8c150408-0952-4a56-8c49-7bf196d3382d                |
|                       | memory.swap.out: ba87a10a-7e53-46e4-ba0d-40285990d5e6               |
|                       | memory.usage: 8c1008d1-a1ca-4986-8526-d95fd1a91886                  |
|                       | memory: 111aae74-7814-4228-b959-b0133b70a600                        |
|                       | perf.cache.misses: 76ac152a-cd9f-4593-be95-c586cc65471e             |
|                       | perf.cache.references: 44dae2f5-67b2-4509-8457-b6b512fee081         |
|                       | perf.cpu.cycles: 6fdcae77-b548-4cd9-b78f-fdbf5dc9057c               |
|                       | perf.instructions: 09357908-90bb-43bb-a74b-8cb86dda8833             |
|                       | vcpus: d1ad1631-b464-4179-95fe-573b2d83ee69                         |
| original_resource_id  | bd7f158f-369c-41dc-81b1-84487a583c6e                                |
| project_id            | d948eedc6f1047bfaf9539e6526dd919                                    |
| revision_end          | None                                                                |
| revision_start        | 2018-04-24T01:17:48.346641+00:00                                    |
| started_at            | 2018-04-24T01:17:48.346622+00:00                                    |
| type                  | instance                                                            |
| user_id               | 8981ef1a6dcb4683b97b82925fd87a9f                                    |
+-----------------------+---------------------------------------------------------------------+

監視の値を取得してみます、memory.usageの表示です。

$ openstack metric measures show 8c1008d1-a1ca-4986-8526-d95fd1a91886
+---------------------------+-------------+-------+
| timestamp                 | granularity | value |
+---------------------------+-------------+-------+
| 2018-04-24T10:15:00+09:00 |       300.0 |  45.0 |
+---------------------------+-------------+-------+

Grafanaによるグラフ化

GrafanaへGnocchi-Pluginのインストール

コマンドラインで監視データが取得できたので、今度はグラフ化に挑みます。 まずはGrafanaへGnocchiをデータソースとして利用するためのプラグインを入れます。

$ juju ssh grafana/0
$ sudo grafana-cli plugins install gnocchixyz-gnocchi-datasource
installing gnocchixyz-gnocchi-datasource @ 1.7.0
from url: https://grafana.com/api/plugins/gnocchixyz-gnocchi-datasource/versions/1.7.0/download
into: /var/lib/grafana/plugins

Failed downloading. Will retry once.
✔ Installed gnocchixyz-gnocchi-datasource successfully 

Restart grafana after installing plugins . <service grafana-server restart>

Grafanaサービスをリスタートし、Grafanaサーバから抜けます。

$ sudo service grafana-server restart
$ exit

Grafanaログイン情報の表示

Grafanaへログインするためのパスワードを表示します。

unit-grafana-0:
  id: 57b95cec-fb95-43e1-86c5-86ad0f274c33
  results:
    password: password5656
  status: completed
  timing:
    completed: 2018-04-24 01:29:02 +0000 UTC
    enqueued: 2018-04-24 01:29:01 +0000 UTC
    started: 2018-04-24 01:29:02 +0000 UTC
  unit: grafana/0

Grafanaへ接続

Grafanaデプロイ先アドレスにWebアクセスします。 ユーザ名はadmin、パスワードは上記で表示されたものを使用します。

http://xx.xx.xx.xx:3000

Data Sourceの設定

続いてData Sourceを設定します。 Gnocchi-Pluginがインストールされていれば、TypeにGnocchiを選択できます。

f:id:virtualtech:20180424131020p:plain

しかしここで問題発生、Gnocchiへの認証モードがkeystoneを使用すると通りません。

f:id:virtualtech:20180424131023p:plain

どうやらCORSを設定しなければならないようですが、jujuの設定項目で解決ができない範囲のようです。

https://blog.sileht.net/configuring-cors-for-gnocchi-and-keystone.html

何とか出来ないものかとpluginの設定項目を探すと、認証にtokenを指定できるのを見つけました。 強引ですが、tokenを引っ張ってきて設定してみます。

$ curl -i -X POST -H "Content-Type: application/json" -d '
{
  "auth": {
    "identity": {
      "methods": [
        "password"
      ],
      "password": {
        "user": {
          "name": "admin",
          "password": "openstack",
          "domain": {
            "name": "admin_domain"
          }
        }
      }
    },
    "scope": {
      "project": {
        "name": "admin",
        "domain": {
          "name": "admin_domain"
        }
      }
    }
  }
}' http://172.17.30.89:5000/v3/auth/tokens

HTTP/1.1 201 Created
Date: Tue, 24 Apr 2018 01:42:59 GMT
Server: Apache/2.4.18 (Ubuntu)
X-Subject-Token: 830d04244cfc4598b8c5cbb4f2fdc31c
Vary: X-Auth-Token
X-Distribution: Ubuntu
x-openstack-request-id: req-ceae75ca-0b04-4fe0-bb3e-cacb630a3a1c
Content-Length: 6557
Content-Type: application/json

{"token": {"is_domain": false, "methods": ["password"], "roles": [{"id": "097ec800c2f64a438a787f058066fbc3", "name": "Admin"}, {"id": "b6b8500fe90048e7b4700bea94ffdb31", "name": "Member"}], (省略)

tokenを渡した所、正常にData Sourceを設定できたようです。

f:id:virtualtech:20180424131025p:plain

グラフ化

設定したDeta Sourceを指定してグラフを表示させてみます。 metric IDを直接指定する方式で値が取れているのがわかります。

f:id:virtualtech:20180424131027p:plain

認証の問題

何とかグラフ化に成功しましたが、tokenの期限が切れてしまうとData Sourceが機能しなくなってしまうため、別の手法を模索する必要があると感じました。 引き続き調査したいと思います。