kubernetes中文手册
  • 前言
    • 序言
  • 云原生
    • 云原生(Cloud Native)的定义
    • 云原生的设计哲学
    • Kubernetes 的诞生
    • Kubernetes 与云原生应用概览
    • 云原生应用之路 —— 从 Kubernetes 到云原生
    • 定义云原生应用
      • OAM
        • Workload
        • Component
        • Trait
        • Application Scope
        • Application Configuration
      • Crossplane
    • 云原生编程语言
      • 云原生编程语言 Ballerina
      • 云原生编程语言 Pulumi
    • 云原生的未来
  • 快速入门
    • 云原生新手入门指南
    • Play with Kubernetes
    • 快速部署一个云原生本地实验环境
    • 使用 Rancher 在阿里云上部署 Kubenretes 集群
  • 概念与原理
    • Kubernetes 架构
      • 设计理念
      • Etcd 解析
      • 开放接口
        • CRI - Container Runtime Interface(容器运行时接口)
        • CNI - Container Network Interface(容器网络接口)
        • CSI - Container Storage Interface(容器存储接口)
      • 资源对象与基本概念解析
    • Pod 状态与生命周期管理
      • Pod 概览
      • Pod 解析
      • Init 容器
      • Pause 容器
      • Pod 安全策略
      • Pod 的生命周期
      • Pod Hook
      • Pod Preset
      • Pod 中断与 PDB(Pod 中断预算)
    • 集群资源管理
      • Node
      • Namespace
      • Label
      • Annotation
      • Taint 和 Toleration(污点和容忍)
      • 垃圾收集
    • 控制器
      • Deployment
      • StatefulSet
      • DaemonSet
      • ReplicationController 和 ReplicaSet
      • Job
      • CronJob
      • Horizontal Pod Autoscaling
        • 自定义指标 HPA
      • 准入控制器(Admission Controller)
    • 服务发现与路由
      • Service
      • 拓扑感知路由
      • Ingress
        • Traefik Ingress Controller
      • Kubernetes Service API
        • Service API 简介
    • 身份与权限控制
      • ServiceAccount
      • 基于角色的访问控制(RBAC)
      • NetworkPolicy
    • 网络
      • Kubernetes 中的网络解析 —— 以 flannel 为例
      • Kubernetes 中的网络解析 —— 以 calico 为例
      • 具备 API 感知的网络和安全性管理开源软件 Cilium
        • Cilium 架构设计与概念解析
    • 存储
      • Secret
      • ConfigMap
        • ConfigMap 的热更新
      • Volume
      • 持久化卷(Persistent Volume)
      • Storage Class
      • 本地持久化存储
    • 集群扩展
      • 使用自定义资源扩展 API
      • 使用 CRD 扩展 Kubernetes API
      • Aggregated API Server
      • APIService
      • Service Catalog
    • 多集群管理
      • 多集群服务 API(Multi-Cluster Services API)
      • 集群联邦(Cluster Federation)
    • 资源调度
      • 服务质量等级(QoS)
  • 用户指南
    • 用户指南概览
    • 资源对象配置
      • 配置 Pod 的 liveness 和 readiness 探针
      • 配置 Pod 的 Service Account
      • Secret 配置
      • 管理 namespace 中的资源配额
    • 命令使用
      • Docker 用户过渡到 kubectl 命令行指南
      • kubectl 命令概览
      • kubectl 命令技巧大全
      • 使用 etcdctl 访问 Kubernetes 数据
    • 集群安全性管理
      • 管理集群中的 TLS
      • kubelet 的认证授权
      • TLS Bootstrap
      • 创建用户认证授权的 kubeconfig 文件
      • IP 伪装代理
      • 使用 kubeconfig 或 token 进行用户身份认证
      • Kubernetes 中的用户与身份认证授权
      • Kubernetes 集群安全性配置最佳实践
    • 访问 Kubernetes 集群
      • 访问集群
      • 使用 kubeconfig 文件配置跨集群认证
      • 通过端口转发访问集群中的应用程序
      • 使用 service 访问群集中的应用程序
      • 从外部访问 Kubernetes 中的 Pod
      • Cabin - Kubernetes 手机客户端
      • Lens - Kubernetes IDE/桌面客户端
      • Kubernator - 更底层的 Kubernetes UI
    • 在 Kubernetes 中开发部署应用
      • 适用于 Kubernetes 的应用开发部署流程
      • 迁移传统应用到 Kubernetes 中 —— 以 Hadoop YARN 为例
      • 使用 StatefulSet 部署用状态应用
  • 最佳实践
    • 最佳实践概览
    • 在 CentOS 上部署 Kubernetes 集群
      • 创建 TLS 证书和秘钥
      • 创建 kubeconfig 文件
      • 创建高可用 etcd 集群
      • 安装 kubectl 命令行工具
      • 部署 master 节点
      • 安装 flannel 网络插件
      • 部署 node 节点
      • 安装 kubedns 插件
      • 安装 dashboard 插件
      • 安装 heapster 插件
      • 安装 EFK 插件
    • 生产级的 Kubernetes 简化管理工具 kubeadm
      • 使用 kubeadm 在 Ubuntu Server 16.04 上快速构建测试集群
    • 服务发现与负载均衡
      • 安装 Traefik ingress
      • 分布式负载测试
      • 网络和集群性能测试
      • 边缘节点配置
      • 安装 Nginx ingress
      • 安装配置 DNS
        • 安装配置 Kube-dns
        • 安装配置 CoreDNS
    • 运维管理
      • Master 节点高可用
      • 服务滚动升级
      • 应用日志收集
      • 配置最佳实践
      • 集群及应用监控
      • 数据持久化问题
      • 管理容器的计算资源
    • 存储管理
      • GlusterFS
        • 使用 GlusterFS 做持久化存储
        • 使用 Heketi 作为 Kubernetes 的持久存储 GlusterFS 的 external provisioner
        • 在 OpenShift 中使用 GlusterFS 做持久化存储
      • GlusterD-2.0
      • Ceph
        • 用 Helm 托管安装 Ceph 集群并提供后端存储
        • 使用 Ceph 做持久化存储
        • 使用 rbd-provisioner 提供 rbd 持久化存储
      • OpenEBS
        • 使用 OpenEBS 做持久化存储
      • Rook
      • NFS
        • 利用 NFS 动态提供 Kubernetes 后端存储卷
    • 集群与应用监控
      • Heapster
        • 使用 Heapster 获取集群和对象的 metric 数据
      • Prometheus
        • 使用 Prometheus 监控 Kubernetes 集群
        • Prometheus 查询语言 PromQL 使用说明
      • 使用 Vistio 监控 Istio 服务网格中的流量
    • 分布式追踪
      • OpenTracing
    • 服务编排管理
      • 使用 Helm 管理 Kubernetes 应用
      • 构建私有 Chart 仓库
    • 持续集成与发布
      • 使用 Jenkins 进行持续集成与发布
      • 使用 Drone 进行持续集成与发布
    • 更新与升级
      • 手动升级 Kubernetes 集群
      • 升级 dashboard
    • 扩展控制器
      • OpenKruise
        • 原地升级
    • 安全策略
      • 开放策略代理(OPA)
      • 云原生安全
  • 服务网格
    • 服务网格(Service Mesh)
    • 企业级服务网格架构
      • 服务网格基础
      • 服务网格技术对比
      • 服务网格对比 API 网关
      • 采纳和演进
      • 定制和集成
      • 总结
    • Istio
      • 使用 Istio 前需要考虑的问题
      • Istio 中 sidecar 的注入规范及示例
      • 如何参与 Istio 社区及注意事项
      • Istio 免费学习资源汇总
      • Sidecar 的注入与流量劫持
      • Envoy Sidecar 代理的路由转发
      • Istio 如何支持虚拟机
      • Istio 支持虚拟机的历史
    • Envoy
      • Envoy 的架构与基本术语
      • Envoy 作为前端代理
      • Envoy mesh 教程
  • 领域应用
    • 领域应用概览
    • 微服务架构
      • 微服务中的服务发现
      • 使用 Java 构建微服务并发布到 Kubernetes 平台
        • Spring Boot 快速开始指南
    • 大数据
      • Spark 与 Kubernetes
        • Spark standalone on Kubernetes
        • 运行支持 Kubernetes 原生调度的 Spark 程序
    • Serverless 架构
      • 理解 Serverless
      • FaaS(函数即服务)
        • OpenFaaS 快速入门指南
      • Knative
    • 边缘计算
    • 人工智能
    • 可观察性
  • 开发指南
    • 开发指南概览
    • SIG 和工作组
    • 开发环境搭建
      • 本地分布式开发环境搭建(使用 Vagrant 和 Virtualbox)
    • 单元测试和集成测试
    • client-go 示例
      • client-go 中的 informer 源码分析
    • Operator
      • operator-sdk
    • kubebuilder
      • 使用 kubebuilder 创建 operator 示例
    • 高级开发指南
    • 社区贡献
    • Minikube
  • 社区及生态
    • 云原生计算基金会(CNCF)
      • CNCF 章程
      • CNCF 特别兴趣小组(SIG)说明
      • 开源项目加入 CNCF Sandbox 的要求
      • CNCF 中的项目治理
      • CNCF Ambassador
    • 认证及培训
      • 认证 Kubernetes 服务提供商(KCSP)说明
      • 认证 Kubernetes 管理员(CKA)说明
  • 附录
    • 附录说明
    • Kubernetes 中的应用故障排查
    • Kubernetes 相关资讯和情报链接
    • Docker 最佳实践
    • Kubernetes 使用技巧
    • Kubernetes 相关问题记录
    • Kubernetes 及云原生年度总结及展望
      • Kubernetes 与云原生 2017 年年终总结及 2018 年展望
      • Kubernetes 与云原生 2018 年年终总结及 2019 年展望
    • CNCF 年度报告解读
      • CNCF 2018 年年度报告解读
      • CNCF 2020 年年度报告解读
