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) |
通常不修改 |
下图展示了项目初始化后的核心文件依赖关系与数据流向:
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 采用多阶段构建策略,分为两个阶段:
- 构建阶段(builder):基于
golang:1.21镜像,编译 Go 代码,生成静态链接的二进制文件。 - 运行阶段:基于
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 的多阶段构建流程:
3.5 初始化后的下一步操作
项目初始化完成后,建议按以下顺序进行验证:
- 检查依赖:运行
go mod tidy确保所有依赖正确下载。 - 编译测试:运行
make build确认二进制文件生成成功。 - 本地运行:使用
make install && make run在本地启动 Operator(需连接 Kubernetes 集群)。 - 查看生成清单:检查
config/crd和config/rbac目录下的 YAML 文件是否完整。
最佳实践:在开始编写控制器逻辑前,先提交一次初始化后的代码到 Git,记录干净的脚手架状态。后续所有修改都可以通过
git diff 清晰追踪。