【高校竞赛实战】腾讯云助手辅助云原生竞赛:5 分钟从题目到生产级 K8s YAML 配置

摘要:全国职业院校技能大赛、华为 ICT、CKA/CKS、各类云计算赛项中,K8s 编排是最核心的得分点。本文以一道真实的省赛模拟题为例,演示如何用腾讯云助手在 5 分钟内生成可直接 kubectl apply 通过的生产级 YAML——包含 Deployment、Service、Ingress、HPA、ConfigMap、StatefulSet、NetworkPolicy、PDB,并附竞赛现场最实用的 YAML 校验与排错技巧。

关键词:云原生竞赛 / Kubernetes / K8s YAML / 腾讯云助手 / 高校竞赛 / 容器编排 / CKA


一、竞赛题长什么样:先读懂"隐藏得分点"

模拟一道省赛题:

题目:在 prod-app 命名空间部署一个三层应用。

  1. 前端 nginx 3 副本,对外暴露(Ingress 域名 app.exam.local);
  2. 后端 api 3 副本,Go 应用,端口 8080,需读取配置和密钥;
  3. 数据库 mysql 单实例,需要持久化存储;
  4. 后端需支持自动扩缩容(CPU 70%);
  5. 所有 Pod 需配置资源限制与健康探针;
  6. 数据库只允许后端访问。

新手常见做法:把 6 个 YAML 文件分别写出来,kubectl apply 能跑就算完。

拿不到高分的原因:题目里"隐藏"了至少 10 个评分点,而这些点恰恰是阅卷脚本/裁判重点看的:

