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的配置,比较费时。

相关文章
相关标签/搜索