Kubernetes 部署完全指南

Kubernetes 部署完全指南


一、什么是 Kubernetes?

Kubernetes(简称 K8s)是一个容器编排平台,解决的核心问题是:如何在大规模集群中自动化部署、扩缩容、管理容器化应用。

没有 K8s 时:

复制代码
手动 SSH 到服务器 → docker run → 服务挂了手动重启 → 扩容手动加机器

有 K8s 后:

复制代码
提交一份 YAML 声明 → K8s 自动部署 → 自动重启 → 自动扩缩容 → 自动负载均衡

一句话:你告诉 K8s "我要什么",它负责"怎么做到"。


注:

博客:

https://blog.csdn.net/badao_liumang_qizhi

二、核心概念

2.1 架构总览

复制代码
┌─────────────────────────────────────────────────────────────────┐
│                        Kubernetes Cluster                         │
├─────────────────────────────────────────────────────────────────┤
│                                                                  │
│  ┌─── Master Node(控制平面)───────────────────────────────┐   │
│  │  API Server  │  Scheduler  │  Controller Manager  │  etcd │   │
│  └──────────────────────────────────────────────────────────┘   │
│                          │                                       │
│          ┌───────────────┼───────────────┐                      │
│          ↓               ↓               ↓                      │
│  ┌─── Worker Node 1 ──┐ ┌─── Worker Node 2 ──┐ ┌─── Node 3 ─┐ │
│  │ kubelet │ kube-proxy│ │ kubelet │ kube-proxy│ │            │ │
│  │ ┌─────┐ ┌─────┐    │ │ ┌─────┐ ┌─────┐   │ │            │ │
│  │ │ Pod │ │ Pod │    │ │ │ Pod │ │ Pod │   │ │            │ │
│  │ └─────┘ └─────┘    │ │ └─────┘ └─────┘   │ │            │ │
│  └─────────────────────┘ └────────────────────┘ └────────────┘ │
└─────────────────────────────────────────────────────────────────┘

2.2 核心组件

组件 职责 类比
API Server 集群的入口,所有操作都通过它 公司前台
Scheduler 决定 Pod 运行在哪个 Node 上 HR 分配工位
Controller Manager 确保集群状态符合预期 主管巡检
etcd 存储集群所有状态数据 公司数据库
kubelet 每个 Node 上的代理,管理 Pod 每层楼的物业
kube-proxy 网络代理,实现 Service 负载均衡 网络路由器

2.3 核心资源对象

资源 含义 类比
Pod 最小部署单元,包含一个或多个容器 一个房间(可住1-N个人)
Deployment 管理 Pod 的副本数、滚动更新 部署计划书
Service 为一组 Pod 提供稳定的访问入口 公司总机号码
ConfigMap 非敏感配置(键值对) 配置文件
Secret 敏感配置(密码、证书) 保险箱
Namespace 逻辑隔离(如 dev/staging/prod) 不同楼层
Ingress HTTP 路由入口(域名 → Service) 大楼门牌
HPA 水平自动扩缩容 根据客流加减收银台
PV/PVC 持久化存储 文件柜

2.4 资源层级关系

复制代码
Deployment(声明式管理)
  └── ReplicaSet(保证副本数)
       └── Pod(运行容器)
            └── Container(实际进程)
                 └── Docker Image(代码 + 环境)

三、从 Docker 到 K8s

3.1 Dockerfile

dockerfile 复制代码
# 基础镜像
FROM eclipse-temurin:17-jre-alpine

# 工作目录
WORKDIR /app

# 复制 JAR(从 Maven 构建产出)
COPY target/my-order-service-1.0.0.jar app.jar

# 暴露端口
EXPOSE 8080

# 健康检查
HEALTHCHECK --interval=30s --timeout=3s --retries=3 \
  CMD wget --no-verbose --tries=1 --spider http://localhost:8080/actuator/health || exit 1

# 启动命令
ENTRYPOINT ["java", \
  "-XX:+UseG1GC", \
  "-XX:MaxGCPauseMillis=200", \
  "-Xms512m", \
  "-Xmx512m", \
  "-jar", "app.jar"]

3.2 构建并推送镜像

bash 复制代码
# 构建镜像
docker build -t registry.example.com/team/order-service:1.0.0 .

