Kubernetes上云实战 - 从"手工部署"到"自动驾驶"的飞跃🚀

7 阅读12分钟

第12天:Kubernetes上云实战 - 从"手工部署"到"自动驾驶"的飞跃🚀

一、Kubernetes:微服务的"自动驾驶系统"

零基础全栈开发Java微服务版本实战-后端-前端-运维-实战企业级三个实战项目

资源获取:关注公众号: 小坏说Java ,获取本文所有示例代码、配置模板及导出工具。

场景对比:传统部署 vs Kubernetes

传统部署(手动挡)

  • 买服务器 → 装系统 → 装环境 → 部署应用 → 监控 → 扩容(半夜爬起来)→ 故障处理(手忙脚乱)

Kubernetes(自动驾驶)

  • 告诉K8S要什么 → K8S自动调度 → 自动部署 → 自动监控 → 自动扩容(流量来了自动加)→ 自动修复(挂了自动重启)→ 睡觉💤

Kubernetes能干啥?

  1. 自动化部署:告诉K8S要部署什么,它自己搞定
  2. 自动扩缩容:流量来了自动加实例,流量没了自动减
  3. 自愈能力:容器挂了自动重启,节点挂了自动迁移
  4. 服务发现:自动发现服务,自动负载均衡
  5. 滚动更新:不停机更新,用户无感知
  6. 配置管理:统一管理配置和密钥

二、Kubernetes核心概念(5分钟搞懂)

零基础全栈开发Java微服务版本实战-后端-前端-运维-实战企业级三个实战项目

资源获取:关注公众号: 小坏说Java ,获取本文所有示例代码、配置模板及导出工具。

1. Pod(豆荚)🥜

  • 最小调度单元:1个或多个容器组成
  • 共享网络和存储:Pod内容器共享网络IP和存储卷
  • 同生共死:Pod里的容器一起创建、一起销毁

2. Deployment(部署)📦

  • 管理Pod的控制器:声明Pod的期望状态
  • 副本管理:保证指定数量的Pod运行
  • 滚动更新:零停机部署
  • 回滚能力:一键回滚到上一版本

3. Service(服务)🔗

  • 服务发现和负载均衡:给Pod一个固定访问地址
  • 集群内访问:其他Pod通过Service访问
  • 类型:ClusterIP(集群内)、NodePort(节点端口)、LoadBalancer(云厂商负载均衡)

4. ConfigMap(配置)⚙️

  • 配置管理中心:把配置从代码中分离
  • 热更新:改配置不用重启Pod
  • 多种格式:YAML、JSON、Properties

5. Secret(密钥)🔐

  • 敏感信息管理:密码、Token、证书
  • 加密存储:Base64编码(不是加密!)
  • 挂载使用:以文件或环境变量方式使用

6. Namespace(命名空间)🗂️

  • 资源隔离:类似文件夹,隔离资源
  • 多环境:dev、test、prod不同Namespace
  • 资源配额:限制CPU、内存使用

7. Ingress(入口)🚪

  • 外部访问入口:7层负载均衡
  • 域名路由:根据域名路由到不同Service
  • SSL终止:HTTPS证书管理

三、安装Kubernetes(5分钟搞定)

零基础全栈开发Java微服务版本实战-后端-前端-运维-实战企业级三个实战项目

资源获取:关注公众号: 小坏说Java ,获取本文所有示例代码、配置模板及导出工具。

方案1:Minikube(本地开发)

# 安装Minikube(需要VirtualBox或Docker)
curl -LO https://storage.googleapis.com/minikube/releases/latest/minikube-linux-amd64
sudo install minikube-linux-amd64 /usr/local/bin/minikube

# 启动Minikube(使用Docker驱动)
minikube start --driver=docker --memory=4096 --cpus=2

# 验证安装
minikube status
kubectl version
minikube dashboard  # 打开Web界面

方案2:K3s(轻量级生产)

# 一键安装(国内镜像)
curl -sfL https://rancher-mirror.rancher.cn/k3s/k3s-install.sh | INSTALL_K3S_MIRROR=cn sh -

# 验证
sudo k3s kubectl get nodes

# 获取kubeconfig
sudo cat /etc/rancher/k3s/k3s.yaml

# 配置kubectl
mkdir -p ~/.kube
sudo cp /etc/rancher/k3s/k3s.yaml ~/.kube/config
sudo chown $USER ~/.kube/config
export KUBECONFIG=~/.kube/config

方案3:Kind(基于Docker)

# 安装Kind
curl -Lo ./kind https://kind.sigs.k8s.io/dl/v0.20.0/kind-linux-amd64
chmod +x ./kind
sudo mv ./kind /usr/local/bin/kind

# 创建集群
kind create cluster --name microservices --config kind-config.yaml

# kind-config.yaml
kind: Cluster
apiVersion: kind.x-k8s.io/v1alpha4
nodes:
- role: control-plane
  extraPortMappings:
  - containerPort: 30000
    hostPort: 30000
  - containerPort: 30001
    hostPort: 30001
- role: worker
- role: worker

方案4:云服务商(生产环境)

# AWS EKS
eksctl create cluster --name microservices --region us-east-1 --node-type t3.medium --nodes 3

# Azure AKS
az aks create --resource-group myResourceGroup --name microservices --node-count 3

# Google GKE
gcloud container clusters create microservices --num-nodes=3 --zone us-central1-a

# 阿里云ACK
aliyun cs CreateCluster --name microservices --region cn-hangzhou --node-count 3

四、把微服务部署到K8S

零基础全栈开发Java微服务版本实战-后端-前端-运维-实战企业级三个实战项目

资源获取:关注公众号: 小坏说Java ,获取本文所有示例代码、配置模板及导出工具。

