介绍
Kubernetes 可以通过新的资源类型进行扩展。自定义资源定义(CustomResourceDefinition,简称 CRD)用于向 Kubernetes API 服务器注册新的 API 资源。注册完成后,你就可以使用熟悉的 kubectl 命令来创建、获取、描述、标记和修补(patch)这些新类型的对象。
在本实验中,你将创建一个名为 AppProfile 的小型命名空间级 CRD,通过 Kubernetes API 发现命令来识别它,从 YAML 文件创建自定义资源,并像操作常规 Kubernetes 对象一样更新它们。本实验不需要控制器;重点在于理解自定义资源类型是如何呈现的,以及如何操作这些对象。
准备自定义资源命名空间
在此步骤中,你将准备一个干净的命名空间,用于自定义资源的练习。
从 /home/labex/project 开始。你将在该目录下编写 CRD 和自定义资源清单。
mkdir -p /home/labex/project
cd /home/labex/project
检查 Kubernetes API 服务器是否可访问。如果虚拟机刚启动且节点尚未就绪,请等待几秒钟后再运行该命令。
kubectl get nodes --request-timeout=5s
预期输出包括:
NAME STATUS ROLES AGE VERSION
labex-v135 Ready control-plane ... v1.35...
在创建应用程序对象之前,请等待集群网络 Pod 处于就绪(Ready)状态。
kubectl wait --namespace kube-system --for=condition=Ready pod -l k8s-app=calico-node --timeout=120s
预期输出:
pod/calico-node-... condition met
创建一个名为 ckad-prep-customresources 的命名空间:
kubectl create namespace ckad-prep-customresources
将此命名空间设置为当前上下文的命名空间:
kubectl config set-context --current --namespace=ckad-prep-customresources
确认当前命名空间:
kubectl config view --minify --output 'jsonpath={..namespace}'; echo
预期输出:
ckad-prep-customresources
使用 CRD 注册新的资源类型
在此步骤中,你将创建一个名为 AppProfile 的自定义资源定义(CRD)。
CRD 有两个重要的命名层级。metadata.name 是复数资源名称加上 API 组,例如 appprofiles.training.labex.io。spec.names 部分定义了用户如何引用该资源:kind: AppProfile、plural: appprofiles、singular: appprofile 以及简写名称 appprof。
创建 app-profile-crd.yaml:
cat > app-profile-crd.yaml <<'EOF'
apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
name: appprofiles.training.labex.io
spec:
group: training.labex.io
scope: Namespaced
names:
plural: appprofiles
singular: appprofile
kind: AppProfile
shortNames:
- appprof
versions:
- name: v1
served: true
storage: true
schema:
openAPIV3Schema:
type: object
properties:
spec:
type: object
required:
- image
- replicas
properties:
image:
type: string
replicas:
type: integer
minimum: 1
tier:
type: string
EOF
应用 CRD:
kubectl apply -f app-profile-crd.yaml
预期输出:
customresourcedefinition.apiextensions.k8s.io/appprofiles.training.labex.io created
等待 API 服务器报告 CRD 已建立(Established):
kubectl wait --for=condition=Established crd/appprofiles.training.labex.io --timeout=120s
预期输出:
customresourcedefinition.apiextensions.k8s.io/appprofiles.training.labex.io condition met
检查 CRD 的名称和作用域:
kubectl get crd appprofiles.training.labex.io -o 'jsonpath={.spec.names.kind}{" "}{.spec.names.plural}{" "}{.spec.scope}{"\n"}'
预期输出:
AppProfile appprofiles Namespaced
发现并创建自定义资源
在此步骤中,你将发现新的资源类型并创建你的第一个 AppProfile。
kubectl api-resources 会列出 API 服务器已知的资源类型。CRD 建立后,它会出现在此发现输出中,与内置资源类型并列。
kubectl api-resources --api-group=training.labex.io
预期输出包括:
NAME SHORTNAMES APIVERSION NAMESPACED KIND
appprofiles appprof training.labex.io/v1 true AppProfile
使用 kubectl explain 读取 Kubernetes 从 CRD 中学习到的模式。spec 字段是存放应用程序特定设置的地方。
kubectl explain appprofile.spec
预期输出包括:
GROUP: training.labex.io
KIND: AppProfile
VERSION: v1
FIELD: spec <Object>
创建 frontend-profile.yaml:
cat > frontend-profile.yaml <<'EOF'
apiVersion: training.labex.io/v1
kind: AppProfile
metadata:
name: frontend
labels:
app.kubernetes.io/part-of: storefront
tier: web
spec:
image: nginx:1.27
replicas: 2
tier: web
EOF
应用自定义资源:
kubectl apply -f frontend-profile.yaml
预期输出:
appprofile.training.labex.io/frontend created
使用复数名称列出自定义资源:
kubectl get appprofiles
预期输出包括:
NAME AGE
frontend ...
使用 jsonpath 读取自定义资源中的字段:
kubectl get appprofile frontend -o 'jsonpath={.spec.image}{" "}{.spec.replicas}{" "}{.spec.tier}{"\n"}'
预期输出:
nginx:1.27 2 web
更新并筛选自定义资源
在此步骤中,你将使用与内置对象相同的 kubectl 模式来管理自定义资源。
修补(Patch)frontend 自定义资源以更改其所需的副本数。--type=merge 选项告诉 Kubernetes 将你的 JSON 对象合并到现有对象中,而不是替换整个资源。
kubectl patch appprofile frontend --type=merge -p '{"spec":{"replicas":3}}'
预期输出:
appprofile.training.labex.io/frontend patched
确认更新后的值:
kubectl get appprofile frontend -o 'jsonpath={.spec.replicas}{"\n"}'
预期输出:
3
创建第二个名为 worker 的自定义资源:
cat > worker-profile.yaml <<'EOF'
apiVersion: training.labex.io/v1
kind: AppProfile
metadata:
name: worker
labels:
app.kubernetes.io/part-of: storefront
tier: worker
spec:
image: busybox:1.36
replicas: 1
tier: worker
EOF
kubectl apply -f worker-profile.yaml
预期输出:
appprofile.training.labex.io/worker created
仅列出属于 storefront 应用程序的自定义资源。由于自定义资源支持标准的 Kubernetes 标签,因此该操作有效。
kubectl get appprofiles -l app.kubernetes.io/part-of=storefront
预期输出包括:
NAME AGE
frontend ...
worker ...
使用简写名称 appprof 打印每个资源的名称和副本数:
kubectl get appprof -o 'jsonpath={range .items[*]}{.metadata.name}{"="}{.spec.replicas}{"\n"}{end}'
预期输出包括:
frontend=3
worker=1
总结
你创建了一个 CRD,等待其建立,通过 kubectl api-resources 和 kubectl explain 发现了新的 API 资源,创建了自定义资源,修补了自定义资源,按标签进行了筛选,并使用了简写名称。这些操作技能与你在 CKAD 任务中处理由 Operator、控制器或平台扩展安装的资源时所使用的技能完全一致。


