介绍
Kubernetes API 会不断演进。在旧集群上运行正常的清单文件,可能会因为 API 版本被移除或字段结构发生变化而在新集群上失效。在 CKAD 的工作中,这通常表现为一项实际的维护任务:阅读错误信息、确定当前的 API 版本、更新清单,并验证新版本已被集群接受。
在本实验中,你将把一个旧的 Ingress 清单从 networking.k8s.io/v1beta1 迁移到 networking.k8s.io/v1。你将首先创建一个供 Ingress 引用的 Service,观察旧清单报错,使用 kubectl 发现命令检查当前的 API,重写清单,最后应用修正后的 Ingress。
准备 Service 引用
在此步骤中,你将准备一个干净的命名空间和一个简单的 Service。旧的和新的 Ingress 清单都将指向此 Service,这样迁移工作的重点将保持在 API 结构上,而不是 Pod 的就绪状态或流量路由上。
从 /home/labex/project 开始:
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...
创建一个名为 ckad-prep-api-migration 的命名空间,并将其设置为当前命名空间:
kubectl create namespace ckad-prep-api-migration
kubectl config set-context --current --namespace=ckad-prep-api-migration
创建一个名为 app-web 的 ClusterIP Service。--tcp=80:80 选项表示 Service 监听端口 80,如果存在匹配的 Pod,它会将流量转发到目标端口 80。对于本次迁移实验,Service 对象本身就足够了,因为你验证的是 Ingress API 字段,而不是 HTTP 流量。
kubectl create service clusterip app-web --tcp=80:80
确认 Service 已存在:
kubectl get service app-web
预期输出包括:
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
app-web ClusterIP ... <none> 80/TCP ...
观察已弃用清单的失败情况
在此步骤中,你将创建一个旧的 Ingress 清单,并让当前集群拒绝它。这是一种很有用的练习,因为迁移任务中的第一个线索通常就是 API 服务器的错误消息。
创建 old-ingress.yaml:
cat > old-ingress.yaml <<'EOF'
apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
name: app-web
spec:
rules:
- host: app.example.local
http:
paths:
- path: /
backend:
serviceName: app-web
servicePort: 80
EOF
读取文件的前几行。apiVersion 字段告诉 Kubernetes 应该由哪个 API 组和版本来处理此对象。
sed -n '1,20p' old-ingress.yaml
预期输出包括:
apiVersion: networking.k8s.io/v1beta1
kind: Ingress
...
serviceName: app-web
servicePort: 80
请求 API 服务器验证该清单而不创建它。--dry-run=server 会将对象发送到 API 服务器进行验证,而 || true 可以让教程继续进行,因为这种失败是预料之中的。
kubectl apply --dry-run=server -f old-ingress.yaml || true
预期输出包含类似以下的错误:
error: resource mapping not found for name: "app-web" namespace: "" from "old-ingress.yaml": no matches for kind "Ingress" in version "networking.k8s.io/v1beta1"
重要的证据是 no matches for kind "Ingress" in version "networking.k8s.io/v1beta1"。这意味着当前集群不再提供此 API 版本。
发现当前的 Ingress API 结构
在此步骤中,你将在重写文件之前检查当前的 Ingress API。这是保持迁移工作规范化的关键部分:当集群可以向你展示可接受的结构时,不要去猜测新的字段。
列出当前提供的 Ingress 资源:
kubectl api-resources | grep -i '^ingresses'
预期输出包括:
ingresses ing networking.k8s.io/v1 true Ingress
使用 kubectl explain 检查当前的后端 Service 字段。路径很长,因为 Service 后端嵌套在 spec.rules[].http.paths[].backend.service 下。
kubectl explain ingress.spec.rules.http.paths.backend.service --recursive | sed -n '1,80p'
预期输出包括:
GROUP: networking.k8s.io
KIND: Ingress
VERSION: v1
FIELD: service <IngressServiceBackend>
...
name <string> -required-
port <ServiceBackendPort> -required-
现在创建迁移后的 current-ingress.yaml。新清单使用了 networking.k8s.io/v1,添加了 pathType,并将 serviceName 和 servicePort 替换为嵌套的 service.name 和 service.port.number 字段。
cat > current-ingress.yaml <<'EOF'
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: app-web
spec:
rules:
- host: app.example.local
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: app-web
port:
number: 80
EOF
通过服务端试运行(server-side dry run)验证迁移后的清单:
kubectl apply --dry-run=server -f current-ingress.yaml
预期输出:
ingress.networking.k8s.io/app-web created (server dry run)
应用并检查迁移后的 Ingress
在此步骤中,你将创建迁移后的 Ingress 并检查 Kubernetes 存储的字段。应用资源是证明清单现在符合当前 API 服务器要求的最终证据。
应用迁移后的清单:
kubectl apply -f current-ingress.yaml
预期输出:
ingress.networking.k8s.io/app-web created
列出 Ingress:
kubectl get ingress app-web
预期输出包括:
NAME CLASS HOSTS ADDRESS PORTS AGE
app-web ... app.example.local ... 80 ...
直接从存储的对象中检查迁移后的后端字段:
kubectl get ingress app-web -o jsonpath='{.apiVersion}{" "}{.spec.rules[0].http.paths[0].pathType}{" "}{.spec.rules[0].http.paths[0].backend.service.name}{":"}{.spec.rules[0].http.paths[0].backend.service.port.number}{"\n"}'
预期输出:
networking.k8s.io/v1 Prefix app-web:80
此输出同时证明了三件事:对象使用了当前的 API 版本,路径具有明确的 pathType,并且后端使用了 networking.k8s.io/v1 所要求的嵌套 Service 引用。
总结
你练习了一个实用的 API 迁移工作流。你创建了一个旧的 networking.k8s.io/v1beta1 Ingress 清单,使用服务端试运行确认当前集群拒绝了它,检查了当前提供的 networking.k8s.io/v1 API,通过添加 pathType 和嵌套的 Service 引用重写了后端字段,最后应用并检查了迁移后的 Ingress。