步骤1:准备K8S资源配置文件

创建目录结构:

k8s/
├── namespace.yaml          # 命名空间
├── configmap.yaml          # 配置
├── secret.yaml            # 密钥
├── mysql.yaml             # MySQL数据库
├── redis.yaml             # Redis缓存
├── nacos.yaml             # Nacos注册中心
├── user-service/          # 用户服务
│   ├── deployment.yaml
│   ├── service.yaml
│   └── ingress.yaml
├── order-service/         # 订单服务
│   ├── deployment.yaml
│   ├── service.yaml
│   └── hpa.yaml          # 水平自动扩缩容
└── ingress.yaml           # 统一入口

步骤2:创建命名空间

# k8s/namespace.yaml
apiVersion: v1
kind: Namespace
metadata:
  name: microservices
  labels:
    name: microservices
    env: production

步骤3:创建ConfigMap(配置)

# k8s/configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: microservices-config
  namespace: microservices
data:
  # 应用配置
  application.yml: |
    spring:
      application:
        name: user-service
      cloud:
        nacos:
          discovery:
            server-addr: nacos:8848
          config:
            server-addr: nacos:8848
            file-extension: yaml
      datasource:
        url: jdbc:mysql://mysql:3306/user_db?useSSL=false&characterEncoding=utf8
        driver-class-name: com.mysql.cj.jdbc.Driver
      redis:
        host: redis
        port: 6379
      sleuth:
        sampler:
          probability: 1.0
      zipkin:
        base-url: http://zipkin:9411
    
    # 日志配置
    logging:
      level:
        root: INFO
        com.example: DEBUG
      file:
        name: /app/logs/app.log
      pattern:
        file: "%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n"
  
  # JVM参数
  jvm-options: |
    -Xms512m
    -Xmx512m
    -XX:+UseG1GC
    -XX:MaxGCPauseMillis=200
    -XX:+HeapDumpOnOutOfMemoryError
    -XX:HeapDumpPath=/app/heapdump.hprof
    -XX:+PrintGCDetails
    -XX:+PrintGCDateStamps
    -Xloggc:/app/logs/gc.log

步骤4:创建Secret(密钥)

# 生成Base64编码的密码
echo -n 'mysecretpassword' | base64
# 输出:bXlzZWNyZXRwYXNzd29yZA==

echo -n 'admin123' | base64
# 输出:YWRtaW4xMjM=
# k8s/secret.yaml
apiVersion: v1
kind: Secret
metadata:
  name: microservices-secret
  namespace: microservices
type: Opaque
data:
  mysql-root-password: bXlzZWNyZXRwYXNzd29yZA==  # mysecretpassword
  mysql-database-password: bXlzZWNyZXRwYXNzd29yZA==
  redis-password: YWRtaW4xMjM=  # admin123
  nacos-username: bmFjb3M=  # nacos
  nacos-password: bmFjb3M=  # nacos
  jwt-secret: c3VwZXItc2VjcmV0LWp3dC1rZXktZm9yLWF1dGg=  # super-secret-jwt-key-for-auth

步骤5:部署MySQL

# k8s/mysql.yaml
apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: mysql
  namespace: microservices
  labels:
    app: mysql
spec:
  serviceName: mysql
  replicas: 1
  selector:
    matchLabels:
      app: mysql
  template:
    metadata:
      labels:
        app: mysql
    spec:
      containers:
      - name: mysql
        image: mysql:8.0
        imagePullPolicy: IfNotPresent
        ports:
        - containerPort: 3306
        env:
        - name: MYSQL_ROOT_PASSWORD
          valueFrom:
            secretKeyRef:
              name: microservices-secret
              key: mysql-root-password
        - name: MYSQL_DATABASE
          value: "microservices"
        - name: TZ
          value: "Asia/Shanghai"
        args:
        - --character-set-server=utf8mb4
        - --collation-server=utf8mb4_unicode_ci
        - --default-authentication-plugin=mysql_native_password
        - --max_connections=1000
        - --innodb_buffer_pool_size=512M
        resources:
          requests:
            memory: "512Mi"
            cpu: "250m"
          limits:
            memory: "1Gi"
            cpu: "500m"
        volumeMounts:
        - name: mysql-data
          mountPath: /var/lib/mysql
        - name: mysql-config
          mountPath: /etc/mysql/conf.d
        livenessProbe:
          exec:
            command:
            - mysqladmin
            - ping
            - -h
            - localhost
            - -uroot
            - -p$(MYSQL_ROOT_PASSWORD)
          initialDelaySeconds: 30
          periodSeconds: 10
          timeoutSeconds: 5
        readinessProbe:
          exec:
            command:
            - mysql
            - -h
            - localhost
            - -uroot
            - -p$(MYSQL_ROOT_PASSWORD)
            - -e
            - "SELECT 1"
          initialDelaySeconds: 5
          periodSeconds: 5
          timeoutSeconds: 1
      volumes:
      - name: mysql-config
        configMap:
          name: mysql-config
      securityContext:
        fsGroup: 999
  volumeClaimTemplates:
  - metadata:
      name: mysql-data
    spec:
      accessModes: [ "ReadWriteOnce" ]
      storageClassName: "standard"
      resources:
        requests:
          storage: 10Gi
---
apiVersion: v1
kind: Service
metadata:
  name: mysql
  namespace: microservices
spec:
  selector:
    app: mysql
  ports:
  - port: 3306
    targetPort: 3306
  clusterIP: None  # Headless Service,直接使用Pod IP

步骤6:部署Redis

# k8s/redis.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: redis
  namespace: microservices
