Back to Article

07. Docker、Kubernetes 与云原生教程

07. Docker、Kubernetes 与云原生教程

本章从“会 docker run”推进到“理解容器和 Kubernetes 基础,并能部署一个服务”。重点是概念、命令、配置对象和排查路径。

1. Docker 基础概念

1.1 镜像和容器

镜像是只读模板,容器是镜像运行后的进程环境。

docker run --name demo-nginx -p 8080:80 nginx:alpine

这条命令做了:

  1. 如果本地没有 nginx:alpine,从 registry 拉取镜像。
  2. 创建容器。
  3. 启动容器中的 nginx 进程。
  4. 把宿主机 8080 端口映射到容器 80 端口。

删除容器不会删除镜像,删除容器也会丢失写在容器可写层里的数据。

1.2 Volume

数据库数据不能只存在容器可写层。

docker volume create pgdata
docker run --name pg \
  -e POSTGRES_PASSWORD=postgres \
  -v pgdata:/var/lib/postgresql/data \
  -p 5432:5432 \
  postgres:16

1.3 Network

Compose 默认会创建网络,同一 Compose 项目内服务可以用服务名互相访问。

services:
  api:
    build: .
    environment:
      DB_HOST: db
  db:
    image: postgres:16

api 访问 db:5432,不是访问 localhost:5432

2. Dockerfile

Go 服务多阶段构建:

FROM golang:1.23 AS build
WORKDIR /src
COPY go.mod go.sum ./
RUN go mod download
COPY . .
RUN CGO_ENABLED=0 go build -o /out/api ./cmd/api

FROM gcr.io/distroless/static-debian12
COPY --from=build /out/api /api
EXPOSE 8080
ENTRYPOINT ["/api"]

Java Spring Boot 服务:

FROM eclipse-temurin:21-jre
WORKDIR /app
COPY target/app.jar app.jar
EXPOSE 8080
ENTRYPOINT ["java", "-jar", "app.jar"]

最佳实践:

  • 使用明确 tag,不要生产使用 latest
  • 多阶段构建减少镜像体积。
  • 不把密钥写进镜像。
  • 应用配置运行时注入。
  • 尽量非 root 用户运行。
  • 定期更新基础镜像。

3. Compose:本地多容器开发

示例:

services:
  api:
    build: .
    ports:
      - "8080:8080"
    environment:
      DB_DSN: postgres://postgres:postgres@db:5432/payments?sslmode=disable
      REDIS_ADDR: redis:6379
    depends_on:
      - db
      - redis

  db:
    image: postgres:16
    environment:
      POSTGRES_PASSWORD: postgres
      POSTGRES_DB: payments
    volumes:
      - pgdata:/var/lib/postgresql/data

  redis:
    image: redis:7

volumes:
  pgdata:

常用命令:

docker compose up --build
docker compose logs -f api
docker compose exec db psql -U postgres -d payments
docker compose down
docker compose down --volumes

注意:down --volumes 会删除数据卷,学习环境可以用,生产要谨慎。

4. Kubernetes 核心对象

4.1 Pod

Pod 是 Kubernetes 最小调度单元,包含一个或多个容器。不要直接长期管理裸 Pod,通常用 Deployment 管理。

4.2 Deployment

apiVersion: apps/v1
kind: Deployment
metadata:
  name: payments-api
spec:
  replicas: 2
  selector:
    matchLabels:
      app: payments-api
  template:
    metadata:
      labels:
        app: payments-api
    spec:
      containers:
        - name: api
          image: example.com/payments-api:1.0.0
          ports:
            - containerPort: 8080
          env:
            - name: DB_DSN
              valueFrom:
                secretKeyRef:
                  name: payments-secret
                  key: db-dsn
          readinessProbe:
            httpGet:
              path: /readyz
              port: 8080
            initialDelaySeconds: 5
            periodSeconds: 5
          livenessProbe:
            httpGet:
              path: /healthz
              port: 8080
            initialDelaySeconds: 15
            periodSeconds: 10
          resources:
            requests:
              cpu: "100m"
              memory: "128Mi"
            limits:
              cpu: "500m"
              memory: "512Mi"

4.3 Service

apiVersion: v1
kind: Service
metadata:
  name: payments-api
spec:
  selector:
    app: payments-api
  ports:
    - port: 80
      targetPort: 8080

Service 给一组 Pod 提供稳定访问入口。

4.4 Ingress

Ingress 用于 HTTP/HTTPS 入口路由。Kubernetes 文档说明 Ingress 可按规则把流量映射到不同后端,并可做 TLS 终止等。现在新能力更多进入 Gateway API,但 Ingress 仍大量存在。

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: payments-api
spec:
  rules:
    - host: payments.local
      http:
        paths:
          - path: /
            pathType: Prefix
            backend:
              service:
                name: payments-api
                port:
                  number: 80

