Kubernetes Operator SDKチュートリアルをやってみる

[昨日作ったKubeクラスター](https://qiita.com/rk05231977/items/347dbc5fc08f7250ba5a)を使って、Kubernetes Operator SDKのチュートリアルをやってみる。

Operator SDK
https://github.com/operator-framework/operator-sdk

# 事前準備
https://github.com/operator-framework/operator-sdk#prerequisites
まずはPrerequisitesの整備をば。

* git
* go version v1.13+.
* mercurial version 3.9+
* docker version 17.03+. Alternatively podman v1.2.0+ or buildah v1.7+
* kubectl version v1.12.0+.
* Access to a Kubernetes v1.12.0+ cluster.
* Optional: delve version 1.2.0+ (for run --local --enable-delve).

## git
```
$ sudo -i
# yum install -y git
```

## go
https://golang.org/dl/
からgo1.13.8.linux-amd64.tar.gzをダウンロードして展開して移動。
ちなみにgoの置き場所がユーザーのホームディレクトリ直下（例えば /root/go）だと色々面倒くさい。
また、「export GOROOT～」は、バグだと思うが現状無いとチュートリアルが途中で詰まる。

```
# curl -O https://dl.google.com/go/go1.13.8.linux-amd64.tar.gz
# tar xf go1.13.8.linux-amd64.tar.gz
# mv go /opt
# echo 'PATH=$PATH:/opt/go/bin' >> ~/.bashrc
# echo 'export GOROOT=$(go env GOROOT)' >> ~/.bashrc
# . ~/.bashrc
```

## mercurial
https://www.mercurial-scm.org/downloads
からMercurial 5.2.2 for centos 7をダウンロードしてインストール。

```
# curl -O https://www.mercurial-scm.org/release/centos7/mercurial-
5.2.2-1.x86_64.rpm
# rpm -i mercurial-5.2.2-1.x86_64.rpm
```

## delve
https://github.com/go-delve/delve/blob/master/Documentation/installation/linux/install.md
docker、kubectl、kubernetsは前回インストール済みのため割愛。最後にdelveをgo get。

```
# go get -u github.com/go-delve/delve/cmd/dlv
```

# Operator SDK CLIをインストールする
https://github.com/operator-framework/operator-sdk/blob/master/doc/user/install-operator-sdk.md

```
# RELEASE_VERSION=v0.15.2
# curl -LO https://github.com/operator-framework/operator-sdk/releases/download/${RELEASE_VERSION}/operator-sdk-${RELEASE_VERSION}-x86_64-linux-gnu
# chmod +x operator-sdk-${RELEASE_VERSION}-x86_64-linux-gnu && sudo mkdir -p /usr/local/bin/ && sudo cp operator-sdk-${RELEASE_VERSION}-x86_64-linux-gnu /usr/local/bin/operator-sdk
# rm operator-sdk-${RELEASE_VERSION}-x86_64-linux-gnu
# echo 'PATH=$PATH:/usr/local/bin' >> ~/.bashrc
# . ~/.bashrc
```

# Operatorを作る
## Operatorのひな型を作る
```
# mkdir -p $HOME/projects/example-inc/
# cd $HOME/projects/example-inc/
# operator-sdk new app-operator --repo github.com/example-inc/app-operator
# cd app-operator
```

初回だけインターネットから大量に何かをダウンロードしてくる。
上手く行けば「INFO[0059] Project creation complete.」と表示される。

## CRD用のAPIを追加する
何を言っているのかわからねーと思うが、おれも良くわからねー。
deepcopyが何とか言うエラーで止まる場合は、GOROOTを設定していないと思われ。

```
# operator-sdk add api --api-version=app.example.com/v1alpha1 --kind=AppService

（出力例）
[root@ip-172-26-4-124 app-operator]# operator-sdk add api --api-version=app.example.com/v1
alpha1 --kind=AppService
INFO[0000] Generating api version app.example.com/v1alpha1 for kind AppService. 
INFO[0000] Created pkg/apis/app/group.go                
INFO[0016] Created pkg/apis/app/v1alpha1/appservice_types.go 
INFO[0016] Created pkg/apis/addtoscheme_app_v1alpha1.go 
INFO[0016] Created pkg/apis/app/v1alpha1/register.go    
INFO[0016] Created pkg/apis/app/v1alpha1/doc.go         
INFO[0016] Created deploy/crds/app.example.com_v1alpha1_appservice_cr.yaml 
INFO[0016] Running deepcopy code-generation for Custom Resource group versions: [app:[v1al
pha1], ] 
INFO[0025] Code-generation complete.                    
INFO[0025] Running CRD generator.                       
INFO[0026] CRD generation complete.                     
INFO[0026] API generation complete.
```

## CRD用のコントローラーを追加する
Operatorっぽくなってきた。きたのか？

```
# operator-sdk add controller --api-version=app.example.com/v1alpha1 --kind=AppService

（出力例）
[root@ip-172-26-4-124 app-operator]# operator-sdk add controller --api-version=app.example
.com/v1alpha1 --kind=AppService
INFO[0000] Generating controller version app.example.com/v1alpha1 for kind AppService. 
INFO[0000] Created pkg/controller/appservice/appservice_controller.go 
INFO[0000] Created pkg/controller/add_appservice.go     
INFO[0000] Controller generation complete.
```

## Operatorをビルド
チュートリアルではquay.ioにイメージをプッシュしているが、今回シングルノードクラスタなのでローカルにイメージがあれば十分。
build実行すると数十秒黙ることがあり不安になるが、待つ。
成功したら「INFO[0069] Operator build complete.」と表示される。

```
# operator-sdk build app-operator
```

# Operatorをデプロイする
## マニフェストファイルを修正する
ひな型のイメージ名を修正する。
また、ローカルdockerのイメージを使うためImagePullPolicyをNeverに。

```
# sed -i "s|REPLACE_IMAGE|app-operator|g" deploy/operator.yaml
# sed -i "s|imagePullPolicy:.*|imagePullPolicy: Never|" deploy/operator.yaml
```

## KubernetesにService Account、RBAC、CRDをセットアップする

```
# kubectl create -f deploy/service_account.yaml
# kubectl create -f deploy/role.yaml
# kubectl create -f deploy/role_binding.yaml
# kubectl create -f deploy/crds/app.example.com_appservices_crd.yaml
```

## KubernetesにOperatorをデプロイする
```
# kubectl create -f deploy/operator.yaml

（確認）
# kubectl get pod
NAME                            READY   STATUS    RESTARTS   AGE
app-operator-6b54445bdc-bkx9r   1/1     Running   0          5s
```

# Operatorの動作を確認する
ここまでで、いわゆるOperatorのデプロイが出来たので、KubernetesのCR（Custom Resource）を追加して、Operatorが良い感じにCRを扱ってくれるかを確認する。

## CRをデプロイする
```
# kubectl create -f deploy/crds/app.example.com_v1alpha1_appservice_cr.yaml
```
上記、デプロイしたCRの内容は以下のとおり。API名と、sizeの指定ぐらいの簡単なもの。

```
[root@ip-172-26-4-124 app-operator]# cat deploy/crds/app.example.com_v1alpha1_appservice_cr.yaml 
apiVersion: app.example.com/v1alpha1
kind: AppService
metadata:
  name: example-appservice
spec:
  # Add fields here
  size: 3
```

すると、Kubernetesにexample-appservice-podというpodが立ち上がる。

```
[root@ip-172-26-4-124 app-operator]# kubectl get pod
NAME                            READY   STATUS    RESTARTS   AGE
app-operator-6b54445bdc-bkx9r   1/1     Running   0          3h35m
example-appservice-pod          1/1     Running   0          3m7s
```

中身はbusybox sleep 3600なのだけども、ReplicaSetというわけでも無いのにexample-appservice-pod Podを削除してもすぐに復活する。Operatorが状態を監視して起動しなおしているため。

```
[root@ip-172-26-4-124 app-operator]# kubectl delete pod example-appservice-pod
pod "example-appservice-pod" deleted
[root@ip-172-26-4-124 app-operator]# kubectl get pod
NAME                            READY   STATUS    RESTARTS   AGE
app-operator-6b54445bdc-bkx9r   1/1     Running   0          3h41m
example-appservice-pod          1/1     Running   0          64s
```

## CRを削除する
CRを削除すると、Operatorの管理対象であるexample-appservice-podが削除される。
気が付いたのだけど、CRはget allで表示されない様。

```
[root@ip-172-26-4-124 app-operator]# kubectl get AppService
NAME                 AGE
example-appservice   12m
[root@ip-172-26-4-124 app-operator]# kubectl get all
NAME                                READY   STATUS    RESTARTS   AGE
pod/app-operator-6b54445bdc-bkx9r   1/1     Running   0          3h45m
pod/example-appservice-pod          1/1     Running   0          4m59s

NAME                           TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)          
   AGE
service/app-operator-metrics   ClusterIP   10.97.212.211   <none>        8383/TCP,8686/TCP
   3h45m
service/kubernetes             ClusterIP   10.96.0.1       <none>        443/TCP          
   28h

NAME                           READY   UP-TO-DATE   AVAILABLE   AGE
deployment.apps/app-operator   1/1     1            1           3h45m

NAME                                      DESIRED   CURRENT   READY   AGE
replicaset.apps/app-operator-6b54445bdc   1         1         1       3h45m
[root@ip-172-26-4-124 app-operator]# kubectl delete AppService example-appservice
appservice.app.example.com "example-appservice" deleted
[root@ip-172-26-4-124 app-operator]# kubectl get pod
NAME                            READY   STATUS        RESTARTS   AGE
app-operator-6b54445bdc-bkx9r   1/1     Running       0          3h46m
example-appservice-pod          1/1     Terminating   0          6m10s
[root@ip-172-26-4-124 app-operator]# kubectl get pod
NAME                            READY   STATUS    RESTARTS   AGE
app-operator-6b54445bdc-bkx9r   1/1     Running   0          3h48m
```

# Operatorを削除する
```
# kubectl delete -f deploy/operator.yaml
# kubectl delete -f deploy/role.yaml
# kubectl delete -f deploy/role_binding.yaml
# kubectl delete -f deploy/service_account.yaml
# kubectl delete -f deploy/crds/app.example.com_appservices_crd.yaml
```

# 次は
さてー。。まずは環境でOperator SDKのサンプルが動作することは確認できた。
とりま、重要そうなファイルは「pkg/apis/app/v1alpha1/appservice_types.go」と「pkg/controller/appservice/appservice_controller.go」だろうか。次はその中身の理解に進もうか。Go言語良くわからんな。

（[続き](https://qiita.com/rk05231977/items/b4da78907bb9774481dd)）