spec:
  replicas: 1
  selector:
    matchLabels:
      app: redis
  template:
    metadata:
      labels:
        app: redis
    spec:
      containers:
      - name: redis
        image: redis:7-alpine
        imagePullPolicy: IfNotPresent
        ports:
        - containerPort: 6379
        env:
        - name: REDIS_PASSWORD
          valueFrom:
            secretKeyRef:
              name: microservices-secret
              key: redis-password
        command:
        - redis-server
        - "--requirepass"
        - "$(REDIS_PASSWORD)"
        - "--appendonly"
        - "yes"
        - "--maxmemory"
        - "256mb"
        - "--maxmemory-policy"
        - "allkeys-lru"
        resources:
          requests:
            memory: "128Mi"
            cpu: "100m"
          limits:
            memory: "256Mi"
            cpu: "200m"
        volumeMounts:
        - name: redis-data
          mountPath: /data
        livenessProbe:
          tcpSocket:
            port: 6379
          initialDelaySeconds: 30
          periodSeconds: 10
        readinessProbe:
          exec:
            command:
            - redis-cli
            - -a
            - "$(REDIS_PASSWORD)"
            - ping
          initialDelaySeconds: 5
          periodSeconds: 5
      volumes:
      - name: redis-data
        emptyDir: {}
---
apiVersion: v1
kind: Service
metadata:
  name: redis
  namespace: microservices
spec:
  selector:
    app: redis
  ports:
  - port: 6379
    targetPort: 6379

步骤7:部署Nacos

# k8s/nacos.yaml
apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: nacos
  namespace: microservices
spec:
  serviceName: nacos
  replicas: 3  # 集群模式,3个节点
  selector:
    matchLabels:
      app: nacos
  template:
    metadata:
      labels:
        app: nacos
    spec:
      containers:
      - name: nacos
        image: nacos/nacos-server:v2.2.3
        imagePullPolicy: IfNotPresent
        ports:
        - containerPort: 8848
          name: client
        - containerPort: 9848
          name: raft
        - containerPort: 9849
          name: grpc
        env:
        - name: MODE
          value: "cluster"
        - name: NACOS_SERVERS
          value: "nacos-0.nacos-headless.microservices.svc.cluster.local:8848 nacos-1.nacos-headless.microservices.svc.cluster.local:8848 nacos-2.nacos-headless.microservices.svc.cluster.local:8848"
        - name: SPRING_DATASOURCE_PLATFORM
          value: "mysql"
        - name: MYSQL_SERVICE_HOST
          value: "mysql"
        - name: MYSQL_SERVICE_PORT
          value: "3306"
        - name: MYSQL_SERVICE_DB_NAME
          value: "nacos"
        - name: MYSQL_SERVICE_USER
          value: "root"
        - name: MYSQL_SERVICE_PASSWORD
          valueFrom:
            secretKeyRef:
              name: microservices-secret
              key: mysql-root-password
        - name: NACOS_AUTH_ENABLE
          value: "true"
        - name: NACOS_AUTH_IDENTITY_KEY
          valueFrom:
            secretKeyRef:
              name: microservices-secret
              key: nacos-username
        - name: NACOS_AUTH_IDENTITY_VALUE
          valueFrom:
            secretKeyRef:
              name: microservices-secret
              key: nacos-password
        resources:
          requests:
            memory: "1Gi"
            cpu: "500m"
          limits:
            memory: "2Gi"
            cpu: "1000m"
        volumeMounts:
        - name: nacos-logs
          mountPath: /home/nacos/logs
        livenessProbe:
          httpGet:
            path: /nacos/actuator/health
            port: 8848
          initialDelaySeconds: 60
          periodSeconds: 10
        readinessProbe:
          httpGet:
            path: /nacos/actuator/health
            port: 8848
          initialDelaySeconds: 30
          periodSeconds: 5
      volumes:
      - name: nacos-logs
        emptyDir: {}
---
apiVersion: v1
kind: Service
metadata:
  name: nacos
  namespace: microservices
spec:
  selector:
    app: nacos
  ports:
  - name: client
    port: 8848
    targetPort: 8848
  - name: raft
    port: 9848
    targetPort: 9848
  - name: grpc
    port: 9849
    targetPort: 9849
---
apiVersion: v1
kind: Service
metadata:
  name: nacos-headless
  namespace: microservices
spec:
  clusterIP: None
  selector:
    app: nacos
  ports:
  - name: client
    port: 8848
    targetPort: 8848

步骤8:部署User Service(重点!)

# k8s/user-service/deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: user-service
  namespace: microservices
  labels:
    app: user-service
    version: v1.0.0
