Best Practices für Spring Boot + k8s

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/readinessDie 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/shutdownund 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/metricund /actuator/prometheusverbunden, 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
 

Guess you like

Origin blog.csdn.net/qq_28165595/article/details/132127686