Vorwort
K8s + Spring Boot erreicht eine Veröffentlichung ohne Ausfallzeiten: Gesundheitsprüfung + fortlaufendes Update + ordnungsgemäßes Herunterfahren + elastische Skalierung + Prometheus-Überwachung + Konfigurationstrennung (Spiegelwiederverwendung)
Aufbau
Gesundheitsuntersuchung
- Art der Gesundheitsprüfung: Bereitschaftssonde (Bereitschaft) + Überlebenssonde (Lebendigkeit)
- Sondentyp: exec (Container zum Ausführen des Skripts eingeben), tcpSocket (Port erkennen), httpGet (Schnittstelle aufrufen)
Unternehmensebene
Das Projekt hängt von pom.xml ab
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
Definieren Sie Zugriffsports, Pfade und Berechtigungen application.yaml
management:
server:
port: 50000 # 启用独立运维端口
endpoint: # 开启health端点
health:
probes:
enabled: true
endpoints:
web:
exposure:
base-path: /actuator # 指定上下文路径,启用相应端点
include: health
Es werden zwei Schnittstellen verfügbar gemacht . /actuator/health/readiness
Die Zugriffsmethoden lauten wie folgt:/actuator/health/liveness
http://127.0.0.1:50000/actuator/health/readiness
http://127.0.0.1:50000/actuator/health/liveness
Betriebs- und Wartungsebene
k8s-Bereitstellungsvorlage „deployment.yaml“.
apiVersion: apps/v1
kind: Deployment
spec:
template:
spec:
containers:
- name: {APP_NAME}
image: {IMAGE_URL}
imagePullPolicy: Always
ports:
- containerPort: {APP_PORT}
- name: management-port
containerPort: 50000 # 应用管理端口
readinessProbe: # 就绪探针
httpGet:
path: /actuator/health/readiness
port: management-port
initialDelaySeconds: 30 # 延迟加载时间
periodSeconds: 10 # 重试时间间隔
timeoutSeconds: 1 # 超时时间设置
successThreshold: 1 # 健康阈值
failureThreshold: 6 # 不健康阈值
livenessProbe: # 存活探针
httpGet:
path: /actuator/health/liveness
port: management-port
initialDelaySeconds: 30 # 延迟加载时间
periodSeconds: 10 # 重试时间间隔
timeoutSeconds: 1 # 超时时间设置
successThreshold: 1 # 健康阈值
failureThreshold: 6 # 不健康阈值
rollierendes Update
Die fortlaufende Aktualisierungsstrategie der k8s-Ressourcenplanung muss die Gesundheitsprüfung unterstützen, um eine Veröffentlichung ohne Ausfallzeiten zu erreichen
apiVersion: apps/v1
kind: Deployment
metadata:
name: {APP_NAME}
labels:
app: {APP_NAME}
spec:
selector:
matchLabels:
app: {APP_NAME}
replicas: {REPLICAS} # Pod副本数
strategy:
type: RollingUpdate # 滚动更新策略
rollingUpdate:
maxSurge: 1 # 升级过程中最多可以比原先设置的副本数多出的数量
maxUnavailable: 1 # 升级过程中最多有多少个POD处于无法提供服务的状态
ordnungsgemäßes Herunterfahren
Bevor wir in K8s fortlaufende Upgrades implementieren, müssen wir ein ordnungsgemäßes Herunterfahren auf Anwendungsebene implementieren. Andernfalls wirkt sich das fortlaufende Upgrade weiterhin auf das Geschäft aus. Lassen Sie die Anwendung den Thread schließen, die Verbindungsressource freigeben und dann den Dienst stoppen.
Unternehmensebene
Das Projekt hängt von pom.xml ab
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
Definieren Sie Zugriffsports, Pfade und Berechtigungen application.yaml
spring:
application:
name: <xxx>
profiles:
active: @profileActive@
lifecycle:
timeout-per-shutdown-phase: 30s # 停机过程超时时长设置30s,超过30s,直接停机
server:
port: 8080
shutdown: graceful # 默认为IMMEDIATE,表示立即关机;GRACEFUL表示优雅关机
management:
server:
port: 50000 # 启用独立运维端口
endpoint: # 开启shutdown和health端点
shutdown:
enabled: true
health:
probes:
enabled: true
endpoints:
web:
exposure:
base-path: /actuator # 指定上下文路径,启用相应端点
include: health,shutdown
Die Schnittstelle wird verfügbar gemacht /actuator/shutdown
und die aufrufende Methode lautet wie folgt:
curl -X POST 127.0.0.1:50000/actuator/shutdown
Betriebs- und Wartungsebene
Stellen Sie sicher, dass die Dockerfile-Vorlage das Curl-Tool integriert, andernfalls kann der Curl-Befehl nicht verwendet werden
FROM openjdk:8-jdk-alpine
#构建参数
ARG JAR_FILE
ARG WORK_PATH="/app"
ARG EXPOSE_PORT=8080
#环境变量
ENV JAVA_OPTS=""\
JAR_FILE=${JAR_FILE}
#设置时区
RUN ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime && echo 'Asia/Shanghai' >/etc/timezone
RUN sed -i 's/dl-cdn.alpinelinux.org/mirrors.ustc.edu.cn/g' /etc/apk/repositories \
&& apk add --no-cache curl
#将maven目录的jar包拷贝到docker中,并命名为for_docker.jar
COPY target/$JAR_FILE $WORK_PATH/
#设置工作目录
WORKDIR $WORK_PATH
# 指定于外界交互的端口
EXPOSE $EXPOSE_PORT
# 配置容器,使其可执行化
ENTRYPOINT exec java $JAVA_OPTS -jar $JAR_FILE
k8s-Bereitstellungsvorlage „deployment.yaml“ Hinweis: Nach der Überprüfung kann das Java-Projekt die Konfiguration des End-Callback-Hooks weglassen. Wenn Sie den Callback-Hook verwenden müssen, müssen Sie außerdem sicherstellen, dass das Curl-Tool im Bild enthalten ist Sie müssen darauf achten, dass der Anwendungsverwaltungsport (50000) nicht dem öffentlichen Netzwerk zugänglich gemacht werden kann
apiVersion: apps/v1
kind: Deployment
spec:
template:
spec:
containers:
- name: {APP_NAME}
image: {IMAGE_URL}
imagePullPolicy: Always
ports:
- containerPort: {APP_PORT}
- containerPort: 50000
lifecycle:
preStop: # 结束回调钩子
exec:
command: ["curl", "-XPOST", "127.0.0.1:50000/actuator/shutdown"]
elastische Ausdehnung
Nachdem Sie Ressourcenlimits für die Pods festgelegt haben, erstellen Sie die HPA
apiVersion: apps/v1
kind: Deployment
metadata:
name: {APP_NAME}
labels:
app: {APP_NAME}
spec:
template:
spec:
containers:
- name: {APP_NAME}
image: {IMAGE_URL}
imagePullPolicy: Always
resources: # 容器资源管理
limits: # 资源限制(监控使用情况)
cpu: 0.5
memory: 1Gi
requests: # 最小可用资源(灵活调度)
cpu: 0.15
memory: 300Mi
---
kind: HorizontalPodAutoscaler # 弹性伸缩控制器
apiVersion: autoscaling/v2beta2
metadata:
name: {APP_NAME}
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: {APP_NAME}
minReplicas: {REPLICAS} # 缩放范围
maxReplicas: 6
metrics:
- type: Resource
resource:
name: cpu # 指定资源指标
target:
type: Utilization
averageUtilization: 50
Prometheus-Integration
Unternehmensebene
Das Projekt hängt von pom.xml ab
<!-- 引入Spring boot的监控机制-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>io.micrometer</groupId>
<artifactId>micrometer-registry-prometheus</artifactId>
</dependency>
Definieren Sie Zugriffsports, Pfade und Berechtigungen application.yaml
management:
server:
port: 50000 # 启用独立运维端口
metrics:
tags:
application: ${spring.application.name}
endpoints:
web:
exposure:
base-path: /actuator # 指定上下文路径,启用相应端点
include: metrics,prometheus
Wird verfügbar gemacht /actuator/metric
und /actuator/prometheus
verbunden, die Zugriffsmethode lautet wie folgt:
http://127.0.0.1:50000/actuator/metric
http://127.0.0.1:50000/actuator/prometheus
Betriebs- und Wartungsebene
Bereitstellung.yaml
apiVersion: apps/v1
kind: Deployment
spec:
template:
metadata:
annotations:
prometheus:io/port: "50000"
prometheus.io/path: /actuator/prometheus # 在流水线中赋值
prometheus.io/scrape: "true" # 基于pod的服务发现
Konfigurationstrennung
Lösung: Hängen Sie die externe Konfigurationsdatei über configmap ein und geben Sie die auszuführende Aktivierungsumgebung an
Rolle: Trennung von Konfigurationen, um den Verlust sensibler Informationen zu verhindern; Multiplexing von Bildern, um die Liefereffizienz zu verbessern
Konfigmap aus Datei generieren
# 通过dry-run的方式生成yaml文件
kubectl create cm -n <namespace> <APP_NAME> --from-file=application-test.yaml --dry-run=1 -oyaml > configmap.yaml
# 更新
kubectl apply -f configmap.yaml
Mounten Sie configmap und geben Sie die Aktivierungsumgebung an
apiVersion: apps/v1
kind: Deployment
metadata:
name: {APP_NAME}
labels:
app: {APP_NAME}
spec:
template:
spec:
containers:
- name: {APP_NAME}
image: {IMAGE_URL}
imagePullPolicy: Always
env:
- name: SPRING_PROFILES_ACTIVE # 指定激活环境
value: test
volumeMounts: # 挂载configmap
- name: conf
mountPath: "/app/config" # 与Dockerfile中工作目录一致
readOnly: true
volumes:
- name: conf
configMap:
name: {APP_NAME}
zusammenfassende Konfiguration
Unternehmensebene
Das Projekt hängt von pom.xml ab
<!-- 引入Spring boot的监控机制-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>io.micrometer</groupId>
<artifactId>micrometer-registry-prometheus</artifactId>
</dependency>
Definieren Sie Zugriffsports, Pfade und Berechtigungen application.yaml
spring:
application:
name: project-sample
profiles:
active: @profileActive@
lifecycle:
timeout-per-shutdown-phase: 30s # 停机过程超时时长设置30s,超过30s,直接停机
server:
port: 8080
shutdown: graceful # 默认为IMMEDIATE,表示立即关机;GRACEFUL表示优雅关机
management:
server:
port: 50000 # 启用独立运维端口
metrics:
tags:
application: ${spring.application.name}
endpoint: # 开启shutdown和health端点
shutdown:
enabled: true
health:
probes:
enabled: true
endpoints:
web:
exposure:
base-path: /actuator # 指定上下文路径,启用相应端点
include: health,shutdown,metrics,prometheus
Betriebs- und Wartungsebene
Stellen Sie sicher, dass die Dockerfile-Vorlage das Curl-Tool integriert, andernfalls kann der Curl-Befehl nicht verwendet werden
FROM openjdk:8-jdk-alpine
#构建参数
ARG JAR_FILE
ARG WORK_PATH="/app"
ARG EXPOSE_PORT=8080
#环境变量
ENV JAVA_OPTS=""\
JAR_FILE=${JAR_FILE}
#设置时区
RUN ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime && echo 'Asia/Shanghai' >/etc/timezone
RUN sed -i 's/dl-cdn.alpinelinux.org/mirrors.ustc.edu.cn/g' /etc/apk/repositories \
&& apk add --no-cache curl
#将maven目录的jar包拷贝到docker中,并命名为for_docker.jar
COPY target/$JAR_FILE $WORK_PATH/
#设置工作目录
WORKDIR $WORK_PATH
# 指定于外界交互的端口
EXPOSE $EXPOSE_PORT
# 配置容器,使其可执行化
ENTRYPOINT exec java $JAVA_OPTS -jar $JAR_FILE
k8s-Bereitstellungsvorlage „deployment.yaml“.
apiVersion: apps/v1
kind: Deployment
metadata:
name: {APP_NAME}
labels:
app: {APP_NAME}
spec:
selector:
matchLabels:
app: {APP_NAME}
replicas: {REPLICAS} # Pod副本数
strategy:
type: RollingUpdate # 滚动更新策略
rollingUpdate:
maxSurge: 1
maxUnavailable: 0
template:
metadata:
name: {APP_NAME}
labels:
app: {APP_NAME}
annotations:
timestamp: {TIMESTAMP}
prometheus.io/port: "50000" # 不能动态赋值
prometheus.io/path: /actuator/prometheus
prometheus.io/scrape: "true" # 基于pod的服务发现
spec:
affinity: # 设置调度策略,采取多主机/多可用区部署
podAntiAffinity:
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 100
podAffinityTerm:
labelSelector:
matchExpressions:
- key: app
operator: In
values:
- {APP_NAME}
topologyKey: "kubernetes.io/hostname" # 多可用区为"topology.kubernetes.io/zone"
terminationGracePeriodSeconds: 30 # 优雅终止宽限期
containers:
- name: {APP_NAME}
image: {IMAGE_URL}
imagePullPolicy: Always
ports:
- containerPort: {APP_PORT}
- name: management-port
containerPort: 50000 # 应用管理端口
readinessProbe: # 就绪探针
httpGet:
path: /actuator/health/readiness
port: management-port
initialDelaySeconds: 30 # 延迟加载时间
periodSeconds: 10 # 重试时间间隔
timeoutSeconds: 1 # 超时时间设置
successThreshold: 1 # 健康阈值
failureThreshold: 9 # 不健康阈值
livenessProbe: # 存活探针
httpGet:
path: /actuator/health/liveness
port: management-port
initialDelaySeconds: 30 # 延迟加载时间
periodSeconds: 10 # 重试时间间隔
timeoutSeconds: 1 # 超时时间设置
successThreshold: 1 # 健康阈值
failureThreshold: 6 # 不健康阈值
resources: # 容器资源管理
limits: # 资源限制(监控使用情况)
cpu: 0.5
memory: 1Gi
requests: # 最小可用资源(灵活调度)
cpu: 0.1
memory: 200Mi
env:
- name: TZ
value: Asia/Shanghai
---
kind: HorizontalPodAutoscaler # 弹性伸缩控制器
apiVersion: autoscaling/v2beta2
metadata:
name: {APP_NAME}
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: {APP_NAME}
minReplicas: {REPLICAS} # 缩放范围
maxReplicas: 6
metrics:
- type: Resource
resource:
name: cpu # 指定资源指标
target:
type: Utilization
averageUtilization: 50