spec:
  replicas: 3  # 初始3个副本
  revisionHistoryLimit: 10  # 保留10个历史版本
  selector:
    matchLabels:
      app: user-service
  strategy:
    type: RollingUpdate  # 滚动更新策略
    rollingUpdate:
      maxSurge: 1  # 最多多出1个Pod
      maxUnavailable: 0  # 更新时保证最少可用Pod数
  template:
    metadata:
      labels:
        app: user-service
        version: v1.0.0
      annotations:
        prometheus.io/scrape: "true"
        prometheus.io/port: "8080"
        prometheus.io/path: "/actuator/prometheus"
    spec:
      containers:
      - name: user-service
        image: registry.mycompany.com/microservices/user-service:v1.0.0
        imagePullPolicy: IfNotPresent
        ports:
        - containerPort: 8080
          name: http
        env:
        - name: SPRING_PROFILES_ACTIVE
          value: "k8s"
        - name: JAVA_OPTS
          value: "-Xms512m -Xmx512m -XX:+UseG1GC -XX:MaxGCPauseMillis=200"
        - name: POD_NAME
          valueFrom:
            fieldRef:
              fieldPath: metadata.name
        - name: POD_IP
          valueFrom:
            fieldRef:
              fieldPath: status.podIP
        - name: NODE_NAME
          valueFrom:
            fieldRef:
              fieldPath: spec.nodeName
        resources:
          requests:
            memory: "512Mi"
            cpu: "250m"
          limits:
            memory: "1Gi"
            cpu: "500m"
        volumeMounts:
        - name: config-volume
          mountPath: /app/config
          readOnly: true
        - name: logs-volume
          mountPath: /app/logs
        - name: tmp-volume
          mountPath: /tmp
        livenessProbe:  # 存活探针
          httpGet:
            path: /actuator/health/liveness
            port: 8080
            httpHeaders:
            - name: Custom-Header
              value: Awesome
          initialDelaySeconds: 60  # 容器启动60秒后开始检查
          periodSeconds: 10  # 每10秒检查一次
          timeoutSeconds: 5  # 超时时间5秒
          successThreshold: 1  # 成功阈值
          failureThreshold: 3  # 失败3次判定为不健康
        readinessProbe:  # 就绪探针
          httpGet:
            path: /actuator/health/readiness
            port: 8080
          initialDelaySeconds: 30
          periodSeconds: 5
          timeoutSeconds: 3
          successThreshold: 1
          failureThreshold: 3
        startupProbe:  # 启动探针(K8S 1.16+)
          httpGet:
            path: /actuator/health/startup
            port: 8080
          failureThreshold: 30  # 最多检查30次
          periodSeconds: 10  # 每10秒检查一次
        lifecycle:
          postStart:  # 容器启动后执行
            exec:
              command:
              - "/bin/sh"
              - "-c"
              - "echo '容器启动完成,时间:' && date"
          preStop:  # 容器停止前执行
            exec:
              command:
              - "/bin/sh"
              - "-c"
              - "sleep 30 && echo '正在优雅关闭...'"
        securityContext:
          runAsNonRoot: true
          runAsUser: 1000
          allowPrivilegeEscalation: false
          readOnlyRootFilesystem: true
          capabilities:
            drop:
            - ALL
      volumes:
      - name: config-volume
        configMap:
          name: microservices-config
          items:
          - key: application.yml
            path: application.yml
      - name: logs-volume
        emptyDir: {}
      - name: tmp-volume
        emptyDir:
          medium: Memory
          sizeLimit: 100Mi
      imagePullSecrets:
      - name: regcred  # 私有仓库认证
      nodeSelector:  # 节点选择器
        node-type: application
      tolerations:  # 容忍
      - key: "node-type"
        operator: "Equal"
        value: "application"
        effect: "NoSchedule"
      affinity:  # 亲和性
        podAntiAffinity:  # Pod反亲和,分散到不同节点
          preferredDuringSchedulingIgnoredDuringExecution:
          - weight: 100
            podAffinityTerm:
              labelSelector:
                matchExpressions:
                - key: app
                  operator: In
                  values:
                  - user-service
              topologyKey: kubernetes.io/hostname
---
# 水平自动扩缩容(HPA)
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
  name: user-service-hpa
  namespace: microservices
spec:
  scaleTargetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: user-service
  minReplicas: 2  # 最小副本数
  maxReplicas: 10  # 最大副本数
  metrics:
  - type: Resource
    resource:
      name: cpu
      target:
        type: Utilization
        averageUtilization: 70  # CPU使用率70%触发扩容
  - type: Resource
    resource:
      name: memory
      target:
        type: Utilization
        averageUtilization: 80  # 内存使用率80%触发扩容
  - type: Pods
    pods:
      metric:
        name: http_requests_per_second
      target:
        type: AverageValue
        averageValue: 100  # 平均每秒100个请求触发扩容
  behavior:  # 扩缩容行为
    scaleUp:
      policies:
      - type: Pods
        value: 2
        periodSeconds: 60
      - type: Percent
        value: 50
        periodSeconds: 60
      selectPolicy: Max
      stabilizationWindowSeconds: 0
    scaleDown:
      policies:
      - type: Pods
        value: 1
        periodSeconds: 300
      - type: Percent
        value: 20
        periodSeconds: 300
      selectPolicy: Max
      stabilizationWindowSeconds: 300

步骤9:创建Service

# k8s/user-service/service.yaml
apiVersion: v1
kind: Service
metadata:
  name: user-service
  namespace: microservices
  labels:
    app: user-service
  annotations:
    # 负载均衡配置
    service.beta.kubernetes.io/aws-load-balancer-type: "nlb"
    # 会话保持
    service.beta.kubernetes.io/aws-load-balancer-backend-protocol: "tcp"
    # 健康检查
    service.beta.kubernetes.io/aws-load-balancer-healthcheck-interval: "30"
spec:
  selector:
    app: user-service
  ports:
  - name: http
    port: 80
    targetPort: 8080
    protocol: TCP
  - name: management
    port: 8081
    targetPort: 8081
    protocol: TCP
  type: ClusterIP  # 集群内访问
  # type: NodePort  # 节点端口访问
  # type: LoadBalancer  # 云厂商负载均衡
  sessionAffinity: ClientIP  # 会话保持
  sessionAffinityConfig:
    clientIP:
      timeoutSeconds: 10800
---
# 为Prometheus添加ServiceMonitor
apiVersion: monitoring.coreos.com/v1
kind: ServiceMonitor
metadata:
  name: user-service-monitor
  namespace: microservices