# 推送到镜像仓库
docker push registry.example.com/team/order-service:1.0.0

四、K8s 核心资源 YAML 详解

4.1 Namespace

yaml 复制代码
# namespace.yaml
apiVersion: v1
kind: Namespace
metadata:
  name: order-system
  labels:
    env: production
kubectl apply -f namespace.yaml
kubectl get namespaces

4.2 ConfigMap(非敏感配置)

yaml 复制代码
# configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: order-service-config
  namespace: order-system
data:
  # 单个值
  SERVER_PORT: "8080"
  SPRING_PROFILES_ACTIVE: "prod"
  LOG_LEVEL: "info"
  
  # 整个配置文件
  application-prod.yml: |
    spring:
      datasource:
        url: jdbc:mysql://mysql-service:3306/order_db
        hikari:
          maximum-pool-size: 50
      data:
        redis:
          host: redis-service
          port: 6379
    server:
      port: 8080
      tomcat:
        threads:
          max: 400

4.3 Secret(敏感配置)

yaml 复制代码
# secret.yaml
apiVersion: v1
kind: Secret
metadata:
  name: order-service-secret
  namespace: order-system
type: Opaque
data:
  # 值必须 base64 编码
  DB_USERNAME: b3JkZXJfdXNlcg==          
  DB_PASSWORD: UEBzc3cwcmQxMjM=          
  REDIS_PASSWORD: cmVkaXNQQHNz            
# 命令行创建 Secret(避免手动 base64)
kubectl create secret generic order-service-secret \
  --namespace=order-system \
  --from-literal=DB_USERNAME=order_user \
  --from-literal=DB_PASSWORD='P@xxx' \
  --from-literal=REDIS_PASSWORD='xxxx@ss'

4.4 Deployment(核心)

yaml 复制代码
# deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: order-service
  namespace: order-system
  labels:
    app: order-service
    version: "1.0.0"
spec:
  replicas: 3                      # 运行 3 个 Pod 副本
  
  # 选择器:管理哪些 Pod
  selector:
    matchLabels:
      app: order-service
  
  # 滚动更新策略
  strategy:
    type: RollingUpdate
    rollingUpdate:
      maxSurge: 1                  # 更新时最多多创建 1 个 Pod
      maxUnavailable: 0            # 更新时不允许有 Pod 不可用
  
  # Pod 模板
  template:
    metadata:
      labels:
        app: order-service
        version: "1.0.0"
      annotations:
        prometheus.io/scrape: "true"
        prometheus.io/port: "8080"
        prometheus.io/path: "/actuator/prometheus"
    spec:
      # 优雅停机
      terminationGracePeriodSeconds: 60
      
      # 容器定义
      containers:
        - name: order-service
          image: registry.example.com/team/order-service:1.0.0
          imagePullPolicy: Always
          
          # 端口
          ports:
            - name: http
              containerPort: 8080
              protocol: TCP
          
          # 环境变量(从 ConfigMap 和 Secret 引用)
          env:
            - name: SPRING_PROFILES_ACTIVE
              valueFrom:
                configMapKeyRef:
                  name: order-service-config
                  key: SPRING_PROFILES_ACTIVE
            - name: DB_USERNAME
              valueFrom:
                secretKeyRef:
                  name: order-service-secret
                  key: DB_USERNAME
            - name: DB_PASSWORD
              valueFrom:
                secretKeyRef:
                  name: order-service-secret
                  key: DB_PASSWORD
            - name: JAVA_OPTS
              value: "-Xms512m -Xmx512m -XX:+UseG1GC"
          
          # 挂载配置文件
          volumeMounts:
            - name: config-volume
              mountPath: /app/config
              readOnly: true
          
          # 资源限制
          resources:
            requests:              # 最低保证
              cpu: "500m"          # 0.5 核
              memory: "512Mi"      # 512MB
            limits:                # 最大上限
              cpu: "2000m"         # 2 核
              memory: "1024Mi"     # 1GB
          
          # 存活探针:判断容器是否需要重启
          livenessProbe:
            httpGet:
              path: /actuator/health/liveness
              port: 8080
            initialDelaySeconds: 60    # 启动后等 60s 再检查
            periodSeconds: 10          # 每 10s 检查一次
            timeoutSeconds: 3          # 超时 3s
            failureThreshold: 3        # 连续失败 3 次则重启
          
          # 就绪探针:判断 Pod 是否可以接收流量
          readinessProbe:
            httpGet:
              path: /actuator/health/readiness
              port: 8080
            initialDelaySeconds: 30    # 启动后等 30s
            periodSeconds: 5           # 每 5s 检查
            timeoutSeconds: 3
            failureThreshold: 3
          
          # 启动探针:慢启动应用专用
          startupProbe:
            httpGet:
              path: /actuator/health
              port: 8080
            initialDelaySeconds: 10
            periodSeconds: 5
            failureThreshold: 30       # 最多等 10 + 5*30 = 160s
          
          # 生命周期钩子
          lifecycle:
            preStop:
              exec:
                command: ["sh", "-c", "sleep 10"]  # 优雅停机等待
      
      # 卷定义
      volumes:
        - name: config-volume
          configMap:
            name: order-service-config
      
      # 镜像拉取凭证
      imagePullSecrets:
        - name: registry-credentials

