最近当ブログでよく書かれているKubernetes。 そのKubernetesについて、物理サーバを使用した構築を行ってみようと考えました。
今回はJUJU + MAASによるKubernetes(k8s)の構築と、 PrometheusとGrafanaを使用したリソース監視の環境を作成した結果を公開いたします。
JUJU、MAAS、Kubernetesの基本的な説明については以前のエントリーを参照ください。 http://tech.virtualtech.jp/entry/2018/02/05/124557
申し遅れました、今回の筆者を努めます コムシス情報システム株式会社 山本 聡(やまもと さとる)と申します。 現在、日本仮想化技術株式会社様の元でKubernetesを学習させていただいております。
実行環境
構成を単純化するため、JUJUデプロイまでは全て物理サーバでの構築を行いました。 JUJU+MAAS以外のサーバはJUJU+MAASが自動的にアドレスを割り当てます。 今回のKubernetes構築ではMatser1台、Worker2台で構成します。

MAASのインストール
MAASサーバのみ手動でUbuntuのインストールを実施します。
Ubuntu Serverをインストール
Ubuntu Serverについては、ベーシックなインストール設定とします。 インストール後にSSHで操作するため、OpenSSH Serverを選択しています。
インストールモード:Install Ubuntu Server(通常のインストール)
Language:日本語
Timezone:日本
Keyboard:Japanese
ソフトウェアの選択:OpenSSH Server
ネットワーク設定
まずはネットワーク設定を行いましょう。
vim /etc/network/interfaces
# This file describes the network interfaces available on your system # and how to activate them. For more information, see interfaces(5). source /etc/network/interfaces.d/* # The loopback network interface auto lo iface lo inet loopback # eno1 auto iface eno1 inet static address 172.17.30.10 network 172.17.30.0 netmask 255.255.255.0 broadcast 172.17.30.255 gateway 172.17.30.1 dns-nameservers 8.8.8.8
インターフェース有効化のため再起動
$ sudo reboot
アップデート
$ sudo apt -y update $ sudo apt -y upgrade
MAASインストール
$ sudo apt install maas
執筆時点でのバージョンは2.3.0がインストールされました。
MAASユーザ設定
MAASの管理者を作成します。 今回はmaasadminというユーザを作成しました。 import SSH keysは後で入力するため、ここではEnterでスキップしておきます。
$ sudo maas createadmin Username:maasadmin Password:maasadmin Again:maasadmin Email: Import SSH keys [] (lp:user-id or gh:user-id):
MAASダッシュボードを開く
ここまで完了すると、MAASの管理画面を開くことができます。 Port:5240 へWEBブラウザからアクセスしてみましょう。 MAASユーザ設定で使用した情報を使ってログインします。

MAASネットワーク設定
次に、MAAS-DHCPが使用するアドレス帯(Reserve Dynamic range)と 優先的に使用しないアドレス帯(Reserve range)を設定します。
subnet → VLAN
Reserve dynamic range :172.17.30.240 - 254
Reserve range :172.17.30.1 - 50

MAAS鍵設定
画面右上のユーザ名からUser Preferencesを表示し、MAAS Keysを確認して控えておきます。
またMAASが使用するssh公開鍵をSSH keysに登録しましょう。
SSH keyはssh-keygen -t rsaを使用して予め作成しておきます。

