概要
Kubernetes API の機能を拡張したものとして「Operator」と呼ばれるものがあるようで、使えると結構便利らしい。が、記事を読んだりしてみても一体どんな風に便利に使えるのかがなかなかピンと来ない…。こんな時は「手を動かしてなんぼ」なのかなあと思い始めて、Operatorのサンプルを動かしてみることにした。本記事では、初めてKubernetesのOperatorを作成する筆者がそれなりにつまづきながら試行錯誤した内容をまとめる。
Operatorを実装できるツールは幾つかあるみたいだが、一番有名なのは「Operator Framework」のようだ。以下サイトの "Quickstart for Go-based Operators" の手順に従えば、MemcachedのカスタムリソースとOperatorを「とりあえず形だけ」作れるようなので試してみることにする。
本記事の対象者
主にKubernetesのOperatorを初めて触ってみる方で、かつPush可能なDocker Registryを持っていない人向け。
途中で「作ったOperatorをDocker RegistryにPush&Pullする」手順が出てくるが、PushできるDocker Registryを持っていないと、筆者がそうであったようにここでつまづいてしまう。その際の対処法として、Docker Registryを自作する方法と関連する設定を記載している。
逆にPush可能なDocker Registryをお持ちの方にとっては余計な手順が沢山書かれているので、素直にQuickstart for Go-based Operatorsの手順を実行したほうがいいと思われる。
環境
- Kubernetes(kubectl等)
- バージョン : v1.24.3
- クラスター構成
- control plane(master)
- OS : Debian GNU/Linux 10
- CPUアーキテクチャ : x86_64
- node(worker)も兼務
- node(worker)
- OS : Ubuntu 20.04.4 LTS
- CPUアーキテクチャ : x86_64
- control plane(master)
- Go言語
- バージョン : go1.18.4
- Operator SDK CLI
- バージョン : v1.22.2
※以後の作業は、特段記載がない場合control planeで行う。
必要な準備
-
Kubernetesのインストール
- オーソドックスに、kubeadmを使ってインストール
- 複数マシンでクラスターを作る場合は、ワーカーノードのjoinやマシン間のCNI設定が必要
-
Go言語のインストール
- ダウンロードしたバイナリを配置してPATHを通すだけなので、そんなに苦労しないはず
-
Operator SDK CLIのインストール
- Linuxの場合、「Install from GitHub release」の手順で行ける
-
Dockerのインストール
- OSに応じて適宜、上記サイトの各リンクを参照
- Kubernetesのv1.24以降はコンテナランタイムにDockerを標準で使わなくなった(containerdのみで動く!)みたいだが、Operatorの作成でDockerが必要となる。
-
Pushが可能なDocker Registry
- 作ったOperatorを格納するのに必要!
- 本記事はこれを持っていない方向け
Docker Registryをローカル環境に作成
必要な準備の最後、「Pushが可能なDocker Registry」を筆者は持っていなかった…。ここが準備できていないと、Quickstartの「Build and push your operator’s image」で作ったDockerイメージがPushできずに困ることになる。
そこでまずは以下コマンドで、ローカル環境(control planeでなくてもいい)にDocker Registryを作成する。
$ docker run -d --name docker-registry -p 5000:5000 registry
一応、IPを名前解決できるように、control planeの/etc/hosts
に以下を追記
a.b.c.d [hostname-registry]
-
a.b.c.d
はDocker RegistryのホストOSのIPアドレスの記載が必要 -
[hostname-registry]
は任意のホスト名を記載
念のためDocker Registryが動いているか確認。
$ curl http://[hostname-registry]:5000/v2/_catalog
{"repositories":[]}
memcached-operatorのビルド
QuickstartのStepsに従ってセットアップしていく。
(1) プロジェクトの初期化
$ mkdir memcached-operator
$ cd memcached-operator
$ operator-sdk init --domain [hostname-registry] --repo github.com/example/memcached-operator
コマンドを実行すると、以下のような構成になる。
config/default配下等に、k8sのマニフェストと思われるyamlファイルが格納されている。
$ tree -L 2 .
.
├── Dockerfile
├── Makefile
├── PROJECT
├── README.md
├── config
│ ├── default
│ ├── manager
│ ├── manifests
│ ├── prometheus
│ ├── rbac
│ └── scorecard
├── go.mod
├── go.sum
├── hack
│ └── boilerplate.go.txt
└── main.go
(2) Memcached APIの作成
$ operator-sdk create api --group cache --version v1alpha1 --kind Memcached --resource --controller
再びディレクトリ構成を見ると、以下のように*印部分が追加されている。おそらくはここで、CustomResourceDefinition(CRD)のマニフェスト、およびカスタムコントローラーを作るための資材が作られていると思われる。
$ tree -L 2 .
.
├── Dockerfile
├── Makefile
├── PROJECT
├── README.md
├── api *
│ └── v1alpha1 *
├── bin *
│ └── controller-gen *
├── config
│ ├── crd *
│ ├── default
│ ├── manager
│ ├── manifests
│ ├── prometheus
│ ├── rbac
│ ├── samples *
│ └── scorecard
├── controllers *
│ ├── memcached_controller.go *
│ └── suite_test.go *
├── go.mod
├── go.sum
├── hack
│ └── boilerplate.go.txt
└── main.go
(3) memcached-operatorイメージのビルドとプッシュ
Makefileにイメージを作ってPushする定義が書かれているので、それに従って実行。
$ make docker-build docker-push IMG="[hostname-registry]:5000/memcached-operator:v0.0.1"
すると、次のようなエラーが出て失敗する。
The push refers to repository [[hostname-registry]:5000/memcached-operator]
Get "https://[hostname-registry]:5000/v2/": http: server gave HTTP response to HTTPS client
どうやら、httpsのDocker Registryしか受け付けない模様。
https化するのは若干面倒なので、/etc/docker/daemon.json
を作って以下を追記することで解決する。この設定をすれば、httpのDocker Registryとも接続できるようになる。(参考サイト)
{
"insecure-registries": ["[hostname-registry]:5000"]
}
Dockerサービスの再起動を忘れずに。
$ sudo systemctl restart docker
再び以下のコマンドを実行すれば、Pushに成功するはず!
$ make docker-push IMG="[hostname-registry]:5000/memcached-operator:v0.0.1"
(4) OLM(Operator Lifecycle Manager)のデプロイ
OLMのインストールと、memcached-operator-bundleのイメージ作成とPushは問題なくできるはず。
(2番目のコマンド「make bundle IMG=...」で対話式入力が必要になるが、requiredと言われる部分だけ何かしら文字列を入力したら問題なさそう)
$ operator-sdk olm install
$ make bundle IMG="[hostname-registry]:5000/memcached-operator:v0.0.1"
$ make bundle-build bundle-push BUNDLE_IMG="[hostname-registry]:5000/memcached-operator-bundle:v0.0.1"
以下でDocker RegistryにイメージがPushされていることを確認可能。
$ curl http://[hostname-registry]:5000/v2/_catalog
{"repositories":["memcached-operator","memcached-operator-bundle"]}
ローカルにDocker Registryを作り、かつバージョンがKubernetesのv1.24以降の場合、次の「Run your bundle」のコマンドでcontainerdにイメージをPullする際に以下のように失敗する。どうやら接続するDocker Registryがhttpだとダメな模様…。
$ operator-sdk run bundle [hostname-registry]:5000/memcached-operator-bundle:v0.0.1
INFO[0000] trying next host error="failed to do request: Head \"https://[hostname-registry]:5000/v2/memcached-operator-bundle/manifests/v0.0.1\": http: server gave HTTP response to HTTPS client" host="[hostname-registry]:5000"
FATA[0000] Failed to run bundle: pull bundle image: error pulling image [hostname-registry]:5000/memcached-operator-bundle:v0.0.1: error resolving name : failed to do request: Head "https://[hostname-registry]:5000/v2/memcached-operator-bundle/manifests/v0.0.1": http: server gave HTTP response to HTTPS client
そこでクラスター内のマシン全てに対して、containerdの設定ファイルに自作のDocker Registryとhttpでやり取りできるよう、以下のように2つの設定ファイルを作成する必要あり。(参考サイト)
※下記の設定はcontainerdのバージョンがv1.5以上が対象のようなので、それ以前のバージョンの場合はアップグッレードが必要
1つ目は、/etc/containerd/config.toml
というファイル
version = 2
[plugins."io.containerd.grpc.v1.cri".registry]
config_path = "/etc/containerd/certs.d"
2つ目は、/etc/containerd/certs.d/[hostname-registry]:5000/hosts.toml
というファイル
server = "http://[hostname-registry]:5000"
[host."http://[hostname-registry]:5000"]
capabilities = ["pull", "resolve"]
skip_verify = true
ファイル編集後、containerdサービスの再起動を忘れずに。
$ sudo systemctl restart containerd
改めて「Run your bundle」のコマンドを実行。
この時に「--use-http」のオプションをつけること!
$ operator-sdk run bundle [hostname-registry]:5000/memcached-operator-bundle:v0.0.1 --use-http
以下のような出力が出て来て、問題なくインストールされる(はず)!
INFO[0026] Creating a File-Based Catalog of the bundle "[hostname-registry]:5000/memcached-operator-bundle:v0.0.1"
INFO[0026] Generated a valid File-Based Catalog
INFO[0029] Created registry pod: [hostname-registry]-5000-memcached-operator-bundle-v0-0-1
INFO[0029] Created CatalogSource: memcached-catalog
INFO[0029] Created Subscription: memcached-v0-0-1-sub
INFO[0034] Approved InstallPlan install-4h5hn for the Subscription: memcached-v0-0-1-sub
INFO[0034] Waiting for ClusterServiceVersion "default/memcached.v0.0.1" to reach 'Succeeded' phase
INFO[0034] Waiting for ClusterServiceVersion "default/memcached.v0.0.1" to appear
INFO[0057] Found ClusterServiceVersion "default/memcached.v0.0.1" phase: Pending
INFO[0059] Found ClusterServiceVersion "default/memcached.v0.0.1" phase: Installing
INFO[0100] Found ClusterServiceVersion "default/memcached.v0.0.1" phase: Succeeded
INFO[0100] OLM has successfully installed "memcached.v0.0.1"
出来たリソースを確認してみる。
$ kubectl get all -n default
NAME READY STATUS RESTARTS AGE
pod/4cd7b9b9d399f3080f29723704f3c5288d8f0b632a3e194f8ca26bdae76tmfj 0/1 Completed 0 51m
pod/memcached-controller-manager-7594bd5b47-pw9bv 2/2 Running 0 51m
pod/[hostname-registry]-5000-memcached-operator-bundle-v0-0-1 1/1 Running 0 51m
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 3d7h
service/memcached-controller-manager-metrics-service ClusterIP 10.97.214.249 <none> 8443/TCP 51m
NAME READY UP-TO-DATE AVAILABLE AGE
deployment.apps/memcached-controller-manager 1/1 1 1 51m
NAME DESIRED CURRENT READY AGE
replicaset.apps/memcached-controller-manager-7594bd5b47 1 1 1 51m
NAME COMPLETIONS DURATION AGE
job.batch/4cd7b9b9d399f3080f29723704f3c5288d8f0b632a3e194f8ca26bdae798ad0 1/1 19s 51m
ようやく最後に、Memcachedカスタムリソースをデプロイする。
$ kubectl apply -f config/samples/cache_v1alpha1_memcached.yaml
memcached.cache.raspberrypi.local/memcached-sample created
内容確認
$ kubectl get memcached -n default
NAME AGE
memcached-sample 6m25s
後片付けは以下のコマンド。
$ operator-sdk cleanup memcached-operator
筆者環境だとなぜか上のコマンドでうまく消せず、次のコマンドで無理やり消した。
$ kubectl delete catalogsources.operators.coreos.com memcached-catalog; \
kubectl delete subscriptions.operators.coreos.com memcached-v0-0-1-sub; \
kubectl delete clusterserviceversion.operators.coreos.com memcached.v0.0.1;
(4)の別手段 : Direct deployment
Makefileでmake deploy
すれば、olmのインストールとbundleイメージの作成は無しでデプロイ可能。
ちょっと試すぶんにはolmを使うよりは「Direct deployment」の方が簡単そう。
$ make deploy IMG="[hostname-registry]:5000/memcached-operator:v0.0.1"
この場合は、Namespaceはdefaultではなくてmemcached-systemにリソースが作成される。
また、olm経由でデプロイの場合にあったJobが生成されない等の違いがある。
$ kubectl get all -n memcached-system
NAME READY STATUS RESTARTS AGE
pod/memcached-controller-manager-89f9468f6-v9lgh 2/2 Running 0 14s
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/memcached-controller-manager-metrics-service ClusterIP 10.101.107.214 <none> 8443/TCP 14s
NAME READY UP-TO-DATE AVAILABLE AGE
deployment.apps/memcached-controller-manager 1/1 1 1 14s
NAME DESIRED CURRENT READY AGE
replicaset.apps/memcached-controller-manager-89f9468f6 1 1 1 14s
Memcachedカスタムリソースはolm利用時と同じようにデプロイ可能。
$ kubectl apply -f config/samples/cache_v1alpha1_memcached.yaml
memcached.cache.raspberrypi.local/memcached-sample created
以下で後片付け。
$ make undeploy
おわりに
この時点では空のMemcachedリソースが作られただけで、残念ながら実体はない…。ここに魂を入れてサービスが提供できる状態にするには、full tutorialに従ってgoのソースを修正してビルドする必要あり。
こちらのサイトで実際にfull tutorialを試した内容が書かれていて参考になりそう!
参考サイト