由 GitBook 提供支持
在本页
  • 准备
  • Minikube 的 DNS 解析问题
  • 名词解释
  • 安装 kubebuilder
  • 创建项目
  • 初始化和创建 API
  • 安装 CRD
  • 部署 controller
  • 创建 CR
  • 增加业务逻辑
  • 修改 CRD
  • 修改 Reconcile 函数
  • 运行测试
  • 更多
  • 参考
  1. 开发指南
  2. kubebuilder

使用 kubebuilder 创建 operator 示例

上一页kubebuilder下一页高级开发指南

最后更新于3年前

本文作为 Kubebuilder 教程,将指导您如何使用 kubebuilder 创建一个 Kubernetes Operator。

准备

本文中的示例运行环境及相关软件版本如下:

  • Kubernetes MiniKube v1.9.2

  • Kubernetes v1.18.0

  • Go 1.14

  • Kubebuilder 2.3.1

  • kustomize 3.6.1

  • Docker 19.03.8

使用 Minikube 安装 Kubernetes 集群,Kubernetes 安装好后,检查集群是否可用。

Minikube 的 DNS 解析问题

如果遇到 Kubernetes 集群无法拉取镜像,DNS 解析出现问题,解决方式见 。

使用 minikube ssh 进入 minikube 主机,修改 /etc/systemd/resolved.conf 文件,将其中的 DNS 配置字段修改为 DNS=8.8.8.8,然后执行 sudo systemctl restart systemd-resolved 即可更改 DNS,切勿直接修改 /etc/resolv.conf 文件。