5. ConfigMap 与 Secret

ConfigMap 保存非敏感配置:

apiVersion: v1
kind: ConfigMap
metadata:
  name: payments-config
data:
  LOG_LEVEL: "info"
  RISK_ENDPOINT: "http://risk-api"

Secret 保存敏感配置,但默认只是 base64 编码,不等于加密。生产要结合云厂商 KMS、External Secrets、Sealed Secrets 或平台方案。

apiVersion: v1
kind: Secret
metadata:
  name: payments-secret
type: Opaque
stringData:
  db-dsn: postgres://user:pass@db:5432/payments

6. Probe:健康检查

  • readinessProbe:是否可以接流量。
  • livenessProbe:进程是否需要重启。
  • startupProbe:慢启动应用是否已经启动完成。

常见错误:

  • readiness 和 liveness 用同一个重依赖检查,导致 DB 抖动时 Pod 被反复重启。
  • liveness 过于敏感。
  • 没有 startupProbe,慢启动 Java 应用被提前杀死。

建议:

  • /healthz 只检查进程基本存活。
  • /readyz 检查关键依赖是否可服务。
  • Java/Spring 可结合 Actuator readiness/liveness。

7. 资源与扩缩容

requests 是调度依据,limits 是上限。

resources:
  requests:
    cpu: "200m"
    memory: "256Mi"
  limits:
    cpu: "1"
    memory: "1Gi"

HPA 示例:

apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
  name: payments-api
spec:
  scaleTargetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: payments-api
  minReplicas: 2
  maxReplicas: 10
  metrics:
    - type: Resource
      resource:
        name: cpu
        target:
          type: Utilization
          averageUtilization: 60

8. 排查命令

kubectl get pods
kubectl describe pod <pod>
kubectl logs <pod>
kubectl logs -f deployment/payments-api
kubectl exec -it <pod> -- sh
kubectl get events --sort-by=.metadata.creationTimestamp
kubectl rollout status deployment/payments-api
kubectl rollout history deployment/payments-api
kubectl rollout undo deployment/payments-api

常见问题:

  • ImagePullBackOff:镜像名、tag、仓库认证错误。
  • CrashLoopBackOff:应用启动后崩溃。
  • Pending:资源不足或调度约束不满足。
  • Service 无法访问:selector 不匹配或 Pod readiness 失败。
  • Ingress 不通:Ingress Controller 未安装、DNS/host 不对、Service 端口错误。

9. Kubernetes 安全基础

CISA/NSA Kubernetes hardening guidance 关注误配置和集群安全。入门阶段至少做到:

  • 不用 privileged 容器。
  • 不用 root 用户运行应用。
  • 设置 requests/limits。
  • Secret 不进镜像和 Git。
  • RBAC 最小权限。
  • NetworkPolicy 限制东西向流量。
  • 镜像来源可信并扫描。
  • 控制平面和 kubeconfig 保护好。

Pod 安全上下文示例:

securityContext:
  runAsNonRoot: true
  runAsUser: 10001
  allowPrivilegeEscalation: false
  capabilities:
    drop: ["ALL"]

10. Helm 与 Kustomize

Kustomize 适合按环境 patch:

base/
  deployment.yaml
  service.yaml
overlays/
  dev/
  prod/

Helm 适合模板化发布包:

charts/payments/
  Chart.yaml
  values.yaml
  templates/

学习建议:

  • 先写原生 YAML。
  • 再用 Kustomize 管理环境差异。
  • 最后学习 Helm 管理可复用 Chart。

11. 本章练习

练习 1:容器化 Go API

  • 写 Dockerfile。
  • 本地 docker build
  • docker run 暴露 8080。
  • 访问 /healthz

练习 2:Compose 本地环境

  • Go API。
  • Postgres。
  • Redis。
  • 持久化 Postgres 数据。
  • 用服务名访问依赖。

练习 3:部署到 Kubernetes

  • Deployment。
  • Service。
  • ConfigMap。
  • Secret。
  • readiness/liveness。
  • Ingress。
  • 修改镜像 tag 并滚动发布。

练习 4:故障演练

  • 故意配置错误镜像 tag,观察 ImagePullBackOff
  • 故意让 readiness 返回失败,观察 Service endpoints。
  • 扩容 replicas 到 5,观察负载分发。

12. 本章检查清单

  • 能解释 image、container、volume、network。
  • 能写 Go/Java 服务 Dockerfile。
  • 能用 Compose 管理 app + db + redis。
  • 能写 Deployment、Service、Ingress。
  • 能配置 ConfigMap、Secret、probe、resources。
  • 能用 kubectl 定位常见部署问题。