4.5 Service(网络访问)

yaml 复制代码
# service.yaml
apiVersion: v1
kind: Service
metadata:
  name: order-service
  namespace: order-system
  labels:
    app: order-service
spec:
  type: ClusterIP                # 集群内部访问(默认)
  selector:
    app: order-service           # 匹配 Pod 的 label
  ports:
    - name: http
      port: 80                   # Service 端口
      targetPort: 8080           # Pod 端口
      protocol: TCP

Service 类型:

类型 用途 访问方式
ClusterIP 集群内部通信(默认) order-service.order-system.svc.cluster.local
NodePort 通过节点 IP + 端口暴露 <NodeIP>:30080
LoadBalancer 云厂商负载均衡器 外部 IP

4.6 Ingress(外部路由)

yaml 复制代码
# ingress.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: order-service-ingress
  namespace: order-system
  annotations:
    nginx.ingress.kubernetes.io/rewrite-target: /
    nginx.ingress.kubernetes.io/ssl-redirect: "true"
    nginx.ingress.kubernetes.io/proxy-body-size: "10m"
    nginx.ingress.kubernetes.io/proxy-read-timeout: "60"
spec:
  ingressClassName: nginx
  tls:
    - hosts:
        - api.example.com
      secretName: tls-secret
  rules:
    - host: api.example.com
      http:
        paths:
          - path: /api/order
            pathType: Prefix
            backend:
              service:
                name: order-service
                port:
                  number: 80
          - path: /api/product
            pathType: Prefix
            backend:
              service:
                name: product-service
                port:
                  number: 80

4.7 HPA(水平自动扩缩容)

yaml 复制代码
# hpa.yaml
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
  name: order-service-hpa
  namespace: order-system
spec:
  scaleTargetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: order-service
  minReplicas: 3                # 最少 3 个 Pod
  maxReplicas: 20               # 最多 20 个 Pod
  metrics:
    # CPU 使用率超过 70% 则扩容
    - type: Resource
      resource:
        name: cpu
        target:
          type: Utilization
          averageUtilization: 70
    # 内存使用率超过 80% 则扩容
    - type: Resource
      resource:
        name: memory
        target:
          type: Utilization
          averageUtilization: 80
  behavior:
    scaleUp:
      stabilizationWindowSeconds: 60    # 扩容冷却 60s
      policies:
        - type: Pods
          value: 2                      # 每次最多扩 2 个
          periodSeconds: 60
    scaleDown:
      stabilizationWindowSeconds: 300   # 缩容冷却 5 分钟
      policies:
        - type: Pods
          value: 1                      # 每次最多缩 1 个
          periodSeconds: 120

五、健康检查(Probes)详解

5.1 三种探针

探针 触发时机 失败后果 用途
startupProbe 容器启动阶段 继续等待(不杀容器) 慢启动应用(Java 启动需 30-60s)
livenessProbe 容器运行期间 杀掉容器重启 检测死锁、僵死
readinessProbe 容器运行期间 从 Service 摘除(不接流量) 检测是否准备好服务

5.2 执行顺序

复制代码
Pod 启动
  ↓
startupProbe 检查中...(其他探针暂停)
  ↓ 成功
livenessProbe + readinessProbe 同时开始周期检查
  ↓
readinessProbe 成功 → Pod 加入 Service 端点(开始接流量)
livenessProbe 成功 → Pod 正常运行
  ↓