spec:
  selector:
    matchLabels:
      app: user-service
  endpoints:
  - port: http
    interval: 30s
    path: /actuator/prometheus
    scrapeTimeout: 10s
    honorLabels: true
    relabelings:
    - action: replace
      sourceLabels: [__meta_kubernetes_pod_node_name]
      targetLabel: kubernetes_node
  namespaceSelector:
    matchNames:
    - microservices

步骤10:部署Ingress(入口)

# k8s/ingress.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: microservices-ingress
  namespace: microservices
  annotations:
    # Nginx Ingress Controller注解
    kubernetes.io/ingress.class: "nginx"
    nginx.ingress.kubernetes.io/ssl-redirect: "true"
    nginx.ingress.kubernetes.io/force-ssl-redirect: "true"
    nginx.ingress.kubernetes.io/proxy-body-size: "10m"
    nginx.ingress.kubernetes.io/proxy-connect-timeout: "30"
    nginx.ingress.kubernetes.io/proxy-read-timeout: "30"
    nginx.ingress.kubernetes.io/proxy-send-timeout: "30"
    nginx.ingress.kubernetes.io/enable-cors: "true"
    nginx.ingress.kubernetes.io/cors-allow-methods: "PUT, GET, POST, OPTIONS, DELETE"
    nginx.ingress.kubernetes.io/cors-allow-origin: "*"
    nginx.ingress.kubernetes.io/cors-allow-headers: "DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Authorization"
    # 限流
    nginx.ingress.kubernetes.io/limit-rps: "100"
    nginx.ingress.kubernetes.io/limit-burst: "200"
    # 重试
    nginx.ingress.kubernetes.io/proxy-next-upstream: "error timeout http_502 http_503 http_504"
    nginx.ingress.kubernetes.io/proxy-next-upstream-tries: "3"
    nginx.ingress.kubernetes.io/proxy-next-upstream-timeout: "10"
    # 会话保持
    nginx.ingress.kubernetes.io/affinity: "cookie"
    nginx.ingress.kubernetes.io/session-cookie-name: "route"
    nginx.ingress.kubernetes.io/session-cookie-expires: "172800"
    nginx.ingress.kubernetes.io/session-cookie-max-age: "172800"
spec:
  tls:
  - hosts:
    - api.mycompany.com
    secretName: tls-secret  # SSL证书
  rules:
  - host: api.mycompany.com
    http:
      paths:
      - path: /user-service
        pathType: Prefix
        backend:
          service:
            name: user-service
            port:
              number: 80
        # 路径重写
        path: /user-service(/|$)(.*)
        pathType: ImplementationSpecific
      - path: /order-service
        pathType: Prefix
        backend:
          service:
            name: order-service
            port:
              number: 80
      - path: /product-service
        pathType: Prefix
        backend:
          service:
            name: product-service
            port:
              number: 80
      - path: /api-gateway
        pathType: Prefix
        backend:
          service:
            name: api-gateway
            port:
              number: 80
      - path: /admin
        pathType: Prefix
        backend:
          service:
            name: admin-server
            port:
              number: 80
      - path: /
        pathType: Prefix
        backend:
          service:
            name: api-gateway
            port:
              number: 80

五、部署实战

1. 应用配置

# src/main/resources/application-k8s.yml
spring:
  application:
    name: user-service
  
  cloud:
    kubernetes:
      enabled: true
      # 自动发现Service
      discovery:
        enabled: true
        all-namespaces: false
        namespaces:
          - microservices
      # 从ConfigMap加载配置
      config:
        enabled: true
        sources:
          - namespace: microservices
            name: microservices-config
    
    nacos:
      discovery:
        # 使用K8S Service名称
        server-addr: nacos.microservices.svc.cluster.local:8848
      config:
        server-addr: nacos.microservices.svc.cluster.local:8848
  
  config:
    import: optional:configmap:microservices-config  # 从ConfigMap导入
  
  datasource:
    url: jdbc:mysql://mysql.microservices.svc.cluster.local:3306/user_db?useSSL=false&characterEncoding=utf8
    username: root
    password: ${DB_PASSWORD}
    hikari:
      maximum-pool-size: 10
      minimum-idle: 5
      connection-timeout: 30000
      idle-timeout: 600000
      max-lifetime: 1800000
  
  redis:
    host: redis.microservices.svc.cluster.local
    port: 6379
    password: ${REDIS_PASSWORD}
    lettuce:
      pool:
        max-active: 8
        max-idle: 8
        min-idle: 0
  
  # K8S Actuator端点
  management:
    endpoints:
      web:
        exposure:
          include: health,info,metrics,prometheus,env
        base-path: /actuator
    endpoint:
      health:
        show-details: always
        probes:
          enabled: true
    health:
      livenessstate:
        enabled: true
      readinessstate:
        enabled: true
    metrics:
      export:
        prometheus:
          enabled: true
      tags:
        application: ${spring.application.name}
        pod: ${HOSTNAME}
        namespace: ${KUBERNETES_NAMESPACE:default}
    
    # K8S探针
    kubernetes:
      probes:
        enabled: true
        liveness:
          path: /actuator/health/liveness
          initial-delay: 60
        readiness:
          path: /actuator/health/readiness
          initial-delay: 30

# 日志配置
logging:
  level:
    root: INFO
    com.example: DEBUG
    org.springframework.cloud.kubernetes: INFO
  file:
    name: /app/logs/app.log
  pattern:
    file: "%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level [%X{traceId:-},%X{spanId:-}] %logger{36} - %msg%n"
    console: "%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level [%X{traceId:-},%X{spanId:-}] %logger{36} - %msg%n"

# 链路追踪
zipkin:
  base-url: http://zipkin.microservices.svc.cluster.local:9411

# 服务端口
server:
  port: 8080
  servlet:
    context-path: /
  tomcat:
    max-threads: 200
    min-spare-threads: 20
    accept-count: 100

