kubebuilder2.0學習筆記——搭建和使用

建議版本:

  • docker 18.06
  • k8s 1.14

1. Install

安裝kubebuilder

執行下面的腳本:html

os=$(go env GOOS)
arch=$(go env GOARCH)

# download kubebuilder and extract it to tmp
curl -sL https://go.kubebuilder.io/dl/2.0.0-beta.0/${os}/${arch} | tar -xz -C /tmp/

# move to a long-term location and put it on your path
# (you'll need to set the KUBEBUILDER_ASSETS env var if you put it somewhere else)
mv /tmp/kubebuilder_2.0.0-beta.0_${os}_${arch} /usr/local/kubebuilder
export PATH=$PATH:/usr/local/kubebuilder/bin

便可git

安裝kustomize

2. Dev

建立project

使用kubebuilder前,必需要確保本地的go版本爲1.11或以上,開啓了go module (export GO111MODULE=ongithub

咱們在GOPATH下新建一個目錄。並在其中執行kubebuilder init --domain netease.com
會發現報錯:golang

go: sigs.k8s.io/controller-runtime@v0.2.0-beta.4: unrecognized import path "sigs.k8s.io/controller-runtime" (https fetch: Get https://sigs.k8s.io/controller-runtime?go-get=1: dial tcp 35.201.71.162:443: i/o timeout)
go: error loading module requirements

沒法直接clone sigs.k8s.io/controller-runtime,那麼咱們能夠經過對go mod配置proxy,走代理下載: export GOPROXY=https://goproxy.ioweb

將目錄清理,並從新執行kubebuilder init --domain netease.comdocker

# kubebuilder init --domain my.domain
go mod tidy
Running make...
make
go get sigs.k8s.io/controller-tools/cmd/controller-gen@v0.2.0-beta.4
go: finding sigs.k8s.io/controller-tools/cmd/controller-gen v0.2.0-beta.4
go: finding sigs.k8s.io/controller-tools/cmd v0.2.0-beta.4
/root/mygo/bin/controller-gen object:headerFile=./hack/boilerplate.go.txt paths=./api/...
go fmt ./...
go vet ./...
go build -o bin/manager main.go
Next: Define a resource with:
$ kubebuilder create api
# ls
bin  config  Dockerfile  go.mod  go.sum  hack  main.go    Makefile  PROJECT

init以後生成了一些代碼、hack腳本、dockerfile、makefile,這意味着kubebuilder幫咱們生成了一個operator須要的基礎代碼內容。另外bin目錄下編譯出了一個manager二進制文件。這就是kubebuilder最終幫咱們製做的程序,它包括:json

  • 一個metrics接口(for prometheus)
  • 運行0或多個controller
  • 運行0或多個webhook server

建立一個API (和控制器)

執行:kubebuilder create api --group ops --version v1 --kind Playbookapi

# kubebuilder create api --group ops --version v1 --kind Playbook
Create Resource [y/n]
y
Create Controller [y/n]      # 若是咱們只須要建立一個api,不須要開發一個控制器,這裏選n便可
y
Writing scaffold for you to edit...
api/v1/guestbook_types.go
controllers/guestbook_controller.go
Running make...
go get sigs.k8s.io/controller-tools/cmd/controller-gen@v0.2.0-beta.4
go: finding sigs.k8s.io/controller-tools/cmd/controller-gen v0.2.0-beta.4
go: finding sigs.k8s.io/controller-tools/cmd v0.2.0-beta.4
/root/mygo/bin/controller-gen object:headerFile=./hack/boilerplate.go.txt paths=./api/...
go fmt ./...
go vet ./...
go: downloading github.com/onsi/ginkgo v1.8.0
go: downloading github.com/onsi/gomega v1.5.0
go: extracting github.com/onsi/gomega v1.5.0
go: extracting github.com/onsi/ginkgo v1.8.0
go build -o bin/manager main.go
# ls
api  bin  config  controllers  Dockerfile  go.mod  go.sum  hack  main.go  Makefile  PROJECT

上述操做執行完後,須要關注兩個地方數組

  • api/v1/playbook_types.go

這個文件包含了對Playbook這個CRD的定義,咱們能夠在裏面進行修改,加上咱們須要的字段。併發

好比咱們給Playbook.Spec增長一個字段Abstract,類型爲string,表示該Playbook的摘要;給Playbook.Status增長一個字段Progress,類型爲int32,表示這本Playbook看到百分幾。

  • controllers/playbook_controller.go

這個文件裏,有以下函數:

func (r *PlaybookReconciler) Reconcile(req ctrl.Request) (ctrl.Result, error) {
        _ = context.Background()
        _ = r.Log.WithValues("playbook", req.NamespacedName)

        // your logic here

        return ctrl.Result{}, nil
}

這就是控制器的處理函數,每當集羣中有Playbook資源的變更(CRUD),都會觸發這個函數進行協調。

好比咱們在Reconcile中獲取進入協調的Playbook對象,檢查它的status.progress是否等於100,若是是,就直接調用Delete接口刪除它。

咱們開發完畢後,能夠直接運行make run, 會從新編譯出一個/bin/manager並運行,因爲咱們在一開始指定要生成controller,kubebuilder會在manager中注入controller,當manager運行起來後,會運行起咱們開發的controller。

須要注意的是,直接make run可能會報錯提示8080端口已經被佔用,檢查是否你的apisever監聽在該端口,或者直接修改main.go中的代碼,將metrics接口服務監聽在別的端口上

當咱們看到以下的日誌時,說明manager中的控制器已經在工做了:

2019-09-09T17:43:35.290+0800    INFO    controller-runtime.controller    Starting Controller    {"controller": "playbook"}

建立一個api的webhook

咱們若是須要在Playbook CRUD 時進行操做合法性檢查, 能夠開發一個webhook實現。webhook的腳手架同樣能夠用kubebuilder生成:

# kubebuilder create webhook --group ops --version v1 --kind Playbook --programmatic-validation --defaulting
Writing scaffold for you to edit...
api/v1/playbook_webhook.go

執行後會生成api/v1/playbook_webhook.go文件,因爲咱們指定了參數--programmatic-validation(能夠在建立、更新guestbook時觸發的字段驗證函數)和--defaulting(建立或更新時,用於配置guestbook某些字段默認值的函數)
咱們能夠對上述函數進行自定義的修改。體如今代碼中就是以下三個方法:

func (r *Playbook) ValidateCreate() error 
func (r *Playbook) ValidateUpdate(old runtime.Object) error
func (r *Playbook) Default()

好比咱們在這裏對playbook.Spec.Abstract的內容進行檢查,若是包含了單詞"yellow",咱們認爲這是本黃書,進行報錯。

webhook的測試和部署

測試和部署的前提是咱們在開發環境中安裝了k8s。這一步不作說明。

  • 執行make,能夠進行main.go編譯
  • 執行make install 能夠將咱們生成的crd註冊到集羣中。
  • 執行make run,能夠前臺運行manager,咱們通過上面的編輯,manager中注入了一個controller和一個webhook。

可是webhook如今編譯會失敗,報錯是找不到webhook server使用的證書文件。咱們須要用k8s的ca簽發一個webhookserver的證書和key,固然咱們也能夠直接用k8s的管理員證書。

cp /etc/kubernetes/pki/apiserver.crt /tmp/k8s_webhook-server/serving-certs/tls.crt
cp /etc/kubernetes/pki/apiserver.key /tmp/k8s_webhook-server/serving-certs/tls.key

再次make run,這下運行起來了。咱們看到終端打印出了以下兩行日誌:

2019-09-09T17:48:06.967+0800    INFO    controller-runtime.builder    Registering a mutating webhook    {"GVK": "ops.netease.com/v1, Kind=Playbook", "path": "/mutate-ops-netease-com-v1-playbook"}
2019-09-09T17:48:06.967+0800    INFO    controller-runtime.builder    Registering a validating webhook    {"GVK": "ops.netease.com/v1, Kind=Playbook", "path": "/validate-ops-netease-com-v1-playbook"}

但此時apiserver並不知道運行了這麼一個webserver,webhook又如何能被調用呢?

make webhook enable

咱們須要建立webhookcfg,讓apiserver本身感知到某些資源(Playbook)的某些請求(CREATE,UPDATE)須要訪問某個服務(service,或者一個url)

幸運的是,kubebuilder幫咱們生成了webhookcfg。在/config/webhook/目錄下,記錄了manifests.yaml 和 service.yaml。

service.yaml是一個service模板,對應的是咱們設計的webhook

manifests.yaml的內容以下:

---
apiVersion: admissionregistration.k8s.io/v1beta1
kind: MutatingWebhookConfiguration
metadata:
  creationTimestamp: null
  name: mutating-webhook-configuration
webhooks:
- clientConfig:
    caBundle: Cg==
    service:
      name: webhook-service
      namespace: system
      path: /mutate-ops-netease-com-v1-playbook
  failurePolicy: Fail
  name: mplaybook.kb.io
  rules:
  - apiGroups:
    - ops.netease.com
    apiVersions:
    - v1
    operations:
    - CREATE
    - UPDATE
    resources:
    - playbooks

---
apiVersion: admissionregistration.k8s.io/v1beta1
kind: ValidatingWebhookConfiguration
metadata:
  creationTimestamp: null
  name: validating-webhook-configuration
webhooks:
- clientConfig:
    caBundle: Cg==
    service:
      name: webhook-service
      namespace: system
      path: /validate-ops-netease-com-v1-playbook
  failurePolicy: Fail
  name: vplaybook.kb.io
  rules:
  - apiGroups:
    - ops.netease.com
    apiVersions:
    - v1
    operations:
    - CREATE
    - UPDATE
    resources:
    - playbooks

很顯然,這裏記錄的就是webhookcfg。由於webhook有多種,咱們上面建立時指定了兩種(--programmatic-validation--defaulting),對應建立了一個ValidatingWebhookConfiguration和一個MutatingWebhookConfiguration

在本地測試的過程當中,咱們可能不想每次代碼修改都要打包成鏡像,併發布成deployment+service。那麼咱們就能夠修改以此處的

clientConfig:
    caBundle: Cg==
    service:
      name: webhook-service
      namespace: system
      path: /validate-ops-netease-com-v1-playbook
  • 去掉service部分,改成url: https://${server}:443/validate-ops-netease-com-v1-playbook ,注意與service.path對應。
  • webhook必須使用https,因此須要申明caBundle,這樣 apiserver 才能夠信任 webhook server 提供的 TLS 證書。將集羣的ca.crt內容(能夠經過kubectl config view --raw -o json | jq -r '.clusters[0].cluster."certificate-authority-data"' | tr -d '"'拿到)填入到caBundle的值中;
  • url中的server值必須是一個webhook證書的有效地址。若是咱們在開發機器上部署了k8s,那麼能夠簡單地使用機器自身的ip(master節點的ip)。
  • 建立出MutatingWebhookConfiguration後,咱們前臺運行着的manager程序中的mutating webhook將會在k8s集羣中生效;
  • 建立出ValidatingWebhookConfiguration後,咱們前臺運行着的manager程序中的validating webhook將會在k8s集羣中生效;

注意到,不論是ValidatingWebhookConfiguration仍是MutatingWebhookConfiguration,他們的webhooks是一個數組,咱們若是在開發過程當中須要設計多個CRD,那麼屢次執行kubebuilder create api **** 後,咱們能夠按照本身的設計,在兩種(或其中一種)WebhookConfitration的webhooks裏增長一個項目,只要填充正確的name,clientConfig.url,rules便可。

這裏介紹的是本地開發環境便於調試的部署方式,測試、線上集羣的部署,應該作到標準化和規範化,那麼如何進行標準化部署呢?

3. Deploy

部署整個manager

  • 安裝cert-manager。cert-manager能夠動態地爲咱們開發的服務配置tls證書。安裝步驟見https://docs.cert-manager.io/...
  • 進行dockerbuild。

    • 修改Makefile,將docker-build 後面的test去掉
    • 修改Dockerfile。一是在拷貝go.mod, go.sum後增長兩個env:

      ENV GO111MODULE=on
      ENV GOPROXY=https://goproxy.io

      二是將FROM gcr.io/distroless/static:latest 替換爲FROM golang:1.12.5;三是若是咱們只寫了個webhook,沒有寫controller,那麼Dockerfile中的COPY controllers/ controllers/要去掉

    • 修改/config/default/kustomization.yaml, 將webhook、certmanager相關的註釋去掉並將patches改成patchesStrategicMerge
    • 修改config/crd/kustomization.yaml,將webhook、certmanager相關的註釋去掉
    • 修改config/default/manager_auth_proxy_patch.yaml文件中的image,改成quay.io/coreos/kube-rbac-proxy:v0.4.0
    • 執行 make docker-build
  • 進行deploy:

    • 執行make deploy

執行完畢後,咱們在集羣中能夠找到${項目名}-system namespace下運行了咱們開發的服務,包括一個deployment,兩個service:

# kubectl  get all -n testop3-system 
NAME                                              READY   STATUS         RESTARTS   AGE
pod/testop3-controller-manager-6f44ddbd68-q7m24   1/2     ErrImagePull   0          15s

NAME                                                 TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)    AGE
service/testop3-controller-manager-metrics-service   ClusterIP   10.107.195.212   <none>        8443/TCP   15s
service/testop3-webhook-service                      ClusterIP   10.110.243.20    <none>        443/TCP    15s

NAME                                         READY   UP-TO-DATE   AVAILABLE   AGE
deployment.apps/testop3-controller-manager   0/1     1            0           15s

NAME                                                    DESIRED   CURRENT   READY   AGE
replicaset.apps/testop3-controller-manager-6f44ddbd68   1         1         0       15s

注意事項

webhookconfiguration

咱們從上文中瞭解到,要讓一個webhook在k8s集羣內可用,須要建立對應的webhookconfiguration,即validatingwebhookconfigurationmutatingwebhookconfiguration.k8s apiserver會根據集羣中已經建立的全部validatingwebhookconfigurationmutatingwebhookconfiguration逐一進行調用,因此,當咱們建立一個crd對象失敗,且日誌顯示訪問某個webhook失敗時,咱們能夠:

確認集羣中的webhookconfiguration是否爲咱們須要的webhook而且要檢查每個webhookconfiguration中,配置的服務地址是否可達。

特別是:當咱們使用本地make run測試,且使用make deploy 測試,會須要不一樣的webhookconfiguration,兩種測試方式建議只選擇一種,不要來回切換,不然要確保webhookconfiguration的配置,比較費時。

相關文章
相關標籤/搜索