readinessProbe 失败 → Pod 从端点摘除(暂停接流量)
livenessProbe 失败 → 容器被杀掉重启

5.3 Spring Boot Actuator 配置

yaml 复制代码
# application.yml
management:
  endpoint:
    health:
      probes:
        enabled: true              # 开启 K8s 探针端点
      show-details: always
  health:
    livenessState:
      enabled: true
    readinessState:
      enabled: true
  endpoints:
    web:
      exposure:
        include: health,info,prometheus

探针端点:

  • /actuator/health/liveness --- 存活检查(只要 JVM 没挂就返回 200)
  • /actuator/health/readiness --- 就绪检查(数据库、Redis 连接正常才返回 200)

六、滚动更新与回滚

6.1 滚动更新过程

复制代码
初始状态(3 个 Pod v1):
  [v1] [v1] [v1]

发布 v2(maxSurge=1, maxUnavailable=0):

Step 1: 创建 1 个新 Pod
  [v1] [v1] [v1] [v2-starting]

Step 2: v2 就绪后,终止 1 个 v1
  [v1] [v1] [v2] [v2-starting]

Step 3: 继续...
  [v1] [v2] [v2] [v2-starting]

Step 4: 完成
  [v2] [v2] [v2]

6.2 触发更新

bash 复制代码
# 方式1:更新镜像版本
kubectl set image deployment/order-service \
  order-service=registry.example.com/team/order-service:1.0.1 \
  -n order-system

# 方式2:修改 YAML 后 apply
kubectl apply -f deployment.yaml

# 方式3:修改环境变量也会触发更新
kubectl set env deployment/order-service LOG_LEVEL=debug -n order-system

6.3 查看更新状态

bash 复制代码
# 查看滚动更新进度
kubectl rollout status deployment/order-service -n order-system

# 查看历史版本
kubectl rollout history deployment/order-service -n order-system

# 查看某个版本详情
kubectl rollout history deployment/order-service --revision=3 -n order-system

6.4 回滚

bash 复制代码
# 回滚到上一版本
kubectl rollout undo deployment/order-service -n order-system

# 回滚到指定版本
kubectl rollout undo deployment/order-service --to-revision=2 -n order-system

# 暂停更新(排查问题)
kubectl rollout pause deployment/order-service -n order-system

# 恢复更新
kubectl rollout resume deployment/order-service -n order-system

七、完整部署示例

7.1 项目文件结构

复制代码
my-order-service/
├── src/
├── pom.xml
├── Dockerfile
└── k8s/
    ├── base/                       # 基础配置
    │   ├── namespace.yaml
    │   ├── configmap.yaml
    │   ├── secret.yaml
    │   ├── deployment.yaml
    │   ├── service.yaml
    │   ├── ingress.yaml
    │   └── hpa.yaml
    ├── overlays/                   # 环境差异配置
    │   ├── dev/
    │   │   └── kustomization.yaml
    │   ├── staging/
    │   │   └── kustomization.yaml
    │   └── prod/
    │       └── kustomization.yaml
    └── deploy.sh                   # 部署脚本

7.2 一键部署脚本

bash 复制代码
#!/bin/bash
# deploy.sh - 构建并部署到 K8s

set -e

# 参数
APP_NAME="order-service"
VERSION=${1:-"latest"}
NAMESPACE=${2:-"order-system"}
REGISTRY="registry.example.com/team"

echo "=========================================="
echo "部署 $APP_NAME:$VERSION 到 $NAMESPACE"
echo "=========================================="

# 1. 构建 JAR
echo "[1/5] 构建 JAR..."
mvn clean package -DskipTests -q

# 2. 构建 Docker 镜像
echo "[2/5] 构建 Docker 镜像..."
docker build -t $REGISTRY/$APP_NAME:$VERSION .
docker tag $REGISTRY/$APP_NAME:$VERSION $REGISTRY/$APP_NAME:latest

# 3. 推送镜像
echo "[3/5] 推送镜像..."
docker push $REGISTRY/$APP_NAME:$VERSION
docker push $REGISTRY/$APP_NAME:latest