修正 Minikube 的 DNS 配置,请执行下面的命令。

minikube ssh
sudo sed -i 's/#DNS=/DNS=8.8.8.8/g' /etc/systemd/resolved.conf
sudo systemctl restart systemd-resolved

名词解释

在阅读下面的文章前,需要先明确以下两个名词的含义。

  • CRD:自定义资源定义,Kubernetes 中的资源类型。

  • CR:Custom Resource,对使用 CRD 创建出来的自定义资源的统称。

安装 kubebuilder

MacOS

对于 Mac 系统,将下载好的安装包解压后将其移动到 /usr/local/kubebuilder 目录下,并将 /usr/local/kubebuilder/bin 添加到您的 $PATH 路径下。

创建项目

我们首先将使用自动配置创建一个项目,该项目在创建 CR 时不会触发任何资源生成。

初始化和创建 API

创建的项目路径位于 $GOPATH/jimmysong.io/kubebuilder-example。下文中的操作没有明确说明的话都是在该项目路径下运行。

在项目路径下使用下面的命令初始化项目。

$ kubebuilder init --domain jimmysong.io

在项目根目录下执行下面的命令创建 API。

$ kubebuilder create api --group webapp --version v1 --kind Guestbook
Create Resource under pkg/apis [y/n]?
y
Create Controller under pkg/controller [y/n]?
y
Writing scaffold for you to edit...
api/v1/guestbook_types.go
controllers/guestbook_controller.go
Running make:
$ make
/Users/jimmysong/Workspace/go/bin/controller-gen object:headerFile="hack/boilerplate.go.txt" paths="./..."
go fmt ./...
go vet ./...
go: finding github.com/onsi/ginkgo v1.11.0
go: finding github.com/onsi/gomega v1.8.1
go: finding github.com/hpcloud/tail v1.0.0
go: finding gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7
go build -o bin/manager main.go