各サーバをPXEブート
MAASのネットワーク設定が終わったら、各サーバをPXEで起動してみてください。 MAASからネットワークアドレスやミニマムなOSが自動的に配信され、enlistが行われます。 Nodesに表示された各サーバをコミッショニングし、StatusがReadyになればサーバの準備は完了です。
Enlist 自動
Commission MAASが認識したサーバを選択、Take Actionからコミッションする
JUJUのインストール
JUJUのインストールと、JUJU Bootstrapサーバを構築します。 コンポーネントのインストールとBootstrap用のyamlファイルを用意しましょう。
MAASサーバにJUJUをインストール
今回はMAASサーバにJUJUのインストールを行いました。
$ sudo snap instal juju --clasic
JUJU Bootstrapの作成
Bootstrap用のyamファイルを作成します。
$ vim mymaas.yaml
clouds:
maas-server:
type: maas
auth-types: [oauth1]
endpoint: http://172.17.30.10/MAAS/
用意したyamlファイルをjuju-addcloudして登録します。
$ juju add-cloud maas-server mymaas.yaml
maas-serverという名前でCloudが作成されているかを確認します。
$ juju clouds Cloud Regions Default Type Description aws 14 us-east-1 ec2 Amazon Web Services aws-china 1 cn-north-1 ec2 Amazon China aws-gov 1 us-gov-west-1 ec2 Amazon (USA Government) azure 26 centralus azure Microsoft Azure azure-china 2 chinaeast azure Microsoft Azure China cloudsigma 5 hnl cloudsigma CloudSigma Cloud google 9 us-east1 gce Google Cloud Platform joyent 6 eu-ams-1 joyent Joyent Cloud oracle 5 uscom-central-1 oracle Oracle Compute Cloud Service rackspace 6 dfw rackspace Rackspace Cloud localhost 1 localhost lxd LXD Container Hypervisor maas-server 0 maas Metal As A Service
MAASとの連携を行うためのMAAS keyをJUJUに登録します。
$ juju add-credential Zner4ZAkAMvsg6xcST:bGQsgV4ALNKj2wmh5u:tz7gGj7Rwc77vUSgq9CGdw5WGW5cPdAJ
MAAS keyが登録されたかを確認します。
$ juju credentials --format yaml --show-secrets
JUJU Bootstrapを作成します。
$ juju bootstrap --constraints tags=bootstrap maas-server maas
もしBootstrap作成に失敗した場合は、kill-controllerを使用して再実行してください。
$ juju kill-controller maas
juju guiの表示
Bootstrapの作成が完了すると、juju guiコマンドで表示されたURLにアクセスするとjujuのGUI画面を表示できます。
$ juju gui GUI 2.12.1 for model "admin/default" is enabled at: https://172.17.30.56:17070/gui/u/admin/default Your login credential is: username: admin password: 765b9d00e1cff4338b193767fd4c9db5
Kubernetesのデプロイ
Kubernetesを構築する準備が整いました。 ここまで構築すれば、JUJUとMAASが自動的にKubernetesを構築してくれます。
MAASで認識された各サーバにタグを付与
Kubernetesのデプロイ用にMAAS上の各ノードにタグを付与します。
master
worker01
worker02

