Kubernetes 部署 Java/前端/微服务集群
概述
Kubernetes(K8s)是当前主流的容器编排平台,提供自动部署、弹性伸缩、服务发现与负载均衡等能力。本文档涵盖 Java Spring Boot 应用、前端 SPA 应用以及微服务集群在 K8s 上的完整部署实践,包含详细的 YAML 配置示例和最佳实践。
Java 应用部署
Spring Boot 容器化
Dockerfile 示例
# 多阶段构建
# 第一阶段:使用 Maven 镜像编译
FROM eclipse-temurin:21-jdk-alpine AS builder
WORKDIR /build
COPY pom.xml .
RUN mvn dependency:go-offline -B
COPY src ./src
RUN mvn package -DskipTests -B
# 第二阶段:运行镜像
FROM eclipse-temurin:21-jre-alpine
WORKDIR /app
# 创建非 root 用户
RUN addgroup -S appgroup && adduser -S appuser -G appgroup
# 从 builder 阶段复制构建产物
COPY --from=builder /build/target/*.jar app.jar
# 暴露端口
EXPOSE 8080
# 切换为非 root 用户运行
USER appuser
ENTRYPOINT ["java", "-jar", "app.jar"]ConfigMap 管理配置
将 application.yml 从镜像中剥离,通过 ConfigMap 注入,实现配置与镜像分离。
ConfigMap 定义
apiVersion: v1
kind: ConfigMap
metadata:
name: user-service-config
namespace: production
data:
application.yml: |
server:
port: 8080
spring:
datasource:
url: jdbc:mysql://mysql-service:3306/user_db?useSSL=false&characterEncoding=utf-8
username: ${DB_USERNAME}
password: ${DB_PASSWORD}
hikari:
maximum-pool-size: 20
minimum-idle: 5
redis:
host: redis-service
port: 6379
logging:
level:
com.example: INFO将 ConfigMap 挂载到 Deployment
apiVersion: apps/v1
kind: Deployment
metadata:
name: user-service
namespace: production
spec:
replicas: 3
selector:
matchLabels:
app: user-service
template:
metadata:
labels:
app: user-service
spec:
containers:
- name: user-service
image: registry.example.com/user-service:1.0.0
ports:
- containerPort: 8080
env:
# 敏感信息通过 Secret 注入
- name: DB_USERNAME
valueFrom:
secretKeyRef:
name: db-secret
key: username
- name: DB_PASSWORD
valueFrom:
secretKeyRef:
name: db-secret
key: password
volumeMounts:
- name: config
mountPath: /app/config/application.yml
subPath: application.yml
volumes:
- name: config
configMap:
name: user-service-config存活探针与就绪探针
K8s 通过探针(Probe)检测容器状态,确保流量只导向健康的 Pod。
Spring Boot Actuator 健康端点
首先在 pom.xml 中添加 Actuator 依赖:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>配置 application.yml 启用健康端点:
management:
endpoints:
web:
exposure:
include: health,info
endpoint:
health:
show-details: always
probes:
enabled: trueDeployment 中的探针配置
apiVersion: apps/v1
kind: Deployment
metadata:
name: user-service
namespace: production
spec:
replicas: 3
selector:
matchLabels:
app: user-service
template:
metadata:
labels:
app: user-service
spec:
containers:
- name: user-service
image: registry.example.com/user-service:1.0.0
ports:
- containerPort: 8080
# 存活探针:检测应用是否存活,失败则重启容器
livenessProbe:
httpGet:
path: /actuator/health/liveness
port: 8080
initialDelaySeconds: 30
periodSeconds: 10
timeoutSeconds: 5
failureThreshold: 3
# 就绪探针:检测应用是否准备好接收流量,失败则从 Service 端点中移除
readinessProbe:
httpGet:
path: /actuator/health/readiness
port: 8080
initialDelaySeconds: 20
periodSeconds: 5
timeoutSeconds: 3
successThreshold: 1
failureThreshold: 2探针配置建议:
| 参数 | 说明 | 推荐值 |
|---|---|---|
initialDelaySeconds | 容器启动后延迟检测的时间 | 存活探针 30s,就绪探针 20s |
periodSeconds | 检测间隔 | 存活探针 10s,就绪探针 5s |
timeoutSeconds | 单次检测超时时间 | 存活探针 5s,就绪探针 3s |
failureThreshold | 连续失败次数阈值 | 存活探针 3,就绪探针 2 |
successThreshold | 连续成功次数阈值 | 默认 1 |
JVM 容器感知参数
在容器环境中,JVM 默认检测宿主机的 CPU 和内存,而非容器的资源限制。必须显式设置 JVM 参数使其感知容器边界。
推荐的 JVM 参数
ENV JAVA_OPTS="\
-XX:+UseContainerSupport \
-XX:InitialRAMPercentage=50.0 \
-XX:MaxRAMPercentage=75.0 \
-XX:MinRAMPercentage=50.0 \
-XX:+PrintFlagsFinal \
-Djava.security.egd=file:/dev/./urandom \
"各参数说明:
-XX:+UseContainerSupport— 启用容器 CPU 和内存感知(JDK 10+ 默认开启,建议显式声明)-XX:InitialRAMPercentage=50.0— JVM 堆初始大小占容器内存限制的百分比-XX:MaxRAMPercentage=75.0— JVM 堆最大大小占容器内存限制的百分比,留 25% 给 JVM 自身和系统-XX:MinRAMPercentage=50.0— 当容器内存较小时的最小堆占比
结合资源限制的 Deployment
apiVersion: apps/v1
kind: Deployment
metadata:
name: user-service
namespace: production
spec:
replicas: 3
selector:
matchLabels:
app: user-service
template:
metadata:
labels:
app: user-service
spec:
containers:
- name: user-service
image: registry.example.com/user-service:1.0.0
ports:
- containerPort: 8080
env:
- name: JAVA_OPTS
value: "-XX:+UseContainerSupport -XX:InitialRAMPercentage=50.0 -XX:MaxRAMPercentage=75.0 -XX:MinRAMPercentage=50.0"
resources:
requests:
memory: "512Mi"
cpu: "500m"
limits:
memory: "1Gi"
cpu: "1"
livenessProbe:
httpGet:
path: /actuator/health/liveness
port: 8080
initialDelaySeconds: 30
periodSeconds: 10
readinessProbe:
httpGet:
path: /actuator/health/readiness
port: 8080
initialDelaySeconds: 20
periodSeconds: 5优雅关闭
Spring Boot 应用在收到 SIGTERM 信号时应优雅关闭,完成正在处理的请求后再退出。
Spring Boot 优雅关闭配置
server:
shutdown: graceful
spring:
lifecycle:
timeout-per-shutdown-phase: 30sK8s 侧配置
K8s 默认发送 SIGTERM 信号,等待 terminationGracePeriodSeconds 后发送 SIGKILL。需确保该值大于 Spring Boot 的优雅关闭超时时间。
apiVersion: apps/v1
kind: Deployment
metadata:
name: user-service
namespace: production
spec:
replicas: 3
selector:
matchLabels:
app: user-service
template:
metadata:
labels:
app: user-service
spec:
# 优雅关闭等待时间,需大于 spring.lifecycle.timeout-per-shutdown-phase
terminationGracePeriodSeconds: 45
containers:
- name: user-service
image: registry.example.com/user-service:1.0.0
ports:
- containerPort: 8080
lifecycle:
preStop:
exec:
command:
- /bin/sh
- -c
- "sleep 10"
env:
- name: JAVA_OPTS
value: "-XX:+UseContainerSupport -XX:InitialRAMPercentage=50.0 -XX:MaxRAMPercentage=75.0"preStop 中的 sleep 10 用于在 SIGTERM 发送前预留时间,确保 K8s 有足够时间将 Pod 从 Service 端点中移除,避免流量中断。
前端部署
Nginx + React/Vue SPA 多阶段构建
Dockerfile 示例
# 第一阶段:构建前端项目
FROM node:20-alpine AS builder
WORKDIR /build
# 先复制依赖文件,利用 Docker 缓存层
COPY package.json package-lock.json ./
RUN npm ci
# 复制源码并构建
COPY . .
RUN npm run build
# 第二阶段:Nginx 运行环境
FROM nginx:1.25-alpine
# 复制构建产物
COPY --from=builder /build/dist /usr/share/nginx/html
# 复制自定义 Nginx 配置
COPY nginx.conf /etc/nginx/conf.d/default.conf
EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]Nginx 配置(静态资源缓存策略)
server {
listen 80;
server_name example.com;
root /usr/share/nginx/html;
index index.html;
# Gzip 压缩
gzip on;
gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript;
gzip_min_length 1024;
gzip_comp_level 6;
# HTML 文件(不缓存,确保始终获取最新版本)
location / {
try_files $uri $uri/ /index.html;
add_header Cache-Control "no-cache, no-store, must-revalidate";
add_header Pragma "no-cache";
add_header Expires 0;
}
# JS/CSS/图片等静态资源(强缓存 + 内容哈希)
location /assets/ {
expires 1y;
add_header Cache-Control "public, immutable, max-age=31536000";
access_log off;
}
# favicon
location = /favicon.ico {
expires 1y;
add_header Cache-Control "public, immutable";
access_log off;
}
# 安全头
add_header X-Frame-Options "SAMEORIGIN" always;
add_header X-Content-Type-Options "nosniff" always;
add_header X-XSS-Protection "1; mode=block" always;
}前端 Deployment
apiVersion: apps/v1
kind: Deployment
metadata:
name: frontend
namespace: production
spec:
replicas: 2
selector:
matchLabels:
app: frontend
template:
metadata:
labels:
app: frontend
spec:
containers:
- name: frontend
image: registry.example.com/frontend:1.0.0
ports:
- containerPort: 80
resources:
requests:
memory: "64Mi"
cpu: "100m"
limits:
memory: "128Mi"
cpu: "250m"
livenessProbe:
httpGet:
path: /
port: 80
initialDelaySeconds: 10
periodSeconds: 15
readinessProbe:
httpGet:
path: /
port: 80
initialDelaySeconds: 5
periodSeconds: 5
---
apiVersion: v1
kind: Service
metadata:
name: frontend
namespace: production
spec:
selector:
app: frontend
ports:
- port: 80
targetPort: 80
type: ClusterIPIngress 路由配置
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: main-ingress
namespace: production
annotations:
# Nginx Ingress 控制器
kubernetes.io/ingress.class: nginx
# 请求体大小限制
nginx.ingress.kubernetes.io/proxy-body-size: 50m
# 超时配置
nginx.ingress.kubernetes.io/proxy-connect-timeout: "30"
nginx.ingress.kubernetes.io/proxy-read-timeout: "60"
# CORS 配置
nginx.ingress.kubernetes.io/enable-cors: "true"
nginx.ingress.kubernetes.io/cors-allow-origin: "https://example.com"
spec:
tls:
- hosts:
- example.com
secretName: example-tls
rules:
- host: example.com
http:
paths:
# 前端路由
- path: /
pathType: Prefix
backend:
service:
name: frontend
port:
number: 80
# 网关 API 路由
- path: /api
pathType: Prefix
backend:
service:
name: gateway-service
port:
number: 8080微服务集群完整示例
以下提供一个完整的微服务集群部署示例,包含用户服务、订单服务、网关服务和 Nacos 注册中心。
命名空间
apiVersion: v1
kind: Namespace
metadata:
name: microserviceNacos 注册中心(StatefulSet + Headless Service)
Nacos 作为有状态服务,使用 StatefulSet 部署,并通过 Headless Service 实现稳定的网络标识和集群内发现。
apiVersion: v1
kind: Service
metadata:
name: nacos-headless
namespace: microservice
labels:
app: nacos
spec:
ports:
- port: 8848
name: nacos
- port: 9848
name: grpc
clusterIP: None
selector:
app: nacos
---
apiVersion: v1
kind: Service
metadata:
name: nacos-service
namespace: microservice
labels:
app: nacos
spec:
type: ClusterIP
ports:
- port: 8848
name: nacos
targetPort: 8848
- port: 9848
name: grpc
targetPort: 9848
selector:
app: nacos
---
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: nacos
namespace: microservice
spec:
serviceName: nacos-headless
replicas: 2
selector:
matchLabels:
app: nacos
template:
metadata:
labels:
app: nacos
spec:
containers:
- name: nacos
image: nacos/nacos-server:v2.3.0
ports:
- containerPort: 8848
- containerPort: 9848
env:
- name: MODE
value: cluster
- name: NACOS_SERVER_PORT
value: "8848"
- name: PREFER_HOST_MODE
value: hostname
- name: NACOS_SERVERS
value: "nacos-0.nacos-headless.microservice.svc.cluster.local:8848 nacos-1.nacos-headless.microservice.svc.cluster.local:8848"
- name: NACOS_APPLICATION_PORT
value: "8848"
- name: JVM_XMS
value: "512m"
- name: JVM_XMX
value: "512m"
- name: JVM_XMN
value: "256m"
resources:
requests:
memory: "768Mi"
cpu: "500m"
limits:
memory: "1Gi"
cpu: "1"
livenessProbe:
httpGet:
path: /nacos/actuator/health
port: 8848
initialDelaySeconds: 30
periodSeconds: 15
readinessProbe:
httpGet:
path: /nacos/actuator/health
port: 8848
initialDelaySeconds: 30
periodSeconds: 10
volumeMounts:
- name: data
mountPath: /home/nacos/data
volumeClaimTemplates:
- metadata:
name: data
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 10Gi用户服务 Deployment + Service
apiVersion: v1
kind: ConfigMap
metadata:
name: user-service-config
namespace: microservice
data:
application.yml: |
server:
port: 8080
shutdown: graceful
spring:
lifecycle:
timeout-per-shutdown-phase: 30s
application:
name: user-service
cloud:
nacos:
discovery:
server-addr: nacos-service.microservice.svc.cluster.local:8848
management:
endpoints:
web:
exposure:
include: health,info
endpoint:
health:
probes:
enabled: true
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: user-service
namespace: microservice
labels:
app: user-service
spec:
replicas: 2
selector:
matchLabels:
app: user-service
strategy:
type: RollingUpdate
rollingUpdate:
maxUnavailable: 1
maxSurge: 1
template:
metadata:
labels:
app: user-service
spec:
terminationGracePeriodSeconds: 45
containers:
- name: user-service
image: registry.example.com/user-service:1.0.0
imagePullPolicy: Always
ports:
- containerPort: 8080
env:
- name: JAVA_OPTS
value: "-XX:+UseContainerSupport -XX:InitialRAMPercentage=50.0 -XX:MaxRAMPercentage=75.0"
- name: DB_USERNAME
valueFrom:
secretKeyRef:
name: db-secret
key: username
- name: DB_PASSWORD
valueFrom:
secretKeyRef:
name: db-secret
key: password
resources:
requests:
memory: "512Mi"
cpu: "250m"
limits:
memory: "1Gi"
cpu: "1"
volumeMounts:
- name: config
mountPath: /app/config/application.yml
subPath: application.yml
livenessProbe:
httpGet:
path: /actuator/health/liveness
port: 8080
initialDelaySeconds: 40
periodSeconds: 10
timeoutSeconds: 5
failureThreshold: 3
readinessProbe:
httpGet:
path: /actuator/health/readiness
port: 8080
initialDelaySeconds: 30
periodSeconds: 5
timeoutSeconds: 3
failureThreshold: 2
lifecycle:
preStop:
exec:
command:
- /bin/sh
- -c
- "sleep 10"
volumes:
- name: config
configMap:
name: user-service-config
---
apiVersion: v1
kind: Service
metadata:
name: user-service
namespace: microservice
labels:
app: user-service
spec:
type: ClusterIP
selector:
app: user-service
ports:
- port: 8080
targetPort: 8080
name: http订单服务 Deployment + Service
apiVersion: v1
kind: ConfigMap
metadata:
name: order-service-config
namespace: microservice
data:
application.yml: |
server:
port: 8080
shutdown: graceful
spring:
lifecycle:
timeout-per-shutdown-phase: 30s
application:
name: order-service
cloud:
nacos:
discovery:
server-addr: nacos-service.microservice.svc.cluster.local:8848
management:
endpoints:
web:
exposure:
include: health,info
endpoint:
health:
probes:
enabled: true
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: order-service
namespace: microservice
labels:
app: order-service
spec:
replicas: 2
selector:
matchLabels:
app: order-service
strategy:
type: RollingUpdate
rollingUpdate:
maxUnavailable: 1
maxSurge: 1
template:
metadata:
labels:
app: order-service
spec:
terminationGracePeriodSeconds: 45
containers:
- name: order-service
image: registry.example.com/order-service:1.0.0
imagePullPolicy: Always
ports:
- containerPort: 8080
env:
- name: JAVA_OPTS
value: "-XX:+UseContainerSupport -XX:InitialRAMPercentage=50.0 -XX:MaxRAMPercentage=75.0"
- name: DB_USERNAME
valueFrom:
secretKeyRef:
name: db-secret
key: username
- name: DB_PASSWORD
valueFrom:
secretKeyRef:
name: db-secret
key: password
resources:
requests:
memory: "512Mi"
cpu: "250m"
limits:
memory: "1Gi"
cpu: "1"
volumeMounts:
- name: config
mountPath: /app/config/application.yml
subPath: application.yml
livenessProbe:
httpGet:
path: /actuator/health/liveness
port: 8080
initialDelaySeconds: 40
periodSeconds: 10
timeoutSeconds: 5
failureThreshold: 3
readinessProbe:
httpGet:
path: /actuator/health/readiness
port: 8080
initialDelaySeconds: 30
periodSeconds: 5
timeoutSeconds: 3
failureThreshold: 2
lifecycle:
preStop:
exec:
command:
- /bin/sh
- -c
- "sleep 10"
volumes:
- name: config
configMap:
name: order-service-config
---
apiVersion: v1
kind: Service
metadata:
name: order-service
namespace: microservice
labels:
app: order-service
spec:
type: ClusterIP
selector:
app: order-service
ports:
- port: 8080
targetPort: 8080
name: http网关服务 Deployment + Service(NodePort)+ ConfigMap
apiVersion: v1
kind: ConfigMap
metadata:
name: gateway-config
namespace: microservice
data:
application.yml: |
server:
port: 8080
spring:
application:
name: gateway-service
cloud:
nacos:
discovery:
server-addr: nacos-service.microservice.svc.cluster.local:8848
gateway:
routes:
- id: user-service
uri: lb://user-service
predicates:
- Path=/api/user/**
- id: order-service
uri: lb://order-service
predicates:
- Path=/api/order/**
management:
endpoints:
web:
exposure:
include: health,info
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: gateway-service
namespace: microservice
labels:
app: gateway-service
spec:
replicas: 2
selector:
matchLabels:
app: gateway-service
strategy:
type: RollingUpdate
rollingUpdate:
maxUnavailable: 1
maxSurge: 1
template:
metadata:
labels:
app: gateway-service
spec:
terminationGracePeriodSeconds: 45
containers:
- name: gateway-service
image: registry.example.com/gateway-service:1.0.0
imagePullPolicy: Always
ports:
- containerPort: 8080
env:
- name: JAVA_OPTS
value: "-XX:+UseContainerSupport -XX:InitialRAMPercentage=50.0 -XX:MaxRAMPercentage=75.0"
resources:
requests:
memory: "512Mi"
cpu: "250m"
limits:
memory: "1Gi"
cpu: "1"
volumeMounts:
- name: config
mountPath: /app/config/application.yml
subPath: application.yml
livenessProbe:
httpGet:
path: /actuator/health/liveness
port: 8080
initialDelaySeconds: 40
periodSeconds: 10
timeoutSeconds: 5
failureThreshold: 3
readinessProbe:
httpGet:
path: /actuator/health/readiness
port: 8080
initialDelaySeconds: 30
periodSeconds: 5
timeoutSeconds: 3
failureThreshold: 2
lifecycle:
preStop:
exec:
command:
- /bin/sh
- -c
- "sleep 10"
volumes:
- name: config
configMap:
name: gateway-config
---
apiVersion: v1
kind: Service
metadata:
name: gateway-service
namespace: microservice
labels:
app: gateway-service
spec:
type: NodePort
selector:
app: gateway-service
ports:
- port: 8080
targetPort: 8080
nodePort: 30080
name: http服务发现
K8s DNS 机制
K8s 内置 DNS 服务(CoreDNS)为 Service 自动分配 DNS 记录,格式为:
<service-name>.<namespace>.svc.cluster.localDNS 记录示例
| Service | Namespace | DNS 名称 |
|---|---|---|
user-service | microservice | user-service.microservice.svc.cluster.local |
order-service | microservice | order-service.microservice.svc.cluster.local |
gateway-service | microservice | gateway-service.microservice.svc.cluster.local |
nacos-service | microservice | nacos-service.microservice.svc.cluster.local |
同 Namespace 内通信
同一 Namespace 内的 Pod 可直接使用 Service 名称访问:
# 订单服务通过 K8s DNS 调用用户服务
spring:
cloud:
gateway:
routes:
- id: user-service
uri: http://user-service:8080
predicates:
- Path=/api/user/**跨 Namespace 通信
跨 Namespace 需要使用完整域名:
http://user-service.microservice.svc.cluster.local:8080在应用配置中使用 K8s DNS
Spring Boot 微服务通过 Nacos 注册时,无需直接配置 K8s DNS,Nacos 会自动管理服务发现。但在 ConfigMap 中配置中间件连接时,可以使用 K8s DNS:
spring:
datasource:
url: jdbc:mysql://mysql-service.database.svc.cluster.local:3306/user_db
redis:
host: redis-service.database.svc.cluster.localNacos 集群内节点发现
Nacos StatefulSet 中,节点之间通过 Headless Service 的 DNS 记录互相发现:
nacos-0.nacos-headless.microservice.svc.cluster.local:8848
nacos-1.nacos-headless.microservice.svc.cluster.local:8848Spring Cloud 集成 K8s 服务发现(可选)
如果不想使用 Nacos,可以直接使用 K8s 原生服务发现,通过 spring-cloud-kubernetes 实现:
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-kubernetes-client-discovery</artifactId>
</dependency>spring:
cloud:
kubernetes:
discovery:
all-namespaces: true
client:
namespace: microservice灰度发布
Deployment 滚动更新策略
K8s Deployment 默认采用滚动更新(RollingUpdate)策略,逐步替换旧版本 Pod,确保更新期间服务不中断。
滚动更新配置
apiVersion: apps/v1
kind: Deployment
metadata:
name: user-service
namespace: production
spec:
replicas: 5
selector:
matchLabels:
app: user-service
strategy:
type: RollingUpdate
rollingUpdate:
# 更新过程中最多允许不可用的 Pod 数量(绝对值或百分比)
maxUnavailable: 1
# 更新过程中最多允许超出期望副本数的 Pod 数量(绝对值或百分比)
maxSurge: 1
template:
...参数说明:
maxUnavailable: 1— 滚动更新过程中,最多允许 1 个 Pod 不可用,确保始终有 4 个 Pod 在处理请求maxSurge: 1— 更新过程中,最多可以额外创建 1 个 Pod,逐步替换旧版本
执行滚动更新
# 方式一:更新镜像版本
kubectl set image deployment/user-service user-service=registry.example.com/user-service:1.1.0 -n production
# 方式二:编辑 Deployment 配置
kubectl edit deployment user-service -n production
# 方式三:使用 YAML 文件更新(推荐)
kubectl apply -f user-service-deploy.yaml -n production查看滚动更新状态
# 查看更新状态
kubectl rollout status deployment/user-service -n production
# 查看更新历史
kubectl rollout history deployment/user-service -n production
# 回滚到上一个版本
kubectl rollout undo deployment/user-service -n production
# 回滚到指定版本
kubectl rollout undo deployment/user-service -n production --to-revision=2多副本管理
HorizontalPodAutoscaler(HPA)
基于 CPU/内存使用率自动扩缩容:
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: user-service-hpa
namespace: production
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
- type: Resource
resource:
name: memory
target:
type: Utilization
averageUtilization: 80PodDisruptionBudget(PDB)
保证主动中断(如节点维护)时最少可用的 Pod 数量:
apiVersion: policy/v1
kind: PodDisruptionBudget
metadata:
name: user-service-pdb
namespace: production
spec:
minAvailable: 2
selector:
matchLabels:
app: user-service灰度发布策略(金丝雀发布)
通过 Service 标签选择器与多个 Deployment 实现灰度发布。
步骤一:部署稳定版
apiVersion: apps/v1
kind: Deployment
metadata:
name: user-service-stable
namespace: production
spec:
replicas: 4
selector:
matchLabels:
app: user-service
version: stable
template:
metadata:
labels:
app: user-service
version: stable
spec:
containers:
- name: user-service
image: registry.example.com/user-service:1.0.0
...步骤二:部署灰度版
apiVersion: apps/v1
kind: Deployment
metadata:
name: user-service-canary
namespace: production
spec:
replicas: 1
selector:
matchLabels:
app: user-service
version: canary
template:
metadata:
labels:
app: user-service
version: canary
spec:
containers:
- name: user-service
image: registry.example.com/user-service:1.1.0
...步骤三:Service 通过标签选择器分发流量
apiVersion: v1
kind: Service
metadata:
name: user-service
namespace: production
spec:
selector:
app: user-service
# 注意:不选择 version 标签,同时匹配 stable 和 canary 的 Pod
ports:
- port: 8080
targetPort: 8080此时流量按 Pod 数量比例分发:稳定版 4 个 Pod 接收 80% 流量,灰度版 1 个 Pod 接收 20% 流量。
步骤四:验证后全量发布
确认灰度版本无问题后,将稳定版镜像升级为新版本并扩容,移除灰度版:
kubectl set image deployment/user-service-stable user-service=registry.example.com/user-service:1.1.0 -n production
kubectl scale deployment/user-service-stable --replicas=5 -n production
kubectl delete deployment user-service-canary -n production蓝绿部署(基于 Ingress 流量切换)
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: user-service-ingress
namespace: production
annotations:
kubernetes.io/ingress.class: nginx
spec:
rules:
- host: api.example.com
http:
paths:
- path: /api/user
pathType: Prefix
backend:
service:
name: user-service-blue
port:
number: 8080蓝绿切换时只需修改 Ingress 中的 service.name 指向 user-service-green 即可完成流量切换。
总结
本文档覆盖了 Java/前端/微服务在 Kubernetes 上的完整部署实践,关键要点总结如下:
| 领域 | 核心要点 |
|---|---|
| Java 部署 | 使用 ConfigMap 管理配置、配置存活/就绪探针、设置 JVM 容器感知参数(UseContainerSupport + MaxRAMPercentage)、实现优雅关闭 |
| 前端部署 | 多阶段构建减小镜像体积、Nginx 配置静态资源缓存策略、Ingress 路由分发 |
| 微服务集群 | Nacos StatefulSet + Headless Service、各业务服务 ClusterIP 内网通信、网关 NodePort 对外暴露 |
| 服务发现 | K8s DNS(服务名.namespace.svc.cluster.local)或 Nacos 注册中心 |
| 灰度发布 | Deployment 滚动更新(maxUnavailable + maxSurge)、金丝雀发布(多 Deployment + 标签选择器)、HPA 自动扩缩容 |