API 创建完成后,在项目根目录下查看目录结构。

.
├── Dockerfile # 用于构建 Operator 镜像
├── Makefile # 构建时使用
├── PROJECT # 项目配置
├── api
│   └── v1
│       ├── groupversion_info.go
│       ├── guestbook_types.go
│       └── zz_generated.deepcopy.go
├── bin
│   └── manager
├── config
│   ├── certmanager
│   │   ├── certificate.yaml
│   │   ├── kustomization.yaml
│   │   └── kustomizeconfig.yaml
│   ├── crd # 新增 CRD 定义
│   │   ├── kustomization.yaml
│   │   ├── kustomizeconfig.yaml
│   │   └── patches
│   ├── default
│   │   ├── kustomization.yaml
│   │   ├── manager_auth_proxy_patch.yaml
│   │   ├── manager_webhook_patch.yaml
│   │   └── webhookcainjection_patch.yaml
│   ├── manager
│   │   ├── kustomization.yaml
│   │   └── manager.yaml
│   ├── prometheus
│   │   ├── kustomization.yaml
│   │   └── monitor.yaml
│   ├── rbac
│   │   ├── auth_proxy_client_clusterrole.yaml
│   │   ├── auth_proxy_role.yaml
│   │   ├── auth_proxy_role_binding.yaml
│   │   ├── auth_proxy_service.yaml
│   │   ├── guestbook_editor_role.yaml
│   │   ├── guestbook_viewer_role.yaml
│   │   ├── kustomization.yaml
│   │   ├── leader_election_role.yaml
│   │   ├── leader_election_role_binding.yaml
│   │   └── role_binding.yaml
│   ├── samples
│   │   └── webapp_v1_guestbook.yaml # CRD 示例
│   └── webhook
│       ├── kustomization.yaml
│       ├── kustomizeconfig.yaml
│       └── service.yaml
├── controllers # 新增 controller
│   ├── guestbook_controller.go
│   └── suite_test.go
├── go.mod
├── go.sum
├── hack
│   └── boilerplate.go.txt
└── main.go # 新增处理逻辑

15 directories, 40 files

以上就是自动初始化出来的文件。

安装 CRD

执行下面的命令安装 CRD。

$ make install
/Users/jimmysong/Workspace/go/bin/controller-gen "crd:trivialVersions=true" rbac:roleName=manager-role webhook paths="./..." output:crd:artifacts:config=config/crd/bases
kustomize build config/crd | kubectl apply -f -
customresourcedefinition.apiextensions.k8s.io/guestbooks.webapp.jimmysong.io created
$ kubectl get crd |grep jimmysong.io
guestbooks.webapp.jimmysong.io           2020-06-06T21:58:17Z

部署 controller

在开始部署 controller 之前,我们需要先检查 kubebuilder 自动生成的 YAML 文件。

修改使用 gcr.io 镜像仓库的镜像地址

对于中国大陆用户,可能无法访问 Google 镜像仓库 gcr.io,因此需要修改 config/default/manager_auth_proxy_patch.yaml 文件中的镜像地址,将其中 gcr.io/kube-rbac-proxy:v0.5.0 修改为 jimmysong/kubebuilder-kube-rbac-proxy:v0.5.0。