Kubernetesデプロイ用yamlファイルの作成
Kubernetes自動構築用のyamlファイルを用意します。 "tags="で記述される箇所がMAASのタグと一致するよう注意してください。
$ vim bundle.yaml
description: A 2-machine Kubernetes cluster, appropriate for PoC. Includes a 1 Kubernetes worker nodes.
machines:
'0':
series: xenial
constraints: "arch=amd64 tags=master"
'1':
series: xenial
constraints: "arch=amd64 tags=worker01"
'2':
series: xenial
constraints: "arch=amd64 tags=worker02"
services:
easyrsa:
annotations:
gui-x: '450'
gui-y: '550'
charm: cs:~containers/easyrsa-27
num_units: 1
to:
- lxd:0
etcd:
annotations:
gui-x: '800'
gui-y: '550'
charm: cs:~containers/etcd-63
num_units: 1
to:
- '0'
flannel:
annotations:
gui-x: '450'
gui-y: '750'
charm: cs:~containers/flannel-40
kubeapi-load-balancer:
annotations:
gui-x: '450'
gui-y: '250'
charm: cs:~containers/kubeapi-load-balancer-53
expose: true
num_units: 1
options:
proxy_read_timeout: 120
to:
- '0'
kubernetes-master:
annotations:
gui-x: '800'
gui-y: '850'
charm: cs:~containers/kubernetes-master-89
num_units: 1
options:
channel: 1.9/stable
to:
- '0'
kubernetes-worker:
annotations:
gui-x: '100'
gui-y: '850'
charm: cs:~containers/kubernetes-worker-106
expose: true
num_units: 2
options:
channel: 1.9/stable
to:
- '1'
- '2'
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
- - flannel:etcd
- etcd:db
- - flannel:cni
- kubernetes-master:cni
- - flannel:cni
- kubernetes-worker:cni
JUJUにk8sのモデルを作成
$ juju add-model k8s $ juju switch k8s $ juju models Controller: maas Model Cloud/Region Status Machines Cores Access Last connection controller maas-server available 1 16 admin just now default maas-server available 0 - admin 2018-03-26 k8s* maas-server available 7 80 admin 4 hours ago
アフタリスクがついている場所が、現在選択されているモデルです。
juju deploy を実行
$ juju deploy bundle.yaml
デプロイ中のログ表示
$ juju debug-log
yamlファイルの記述ミスなどのデプロイ失敗時
デプロイに失敗したなどでやり直す場合、デプロイ先のモデルを再作成して実行しましょう。
$ juju destroy-model k8s $ juju add-model k8s $ juju switch k8s
kubectlをインストール
Kubernetesを操作するためのクライアントをインストールします。
$ sudo snap install kubectl --classic
kubernetesコンフィグファイルのコピー
$ mkdir ~/.kube && touch ~/.kube/config $ juju scp kubernetes-master/0:config ~/.kube/config
kubernetes状態の確認
実際にKubernetesが操作できるかをコマンドで確認してみましょう。
$ kubectl cluster-info Kubernetes master is running at https://172.17.30.58:443 Heapster is running at https://172.17.30.58:443/api/v1/namespaces/kube-system/services/heapster/proxy KubeDNS is running at https://172.17.30.58:443/api/v1/namespaces/kube-system/services/kube-dns:dns/proxy kubernetes-dashboard is running at https://172.17.30.58:443/api/v1/namespaces/kube-system/services/https:kubernetes-dashboard:/proxy Grafana is running at https://172.17.30.58:443/api/v1/namespaces/kube-system/services/monitoring-grafana/proxy InfluxDB is running at https://172.17.30.58:443/api/v1/namespaces/kube-system/services/monitoring-influxdb:http/proxy To further debug and diagnose cluster problems, use 'kubectl cluster-info dump'.
「kubernetes-dashboard is running at...」に表示されるURLがKubernetesのダッシュボードです。 アクセス時は認証を要求されるため、configの閲覧し、アカウントを控えておきます。
$ kubectl config view
apiVersion: v1
clusters:
- cluster:
certificate-authority-data: REDACTED
server: https://172.17.30.58:443
name: juju-cluster
contexts:
- context:
cluster: juju-cluster
user: admin
name: juju-context
current-context: juju-context
kind: Config
preferences: {}
users:
- name: admin
user:
password: chVha5l96WG9720cKwgHpDJuduJpdtGQ
username: admin
Prometheus + AlertManager + Grafanaのデプロイ
PrometheusとGrafanaをデプロイします。 既にデプロイした環境に追加するため、yamlファイルをコピーして編集します。 元のyamlファイルに追記する形で各コンポーネントを記述します。 既にデプロイ済みの環境に対し、追加でデプロイを行う場合は元のyamlにコンポーネントを追記する形を取りましょう。 分けてしまうと、JUJUはまだ使われていないマシンを探し出してデプロイしようとしてしまいます。
$ cp -p bundle.yaml cp -p bundle.yaml addmonitor.yaml $ vim addmonitor.yaml
description: A 2-machine Kubernetes cluster, appropriate for PoC. Includes a 1 Kubernetes worker nodes.
machines:
'0':
series: xenial
constraints: "arch=amd64 tags=master"
'1':
series: xenial
constraints: "arch=amd64 tags=worker01"
'2':
series: xenial
constraints: "arch=amd64 tags=worker02"
services:
easyrsa:
annotations:
gui-x: '450'
gui-y: '550'
charm: cs:~containers/easyrsa-27
num_units: 1
to:
- lxd:0
etcd:
annotations:
gui-x: '800'
gui-y: '550'
charm: cs:~containers/etcd-63
num_units: 1
to:
- '0'
flannel:
annotations:
gui-x: '450'
gui-y: '750'
charm: cs:~containers/flannel-40
kubeapi-load-balancer:
annotations:
gui-x: '450'
gui-y: '250'
charm: cs:~containers/kubeapi-load-balancer-53
expose: true
num_units: 1
options:
proxy_read_timeout: 120
to:
- '0'
kubernetes-master:
annotations:
gui-x: '800'
gui-y: '850'
charm: cs:~containers/kubernetes-master-89
num_units: 1
options:
channel: 1.9/stable
to:
- '0'
kubernetes-worker:
annotations:
gui-x: '100'
gui-y: '850'
charm: cs:~containers/kubernetes-worker-106
expose: true
num_units: 2
options:
channel: 1.9/stable
to:
- '1'
- '2'
prometheus:
charm: "cs:xenial/prometheus-5"
num_units: 1
storage metrics-filesystem: rootfs
options:
install_method: snap
web-listen-port: 9090
static-targets: 172.17.30.62:9100
annotations:
gui-x: '422.25006103515625'
gui-y: '1066.5'
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:0
prometheus-alertmanager:
charm: "cs:xenial/prometheus-alertmanager-2"
num_units: 1
options:
snap_channel: stable
port: 9093
annotations:
gui-x: '720.2500610351562'
gui-y: '1076.5'
to:
- lxd: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
- - flannel:etcd
- etcd:db
- - flannel:cni
- kubernetes-master:cni
- - flannel:cni
- kubernetes-worker:cni
- - grafana:grafana-source
- prometheus:grafana-source
- - prometheus-alertmanager:alertmanager-service
- prometheus:alertmanager-service
デプロイを実行
$ juju deploy addmonitor.yaml
以下のコマンドでデプロイの状態を表示できます。 各コンンポーネントがどのIPアドレスを使用しているかも分かるため、デプロイ後には一度チェックをしておきましょう。
$ juju status Model Controller Cloud/Region Version SLA k8s maas maas-server 2.3.4 unsupported App Version Status Scale Charm Store Rev OS Notes easyrsa 3.0.1 active 1 easyrsa jujucharms 27 ubuntu etcd 2.3.8 active 1 etcd jujucharms 63 ubuntu flannel 0.9.1 active 3 flannel jujucharms 40 ubuntu grafana active 1 grafana jujucharms 9 ubuntu kubeapi-load-balancer 1.10.3 active 1 kubeapi-load-balancer jujucharms 53 ubuntu exposed kubernetes-master 1.9.4 active 1 kubernetes-master jujucharms 89 ubuntu kubernetes-worker 1.9.4 active 2 kubernetes-worker jujucharms 106 ubuntu exposed prometheus active 1 prometheus jujucharms 5 ubuntu prometheus-alertmanager active 1 prometheus-alertmanager jujucharms 2 ubuntu Unit Workload Agent Machine Public address Ports Message easyrsa/0* active idle 0/lxd/0 172.17.30.74 Certificate Authority connected. etcd/0* active idle 0 172.17.30.71 2379/tcp Healthy with 1 known peer grafana/0* active idle 0/lxd/1 172.17.30.76 3000/tcp Started grafana-server kubeapi-load-balancer/0* active idle 0 172.17.30.71 443/tcp Loadbalancer ready. kubernetes-master/0* active idle 0 172.17.30.71 6443/tcp Kubernetes master running. flannel/1 active idle 172.17.30.71 Flannel subnet 10.1.28.1/24 kubernetes-worker/0 active idle 1 172.17.30.72 80/tcp,443/tcp Kubernetes worker running. flannel/2 active idle 172.17.30.72 Flannel subnet 10.1.89.1/24 kubernetes-worker/1* active idle 2 172.17.30.73 80/tcp,443/tcp Kubernetes worker running. flannel/0* active idle 172.17.30.73 Flannel subnet 10.1.64.1/24 prometheus-alertmanager/0* active idle 0/lxd/3 172.17.30.75 9093/tcp Ready prometheus/0* active idle 0/lxd/2 172.17.30.77 9090/tcp,12321/tcp Ready Machine State DNS Inst id Series AZ Message 0 started 172.17.30.71 rdkykf xenial default Deployed 0/lxd/0 started 172.17.30.74 juju-3f8b8d-0-lxd-0 xenial default Container started 0/lxd/1 started 172.17.30.76 juju-3f8b8d-0-lxd-1 xenial default Container started 0/lxd/2 started 172.17.30.77 juju-3f8b8d-0-lxd-2 xenial default Container started 0/lxd/3 started 172.17.30.75 juju-3f8b8d-0-lxd-3 xenial default Container started 1 started 172.17.30.72 cqpcs3 xenial default Deployed 2 started 172.17.30.73 mdc8es xenial default Deployed Relation provider Requirer Interface Type Message easyrsa:client etcd:certificates tls-certificates regular easyrsa:client kubeapi-load-balancer:certificates tls-certificates regular easyrsa:client kubernetes-master:certificates tls-certificates regular easyrsa:client kubernetes-worker:certificates tls-certificates regular etcd:cluster etcd:cluster etcd peer etcd:db flannel:etcd etcd regular etcd:db kubernetes-master:etcd etcd regular kubeapi-load-balancer:loadbalancer kubernetes-master:loadbalancer public-address regular kubeapi-load-balancer:website kubernetes-worker:kube-api-endpoint http regular kubernetes-master:cni flannel:cni kubernetes-cni subordinate kubernetes-master:kube-api-endpoint kubeapi-load-balancer:apiserver http regular kubernetes-master:kube-control kubernetes-worker:kube-control kube-control regular kubernetes-worker:cni flannel:cni kubernetes-cni subordinate prometheus-alertmanager:alertmanager-service prometheus:alertmanager-service http regular prometheus:grafana-source grafana:grafana-source grafana-source regular
NodeExporterのデプロイ
Prometheusが各ノードの情報を取得するためのNodeExporterを導入します。 今回はKubernetesのデーモンセットとして機能させます。 監視コンポーネントのように、ノードに対し一律で配置するようなものについては、Kubernetesデーモンセットを使用すると新規追加したノードにも自動的にコンポーネントが展開されます。
$ vim node-exporter.yml
apiVersion: extensions/v1beta1
kind: DaemonSet
metadata:
name: node-exporter
spec:
template:
metadata:
labels:
app: node-exporter
annotations:
prometheus.io/scrape: 'true'
prometheus.io/port: '9100'
spec:
containers:
- name: node-exporter
image: prom/node-exporter:v0.13.0
ports:
- containerPort: 9100
hostNetwork: true
hostPID: true
$ kubectl create -f node-exporter.yml
Kubernetes-Metricsのデプロイ
Kubernetesクラスタを監視するメトリクスを追加します。
$ vim kubernetes-metrics.yml
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: kube-state-metrics
spec:
replicas: 1
template:
metadata:
labels:
app: kube-state-metrics
annotations:
prometheus.io/scrape: 'true'
prometheus.io/port: '8080'
spec:
containers:
- name: kube-state-metrics
image: gcr.io/google_containers/kube-state-metrics:v0.3.0
ports:
- containerPort: 8080
$ kubectl create -f kubernetes-metrics.yml
Prometheusジョブ設定
jujuからPrometheusの”scrape-jobs (string)”へ追記
- job_name: 'kubernetes-pods'
kubernetes_sd_configs:
- role: pod
relabel_configs:
- source_labels: [__meta_kubernetes_pod_annotation_prometheus_io_scrape]
action: keep
regex: true
- source_labels: [__meta_kubernetes_pod_annotation_prometheus_io_path]
action: replace
target_label: __metrics_path__
regex: (.+)
- source_labels: [__address__, __meta_kubernetes_pod_annotation_prometheus_io_port]
action: replace
regex: (.+):(?:\d+);(\d+)
replacement: ${1}:${2}
target_label: __address__
- action: labelmap
regex: __meta_kubernetes_pod_label_(.+)
- source_labels: [__meta_kubernetes_namespace]
action: replace
target_label: kubernetes_namespace
- source_labels: [__meta_kubernetes_pod_name]
action: replace
target_label: kubernetes_pod_name