2. 构建和推送镜像

#!/bin/bash
# build-push.sh

# 设置变量
VERSION="1.0.0"
REGISTRY="registry.mycompany.com"
NAMESPACE="microservices"
SERVICES=("user-service" "order-service" "product-service" "api-gateway" "admin-server")

# 登录镜像仓库
docker login $REGISTRY -u $USERNAME -p $PASSWORD

# 构建和推送每个服务
for SERVICE in "${SERVICES[@]}"; do
    echo "构建 $SERVICE..."
    
    # 进入目录
    cd $SERVICE
    
    # 构建镜像
    docker build \
        --build-arg APP_VERSION=$VERSION \
        --build-arg BUILD_DATE=$(date -u +'%Y-%m-%dT%H:%M:%SZ') \
        --build-arg VCS_REF=$(git rev-parse --short HEAD) \
        -t $REGISTRY/$NAMESPACE/$SERVICE:$VERSION \
        -t $REGISTRY/$NAMESPACE/$SERVICE:latest \
        .
    
    # 扫描安全漏洞
    echo "安全扫描 $SERVICE..."
    docker scan $REGISTRY/$NAMESPACE/$SERVICE:$VERSION
    
    # 推送镜像
    echo "推送 $SERVICE..."
    docker push $REGISTRY/$NAMESPACE/$SERVICE:$VERSION
    docker push $REGISTRY/$NAMESPACE/$SERVICE:latest
    
    cd ..
done

echo "所有镜像构建和推送完成!"

3. 部署到K8S

#!/bin/bash
# deploy-to-k8s.sh

# 设置命名空间
kubectl apply -f k8s/namespace.yaml

# 创建镜像拉取密钥(如果是私有仓库)
kubectl create secret docker-registry regcred \
  --docker-server=registry.mycompany.com \
  --docker-username=$USERNAME \
  --docker-password=$PASSWORD \
  --namespace=microservices

# 部署基础服务
kubectl apply -f k8s/configmap.yaml
kubectl apply -f k8s/secret.yaml
kubectl apply -f k8s/mysql.yaml
kubectl apply -f k8s/redis.yaml
kubectl apply -f k8s/nacos.yaml

# 等待基础服务就绪
echo "等待基础服务启动..."
kubectl wait --for=condition=ready pod -l app=mysql --timeout=300s -n microservices
kubectl wait --for=condition=ready pod -l app=redis --timeout=300s -n microservices
kubectl wait --for=condition=ready pod -l app=nacos --timeout=300s -n microservices

# 部署微服务
kubectl apply -f k8s/user-service/
kubectl apply -f k8s/order-service/
kubectl apply -f k8s/product-service/
kubectl apply -f k8s/api-gateway/
kubectl apply -f k8s/admin-server/

# 部署Ingress
kubectl apply -f k8s/ingress.yaml

# 查看部署状态
echo "部署状态:"
kubectl get all -n microservices

echo "Pod状态:"
kubectl get pods -n microservices -w

echo "服务状态:"
kubectl get svc -n microservices

echo "Ingress状态:"
kubectl get ingress -n microservices

六、K8S运维命令大全

1. 基础命令

# 查看所有资源
kubectl get all -n microservices

# 查看Pod
kubectl get pods -n microservices
kubectl get pods -n microservices -o wide  # 显示详细信息
kubectl get pods -n microservices -l app=user-service  # 按标签筛选

# 查看服务
kubectl get svc -n microservices

# 查看配置
kubectl get configmap -n microservices
kubectl get secret -n microservices

# 查看部署
kubectl get deployments -n microservices
kubectl get statefulsets -n microservices
kubectl get daemonsets -n microservices

2. 调试命令

# 查看Pod日志
kubectl logs -f user-service-7c6f8d9b8-abc12 -n microservices
kubectl logs -f --tail=100 user-service-7c6f8d9b8-abc12 -n microservices
kubectl logs -f --since=1h user-service-7c6f8d9b8-abc12 -n microservices

# 进入Pod(调试)
kubectl exec -it user-service-7c6f8d9b8-abc12 -n microservices -- /bin/sh
kubectl exec -it user-service-7c6f8d9b8-abc12 -n microservices -- java -version

# 查看Pod描述
kubectl describe pod user-service-7c6f8d9b8-abc12 -n microservices

# 查看事件
kubectl get events -n microservices --sort-by='.lastTimestamp'
kubectl get events -n microservices --field-selector involvedObject.name=user-service-7c6f8d9b8-abc12

3. 维护命令

# 扩容缩容
kubectl scale deployment user-service --replicas=5 -n microservices

# 滚动更新
kubectl set image deployment/user-service user-service=registry.mycompany.com/microservices/user-service:v1.1.0 -n microservices

# 查看更新状态
kubectl rollout status deployment/user-service -n microservices

# 回滚
kubectl rollout undo deployment/user-service -n microservices
kubectl rollout undo deployment/user-service --to-revision=2 -n microservices

# 查看更新历史
kubectl rollout history deployment/user-service -n microservices

# 重启Pod
kubectl rollout restart deployment/user-service -n microservices

# 删除Pod(触发重建)
kubectl delete pod user-service-7c6f8d9b8-abc12 -n microservices

4. 排错命令

# 查看Pod状态异常原因
kubectl describe pod <pod-name> | grep -A 10 Events

# 查看资源使用
kubectl top pods -n microservices
kubectl top nodes

# 端口转发(访问集群内服务)
kubectl port-forward svc/user-service 8080:80 -n microservices
kubectl port-forward pod/user-service-7c6f8d9b8-abc12 8080:8080 -n microservices