有两种方式运行 controller:

  • 本地运行,用于调试

  • 部署到 Kubernetes 上运行,作为生产使用

本地运行 controller

要想在本地运行 controller,只需要执行下面的命令。

make run

你将看到 controller 启动和运行时输出。

将 controller 部署到 Kubernetes

执行下面的命令部署 controller 到 Kubernetes 上,这一步将会在本地构建 controller 的镜像,并推送到 DockerHub 上,然后在 Kubernetes 上部署 Deployment 资源。

make docker-build docker-push IMG=jimmysong/kubebuilder-example:latest
make deploy IMG=jimmysong/kubebuilder-example:latest

在初始化项目时,kubebuilder 会自动根据项目名称创建一个 Namespace,如本文中的 kubebuilder-example-system,查看 Deployment 对象和 Pod 资源。

$ kubectl get deployment -n kubebuilder-example-system
NAME                                     READY   UP-TO-DATE   AVAILABLE   AGE
kubebuilder-example-controller-manager   1/1     1            1           3h26m
$ kubectl get pod -n kubebuilder-example-system
NAME                                                      READY   STATUS    RESTARTS   AGE
kubebuilder-example-controller-manager-77b4c685f9-2npz8   2/2     Running   0          3h16m

创建 CR

Kubebuilder 在初始化项目的时候已生成了示例 CR,执行下面的命令部署 CR。

kubectl apply -f config/samples/webapp_v1_guestbook.yaml

执行下面的命令查看新创建的 CR。

$ kubectl get guestbooks.webapp.jimmysong.io guestbook-sample -o yaml

你将看到类似如下的输出。

apiVersion: webapp.jimmysong.io/v1
kind: Guestbook
metadata:
  annotations:
    kubectl.kubernetes.io/last-applied-configuration: |
      {"apiVersion":"webapp.jimmysong.io/v1","kind":"Guestbook","metadata":{"annotations":{},"name":"guestbook-sample","namespace":"kubebuilder-example-system"},"spec":{"foo":"bar"}}
  creationTimestamp: "2020-06-07T01:04:48Z"
  generation: 1
  managedFields:
  - apiVersion: webapp.jimmysong.io/v1
    fieldsType: FieldsV1
    fieldsV1:
      f:metadata:
        f:annotations:
          .: {}
          f:kubectl.kubernetes.io/last-applied-configuration: {}
      f:spec:
        .: {}
        f:foo: {}
    manager: kubectl
    operation: Update
    time: "2020-06-07T01:04:48Z"
  name: guestbook-sample
  namespace: kubebuilder-example-system
  resourceVersion: "1795834"
  selfLink: /apis/webapp.jimmysong.io/v1/namespaces/kubebuilder-example-system/guestbooks/guestbook-sample
  uid: 051a4266-7f5a-4c57-8180-64222d462bba
spec:
  foo: bar

至此一个基本的 Operator 框架已经创建完成,但这个 Operator 只是修改了 etcd 中的数据而已,实际上什么事情也没做,因为我们没有在 Operator 中的增加业务逻辑。

增加业务逻辑

下面我们将修改 CRD 的数据结构并在 controller 中增加一些日志输出。

修改 CRD

我们将修改上文中使用 kubebuilder 命令生成的默认 CRD 配置,在 CRD 中增加 FirstName、LastName 和 Status 字段。

下面是修改后的 api/v1/guestbook_types.go 文件的内容,对应修改的地方已在代码中注释说明。