Prometheusターゲット設定
jujuからPrometheusの”static-targets (string)”へ追記
172.17.30.72:4194, 172.17.30.73:4194, 172.17.30.72:9100, 172.17.30.73:9100

Prometheusデプロイ
Save Changes → Commit changes
Target確認
Prometheusデプロイ先アドレスにWebアクセスし、targetの状態を確認します。
StatusがUPとなっていれば成功です。
デプロイ先アドレスがわからなくなった場合はjuju statusを使いましょう。
http://172.17.30.77:9090/targets
Grafanaログイン情報の表示
Grafanaへログインするためのパスワードを表示します。
$ juju run-action --wait grafana/0 get-admin-password
unit-grafana-0:
id: a39e3b5d-e975-4348-8479-9d511f52cf86
results:
password: password5656
status: completed
timing:
completed: 2018-03-26 07:33:58 +0000 UTC
enqueued: 2018-03-26 07:33:57 +0000 UTC
started: 2018-03-26 07:33:58 +0000 UTC
unit: grafana/0
Grafanaへ接続
Prometheusデプロイ先アドレスにWebアクセスします。 ユーザ名はadmin、パスワードは上記で表示されたものを使用します。
ダッシュボード作成
Grafanaでダッシュボードを作成します。 importからIDを指定すると、Grafanaで公開されているテンプレートを使用できます。

ID:3119のテンプレートを使用したグラフが以下となります。

今回は性能監視についてKubernetesでの実現方法の一例を取り上げました。 基盤がどのようなものであれ、アプリケーション開発者、インフラ管理者双方が関心を寄せる事項かと思われます。