# 临时运行调试容器
kubectl debug -it user-service-7c6f8d9b8-abc12 --image=busybox --target=user-service -n microservices

# 查看网络策略
kubectl get networkpolicy -n microservices

# 查看存储
kubectl get pvc -n microservices
kubectl get pv

5. 资源管理

# 查看资源限制
kubectl describe pod user-service-7c6f8d9b8-abc12 | grep -A 5 "Limits"

# 设置资源限制
kubectl set resources deployment user-service --limits=cpu=1000m,memory=1Gi --requests=cpu=500m,memory=512Mi -n microservices

# 查看HPA状态
kubectl get hpa -n microservices
kubectl describe hpa user-service-hpa -n microservices

# 手动触发扩缩容
kubectl autoscale deployment user-service --cpu-percent=50 --min=2 --max=10 -n microservices

七、生产环境最佳实践

1. 资源配额和限制

# k8s/resource-quota.yaml
apiVersion: v1
kind: ResourceQuota
metadata:
  name: microservices-quota
  namespace: microservices
spec:
  hard:
    # CPU限制
    limits.cpu: "20"
    limits.memory: 40Gi
    requests.cpu: "10"
    requests.memory: 20Gi
    
    # Pod数量限制
    pods: "50"
    
    # 服务限制
    services: "20"
    services.loadbalancers: "5"
    services.nodeports: "10"
    
    # 存储限制
    persistentvolumeclaims: "10"
    requests.storage: 100Gi

2. 网络策略

# k8s/network-policy.yaml
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: microservices-network-policy
  namespace: microservices
spec:
  podSelector: {}  # 应用到所有Pod
  policyTypes:
  - Ingress
  - Egress
  
  # 入站规则
  ingress:
  - from:
    - namespaceSelector:
        matchLabels:
          name: microservices
    ports:
    - protocol: TCP
      port: 8080
    - protocol: TCP
      port: 3306  # MySQL
    - protocol: TCP
      port: 6379  # Redis
    - protocol: TCP
      port: 8848  # Nacos
    
  - from:
    - ipBlock:
        cidr: 10.0.0.0/8  # 内部网络
    ports:
    - protocol: TCP
      port: 80
    - protocol: TCP
      port: 443
  
  # 出站规则
  egress:
  - to:
    - ipBlock:
        cidr: 0.0.0.0/0
    ports:
    - protocol: TCP
      port: 53  # DNS
    - protocol: UDP
      port: 53  # DNS
    - protocol: TCP
      port: 443  # HTTPS
    - protocol: TCP
      port: 80   # HTTP

3. Pod安全策略

# k8s/pod-security-policy.yaml
apiVersion: policy/v1beta1
kind: PodSecurityPolicy
metadata:
  name: microservices-psp
spec:
  privileged: false  # 禁止特权容器
  allowPrivilegeEscalation: false
  requiredDropCapabilities:
    - ALL
  volumes:
    - 'configMap'
    - 'emptyDir'
    - 'projected'
    - 'secret'
    - 'downwardAPI'
    - 'persistentVolumeClaim'
  hostNetwork: false
  hostIPC: false
  hostPID: false
  runAsUser:
    rule: 'MustRunAsNonRoot'
  seLinux:
    rule: 'RunAsAny'
  supplementalGroups:
    rule: 'MustRunAs'
    ranges:
      - min: 1
        max: 65535
  fsGroup:
    rule: 'MustRunAs'
    ranges:
      - min: 1
        max: 65535
  readOnlyRootFilesystem: true  # 只读根文件系统

4. 监控告警

# k8s/prometheus-alerts.yaml
apiVersion: monitoring.coreos.com/v1
kind: PrometheusRule
metadata:
  name: microservices-alerts
  namespace: monitoring
spec:
  groups:
  - name: microservices.rules
    rules:
    - alert: HighCPUUsage
      expr: 100 * (1 - avg by(instance) (rate(node_cpu_seconds_total{mode="idle"}[5m]))) > 80
      for: 5m
      labels:
        severity: warning
      annotations:
        summary: "高CPU使用率"
        description: "实例 {{ $labels.instance }} CPU使用率超过80%,当前值 {{ $value }}%"
    
    - alert: HighMemoryUsage
      expr: (node_memory_MemTotal_bytes - node_memory_MemAvailable_bytes) / node_memory_MemTotal_bytes * 100 > 85
      for: 5m
      labels:
        severity: warning
      annotations:
        summary: "高内存使用率"
        description: "实例 {{ $labels.instance }} 内存使用率超过85%,当前值 {{ $value }}%"
    
    - alert: PodCrashLooping
      expr: rate(kube_pod_container_status_restarts_total[15m]) * 60 * 5 > 0
      for: 5m
      labels:
        severity: critical
      annotations:
        summary: "Pod频繁重启"
        description: "Pod {{ $labels.pod }} 在5分钟内重启超过5次"
    
    - alert: ServiceDown
      expr: up == 0
      for: 2m
      labels:
        severity: critical
      annotations:
        summary: "服务下线"
        description: "服务 {{ $labels.job }} 实例 {{ $labels.instance }} 已下线超过2分钟"

5. 备份和恢复

#!/bin/bash
# backup-k8s.sh

# 备份命名空间配置
kubectl get all -n microservices -o yaml > backup/microservices-all.yaml
kubectl get configmap -n microservices -o yaml > backup/microservices-configmap.yaml
kubectl get secret -n microservices -o yaml > backup/microservices-secret.yaml
kubectl get pvc -n microservices -o yaml > backup/microservices-pvc.yaml

# 备份MySQL数据
kubectl exec -n microservices mysql-0 -- mysqldump -uroot -p$MYSQL_PASSWORD --all-databases > backup/mysql-all-$(date +%Y%m%d%H%M%S).sql

