前回の記事で紹介した Cluster API を、会社の OpenStack 環境で動かしてみました。

OpenStack 向けに用意されているプロバイダを使います。

kubernetes-sigs/cluster-api-provider-openstack
Contribute to kubernetes-sigs/cluster-api-provider-openstack development by creating an account on GitHub.

あたらしくクラスタを立ち上げ、 node の追加や削除などの操作を試してみましたので、その内容をまとめてみます。

まずは環境構築

プロバイダの実装は、記事作成時点での master の最新 commit のものを使用しています。

https://github.com/kubernetes-sigs/cluster-api-provider-openstack/tree/564ebf706608601f4c653a5e2c1092332feb661e

必要なソフトウェアのインストール

clusterctl のビルド

cluster-api-provider-openstack のリポジトリを $GOPATH 配下に clone し、 clusterctl バイナリを生成します。

いまのところ、利用するプロバイダごとに clusterctl をビルドして実行する必要があるようです。

git clone https://github.com/kubernetes-sigs/cluster-api-provider-openstack $GOPATH/src/sigs.k8s.io/cluster-api-provider-openstack
cd $GOPATH/src/sigs.k8s.io/cluster-api-provider-openstack/cmd/clusterctl
go build
go install

クラスタをつくってみる

1. SSH キーペアの作成

SSH キーペアをあらかじめ作成し OpenStack 上に登録し、構築された VM に SSH 接続できるようにしておきます。

ssh-keygen -t rsa -f ${HOME}/.ssh/openstack_tmp -N ""
openstack keypair create --public-key ~/.ssh/openstack_tmp.pub cluster-api-provider-openstack

2. YAML マニフェストの生成

クラスタを構築する環境に合わせてテンプレートを用意し、スクリプトを使って YAML マニフェストを生成します。

各テンプレートは、元々用意されているフィールドの値を、インストール先の環境に合わせて穴埋めするように書き込んでいけば OK。

cd examples/openstack

# 編集するテンプレートファイルは4つ
# Cluster:
#  Service/Pod の IP レンジやクラスタのドメイン名などの設定
vim cluster.yaml

# Machine:
#  master/worker node に関する設定
#  OpenStack の場合、利用するフレーバーやセキュリティグループなどの指定をここで行う
vim machines.yaml.template

# user-data:
#  VM 起動後に master/worker node それぞれで実行される user-data のスクリプト
#  yum install や kubeadm の実行、ネットワークプラグインのインストールなどを行う
vim provider-component/user-data/centos/templates/master-user-data.sh
vim provider-component/user-data/centos/templates/worker-user-data.sh

# スクリプトを実行し YAML を生成する
./generate-yaml.sh <path/to/clouds.yaml> openstack centos

cd ../..

clouds.yaml は OpenStack 環境に接続するための情報を書き込んだ YAML ファイルです。 リポジトリ内のサンプルOpenStack のドキュメントを参考に用意します。

3. クラスタの作成

生成した YAML ファイルを clusterctl コマンドに渡して、クラスタの構築を開始します。

clusterctl create cluster \
    --bootstrap-type minikube \
    --bootstrap-flags kubernetes-version=v1.12.3 \
    --provider openstack \
    -c examples/openstack/out/cluster.yaml \
    -m examples/openstack/out/machines.yaml \
    -p examples/openstack/out/provider-components.yaml

OpenStack 上にクラスタが出来上がるまでの流れはこんな感じ:

cluster-api-provider-openstack
cluster-api-provider-openstack
  1. ブートストラップクラスタとして minikube による k8s クラスタが立ち上がる
    • clusterctl を実行したディレクトリに minikube.kubeconfig が作られる
    • kubectl に読ませることで、ブートストラップクラスタ上のログ確認などが可能
  2. ブートストラップクラスタ上で openstack-controller が動作する
    • ターゲットクラスタの master node の作成が行われる
    • VM 起動時の user-data で kubeadm init が実行される
    • ネットワークプラグインのインストールなども user-data で行われる
  3. 構築された master 上に Cluster API の CRDs/CR/Controller が展開される
    • このフェーズは “pivot” と呼ばれる
    • ターゲットクラスタ自体の Cluster/Machine リソースが配置される
  4. worker node の作成が行われる
    • VM 起動時の user-data で kubeadm join が実行されクラスタが組まれる
  5. 最後にブートストラップクラスタ (minikube) が削除される
    • 以降の操作はターゲットクラスタ上の Controller が利用できる
    • クラスタ自身の操作や他のクラスタの作成などが可能

clusterctl を実行したディレクトリに kubeconfig が作成されるので、これを利用し作成されたクラスタにアクセスします。

% ls
examples/   kubeconfig  main.go

% kubectl --kubeconfig ./kubeconfig get nodes
NAME                           STATUS    ROLES     AGE       VERSION
cluster-api-k8s-master-24jsp   Ready     master    35m       v1.12.3
cluster-api-k8s-node-zfl5k     Ready     <none>    24m       v1.12.3

ブートストラップ用の minikube 環境は削除されますが、必要な CRD/CR/Controller は pivot フェーズでターゲットクラスタに配置されます。

Controller は openstack-provider-system で Pod として動作しています。

