Cluster API の OpenStack Provider を利用する

# 目的

前回記事である [Cluster API の Docker Provider を利用する](https://qiita.com/yoshi_1010/items/c139079b1ba037f478b6) に記載した通り、Cluster API の OpenStack Provider を利用する。
Docker Provider を利用する場合は kind を利用するために使用した Docker を Provider としてそのまま流用できるが、OpenStack Provider を利用する場合は OpenStack の環境が必要となる。

今回は [DsvStack] の手順を実行し、OpenStack 環境を準備する手順も記載する。
DevStack 環境を含め、1 つのマシン上に必要なソフトウェアをすべてインストールし、Cluster API の OpenStack Provider を動作させる。
インストール手順は下記を参考にする。

- [The Cluster API Book Quick Start](https://cluster-api.sigs.k8s.io/user/quick-start.html#quick-start)

# 構成

下記のマシンを 1 台準備する。

- Disk: 200GB
- Cores: 8 core
- Memory: 24GB
- OS: Ubuntu 20.04

# 手順

## DevStack 

OpenStack を簡易インストールできる DevStack を利用する。
DevStack のインストールについては下記に詳しいことをまとめているため、ご参考までに。

- [新人が DevStack 上で Tacker を動かそうとする話](https://qiita.com/yoshi_1010/items/c1db52099b5897e049d0)

```
sudo useradd -s /bin/bash -d /opt/stack -m stack
sudo chmod +x /opt/stack

echo "stack ALL=(ALL) NOPASSWD: ALL" | sudo tee /etc/sudoers.d/stack
sudo -u stack -i
```

DevStack のインストールのみ stack ユーザで操作する。
DevStack 環境を作成する準備する。

- \<IP Address> にはマシンの IP アドレスを入力する

```
git clone https://opendev.org/openstack/devstack
cd devstack

cat << _EOF_ > local.conf
[[local|localrc]]
ADMIN_PASSWORD=secret
DATABASE_PASSWORD=\$ADMIN_PASSWORD
RABBIT_PASSWORD=\$ADMIN_PASSWORD
SERVICE_PASSWORD=\$ADMIN_PASSWORD

HOST_IP=<IP Address>
enable_plugin octavia https://opendev.org/openstack/octavia
enable_plugin neutron https://opendev.org/openstack/neutron
ENABLED_SERVICES+=,octavia,o-api,o-cw,o-hk,o-hm
_EOF_
```

DevStack をインストールする。

```
$ ./stack.sh
...
DevStack Version: 2023.2
Change: cc49f4debbea1951d745ca7e7994662468e5d6b8 Merge "Enable GLANCE_ENFORCE_SCOPE to True by default" 2023-05-25 01:29:42 +0000
OS Version: Ubuntu 20.04 focal

2023-05-25 11:04:40.585 | stack.sh completed in 3796 seconds.
```

## OS イメージの作成

以降の作業は一般ユーザで操作する。

OpenStack Provider の Workload Cluster は Kubernetes がインストール済みのイメージを利用する。
そのため、Workload Cluster に利用する OS イメージを作成する。

- 参考
  - https://image-builder.sigs.k8s.io/capi/capi.html  
  - https://image-builder.sigs.k8s.io/capi/providers/openstack.html

イメージ作成に必要なソフトウェアをインストールする。

```
sudo apt install python-is-python3
pip install ansible
sudo apt install \
qemu-kvm \
libvirt-daemon-system \
libvirt-clients \
virtinst \
cpu-checker \
libguestfs-tools \
libosinfo-bin

sudo usermod -a -G kvm <user name>
sudo chown root:kvm /dev/kvm
exit
```

イメージサイズを 20GB から 10GB に変更して作成する。

```
git clone https://github.com/kubernetes-sigs/image-builder.git
cd image-builder/images/capi/

$ vim packer/qemu/packer.json
※disk_size を 20480 から 10240 に変更する

sudo apt install jq
make deps-qemu
make build-qemu-ubuntu-2004
```

make build-qemu-ubuntu-2004 を実行すると、下記のように表示される。
実施当時は、Kubernetes v1.24.11 のイメージが作成された。

```
$ make build-qemu-ubuntu-2004
...
==> qemu (shell-local): Running local shell script: /tmp/packer-shell304305661
Build 'qemu' finished after 32 minutes 24 seconds.

==> Wait completed after 32 minutes 24 seconds

==> Builds finished. The artifacts of successful builds are:
--> qemu: VM files in directory: ./output/ubuntu-2004-kube-v1.24.11
--> qemu: VM files in directory: ./output/ubuntu-2004-kube-v1.24.11
--> qemu: VM files in directory: ./output/ubuntu-2004-kube-v1.24.11
```

作成した OS イメージを Glance に登録する。

```
source /opt/stack/devstack/openrc
export IMAGE_NAME=ubuntu-2004-kube-v1.24.11

$ openstack image create --disk-format qcow2 --file ~/image-builder/images/capi/output/$IMAGE_NAME/$IMAGE_NAME $IMAGE_NAME
+------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------+
| Field            | Value                                                                                                                                                         |
+------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------+
| container_format | bare                                                                                                                                                          |
| created_at       | 2023-05-29T09:23:23Z                                                                                                                                          |
| disk_format      | qcow2                                                                                                                                                         |
| file             | /v2/images/9c45522a-88e0-4d05-a472-f42154b5ab5c/file                                                                                                          |
| id               | 9c45522a-88e0-4d05-a472-f42154b5ab5c                                                                                                                          |
| min_disk         | 0                                                                                                                                                             |
| min_ram          | 0                                                                                                                                                             |
| name             | ubuntu-2004-kube-v1.24.11                                                                                                                                     |
| owner            | 431a9715f18a442cb16cd08c9e858675                                                                                                                              |
| properties       | os_hidden='False', owner_specified.openstack.md5='', owner_specified.openstack.object='images/ubuntu-2004-kube-v1.24.11', owner_specified.openstack.sha256='' |
| protected        | False                                                                                                                                                         |
| schema           | /v2/schemas/image                                                                                                                                             |
| status           | queued                                                                                                                                                        |
| tags             |                                                                                                                                                               |
| updated_at       | 2023-05-29T09:23:23Z                                                                                                                                          |
| visibility       | shared                                                                                                                                                        |
+------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------+
```

登録されたイメージを確認する。

```
$ openstack image list
+--------------------------------------+---------------------------+--------+
| ID                                   | Name                      | Status |
+--------------------------------------+---------------------------+--------+
| 111fd03a-fd6f-404f-a567-21f12dcabccd | amphora-x64-haproxy       | active |
| 8674312f-8222-46ec-b1a1-119b9249576e | cirros-0.6.1-x86_64-disk  | active |
| 9c45522a-88e0-4d05-a472-f42154b5ab5c | ubuntu-2004-kube-v1.24.11 | active |
+--------------------------------------+---------------------------+--------+
```

## キーペア作成

キーペアを作成し、OpenStack に登録する。

```
ssh-keygen -t ed25519

$ openstack keypair create --public-key ~/.ssh/id_ed25519.pub keypair1
+-------------+-------------------------------------------------+
| Field       | Value                                           |
+-------------+-------------------------------------------------+
| created_at  | None                                            |
| fingerprint | 1e:55:95:43:65:ca:cf:57:22:7a:a6:96:a5:7c:06:1d |
| id          | keypair1                                        |
| is_deleted  | None                                            |
| name        | keypair1                                        |
| type        | ssh                                             |
| user_id     | a98dd09dce6d4ceb8be8e86dba369fd6                |
+-------------+-------------------------------------------------+
```

登録したキーペアを確認する。

```
$ openstack keypair list
+----------+-------------------------------------------------+------+
| Name     | Fingerprint                                     | Type |
+----------+-------------------------------------------------+------+
| keypair1 | 1e:55:95:43:65:ca:cf:57:22:7a:a6:96:a5:7c:06:1d | ssh  |
+----------+-------------------------------------------------+------+
```

## Docker

Docker をインストールする。

```
sudo apt install docker.io -y
```

一般ユーザが Docker を操作できるようにするため、一般ユーザを docker グループに追加し、再度ログインする。

```
sudo usermod -a -G docker <username>
exit
```

## kubectl

kubectl をインストールする。

```
curl -s https://packages.cloud.google.com/apt/doc/apt-key.gpg | sudo apt-key add -
sudo apt-add-repository "deb http://apt.kubernetes.io/ kubernetes-xenial main"
sudo apt install -y kubectl
```

## kind

kind をインストールする。
インストールした kind は Management Cluster として利用する。

```
curl -Lo ./kind https://kind.sigs.k8s.io/dl/v0.19.0/kind-linux-amd64
chmod +x ./kind
sudo mv ./kind /usr/local/bin/kind
```

Kubernetes Cluster を作成する。

```
kind create cluster
```

作成された Kubernetes Cluster の動作を確認する。

```
$ kubectl get pod -A
NAMESPACE            NAME                                         READY   STATUS    RESTARTS   AGE
kube-system          coredns-5d78c9869d-nvt66                     1/1     Running   0          26s
kube-system          coredns-5d78c9869d-rbbsf                     1/1     Running   0          25s
kube-system          etcd-kind-control-plane                      1/1     Running   0          40s
kube-system          kindnet-x7k95                                1/1     Running   0          26s
kube-system          kube-apiserver-kind-control-plane            1/1     Running   0          40s
kube-system          kube-controller-manager-kind-control-plane   1/1     Running   0          40s
kube-system          kube-proxy-9c4zh                             1/1     Running   0          26s
kube-system          kube-scheduler-kind-control-plane            1/1     Running   0          40s
local-path-storage   local-path-provisioner-6bc4bddd6b-kkfjf      1/1     Running   0          25s
```

## clusterctl

clusterctl をインストールする。
clusterctl は Management Cluster のライフサイクルを処理できる。

```
curl -L https://github.com/kubernetes-sigs/cluster-api/releases/download/v1.4.2/clusterctl-linux-amd64 -o clusterctl
chmod +x ./clusterctl
sudo mv ./clusterctl /usr/local/bin/clusterctl
```

## Management Cluster

### 初期化

Feature Gates (アルファステータスの機能) を有効化する。

```
export CLUSTER_TOPOLOGY=true
```

Management Cluster を初期化する。

```
$ clusterctl init --infrastructure openstack
Fetching providers
Installing cert-manager Version="v1.11.1"
Waiting for cert-manager to be available...
Installing Provider="cluster-api" Version="v1.4.2" TargetNamespace="capi-system"
Installing Provider="bootstrap-kubeadm" Version="v1.4.2" TargetNamespace="capi-kubeadm-bootstrap-system"
Installing Provider="control-plane-kubeadm" Version="v1.4.2" TargetNamespace="capi-kubeadm-control-plane-system"
Installing Provider="infrastructure-openstack" Version="v0.7.2" TargetNamespace="capo-system"

Your management cluster has been initialized successfully!

You can now create your first workload cluster by running the following:

  clusterctl generate cluster [name] --kubernetes-version [version] | kubectl apply -f -
```

### 環境変数の設定

環境変数の設定をするための clouds.yaml を作成する。
clouds.yaml は 1 つ以上のクラウドに接続するために必要なすべてが含まれる構成ファイルである。
これには個人情報が含まれる可能性があり、通常はユーザにとってプライベートなものとみなされる。

利用する OpenStack 環境に合わせて設定するため、auth_url のみ環境によって異なる。
clouds.yaml の記述方法は、OpenStack Client のドキュメントを参考にする。

- [Configuration Files clouds.yaml](https://docs.openstack.org/python-openstackclient/latest/configuration/index.html#clouds-yaml)

```
cat << _EOF_ > clouds.yaml
clouds:
  demo:
    auth:
      auth_url: http://<IP Address>/identity
      project_name: demo
      project_domain_name: Default
      user_domain_name: Default
      username: demo
      password: secret
    region_name: RegionOne
_EOF_
```

Workload Cluster 作成用の環境変数作成時に利用するツールをインストールする。

```
curl https://raw.githubusercontent.com/kubernetes-sigs/cluster-api-provider-openstack/main/templates/env.rc -o ./env.rc
sudo curl -L https://github.com/mikefarah/yq/releases/download/v4.27.3/yq_linux_amd64 -o /usr/local/bin/yq
sudo chmod +x /usr/local/bin/yq
```

Workload Cluster 作成用の環境変数を生成する。

<!-- shell:Environment Generate -->

```
$ openstack network list --external
+--------------------------------------+--------+----------------------------------------------------------------------------+
| ID                                   | Name   | Subnets                                                                    |
+--------------------------------------+--------+----------------------------------------------------------------------------+
| ea7d0bd2-8b1d-456a-ab39-8a24f0fd40e6 | public | a1c76209-3140-4f3b-9ff9-0f937940aedd, a9b3a329-2c29-484f-91c7-0a1e98a57c88 |
+--------------------------------------+--------+----------------------------------------------------------------------------+

source ./env.rc ./clouds.yaml demo

export OPENSTACK_DNS_NAMESERVERS=192.168.122.1
export OPENSTACK_FAILURE_DOMAIN=nova
export OPENSTACK_CONTROL_PLANE_MACHINE_FLAVOR=m1.medium
export OPENSTACK_NODE_MACHINE_FLAVOR=m1.medium
export OPENSTACK_IMAGE_NAME=$IMAGE_NAME
export OPENSTACK_SSH_KEY_NAME=keypair1
export OPENSTACK_EXTERNAL_NETWORK_ID=ea7d0bd2-8b1d-456a-ab39-8a24f0fd40e6
```

### Workload Cluster 作成用のマニフェストファイル作成

Workload Cluster を作成するためのマニフェストファイルを作成する。
今回は capi-quickstart-openstack という名前の Workload Cluster を作成する。

- flavor
インフラストラクチャプロバイダー毎に準備されている Workload Cluster のテンプレート
without-lb はロードバランサーなしで単一の Control Plane を作成する場合に使用する flavor である。
(OpenStack にも flavor という概念が存在しているが、ここでの flavor は Cluster API の flavor である)
- kubernetes-version
Workload Cluster の Kubernetes Version を指定する
OpenStack Provider の場合は [OS イメージの作成] で作成した OS イメージの Kubernetes Version を指定する
- control-plane-machine-count
Workload Cluster の Control Plane の台数を指定する
- worker-machine-count
Workload Cluster の Worker Node の台数を指定する

```
$ clusterctl generate cluster capi-quickstart-openstack \
    --flavor without-lb \
    --kubernetes-version v1.24.11 \
    --control-plane-machine-count=1 \
    --worker-machine-count=1 \
    > capi-quickstart-openstack.yaml
```

作成したマニフェストファイルでは pod のネットワークとして、 `192.168.0.0/16` がデフォルトで指定されている。
自環境でこの範囲を使用している場合、変更することを推奨する。

```
sed -i -e "s|192.168.0.0/16|10.244.0.0/16|g" capi-quickstart-openstack.yaml
```

### Workload Cluster 作成

Workload Cluster を作成する。
上記で作成されたマニフェストをアプライすることで Control Plane と Worker Node が各 1 台ずつ作成される。


```
$ kubectl apply -f capi-quickstart-openstack.yaml
secret/capi-quickstart-openstack-cloud-config created
kubeadmconfigtemplate.bootstrap.cluster.x-k8s.io/capi-quickstart-openstack-md-0 created
cluster.cluster.x-k8s.io/capi-quickstart-openstack created
machinedeployment.cluster.x-k8s.io/capi-quickstart-openstack-md-0 created
kubeadmcontrolplane.controlplane.cluster.x-k8s.io/capi-quickstart-openstack-control-plane created
openstackcluster.infrastructure.cluster.x-k8s.io/capi-quickstart-openstack created
openstackmachinetemplate.infrastructure.cluster.x-k8s.io/capi-quickstart-openstack-control-plane created
openstackmachinetemplate.infrastructure.cluster.x-k8s.io/capi-quickstart-openstack-md-0 created
```

作成状況は下記で確認できる。
MachineDeployment/xxxx の READY 以外が True となっていれば問題ない。
MachineDeployment/xxxx は Calico 等の CNI をインストールすることで True となる。
CNI をインストールすることで Pod ネットワークを構成でき、Workload Cluster 上で Pod を動作させることができるようになる。
そのため、必要があれば CNI をインストールするとよい。


```
$ clusterctl describe cluster capi-quickstart-openstack
NAME                                                                          READY  SEVERITY  REASON                       SINCE  MESSAGE
Cluster/capi-quickstart-openstack                                             True                                          107s
├─ClusterInfrastructure - OpenStackCluster/capi-quickstart-openstack
├─ControlPlane - KubeadmControlPlane/capi-quickstart-openstack-control-plane  True                                          107s
│ └─Machine/capi-quickstart-openstack-control-plane-m7xv4                     True                                          3m17s
└─Workers
  └─MachineDeployment/capi-quickstart-openstack-md-0                          False  Warning   WaitingForAvailableMachines  4m35s  Minimum availability requires 1 replicas, current 0 available
    └─Machine/capi-quickstart-openstack-md-0-6f87866f5cxdnh94-4cxnf           True                                          54s
```

Workload Cluster の kubeconfig を取得する。

```
clusterctl get kubeconfig capi-quickstart-openstack > capi-quickstart-openstack.kubeconfig
```

取得した kubeconfig を利用し、Workload Cluster のノードを確認する。

```
$  kubectl --kubeconfig=./capi-quickstart-openstack.kubeconfig get nodes -o wide
NAME                                            STATUS     ROLES           AGE     VERSION    INTERNAL-IP   EXTERNAL-IP    OS-IMAGE             KERNEL-VERSION      CONTAINER-RUNTIME
capi-quickstart-openstack-control-plane-cn6pz   NotReady   control-plane   2m55s   v1.24.11   10.6.0.159    172.24.4.222   Ubuntu 20.04.6 LTS   5.4.0-149-generic   containerd://1.6.20
capi-quickstart-openstack-md-0-m9knb            NotReady   <none>          45s     v1.24.11   10.6.0.221    <none>         Ubuntu 20.04.6 LTS   5.4.0-149-generic   containerd://1.6.20
```

また、Nova 側でもインスタンスを確認できる。
今回は flavor を without-lb とし、ロードバランサーなしの単一の Control Plane を作成しているため、 Control Plane に接続するための Floating IP (172.24.4.222) が付与されている。

```
$ openstack server list
+--------------------------------------+-----------------------------------------------+--------+-----------------------------------------------------------------------------------+---------------------------+-----------+
| ID                                   | Name                                          | Status | Networks                                                                          | Image                     | Flavor    |
+--------------------------------------+-----------------------------------------------+--------+-----------------------------------------------------------------------------------+---------------------------+-----------+
| 735e6380-3fd6-4ea1-a0bd-631f521beaf2 | capi-quickstart-openstack-md-0-m9knb          | ACTIVE | k8s-clusterapi-cluster-default-capi-quickstart-openstack=10.6.0.221               | ubuntu-2004-kube-v1.24.11 | m1.medium |
| 02bf347f-27a6-4f34-8db7-c0b97df7b755 | capi-quickstart-openstack-control-plane-cn6pz | ACTIVE | k8s-clusterapi-cluster-default-capi-quickstart-openstack=10.6.0.159, 172.24.4.222 | ubuntu-2004-kube-v1.24.11 | m1.medium |
+--------------------------------------+-----------------------------------------------+--------+-----------------------------------------------------------------------------------+---------------------------+-----------+
```

上記のインスタンスには ssh することで接続することができる。
ただ、Securty Group で 22 番ポートが許可されていないため、別途許可する必要がある。

```
$ openstack security group rule create --dst-port 22 --protocol tcp k8s-cluster-default-capi-quickstart-openstack-secgroup-controlplane
+-------------------------+--------------------------------------+
| Field                   | Value                                |
+-------------------------+--------------------------------------+
| created_at              | 2023-05-29T10:39:13Z                 |
| description             |                                      |
| direction               | ingress                              |
| ether_type              | IPv4                                 |
| id                      | 7872e6b7-c5c8-477b-9b7b-b86b40474483 |
| name                    | None                                 |
| normalized_cidr         | 0.0.0.0/0                            |
| port_range_max          | 22                                   |
| port_range_min          | 22                                   |
| project_id              | 431a9715f18a442cb16cd08c9e858675     |
| protocol                | tcp                                  |
| remote_address_group_id | None                                 |
| remote_group_id         | None                                 |
| remote_ip_prefix        | 0.0.0.0/0                            |
| revision_number         | 0                                    |
| security_group_id       | 89fc5205-f3c2-4a78-8dbb-740917907e4b |
| tags                    | []                                   |
| updated_at              | 2023-05-29T10:39:13Z                 |
+-------------------------+--------------------------------------+
```

Control Plane に接続する。

```
ssh ubuntu@172.24.4.222
```

# まとめ

今回は OpenStack Provider を用いて Cluster API の動作を確認した。
OpenStack ではテナントを作成・管理することができ、この機能を利用することでマルチユーザに対してそれぞれ異なる制限を付与できる。
これにより、単一の OpenStack に複数のプロジェクトを動作させることが可能となる。
OpenStack Provider ではこのような OpenStack を利用することによる恩恵を受けることができる。

Docker Provider では利用する Docker が Management Cluster と同じ環境にあるものに限定される。
そのため、リモートにある Docker に対して Workload Cluster を作成できない。
しかし、OpenStack Provider は clouds.yaml で接続先 OpenStack 情報を設定可能なため、リモートにある OpenStack 上に Workload Cluster を作成できる。
そのため、Workload Cluster を作成するマニフェストファイルの接続先 OpenStack 設定を変更するだけで、複数のリモート OpenStack 環境に同じ Workload Cluster を作成できる。

OpenStack Provider を利用する場合、OpenStack 環境の作成、キーペアの作成、イメージの作成等が必要になるため、Docker Provider 利用時よりもハードルが高い。
本記事でそのハードルを低くできれば幸いである。