# 备份ETCD(K8S集群数据)
ETCDCTL_API=3 etcdctl --endpoints=https://127.0.0.1:2379 \
  --cacert=/etc/kubernetes/pki/etcd/ca.crt \
  --cert=/etc/kubernetes/pki/etcd/server.crt \
  --key=/etc/kubernetes/pki/etcd/server.key \
  snapshot save backup/etcd-snapshot-$(date +%Y%m%d%H%M%S).db

# 恢复脚本
#!/bin/bash
# restore-k8s.sh
kubectl apply -f backup/microservices-all.yaml
kubectl apply -f backup/microservices-configmap.yaml
kubectl apply -f backup/microservices-secret.yaml
kubectl apply -f backup/microservices-pvc.yaml

# 恢复MySQL数据
kubectl exec -i -n microservices mysql-0 -- mysql -uroot -p$MYSQL_PASSWORD < backup/mysql-all-20240113120000.sql

# 恢复ETCD
ETCDCTL_API=3 etcdctl snapshot restore backup/etcd-snapshot-20240113120000.db \
  --data-dir /var/lib/etcd-backup \
  --initial-cluster etcd1=https://etcd1:2380 \
  --initial-advertise-peer-urls https://etcd1:2380 \
  --name etcd1 \
  --initial-cluster-token etcd-cluster

八、常见问题解决方案

1. Pod一直Pending

# 查看原因
kubectl describe pod <pod-name> | grep -A 10 Events

# 常见原因和解决:
# 1. 资源不足:kubectl describe nodes | grep -A 5 -B 5 "Allocated resources"
# 2. 没有匹配的节点:检查nodeSelector和tolerations
# 3. PVC挂载失败:kubectl get pvc
# 4. 镜像拉取失败:检查镜像名称和pull secret

2. Pod启动失败

# 查看日志
kubectl logs <pod-name> --previous

# 常见原因:
# 1. 应用启动失败:检查应用日志
# 2. 探针失败:调整initialDelaySeconds
# 3. 配置错误:检查ConfigMap和Secret
# 4. 依赖服务未就绪:增加initContainer等待

3. 服务无法访问

# 检查服务
kubectl get svc <service-name>
kubectl describe svc <service-name>

# 检查Endpoint
kubectl get endpoints <service-name>

# 检查网络策略
kubectl get networkpolicy

# 端口转发测试
kubectl port-forward svc/<service-name> 8080:80
curl http://localhost:8080/actuator/health

4. 内存泄漏

# 添加内存限制和监控
resources:
  limits:
    memory: "1Gi"
  requests:
    memory: "512Mi"

# 添加OOM Killer配置
env:
- name: JAVA_OPTS
  value: "-XX:+ExitOnOutOfMemoryError -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/app/heapdump.hprof"

# 监控内存使用
- alert: MemoryUsageHigh
  expr: (container_memory_working_set_bytes{pod=~"user-service-.*"} / container_spec_memory_limit_bytes{pod=~"user-service-.*"}) * 100 > 90
  for: 5m

5. 滚动更新卡住

# 查看更新状态
kubectl rollout status deployment/user-service

# 查看事件
kubectl describe deployment/user-service | grep -A 20 "Events"

# 常见原因:
# 1. 新版本镜像有问题:回滚 kubectl rollout undo deployment/user-service
# 2. 就绪探针失败:调整探针配置
# 3. 资源不足:检查节点资源

# 强制回滚
kubectl rollout undo deployment/user-service --to-revision=1

九、今儿个总结

零基础全栈开发Java微服务版本实战-后端-前端-运维-实战企业级三个实战项目

资源获取:关注公众号: 小坏说Java ,获取本文所有示例代码、配置模板及导出工具。

学会了啥?

  1. ✅ Kubernetes核心概念:Pod、Deployment、Service、ConfigMap、Secret
  2. ✅ 微服务在K8S的完整部署方案
  3. ✅ 资源配置:Requests、Limits、探针、亲和性
  4. ✅ 服务发现和负载均衡:Service、Ingress
  5. ✅ 自动扩缩容:HPA配置
  6. ✅ 生产环境最佳实践:安全、监控、备份
  7. ✅ 运维命令和故障排查

关键点

  1. 声明式配置:告诉K8S想要什么状态
  2. 资源管理:合理设置Requests和Limits
  3. 健康检查:配置好存活、就绪、启动探针
  4. 滚动更新:零停机部署
  5. 自动恢复:Pod挂了自动重启
  6. 弹性伸缩:根据负载自动扩缩容

十、明儿个学啥?

明天咱学服务网格

  • Service Mesh是啥?为什么需要?
  • Istio vs Linkerd怎么选?
  • 熔断、限流、重试怎么配?
  • 金丝雀发布、A/B测试怎么做?
  • 分布式追踪、指标收集

明天咱给微服务穿上"防弹衣"!🛡️


零基础全栈开发Java微服务版本实战-后端-前端-运维-实战企业级三个实战项目

资源获取:关注公众号: 小坏说Java ,获取本文所有示例代码、配置模板及导出工具。

Kubernetes生产级部署全攻略:SpringCloud微服务上云实战,从零搭建高可用集群

【关注】 🔥 本文为《SpringCloud企业级实战》专栏第12篇,点赞+收藏防丢失
💡 关注获取:完整K8S YAML配置 + 自动化部署脚本 + 监控告警规则
🚀 评论区留言「K8S问题」,获取一对一架构咨询
📚 配套GitHub项目:包含20+生产级K8S配置文件
👨💻 明日预告:Service Mesh实战,Istio让微服务治理更简单