% kubectl --kubeconfig ./kubeconfig -n openstack-provider-system get pods
NAME                                      READY     STATUS    RESTARTS   AGE
clusterapi-controllers-5d9dd965c6-s8t8n   1/1       Running   0          40m

クラスタやノードの設定は Custom Resource として存在しているので kubectl get cluster/machine で確認することが可能です。

% kubectl --kubeconfig ./kubeconfig get cluster
NAME              AGE
cluster-api-k8s   38m

% kubectl --kubeconfig ./kubeconfig get machine
NAME                           AGE
cluster-api-k8s-master-24jsp   38m
cluster-api-k8s-node-zfl5k     38m

クラスタにノードを追加してみる

クラスタ上の Machine リソースは Machine Controller によって監視されており、内容に変化があった場合は実環境への変更が行われます。

新しい Machine リソースを追加して、クラスタの worker node が追加される挙動を確認してみましょう。 ここでは、はじめに生成された YAML ファイルを元に、新しい worker を作ってみます。

# cluster-api-k8s-node02 という name で Machine を作成する
% cp examples/openstack/out/machines.yaml node02.yaml
% vim node02.yaml

% kubectl --kubeconfig ./kubeconfig apply -f node02.yaml
machine.cluster.k8s.io "cluster-api-k8s-node02" created

% kubectl --kubeconfig ./kubeconfig get machine
NAME                           AGE
cluster-api-k8s-master-24jsp   53m
cluster-api-k8s-node-zfl5k     53m
cluster-api-k8s-node02         9s

新しく VM が作成され、 worker 用の user-data スクリプトが流れ終わるのをしばらく待ちます。 その後 kubectl get nodes を打ってみると、新しく node が追加されていることが確認できます。

% kubectl --kubeconfig ./kubeconfig get nodes
NAME                           STATUS    ROLES     AGE       VERSION
cluster-api-k8s-master-24jsp   Ready     master    1h        v1.12.3
cluster-api-k8s-node-zfl5k     Ready     <none>    1h        v1.12.3
cluster-api-k8s-node02         Ready     <none>    7m        v1.12.3

Machine を編集してノードの Kubernetes バージョンを上げてみる

既存の Machine リソースの内容を変え、変更後の内容に合わせて node が再作成される挙動を確認してみましょう。

# versions.kubelet を 1.12.6 に変更してみる
% kubectl --kubeconfig ./kubeconfig edit machine cluster-api-k8s-node02
machine.cluster.k8s.io "cluster-api-k8s-node02" edited

Controller のログを確認してみると、 edit した machine の再作成が開始されたことが確認できます。

% kubectl --kubeconfig ./kubeconfig -n openstack-provider-system logs clusterapi-controllers-5d9dd965c6-s8t8n
...
I0324 16:02:51.148752       1 controller.go:114] Running reconcile Machine for cluster-api-k8s-node02
I0324 16:02:51.749798       1 controller.go:173] Reconciling machine object cluster-api-k8s-node02 triggers idempotent update.
I0324 16:02:51.750283       1 actuator.go:232] re-creating machine cluster-api-k8s-node02 for update.

再作成が完了し kubectl get nodes を実行すると、編集した node の VERSION が変わったことが確認できました。

% kubectl --kubeconfig ./kubeconfig get nodes
NAME                           STATUS    ROLES     AGE       VERSION
cluster-api-k8s-master-24jsp   Ready     master    1h        v1.12.3
cluster-api-k8s-node-zfl5k     Ready     <none>    1h        v1.12.3
cluster-api-k8s-node02         Ready     <none>    27m       v1.12.6

クラスタの削除

構築されたクラスタの削除を README の削除手順の通りに試してみます。

https://github.com/kubernetes-sigs/cluster-api-provider-openstack#cluster-deletion

まずは worker 用 machine を全て削除し、その後 master を削除する。 Machine Resource を削除すると VM の削除も Controller がやってくれる模様。

% kubectl --kubeconfig ./kubeconfig delete machines -l set=node
machine.cluster.k8s.io "cluster-api-k8s-node-zfl5k" deleted
machine.cluster.k8s.io "cluster-api-k8s-node02" deleted
% kubectl --kubeconfig ./kubeconfig get nodes
NAME                           STATUS    ROLES     AGE       VERSION
cluster-api-k8s-master-24jsp   Ready     master    1h        v1.12.3

% kubectl --kubeconfig ./kubeconfig delete machines -l set=master
machine.cluster.k8s.io "cluster-api-k8s-master-24jsp" deleted

あとは、作成された kubeconfig と、事前に作成しておいた SSH キーペアを削除すれば OK。

rm kubeconfig
rm $HOME/.ssh/openstack_tmp*
openstack keypair delete cluster-api-provider-openstack

さいごに

cluster-api-provider-openstack を使い OpenStack 環境上でクラスタ操作を行う例をまとめてみました。

リポジトリの example では、 Kubernetes 環境の構築に必要なスクリプトは user-data として実行される想定になっています。 必要なパッケージのインストールを済ませたイメージを事前に作っておけば、新しくノードを追加する際の時間短縮も図れそうです。

絶賛開発中のプロジェクトで現時点では実運用に持っていくのは難しそうですが、今後も目が離せないプロジェクトです。