3. 创建第一个 Operator 项目:项目初始化与结构解析

本章将带领你从零开始创建一个标准的 Operator 项目,深入理解 operator-sdk init 命令生成的项目骨架、核心目录结构以及构建配置文件(Makefile 与 Dockerfile)的作用。这是后续实现资源配额分配策略的基础工程环境。

3.1 使用 operator-sdk init 初始化项目

在开始之前,请确保已安装 operator-sdk CLI 工具(推荐 v1.30+)并配置好 Go 1.21+ 环境。执行以下命令创建项目:

# 创建项目目录并进入
mkdir quota-operator && cd quota-operator

# 初始化项目,使用 Go 语言,指定 API 组和版本
operator-sdk init \
  --domain=example.com \
  --repo=github.com/example/quota-operator \
  --language=go \
  --owner="Your Name" \
  --project-name=quota-operator
关键参数说明:
  • --domain:API 组的域名部分,通常使用公司或组织域名,如 example.com。
  • --repo:Go module 路径,与 go.mod 中的 module 名称一致。
  • --language=go:目前 Operator SDK 主要支持 Go、Ansible、Helm 三种语言,本课程聚焦 Go。
  • --project-name:项目名称,默认使用当前目录名。

初始化成功后,终端会输出类似以下信息:

Writing kustomize manifests for you to edit...
Writing scaffold for you to edit...
Get controller runtime:
  go get sigs.k8s.io/controller-runtime@v0.17.0
Update dependencies:
  go mod tidy
Next: define a resource with:
  operator-sdk create api

3.2 项目结构深度解析

初始化完成后,项目根目录下会生成一套完整的脚手架文件。下表列出了核心目录和文件的作用:

目录/文件 作用 是否需手动修改
main.go 程序入口,初始化 Manager、注册 Scheme、启动控制器 是(添加新控制器时)
api/ 存放自定义资源(CRD)的 Go 类型定义和验证逻辑 是(定义资源配额结构)
controllers/ 存放控制器(Reconciler)逻辑,实现调谐循环 是(核心业务代码)
config/ Kustomize 配置清单,包括 RBAC、CRD、Webhook 等 是(部署时调整)
Makefile 构建、测试、部署的自动化脚本 是(扩展构建参数)
Dockerfile 多阶段构建镜像,编译 Go 二进制并生成最小运行镜像 是(优化镜像大小)
go.mod / go.sum Go 模块依赖管理 自动维护
hack/ 存放代码生成脚本(如 boilerplate.go.txt) 通常不修改

下图展示了项目初始化后的核心文件依赖关系与数据流向:

Operator 项目初始化结构图 main.go api/ (CRD 类型) controllers/ (Reconciler) config/ (Kustomize) Makefile Dockerfile go.mod / go.sum Operator 二进制 / 容器镜像

3.3 Makefile 详解

生成的 Makefile 是 Operator 项目的自动化构建核心。它封装了以下关键操作:

  • 构建(build):编译 Go 二进制文件,输出到 bin/manager。
  • 镜像构建与推送(docker-build / docker-push):调用 Docker 构建镜像并推送到指定仓库。
  • 部署(deploy):使用 Kustomize 生成并应用 Kubernetes 资源清单。
  • 测试(test):运行单元测试和集成测试。
  • 代码生成(generate):触发 controller-gen 生成 CRD 清单和 RBAC 规则。

核心变量说明:

变量名 默认值 说明
IMG controller:latest 容器镜像标签,构建时可通过 make docker-build IMG=myrepo/myop:v1 覆盖
KUSTOMIZE $(shell which kustomize) Kustomize 可执行文件路径
ENVTEST_K8S_VERSION 1.28.0 环境测试使用的 Kubernetes 版本
实战建议:在开发阶段,建议使用 make install 将 CRD 安装到当前集群,使用 make run 在本地运行 Operator(无需构建镜像),加快调试速度。

3.4 Dockerfile 详解

生成的 Dockerfile 采用多阶段构建策略,分为两个阶段:

  1. 构建阶段(builder):基于 golang:1.21 镜像,编译 Go 代码,生成静态链接的二进制文件。
  2. 运行阶段:基于 gcr.io/distroless/static:nonroot 最小镜像,仅包含二进制文件和必要的 CA 证书,确保安全性和最小攻击面。

关键代码片段:

# 构建阶段
FROM golang:1.21 AS builder
WORKDIR /workspace
COPY go.mod go.mod
COPY go.sum go.sum
RUN go mod download
COPY . .
RUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -a -o manager main.go

# 运行阶段
FROM gcr.io/distroless/static:nonroot
WORKDIR /
COPY --from=builder /workspace/manager .
USER 65532:65532
ENTRYPOINT ["/manager"]
注意:如果 Operator 需要访问集群外的 HTTPS 服务(如外部 API),需要在运行阶段添加 CA 证书:COPY --from=builder /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/。

下图展示了 Dockerfile 的多阶段构建流程:

Dockerfile 多阶段构建流程 阶段1: builder golang:1.21 镜像 编译 → manager 二进制 阶段2: 运行镜像 distroless/static:nonroot 仅含 manager + CA 证书 最终镜像: 约 20MB

3.5 初始化后的下一步操作

项目初始化完成后,建议按以下顺序进行验证:

  1. 检查依赖:运行 go mod tidy 确保所有依赖正确下载。
  2. 编译测试:运行 make build 确认二进制文件生成成功。
  3. 本地运行:使用 make install && make run 在本地启动 Operator(需连接 Kubernetes 集群)。
  4. 查看生成清单:检查 config/crd 和 config/rbac 目录下的 YAML 文件是否完整。
最佳实践:在开始编写控制器逻辑前,先提交一次初始化后的代码到 Git,记录干净的脚手架状态。后续所有修改都可以通过 git diff 清晰追踪。