隐藏得分点为什么重要
resources.requests/limits 都写HPA 依赖 requests,缺了 HPA 不生效
三种探针(startup/readiness/liveness)只写 liveness 容易导致启动期重启循环
labels 用 app.kubernetes.io/* 规范Service selector 匹配的基准
securityContext(runAsNonRoot 等)CKS/等保类考点
imagePullPolicy用 latest 会被判不规范
PDB滚动更新/节点维护可用性考点
NetworkPolicy 的 ingress 规则题目第 6 条,最容易漏
StatefulSet + headless Service数据库正确姿势
rollingUpdate 参数maxSurge/maxUnavailable
命名空间隔离与 ResourceQuota多租户考点

结论:竞赛比的不是"能不能跑",而是**“有没有把所有得分点写全”**。这正好是 AI 助手最擅长的——它不会忘记写探针。


二、用腾讯云助手生成配置:提示词是关键

2.1 别这么问(结果会很水)

帮我写一个 k8s 部署 nginx 的 yaml

它会给你一个 30 行的 Deployment,跟题目无关。

2.2 应该这么问(结构化 + 约束 + 校验要求)

角色:你是通过 CKA/CKS 认证的 Kubernetes 工程师,正在参加云原生竞赛。

任务:根据下面的赛题,生成完整的多文件 YAML 清单。

【赛题】
(粘贴题目原文,含命名空间、副本数、端口、域名、存储、扩缩容、访问控制要求)

【硬性约束】
1. 每个资源单独一个文件,命名规范:01-namespace.yaml、10-deployment-api.yaml ...
2. 所有资源带标签:app.kubernetes.io/name、app.kubernetes.io/component、app.kubernetes.io/part-of=prod-app
3. 必须包含:Namespace、ResourceQuota、LimitRange、ConfigMap、Secret、Deployment×2、
   StatefulSet、Service×3(ClusterIP/Headless/NodePort)、Ingress、HPA、PDB、NetworkPolicy
4. 每个容器必须有 resources.requests 与 limits、startup/readiness/liveness 三种探针
5. 不使用 latest 镜像标签;apiVersion 与当前主流版本(v1.29+)保持一致
6. 不要使用已废弃字段(如 extensions/v1beta1、autoscaling/v2beta2)
7. 每个文件顶部用注释说明"这个文件对应赛题第几条要求"

【输出要求】
- 先输出一份"赛题要求 → 资源文件"的映射表,确认无遗漏
- 再输出 YAML,用 --- 分隔并标注文件名
- 最后输出一个"自检清单",逐条说明如何验证每个要求已满足(给出 kubectl 命令)

关键点:把"赛题 → 资源文件"的映射表放在最前面,可以立刻发现漏项——这在竞赛现场比写得快更重要。


三、生成结果实录(可直接用)

3.1 映射表(助手先输出的)

赛题要求对应资源文件
命名空间隔离Namespace + ResourceQuota + LimitRange01 / 02 / 03
前端 nginx 3 副本Deployment + Service10 / 11
对外暴露域名Ingress12
后端 api 3 副本 8080Deployment + Service20 / 21
读取配置与密钥ConfigMap + Secret22 / 23
数据库持久化StatefulSet + Headless Service + PVC 模板30 / 31
自动扩缩容 CPU70%HPA40
高可用PDB41
数据库仅后端可访问NetworkPolicy50

3.2 01-namespace.yaml

# 对应赛题:命名空间隔离
apiVersion: v1
kind: Namespace
metadata:
  name: prod-app
  labels:
    app.kubernetes.io/part-of: prod-app
    pod-security.kubernetes.io/enforce: restricted

3.3 02-resourcequota.yaml / 03-limitrange.yaml

# 对应赛题:命名空间资源约束
apiVersion: v1
kind: ResourceQuota
metadata:
  name: prod-app-quota
  namespace: prod-app
spec:
  hard:
    requests.cpu: "8"
    requests.memory: 16Gi
    limits.cpu: "16"
    limits.memory: 32Gi
    pods: "30"
    persistentvolumeclaims: "5"
---
apiVersion: v1
kind: LimitRange
metadata:
  name: prod-app-limits
  namespace: prod-app
spec:
  limits:
    - type: Container
      default:            # 未声明 limits 时的默认值
        cpu: 500m
        memory: 512Mi
      defaultRequest:
        cpu: 200m
        memory: 256Mi
      max:
        cpu: "4"
        memory: 8Gi

竞赛小技巧:有了 LimitRange 的 default,即使某处漏写 limits 也不会被 ResourceQuota 拒绝创建 Pod。这是现场救命的写法。

3.4 20-deployment-api.yaml(重点看探针与安全上下文)

# 对应赛题:后端 api 3 副本、端口 8080、资源限制、健康探针、滚动更新
apiVersion: apps/v1
kind: Deployment
metadata:
  name: api
  namespace: prod-app
  labels:
    app.kubernetes.io/name: api
    app.kubernetes.io/component: backend
    app.kubernetes.io/part-of: prod-app
spec:
  replicas: 3
  revisionHistoryLimit: 5
  strategy:
    type: RollingUpdate
    rollingUpdate:
      maxSurge: 1
      maxUnavailable: 0        # 保证更新期间可用副本数不减
  selector:
    matchLabels:
      app.kubernetes.io/name: api
  template:
    metadata:
      labels:
        app.kubernetes.io/name: api
        app.kubernetes.io/component: backend
        app.kubernetes.io/part-of: prod-app
    spec:
      serviceAccountName: api-sa
      securityContext:
        runAsNonRoot: true
        runAsUser: 10001
        fsGroup: 10001
        seccompProfile:
          type: RuntimeDefault
      topologySpreadConstraints:      # 3 副本尽量分散到不同节点
        - maxSkew: 1
          topologyKey: kubernetes.io/hostname
          whenUnsatisfiable: ScheduleAnyway
          labelSelector:
            matchLabels:
              app.kubernetes.io/name: api
      containers:
        - name: api
          image: registry.exam.local/prod/api:1.4.2   # 禁止 latest
          imagePullPolicy: IfNotPresent
          ports:
            - name: http
              containerPort: 8080
              protocol: TCP
          envFrom:
            - configMapRef:
                name: api-config
            - secretRef:
                name: api-secret
          env:
            - name: DB_HOST
              value: mysql-0.mysql-headless.prod-app.svc.cluster.local
          resources:
            requests:
              cpu: 250m
              memory: 256Mi
            limits:
              cpu: "1"
              memory: 1Gi
          startupProbe:                 # 冷启动保护:30 × 2s = 60s 上限
            httpGet:
              path: /healthz
              port: http
            failureThreshold: 30
            periodSeconds: 2
          readinessProbe:               # 就绪后才接流量
            httpGet:
              path: /readyz
              port: http
            initialDelaySeconds: 5
            periodSeconds: 10
            timeoutSeconds: 2
            failureThreshold: 3
          livenessProbe:                # 卡死时重启
            httpGet:
              path: /healthz
              port: http
            periodSeconds: 20
            timeoutSeconds: 3
            failureThreshold: 3
          securityContext:
            allowPrivilegeEscalation: false
            readOnlyRootFilesystem: true
            capabilities:
              drop: ["ALL"]
          volumeMounts:
            - name: tmp
              mountPath: /tmp
      volumes:
        - name: tmp
          emptyDir: {}

这段是得分密集区,现场答辩时可以直接指着说:

  • maxUnavailable: 0 → 更新过程零中断;
  • startupProbe → 避免慢启动应用被 liveness 反复杀掉(这是最常见的"Pod 一直重启"根因);
  • topologySpreadConstraints → 高可用;
  • readOnlyRootFilesystem: true + emptyDir:/tmp → CKS 安全考点。

3.5 21-service-api.yaml

# 对应赛题:后端服务发现
apiVersion: v1
kind: Service
metadata:
  name: api
  namespace: prod-app
  labels:
    app.kubernetes.io/name: api
    app.kubernetes.io/part-of: prod-app
spec:
  type: ClusterIP
  selector:
    app.kubernetes.io/name: api      # 必须与 Deployment 的 pod 标签完全一致
  ports:
    - name: http
      port: 80
      targetPort: http               # 用端口名,避免改端口时漏改
      protocol: TCP

3.6 12-ingress.yaml

# 对应赛题:对外暴露 app.exam.local
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: prod-app-ingress
  namespace: prod-app
  annotations:
    nginx.ingress.kubernetes.io/proxy-body-size: "10m"
    nginx.ingress.kubernetes.io/proxy-connect-timeout: "10"
spec:
  ingressClassName: nginx
  rules:
    - host: app.exam.local
      http:
        paths:
          - path: /api
            pathType: Prefix
            backend:
              service:
                name: api
                port:
                  number: 80
          - path: /
            pathType: Prefix
            backend:
              service:
                name: web
                port:
                  number: 80

3.7 30-statefulset-mysql.yaml(配 headless Service)

# 对应赛题:数据库持久化 + 稳定网络标识
apiVersion: v1
kind: Service
metadata:
  name: mysql-headless
  namespace: prod-app
spec:
  clusterIP: None                  # headless:StatefulSet 的稳定 DNS 依赖
  selector:
    app.kubernetes.io/name: mysql
  ports:
    - name: mysql
      port: 3306
---
apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: mysql
  namespace: prod-app
spec:
  serviceName: mysql-headless      # 必须指向 headless Service
  replicas: 1
  selector:
    matchLabels:
      app.kubernetes.io/name: mysql
  template:
    metadata:
      labels:
        app.kubernetes.io/name: mysql
        app.kubernetes.io/component: database
    spec:
      securityContext:
        fsGroup: 999
      containers:
        - name: mysql
          image: registry.exam.local/prod/mysql:8.0.36
          ports:
            - name: mysql
              containerPort: 3306
          env:
            - name: MYSQL_ROOT_PASSWORD
              valueFrom:
                secretKeyRef:
                  name: api-secret
                  key: mysql-root-password
          resources:
            requests: { cpu: 500m, memory: 1Gi }
            limits:   { cpu: "2",  memory: 4Gi }
          readinessProbe:
            exec:
              command: ["sh", "-c", "mysqladmin ping -h 127.0.0.1 -uroot -p$MYSQL_ROOT_PASSWORD"]
            initialDelaySeconds: 20
            periodSeconds: 10
          volumeMounts:
            - name: data
              mountPath: /var/lib/mysql
  volumeClaimTemplates:
    - metadata:
        name: data
      spec:
        accessModes: ["ReadWriteOnce"]
        storageClassName: local-path
        resources:
          requests:
            storage: 20Gi

3.8 40-hpa.yaml / 41-pdb.yaml / 50-networkpolicy.yaml

# 对应赛题:CPU 70% 自动扩缩容
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
  name: api-hpa
  namespace: prod-app
spec:
  scaleTargetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: api
  minReplicas: 3
  maxReplicas: 10
  metrics:
    - type: Resource
      resource:
        name: cpu
        target:
          type: Utilization
          averageUtilization: 70
  behavior:                        # 防抖动,避免副本数震荡
    scaleUp:
      stabilizationWindowSeconds: 0
      policies:
        - type: Percent
          value: 100
          periodSeconds: 15
    scaleDown:
      stabilizationWindowSeconds: 300
      policies:
        - type: Percent
          value: 25
          periodSeconds: 60
---
# 对应赛题:高可用(节点维护不中断)
apiVersion: policy/v1
kind: PodDisruptionBudget
metadata:
  name: api-pdb
  namespace: prod-app
spec:
  minAvailable: 2
  selector:
    matchLabels:
      app.kubernetes.io/name: api
---
# 对应赛题:数据库仅允许后端访问
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: mysql-allow-api-only
  namespace: prod-app
spec:
  podSelector:
    matchLabels:
      app.kubernetes.io/name: mysql
  policyTypes: ["Ingress"]
  ingress:
    - from:
        - podSelector:
            matchLabels:
              app.kubernetes.io/name: api
      ports:
        - protocol: TCP
          port: 3306

四、生成之后必须做的一步:校验

AI 生成的 YAML 不能直接信,尤其字段名和 API 版本。竞赛现场按这个顺序验:

4.1 离线语法与规范校验(推荐,秒级)

# 方式一:kubectl 客户端校验(无需连集群)
kubectl apply --dry-run=client -f ./manifests/

# 方式二:kubeconform(比 kubeval 维护更活跃,支持 CRD 跳过)
kubeconform -strict -summary -ignore-missing-schemas ./manifests/

# 方式三:kube-linter(规范/最佳实践)
kube-linter lint ./manifests/

4.2 服务端校验(能连集群时最强)

kubectl apply --dry-run=server -f ./manifests/
# 服务端会真正跑准入校验(PSA、ResourceQuota、ValidatingWebhook)

4.3 一键批量落地 + 等待就绪

kubectl apply -f ./manifests/
kubectl wait --for=condition=Available deployment/api -n prod-app --timeout=180s
kubectl get all -n prod-app -o wide
kubectl get ingress -n prod-app

4.4 逐条对照赛题做"验收"

# 副本数
kubectl get deploy -n prod-app -o custom-columns=NAME:.metadata.name,DESIRED:.spec.replicas,READY:.status.readyReplicas

# 探针是否配置
kubectl get deploy api -n prod-app -o jsonpath='{.spec.template.spec.containers[*].readinessProbe}'

# HPA 是否生效(重点看 TARGETS 不是 <unknown>)
kubectl get hpa -n prod-app

# PDB 状态
kubectl get pdb -n prod-app

# NetworkPolicy 是否真的拦住
kubectl exec -n prod-app deploy/api -- nc -zv mysql-headless 3306
kubectl run tmp-test -n prod-app --rm -it --image=busybox -- nc -zv mysql-headless 3306   # 应被拒绝

HPA 显示 <unknown> 的 90% 原因:容器没写 resources.requests.cpu,或者集群没装 metrics-server。这也是竞赛高频扣分点。


五、竞赛现场提速技巧

5.1 用提示词做"批量生成 + 批量修复"

(生成后追加这个提示词)
上面生成的 YAML 存在以下问题,请逐个修正并输出完整文件:
1) HPA 的 TARGETS 显示 unknown,请检查并说明原因
2) kubectl apply 报错:error validating data: ValidationError(...)
   (粘贴完整报错)
3) Ingress 访问 404,请列出排查步骤与最可能的 3 个原因
输出要求:先给修复后的文件,再给"为什么会这样"的 3 句话解释。

5.2 用"模板化"减少重复劳动

让助手把可变部分抽成变量,生成一份可复用的 YAML 骨架 + 一份 envsubst 脚本:

# 现场快速变形:改一个变量,生成一套新环境
export APP=api NAMESPACE=prod-app REPLICAS=3 IMAGE=registry.exam.local/prod/api:1.4.2
envsubst < templates/deployment.tmpl.yaml > manifests/20-deployment-api.yaml

5.3 易错字段速查(背下来能救分)

❌ 错误写法✅ 正确写法说明
apiVersion: extensions/v1beta1networking.k8s.io/v1Ingress 老版本已废弃
apiVersion: autoscaling/v2beta2autoscaling/v2HPA
apiVersion: policy/v1beta1 (PDB)policy/v1PDB
spec.selector 与 pod 标签不一致严格一致Service 无 Endpoint 的头号原因
只写 limits 不写 requests都写HPA 依赖 requests
targetPort 写成容器内不存在的端口与 containerPort 一致连接被拒
PVC 不写 storageClassName显式指定多 SC 集群会 Pending
探针 path 写成 / 且未实现用真实健康检查端点探针失败导致重启循环

六、小结

这套方法的本质:把竞赛从"记忆型任务"变成"审查型任务"。

  • 助手负责穷举——它不会忘记写 PDB、NetworkPolicy、三种探针;
  • 你负责审查与答辩——为什么用 maxUnavailable: 0、为什么用 StartupProbe,这些解释才是评委给你高分的地方。

现场节奏建议:

① 读题 2 分钟,列出所有显性 + 隐性要求
② 结构化提示词 → 生成映射表(1 分钟)→ 核对漏项
③ 生成 YAML(2 分钟)
④ kubectl --dry-run=client 批量校验(30 秒)
⑤ apply + wait + 逐条验收(3 分钟)
⑥ 留 5 分钟练习"故障排查"话术(下一篇的主题)

下一篇进入竞赛的第二大得分板块:

《【高校竞赛实战】K8s 故障演练:用腾讯云助手模拟 8 类 Pod 异常,把排错练成肌肉记忆》


标签:云原生 Kubernetes K8s YAML 高校竞赛 云计算竞赛 腾讯云助手 CKA

更多推荐