/*


Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package v1

import (
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)

// EDIT THIS FILE!  THIS IS SCAFFOLDING FOR YOU TO OWN!
// NOTE: json tags are required.  Any new fields you add must have json tags for the fields to be serialized.

// GuestbookSpec defines the desired state of Guestbook
type GuestbookSpec struct {
	// INSERT ADDITIONAL SPEC FIELDS - desired state of cluster
	// Important: Run "make" to regenerate code after modifying this file

	// Foo is an example field of Guestbook. Edit Guestbook_types.go to remove/update
  // 添加两个新的字段
	FirstName string `json:"firstname"`
	LastName  string `json:"lastname"`
}

// GuestbookStatus defines the observed state of Guestbook
type GuestbookStatus struct {
	// INSERT ADDITIONAL STATUS FIELD - define observed state of cluster
	// Important: Run "make" to regenerate code after modifying this file
	Status string `json:"Status"`
}

// +kubebuilder:object:root=true
// 在这里增加 status 的说明
// +kubebuilder:subresource:status

// Guestbook is the Schema for the guestbooks API
type Guestbook struct {
	metav1.TypeMeta   `json:",inline"`
	metav1.ObjectMeta `json:"metadata,omitempty"`

	Spec   GuestbookSpec   `json:"spec,omitempty"`
	Status GuestbookStatus `json:"status,omitempty"`
}

// +kubebuilder:object:root=true

// GuestbookList contains a list of Guestbook
type GuestbookList struct {
	metav1.TypeMeta `json:",inline"`
	metav1.ListMeta `json:"metadata,omitempty"`
	Items           []Guestbook `json:"items"`
}

func init() {
	SchemeBuilder.Register(&Guestbook{}, &GuestbookList{})
}

上面的代码比原先使用 kubebuilder 生成的默认代码增加了以下内容:

	FirstName string `json:"firstname"`
	LastName  string `json:"lastname"`
	Status string `json:"Status"`
// +kubebuilder:subresource:status

修改 Reconcile 函数

Reconcile 函数是 Operator 的核心逻辑,Operator 的业务逻辑都位于 controllers/guestbook_controller.go 文件的 func (r *GuestbookReconciler) Reconcile(req ctrl.Request) (ctrl.Result, error) 函数中。

// +kubebuilder:rbac:groups=webapp.jimmysong.io,resources=guestbooks,verbs=get;list;watch;create;update;patch;delete
// +kubebuilder:rbac:groups=webapp.jimmysong.io,resources=guestbooks/status,verbs=get;update;patch

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

	// your logic here
	ctx := context.Background()
	_ = r.Log.WithValues("apiexamplea", req.NamespacedName)

  // 获取当前的 CR,并打印
	obj := &webappv1.Guestbook{}
	if err := r.Get(ctx, req.NamespacedName, obj); err != nil {
		log.Println(err, "Unable to fetch object")
	} else {
		log.Println("Geeting from Kubebuilder to", obj.Spec.FirstName, obj.Spec.LastName)
	}
  
  // 初始化 CR 的 Status 为 Running
	obj.Status.Status = "Running"
	if err := r.Status().Update(ctx, obj); err != nil {
		log.Println(err, "unable to update status")
	}

	return ctrl.Result{}, nil
}

这段代码的业务逻辑是当发现有 guestbooks.webapp.jimmysong.io 的 CR 变更时,在控制台中输出日志。

运行测试

修改好 Operator 的业务逻辑后,再测试一下新的逻辑是否可以正常运行。

部署 CRD

跟上文的做法一样,执行下面的命令部署 CRD。

make install

运行 controller

跟上文的做法一样,执行下面的命令运行 controller。为了方便起见,我们将在本地运行 controller,当然您也可以将其部署到 Kubernetes 上运行。

make run

保持该窗口在前台运行。

部署 CR

修改 config/samples/webapp_v1_guestbook.yaml 文件中的配置。

apiVersion: webapp.jimmysong.io/v1
kind: Guestbook
metadata:
  name: guestbook-sample
spec:
  # Add fields here
  firstname: Jimmy
  lastname: Song

将其应用到 Kubernetes。

kubectl apply -f config/samples/webapp_v1_guestbook.yaml

此时转到上文中运行 controller 的窗口,将在命令行前台中看到如下输出。

go fmt ./...
go vet ./...
/Users/jimmysong/Workspace/go/bin/controller-gen "crd:trivialVersions=true" rbac:roleName=manager-role webhook paths="./..." output:crd:artifacts:config=config/crd/bases
go run ./main.go
2020-06-07T16:48:29.966+0800	INFO	controller-runtime.metrics	metrics server is starting to listen	{"addr": ":8080"}
2020-06-07T16:48:29.967+0800	INFO	setup	starting manager
2020-06-07T16:48:29.967+0800	INFO	controller-runtime.manager	starting metrics server	{"path": "/metrics"}
2020-06-07T16:48:29.967+0800	INFO	controller-runtime.controller	Starting EventSource	{"controller": "guestbook", "source": "kind source: /, Kind="}
2020-06-07T16:48:30.068+0800	INFO	controller-runtime.controller	Starting Controller	{"controller": "guestbook"}
2020-06-07T16:48:30.068+0800	INFO	controller-runtime.controller	Starting workers	{"controller": "guestbook", "worker count": 1}
2020/06/07 16:48:30 Geeting from Kubebuilder to Jimmy Song
2020-06-07T16:48:30.080+0800	DEBUG	controller-runtime.controller	Successfully Reconciled	{"controller": "guestbook", "request": "kubebuilder-example-system/guestbook-sample"}

从上面的日志中,可以看到这条输出。

2020/06/07 16:48:30 Geeting from Kubebuilder to Jimmy Song

这正是在 Reconcile 函数中的输出。

获取当前的 CR

使用下面的命令获取当前的 CR。

# kubectl get guestbooks.webapp.jimmysong.io guestbook-sample -o yaml

将看到如下输出。

apiVersion: webapp.jimmysong.io/v1
kind: Guestbook
metadata:
  annotations:
    kubectl.kubernetes.io/last-applied-configuration: |
      {"apiVersion":"webapp.jimmysong.io/v1","kind":"Guestbook","metadata":{"annotations":{},"name":"guestbook-sample","namespace":"kubebuilder-example-system"},"spec":{"firstname":"Jimmy","lastname":"Song"}}
  creationTimestamp: "2020-06-07T02:54:46Z"
  generation: 1
  managedFields:
  - apiVersion: webapp.jimmysong.io/v1
    fieldsType: FieldsV1
    fieldsV1:
      f:metadata:
        f:annotations:
          .: {}
          f:kubectl.kubernetes.io/last-applied-configuration: {}
      f:spec:
        .: {}
        f:firstname: {}
        f:lastname: {}
    manager: kubectl
    operation: Update
    time: "2020-06-07T02:54:46Z"
  - apiVersion: webapp.jimmysong.io/v1
    fieldsType: FieldsV1
    fieldsV1:
      f:status:
        .: {}
        f:Status: {}
    manager: main
    operation: Update
    time: "2020-06-07T02:56:38Z"
  name: guestbook-sample
  namespace: kubebuilder-example-system
  resourceVersion: "1813769"
  selfLink: /apis/webapp.jimmysong.io/v1/namespaces/kubebuilder-example-system/guestbooks/guestbook-sample
  uid: 17da5eae-1020-40d2-821a-9a1f990dd767
spec:
  firstname: Jimmy
  lastname: Song
status:
  Status: Running

我们输出的最后部分:

spec:
  firstname: Jimmy
  lastname: Song
status:
  Status: Running

这正是我们在 CRD 里定义的字段。

删除 CR

使用下面的命令删除 CR。

kubectl delete guestbooks.webapp.jimmysong.io guestbook-sample

此时在 controller 的前台输出中可以看到以下内容。

2020/06/07 20:09:50 Guestbook.webapp.jimmysong.io "guestbook-sample" not found Unable to fetch object
2020/06/07 20:09:50 resource name may not be empty unable to update status
2020-06-07T20:09:50.380+0800	DEBUG	controller-runtime.controller	Successfully Reconciled	{"controller": "guestbook", "request": "kubebuilder-example-system/guestbook-sample"}

因为该 CR 被删除,因此日志中会提示资源找不到。

更多

本示例仅展示了使用 kubebuilder 创建 Operator 的基本逻辑,步骤为:

  • 初始化项目和 API

  • 安装 CRD

  • 部署 Controller

  • 创建 CR

参考

到 kubebuilder 的 上下载与您操作系统对应的 kubebuilder 安装包。

Operator 的核心逻辑都在 controller 的 Reconcile 函数中,请参考 中的 Operator 实现,本书后续将会讨论。

DNS lookup not working when starting minikube with --dns-domain #1674
GitHub release 页面
Awesome Cloud Native
如何使用 KubeBuilder 开发一个 Operator - chenshaowen.com
Kubernetes CRD 如何简单 - sealyun.com
Kubebuilder book - kubebuilder.io