# 4. 部署到 K8s
echo "[4/5] 部署到 Kubernetes..."
kubectl apply -f k8s/base/namespace.yaml
kubectl apply -f k8s/base/configmap.yaml
kubectl apply -f k8s/base/secret.yaml
kubectl apply -f k8s/base/deployment.yaml
kubectl apply -f k8s/base/service.yaml
kubectl apply -f k8s/base/ingress.yaml
kubectl apply -f k8s/base/hpa.yaml

# 更新镜像版本
kubectl set image deployment/$APP_NAME \
  $APP_NAME=$REGISTRY/$APP_NAME:$VERSION \
  -n $NAMESPACE

# 5. 等待部署完成
echo "[5/5] 等待部署就绪..."
kubectl rollout status deployment/$APP_NAME -n $NAMESPACE --timeout=300s

echo "=========================================="
echo "部署成功!"
echo "版本: $VERSION"
echo "Pod 状态:"
kubectl get pods -n $NAMESPACE -l app=$APP_NAME
echo "=========================================="

7.3 GitLab CI 自动部署

yaml 复制代码
# .gitlab-ci.yml
stages:
  - build
  - test
  - package
  - deploy

variables:
  REGISTRY: registry.example.com/team
  APP_NAME: order-service

# 构建 JAR
build:
  stage: build
  image: maven:3.9-eclipse-temurin-17
  script:
    - mvn clean package -DskipTests
  artifacts:
    paths:
      - target/*.jar

# 构建并推送 Docker 镜像
docker-build:
  stage: package
  image: docker:24.0
  services:
    - docker:24.0-dind
  script:
    - docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY
    - docker build -t $REGISTRY/$APP_NAME:$CI_COMMIT_SHORT_SHA .
    - docker push $REGISTRY/$APP_NAME:$CI_COMMIT_SHORT_SHA
  rules:
    - if: '$CI_COMMIT_BRANCH == "main" || $CI_COMMIT_BRANCH == "develop"'

# 部署到开发环境
deploy-dev:
  stage: deploy
  image: bitnami/kubectl:latest
  script:
    - kubectl config use-context dev-cluster
    - kubectl set image deployment/$APP_NAME
        $APP_NAME=$REGISTRY/$APP_NAME:$CI_COMMIT_SHORT_SHA
        -n order-system-dev
    - kubectl rollout status deployment/$APP_NAME -n order-system-dev --timeout=300s
  environment:
    name: development
    url: https://dev-api.example.com
  rules:
    - if: '$CI_COMMIT_BRANCH == "develop"'

# 部署到生产环境(手动触发)
deploy-prod:
  stage: deploy
  image: bitnami/kubectl:latest
  script:
    - kubectl config use-context prod-cluster
    - kubectl set image deployment/$APP_NAME
        $APP_NAME=$REGISTRY/$APP_NAME:$CI_COMMIT_SHORT_SHA
        -n order-system
    - kubectl rollout status deployment/$APP_NAME -n order-system --timeout=300s
  environment:
    name: production
    url: https://api.example.com
  rules:
    - if: '$CI_COMMIT_BRANCH == "main"'
      when: manual

八、常用 kubectl 命令

8.1 基本操作

bash 复制代码
# 查看资源
kubectl get pods -n order-system                    # 查看 Pod
kubectl get pods -o wide                            # 显示更多信息(IP、Node)
kubectl get deployment -n order-system              # 查看 Deployment
kubectl get svc -n order-system                     # 查看 Service
kubectl get ingress -n order-system                 # 查看 Ingress
kubectl get all -n order-system                     # 查看所有资源

# 查看详细信息
kubectl describe pod <pod-name> -n order-system     # Pod 详情(事件、状态)
kubectl describe deployment order-service -n order-system

8.2 日志和调试

bash 复制代码
# 查看日志
kubectl logs <pod-name> -n order-system             # 当前日志
kubectl logs <pod-name> -n order-system --tail=100  # 最后 100 行
kubectl logs <pod-name> -n order-system -f          # 实时追踪
kubectl logs <pod-name> -n order-system --previous  # 上一次(重启前)的日志

# 进入容器
kubectl exec -it <pod-name> -n order-system -- /bin/sh

# 端口转发(本地调试)
kubectl port-forward svc/order-service 8080:80 -n order-system
# 现在可以访问 http://localhost:8080

# 查看资源使用
kubectl top pods -n order-system                    # Pod 的 CPU/内存
kubectl top nodes                                   # Node 的资源使用

8.3 扩缩容

bash 复制代码
# 手动扩容
kubectl scale deployment order-service --replicas=5 -n order-system

# 查看 HPA 状态
kubectl get hpa -n order-system

# 查看 HPA 详情(当前指标、目标指标)
kubectl describe hpa order-service-hpa -n order-system

8.4 配置管理

bash 复制代码
# 修改 ConfigMap
kubectl edit configmap order-service-config -n order-system

# 修改后需要重启 Pod 使配置生效(ConfigMap 挂载为文件时会自动更新,但环境变量需要重启)
kubectl rollout restart deployment/order-service -n order-system

九、优雅停机

9.1 为什么需要优雅停机?

更新或缩容时,K8s 会终止旧 Pod。如果直接杀进程,正在处理的请求会中断。

9.2 停机流程

复制代码
K8s 发出终止信号
    ↓
1. Pod 从 Service 端点摘除(不再接收新请求)
    ↓
2. 执行 preStop 钩子(等待 10s,让已转发的请求完成)
    ↓
3. 发送 SIGTERM 给容器进程
    ↓
4. Spring Boot 开始优雅停机(完成正在处理的请求)
    ↓
5. 等待 terminationGracePeriodSeconds(默认 30s)
    ↓
6. 如果仍未退出,发送 SIGKILL 强制杀掉

9.3 Spring Boot 配置

yaml 复制代码
# application.yml
server:
  shutdown: graceful                    # 开启优雅停机
spring:
  lifecycle:
    timeout-per-shutdown-phase: 30s     # 等待正在处理的请求最多 30s

9.4 K8s 配置

yaml 复制代码
# deployment.yaml 中
spec:
  template:
    spec:
      terminationGracePeriodSeconds: 60    # 给足时间(>= preStop + Spring shutdown)
      containers:
        - lifecycle:
              preStop:
              exec:
                command: ["sh", "-c", "sleep 10"]  # 等 10s 让流量切走

完整时序:

复制代码
t=0s   K8s 下发终止指令,从 Service 端点摘除
t=0s   执行 preStop: sleep 10(等待 kube-proxy 更新路由规则)
t=10s  preStop 完成,发送 SIGTERM
t=10s  Spring Boot 收到 SIGTERM,停止接受新请求
t=10-40s  等待已有请求处理完毕(timeout-per-shutdown-phase: 30s)
t=40s  Spring Boot 关闭完成,进程退出
t=60s  如果进程还没退出,SIGKILL 强制终止(terminationGracePeriodSeconds)

十、资源管理

10.1 requests 和 limits

yaml 复制代码
resources:
  requests:          # 调度保证:K8s 确保节点上至少有这么多资源可用
    cpu: "500m"      # 0.5 核
    memory: "512Mi"
  limits:            # 使用上限:超过则被限流(CPU)或杀掉(内存)
    cpu: "2000m"     # 2 核
    memory: "1024Mi"
参数 含义 超出后果
requests.cpu CPU 最低保证 用于调度决策
limits.cpu CPU 最大使用 被 throttle(限流变慢,不杀)
requests.memory 内存最低保证 用于调度决策
limits.memory 内存最大使用 OOM Kill(容器被杀重启)

10.2 CPU 单位说明

表达式 含义
1 1 个完整 CPU 核
500m 0.5 核(m = milli,千分之一)
250m 0.25 核
2000m2 2 核

10.3 内存单位说明

表达式 含义
128Mi 128 MiB(1 MiB = 1024 KiB)
1Gi 1 GiB
512M 512 MB(1 MB = 1000 KB,注意不同于 Mi)

10.4 Java 应用资源配置建议

yaml 复制代码
# Java 应用推荐配置
resources:
  requests:
    cpu: "500m"
    memory: "768Mi"     # JVM 堆 + 非堆 + 额外开销
  limits:
    cpu: "2000m"
    memory: "1024Mi"

对应的 JVM 参数:

复制代码
-Xms512m -Xmx512m       # 堆内存 512MB
# 非堆(元空间、线程栈、NIO Buffer 等)约 200-300MB
# 总内存需求 ≈ 512 + 300 = 812MB → limits 设 1024Mi 留余量

关键原则limits.memory > JVM 堆 + 非堆 + 200MB 余量,否则会被 OOM Kill。


十一、持久化存储

11.1 PV 和 PVC

yaml 复制代码
# persistent-volume-claim.yaml
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: order-service-logs
  namespace: order-system
spec:
  accessModes:
    - ReadWriteOnce           # 单 Pod 读写
  storageClassName: standard   # 存储类型(云厂商提供)
  resources:
    requests:
      storage: 10Gi            # 申请 10GB

在 Deployment 中使用:

yaml 复制代码
spec:
  template:
    spec:
      containers:
        - name: order-service
          volumeMounts:
            - name: log-storage
              mountPath: /app/logs
      volumes:
        - name: log-storage
          persistentVolumeClaim:
            claimName: order-service-logs

11.2 存储类型

accessMode 含义 适用
ReadWriteOnce (RWO) 单节点读写 数据库、单实例日志
ReadOnlyMany (ROX) 多节点只读 静态配置文件
ReadWriteMany (RWX) 多节点读写 共享文件存储

十二、多环境管理(Kustomize)

12.1 目录结构

复制代码
k8s/
├── base/                          # 基础配置(所有环境共享)
│   ├── deployment.yaml
│   ├── service.yaml
│   ├── configmap.yaml
│   └── kustomization.yaml
├── overlays/
│   ├── dev/                       # 开发环境差异
│   │   ├── kustomization.yaml
│   │   └── patch-replicas.yaml
│   ├── staging/                   # 预发布环境差异
│   │   ├── kustomization.yaml
│   │   └── patch-replicas.yaml
│   └── prod/                      # 生产环境差异
│       ├── kustomization.yaml
│       ├── patch-replicas.yaml
│       └── patch-resources.yaml

12.2 base/kustomization.yaml

yaml 复制代码
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
  - deployment.yaml
  - service.yaml
  - configmap.yaml

12.3 overlays/prod/kustomization.yaml

yaml 复制代码
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization

# 引用 base
resources:
  - ../../base

# 命名空间
namespace: order-system-prod

# 通用标签
commonLabels:
  env: production

# 镜像覆盖
images:
  - name: registry.example.com/team/order-service
    newTag: "1.0.0"

# 补丁
patches:
  - path: patch-replicas.yaml
  - path: patch-resources.yaml

12.4 overlays/prod/patch-replicas.yaml

yaml 复制代码
apiVersion: apps/v1
kind: Deployment
metadata:
  name: order-service
spec:
  replicas: 5                      # 生产环境 5 个副本

12.5 overlays/prod/patch-resources.yaml

yaml 复制代码
apiVersion: apps/v1
kind: Deployment
metadata:
  name: order-service
spec:
  template:
    spec:
      containers:
        - name: order-service
          resources:
            requests:
              cpu: "1000m"         # 生产环境给更多资源
              memory: "1024Mi"
            limits:
              cpu: "4000m"
              memory: "2048Mi"

12.6 部署命令

bash 复制代码
# 预览生成的完整 YAML(不实际部署)
kubectl kustomize k8s/overlays/prod

# 部署到生产环境
kubectl apply -k k8s/overlays/prod

# 部署到开发环境
kubectl apply -k k8s/overlays/dev

十三、监控与告警

13.1 Prometheus + Grafana

yaml 复制代码
# ServiceMonitor(让 Prometheus 自动发现并抓取指标)
apiVersion: monitoring.coreos.com/v1
kind: ServiceMonitor
metadata:
  name: order-service-monitor
  namespace: order-system
spec:
  selector:
    matchLabels:
      app: order-service
  endpoints:
    - port: http
      path: /actuator/prometheus
      interval: 15s

13.2 关键监控指标

指标 来源 告警阈值
Pod 重启次数 kube_pod_container_status_restarts_total > 3 次/小时
CPU 使用率 container_cpu_usage_seconds_total > 80%
内存使用率 container_memory_usage_bytes > 85%
Pod 就绪状态 kube_pod_status_ready 不等于 1
请求错误率 http_server_requests_seconds_count{status=~"5.."} > 1%
请求延迟 P99 http_server_requests_seconds > 2s

十四、安全最佳实践

14.1 Pod 安全上下文

yaml 复制代码
spec:
  template:
    spec:
      securityContext:
        runAsNonRoot: true          # 禁止以 root 运行
        runAsUser: 1000             # 指定用户 ID
        fsGroup: 1000
      containers:
        - name: order-service
          securityContext:
            allowPrivilegeEscalation: false
            readOnlyRootFilesystem: true  # 根文件系统只读
            capabilities:
              drop:
                - ALL                     # 移除所有 Linux capabilities

14.2 网络策略

yaml 复制代码
# 只允许 Ingress 访问 order-service,其他 Pod 不允许
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: order-service-network-policy
  namespace: order-system
spec:
  podSelector:
    matchLabels:
      app: order-service
  policyTypes:
    - Ingress
  ingress:
    - from:
        - namespaceSelector:
            matchLabels:
              name: ingress-nginx      # 只允许 Ingress 命名空间
      ports:
        - protocol: TCP
          port: 8080

十五、常见问题 FAQ

Q1: Pod 一直 CrashLoopBackOff 怎么排查?

bash 复制代码
# 1. 查看 Pod 状态和事件
kubectl describe pod <pod-name> -n order-system

# 2. 查看日志(上一次崩溃的日志)
kubectl logs <pod-name> -n order-system --previous

# 3. 常见原因:
# - OOM Kill(内存不够)→ 增加 limits.memory
# - 启动失败(端口冲突、配置错误)→ 看日志
# - 健康检查失败(initialDelaySeconds 太短)→ 增加等待时间

Q2: Pod 一直 Pending 怎么办?

bash 复制代码
kubectl describe pod <pod-name> -n order-system
# 看 Events 部分,通常是:
# - 资源不足(Insufficient cpu/memory)→ 减少 requests 或加节点
# - PVC 无法绑定 → 检查 StorageClass
# - 镜像拉取失败 → 检查 imagePullSecrets

Q3: 如何实现零停机部署?

确保以下配置:

  1. readinessProbe 正确配置 → 新 Pod 就绪后才接流量
  2. strategy.rollingUpdate.maxUnavailable: 0 → 不允许可用 Pod 减少
  3. preStop sleep 10s → 等待路由规则更新
  4. Spring Boot server.shutdown: graceful → 完成已有请求

Q4: ConfigMap 更新后如何让 Pod 生效?

  • 环境变量方式引用 :需要重启 Pod(kubectl rollout restart
  • 文件挂载方式:约 1-2 分钟后自动更新(但应用需要监听文件变化)

Q5: 如何限制单个 Namespace 的总资源?

yaml 复制代码
# ResourceQuota
apiVersion: v1
kind: ResourceQuota
metadata:
  name: order-system-quota
  namespace: order-system
spec:
  hard:
    requests.cpu: "20"          # 总 CPU 请求上限
    requests.memory: "40Gi"     # 总内存请求上限
    limits.cpu: "40"
    limits.memory: "80Gi"
    pods: "100"                 # 最多 100 个 Pod

Q6: 如何给不同节点分配不同服务?

使用 nodeSelectornodeAffinity

yaml 复制代码
spec:
  template:
    spec:
      nodeSelector:
        node-type: compute       # 只调度到带此标签的节点
      # 或更灵活的亲和性
      affinity:
        nodeAffinity:
          requiredDuringSchedulingIgnoredDuringExecution:
            nodeSelectorTerms:
              - matchExpressions:
                  - key: node-type
                    operator: In
                    values:
                      - compute
                      - general

十六、总结

资源 作用 一句话
Deployment 声明式管理 Pod 副本和更新 "我要 3 个 v1.0 的实例"
Service 提供稳定的内部访问地址 "统一入口,自动负载均衡"
Ingress 外部 HTTP 路由 "域名/路径 → Service"
ConfigMap 非敏感配置管理 "配置和代码分离"
Secret 敏感信息管理 "密码、证书安全存储"
HPA 自动扩缩容 "流量大自动加 Pod"
Probe 健康检查 "挂了自动重启,没就绪不接流量"
Kustomize 多环境配置管理 "base + overlay 管理差异"

部署一个 Java 微服务的最小清单

复制代码
必须:Deployment + Service + ConfigMap + Secret
推荐:+ Ingress + HPA + Probe 配置
生产:+ ResourceQuota + NetworkPolicy + PodDisruptionBudget

核心原则:声明式管理(用 YAML 描述期望状态)+ 不可变基础设施(不改运行中的容器,只发新版本)。