第一步:编写 CRD 的"蓝图" (YAML 文件)
首先,我们需要告诉 Kubernetes 这个新资源长什么样。新建一个名为 myapp-crd.yaml 的文件,填入以下内容:
apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
name: mycomplexapps.example.com # 命名格式:<复数名>.<组名>
spec:
group: example.com # API 组
scope: Namespaced # 作用域:Namespaced(命名空间级)或 Cluster(集群级)
names:
plural: mycomplexapps
singular: mycomplexapp
kind: MyComplexApp # 资源类型名
shortNames: [mca] # 简写,比如可以用 kubectl get mca
versions:
- name: v1
served: true
storage: true
schema:
openAPIV3Schema:
type: object
properties:
spec:
type: object
properties:
# ================== 1. 副本与基础调度 ==================
replicas:
type: integer
minimum: 0
default: 1
description: 期望的副本数量(对应 Deployment 的 replicas)
podTemplate:
type: object
properties:
metadata:
type: object
description: Pod 的元数据(如 labels, annotations)
spec:
type: object
properties:
# ================== 2. 容器与镜像模板 ==================
containers:
type: array
description: 容器定义列表(对应 Pod.spec.containers)
items:
type: object
properties:
name:
type: string
description: 容器名称
image:
type: string
description: 容器镜像地址(如 nginx:1.25)
command:
type: array
items: { type: string }
description: 容器启动命令(覆盖 Dockerfile 的 ENTRYPOINT)
args:
type: array
items: { type: string }
description: 启动参数(覆盖 Dockerfile 的 CMD)
ports:
type: array
items:
type: object
properties:
containerPort: { type: integer }
name: { type: string }
# --- CPU、内存、GPU 等资源限制 ---
resources:
type: object
properties:
limits:
type: object
properties:
cpu: { type: string, description: "CPU上限,如 '500m', '2'" }
memory: { type: string, description: "内存上限,如 '512Mi', '2Gi'" }
# GPU 资源通常以扩展资源形式存在,比如 nvidia.com/gpu
nvidia.com/gpu: { type: string, description: "GPU数量,如 '1'" }
requests:
type: object
properties:
cpu: { type: string, description: "CPU请求量" }
memory: { type: string, description: "内存请求量" }
nvidia.com/gpu: { type: string, description: "GPU请求量" }
# --- 环境变量 ---
env:
type: array
items:
type: object
properties:
name: { type: string }
value: { type: string }
# 也可以从 ConfigMap 或 Secret 中引用值
valueFrom:
type: object
properties:
configMapKeyRef:
type: object
properties:
name: { type: string }
key: { type: string }
secretKeyRef:
type: object
properties:
name: { type: string }
key: { type: string }
# --- 容器内的存储卷挂载点 ---
volumeMounts:
type: array
items:
type: object
properties
第二步:将 CRD 注册到 Kubernetes 集群
写好蓝图后,使用 kubectl 把它提交给集群:
# 应用 CRD
kubectl apply -f myapp-crd.yaml
# 验证 CRD 是否创建成功
kubectl get crd | grep myapps
# 如果成功,你会看到类似 myapps.example.com 的输出
第三步:创建自定义资源实例 (CR)
CRD 注册成功后,Kubernetes 就认识 MyApp 这种新类型了。现在你可以像创建 Pod 一样,创建一个 MyApp 的实例。新建一个 myapp-sample.yaml 文件:
apiVersion: example.com/v1 # 注意这里的 apiVersion 是 <组>/<版本>
kind: MyApp # 这里的 kind 对应 CRD 里定义的 names.kind
metadata:
name: my-first-app
spec:
replicas: 3
image: nginx:latest
然后把它应用到集群中:
# 创建自定义资源实例
kubectl apply -f myapp-sample.yaml
# 查看你创建的自定义资源(可以用复数,也可以用简写 ma)
kubectl get myapp
# 或者
kubectl get ma
补充
文件夹里存放多个独立的 YAML 文件
my-k8s-app/
├── crd.yaml # 你的"蓝图":定义 MyApp 这种新资源
├── my-app-config.yaml # 具体的"实例":包含 ConfigMap、Secret(密码卷)
└── my-app-instance.yaml # 具体的"实例":创建 MyApp,填写 CPU/GPU、副本数、挂载卷等
你只需要在文件夹的上一级目录,执行这条命令,K8s 就会自动把这个文件夹里所有的 YAML 文件全部应用
kubectl apply -f my-k8s-app/
进阶提示:让 CRD 真正"动"起来
走到这一步,你已经成功在 K8s 里创建了一个可以存储的自定义对象。但你会发现,光有上面的配置,这个 MyApp 只是静静地躺在 etcd 数据库里,它不会自动帮你创建出 3 个 Nginx 容器。
如果你想让它像 Deployment 一样真正干活(比如自动创建 Pod、自动扩容),你就需要编写一个 自定义控制器(Controller)。
- CRD 只是定义了"数据结构"(蓝图)。
- Controller 才是"大脑和手脚",它负责监听你创建的
MyApp实例,并根据spec里的要求,去真正创建底层的 Pod 和 Service。
在实际生产中,大家通常不会纯手写这些代码,而是使用 Kubebuilder 或 Operator SDK 这样的脚手架工具,它们能帮你自动生成 CRD 定义和控制器的基础代码框架,极大地提升开发效率。