目标

部署:

互联网 → Ingress → Service → Deployment(3 副本) → Pods
                          ↑
                    ConfigMap / Secret

一份完整 yaml(拆解版)

Deployment

apiVersion: apps/v1
kind: Deployment
metadata:
  name: webapp
  labels: { app: webapp }
spec:
  replicas: 3
  selector:
    matchLabels: { app: webapp }
  template:
    metadata:
      labels: { app: webapp }
    spec:
      containers:
        - name: webapp
          image: ghcr.io/me/webapp:1.4.2     # 永远具体版本
          ports:
            - containerPort: 8080
          resources:
            requests: { cpu: 100m, memory: 128Mi }
            limits:   { cpu: 500m, memory: 512Mi }
          env:
            - name: NODE_ENV
              value: production
            - name: DATABASE_URL
              valueFrom:
                secretKeyRef: { name: webapp-secret, key: db-url }
          envFrom:
            - configMapRef: { name: webapp-config }
          readinessProbe:
            httpGet: { path: /health, port: 8080 }
            initialDelaySeconds: 5
            periodSeconds: 10
          livenessProbe:
            httpGet: { path: /health, port: 8080 }
            initialDelaySeconds: 30
            periodSeconds: 30

要点:

  • resources 要写requests 决定调度上限,limits 决定 OOMKill 触发;不写就乱了
  • readiness vs liveness:readiness = "能接流量了吗";liveness = "进程还活吗"。两个都重要
  • initialDelay:应用慢启动的话给够时间,否则 liveness 会一直 kill

Service

apiVersion: v1
kind: Service
metadata:
  name: webapp
spec:
  selector: { app: webapp }
  ports:
    - port: 80
      targetPort: 8080
  type: ClusterIP    # 仅集群内可访问

type 三种:

  • ClusterIP(默认):仅集群内
  • NodePort:集群任一节点 IP:30000+ 可达
  • LoadBalancer:云上自动开 LB;裸金属需要 MetalLB

生产几乎都用 ClusterIP + Ingress

Ingress

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: webapp
  annotations:
    cert-manager.io/cluster-issuer: letsencrypt-prod
spec:
  ingressClassName: nginx
  tls:
    - hosts: [app.wadely.com]
      secretName: webapp-tls
  rules:
    - host: app.wadely.com
      http:
        paths:
          - path: /
            pathType: Prefix
            backend:
              service: { name: webapp, port: { number: 80 } }

需要先装 Ingress Controller(nginx-ingress / Traefik / cloud-native LB)+ cert-manager。

操作命令

kubectl apply -f .            # 应用所有 yaml
kubectl get pods -w           # 实时看 Pod 状态
kubectl describe pod webapp-xxx
kubectl logs webapp-xxx -f    # 流式日志
kubectl logs --previous       # 看上次崩溃前的日志
kubectl exec -it webapp-xxx -- sh
kubectl rollout status deployment/webapp
kubectl rollout undo deployment/webapp

探针的三种类型

类型 失败结果 何时用
livenessProbe 重启容器 应用死锁 / 内存泄漏
readinessProbe 摘出 Service 列表 启动慢 / 间歇不健康
startupProbe 阻塞 liveness 直到通过 应用启动特别慢

3 个都给同一个 /health 端点是反模式——分清职责:

  • /healthz/ready: 依赖(DB / Redis)通了吗
  • /healthz/live: 进程还在 event loop 吗

资源单位

cpu: 100m   = 0.1 核(1000m = 1 核)
memory: 128Mi = 128 兆(Mi 二进制;M 是十进制)

requests 算调度,limits 算限制。memory 超过 limits 直接 OOMKilled;CPU 超过被 throttle。

别忘了 namespace

kubectl apply -f . -n production
kubectl get pods --all-namespaces

不写 namespace 默认 default——别把生产堆这里。

推荐阅读

下一篇:ConfigMap 和 Secret 怎么用对、坑在哪。