第12天:Kubernetes上云实战 - 从"手工部署"到"自动驾驶"的飞跃🚀
一、Kubernetes:微服务的"自动驾驶系统"
零基础全栈开发Java微服务版本实战-后端-前端-运维-实战企业级三个实战项目
资源获取:关注公众号: 小坏说Java ,获取本文所有示例代码、配置模板及导出工具。
场景对比:传统部署 vs Kubernetes
传统部署(手动挡):
- 买服务器 → 装系统 → 装环境 → 部署应用 → 监控 → 扩容(半夜爬起来)→ 故障处理(手忙脚乱)
Kubernetes(自动驾驶):
- 告诉K8S要什么 → K8S自动调度 → 自动部署 → 自动监控 → 自动扩容(流量来了自动加)→ 自动修复(挂了自动重启)→ 睡觉💤
Kubernetes能干啥?
- 自动化部署:告诉K8S要部署什么,它自己搞定
- 自动扩缩容:流量来了自动加实例,流量没了自动减
- 自愈能力:容器挂了自动重启,节点挂了自动迁移
- 服务发现:自动发现服务,自动负载均衡
- 滚动更新:不停机更新,用户无感知
- 配置管理:统一管理配置和密钥
二、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 ,获取本文所有示例代码、配置模板及导出工具。
学会了啥?
- ✅ Kubernetes核心概念:Pod、Deployment、Service、ConfigMap、Secret
- ✅ 微服务在K8S的完整部署方案
- ✅ 资源配置:Requests、Limits、探针、亲和性
- ✅ 服务发现和负载均衡:Service、Ingress
- ✅ 自动扩缩容:HPA配置
- ✅ 生产环境最佳实践:安全、监控、备份
- ✅ 运维命令和故障排查
关键点
- 声明式配置:告诉K8S想要什么状态
- 资源管理:合理设置Requests和Limits
- 健康检查:配置好存活、就绪、启动探针
- 滚动更新:零停机部署
- 自动恢复:Pod挂了自动重启
- 弹性伸缩:根据负载自动扩缩容
十、明儿个学啥?
明天咱学服务网格!
- Service Mesh是啥?为什么需要?
- Istio vs Linkerd怎么选?
- 熔断、限流、重试怎么配?
- 金丝雀发布、A/B测试怎么做?
- 分布式追踪、指标收集
明天咱给微服务穿上"防弹衣"!🛡️
零基础全栈开发Java微服务版本实战-后端-前端-运维-实战企业级三个实战项目
资源获取:关注公众号: 小坏说Java ,获取本文所有示例代码、配置模板及导出工具。
Kubernetes生产级部署全攻略:SpringCloud微服务上云实战,从零搭建高可用集群
【关注】
🔥 本文为《SpringCloud企业级实战》专栏第12篇,点赞+收藏防丢失
💡 关注获取:完整K8S YAML配置 + 自动化部署脚本 + 监控告警规则
🚀 评论区留言「K8S问题」,获取一对一架构咨询
📚 配套GitHub项目:包含20+生产级K8S配置文件
👨💻 明日预告:Service Mesh实战,Istio让微服务治理更简单