Spring Boot + k8s = 王炸!

打印 上一主题 下一主题

主题 900|帖子 900|积分 2700

来源:https://blog.csdn.net/qq_14999375/article/details/123309636
前言

K8s + Spring Boot实现零宕机发布:健康检查+滚动更新+优雅停机+弹性伸缩+Prometheus监控+配置分离(镜像复用)
配置

健康检查


  • 健康检查类型:就绪探针(readiness)+ 存活探针(liveness)
  • 探针类型:exec(进入容器执行脚本)、tcpSocket(探测端口)、httpGet(调用接口)
业务层面

Spring Boot 基础就不介绍了,推荐看这个实战项目:
https://github.com/javastacks/spring-boot-best-practice
项目依赖 pom.xml
  1. <dependency>
  2.     <groupId>org.springframework.boot</groupId>
  3.     <artifactId>spring-boot-starter-actuator</artifactId>
  4. </dependency>
复制代码
定义访问端口、路径及权限 application.yaml
  1. management:
  2.   server:
  3.     port: 50000                         # 启用独立运维端口
  4.   endpoint:                             # 开启health端点
  5.     health:
  6.       probes:
  7.         enabled: true
  8.   endpoints:
  9.     web:
  10.       exposure:
  11.         base-path: /actuator            # 指定上下文路径,启用相应端点
  12.         include: health
复制代码
将暴露/actuator/health/readiness和/actuator/health/liveness两个接口,访问方式如下:
  1. http://127.0.0.1:50000/actuator/health/readiness
  2. http://127.0.0.1:50000/actuator/health/liveness
复制代码
运维层面

k8s部署模版deployment.yaml
  1. apiVersion: apps/v1
  2. kind: Deployment
  3. spec:
  4.   template:
  5.     spec:
  6.       containers:
  7.       - name: {APP_NAME}
  8.         image: {IMAGE_URL}
  9.         imagePullPolicy: Always
  10.         ports:
  11.         - containerPort: {APP_PORT}
  12.         - name: management-port
  13.           containerPort: 50000         # 应用管理端口
  14.         readinessProbe:                # 就绪探针
  15.           httpGet:
  16.             path: /actuator/health/readiness
  17.             port: management-port
  18.           initialDelaySeconds: 30      # 延迟加载时间
  19.           periodSeconds: 10            # 重试时间间隔
  20.           timeoutSeconds: 1            # 超时时间设置
  21.           successThreshold: 1          # 健康阈值
  22.           failureThreshold: 6          # 不健康阈值
  23.         livenessProbe:                 # 存活探针
  24.           httpGet:
  25.             path: /actuator/health/liveness
  26.             port: management-port
  27.           initialDelaySeconds: 30      # 延迟加载时间
  28.           periodSeconds: 10            # 重试时间间隔
  29.           timeoutSeconds: 1            # 超时时间设置
  30.           successThreshold: 1          # 健康阈值
  31.           failureThreshold: 6          # 不健康阈值
复制代码
滚动更新

k8s资源调度之滚动更新策略,若要实现零宕机发布,需支持健康检查
  1. apiVersion: apps/v1
  2. kind: Deployment
  3. metadata:
  4.   name: {APP_NAME}
  5.   labels:
  6.     app: {APP_NAME}
  7. spec:
  8.   selector:
  9.     matchLabels:
  10.       app: {APP_NAME}
  11.   replicas: {REPLICAS}    # Pod副本数
  12.   strategy:
  13.     type: RollingUpdate    # 滚动更新策略
  14.     rollingUpdate:
  15.       maxSurge: 1                   # 升级过程中最多可以比原先设置的副本数多出的数量
  16.       maxUnavailable: 1             # 升级过程中最多有多少个POD处于无法提供服务的状态
复制代码
优雅停机

在K8s中,当我们实现滚动升级之前,务必要实现应用级别的优雅停机。否则滚动升级时,还是会影响到业务。使应用关闭线程、释放连接资源后再停止服务
业务层面

项目依赖 pom.xml
  1. <dependency>
  2.     <groupId>org.springframework.boot</groupId>
  3.     <artifactId>spring-boot-starter-actuator</artifactId>
  4. </dependency>
复制代码
定义访问端口、路径及权限 application.yaml
  1. spring:
  2.   application:
  3.     name: <xxx>
  4.   profiles:
  5.     active: @profileActive@
  6.   lifecycle:
  7.     timeout-per-shutdown-phase: 30s     # 停机过程超时时长设置30s,超过30s,直接停机
  8. server:
  9.   port: 8080
  10.   shutdown: graceful                    # 默认为IMMEDIATE,表示立即关机;GRACEFUL表示优雅关机
  11. management:
  12.   server:
  13.     port: 50000                         # 启用独立运维端口
  14.   endpoint:                             # 开启shutdown和health端点
  15.     shutdown:
  16.       enabled: true
  17.     health:
  18.       probes:
  19.         enabled: true
  20.   endpoints:
  21.     web:
  22.       exposure:
  23.         base-path: /actuator            # 指定上下文路径,启用相应端点
  24.         include: health,shutdown
复制代码
将暴露/actuator/shutdown接口,调用方式如下:
  1. curl -X POST 127.0.0.1:50000/actuator/shutdown
复制代码
运维层面

确保dockerfile模版集成curl工具,否则无法使用curl命令
  1. FROM openjdk:8-jdk-alpine
  2. #构建参数
  3. ARG JAR_FILE
  4. ARG WORK_PATH="/app"
  5. ARG EXPOSE_PORT=8080
  6. #环境变量
  7. ENV JAVA_OPTS=""\
  8.     JAR_FILE=${JAR_FILE}
  9. #设置时区
  10. RUN ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime && echo 'Asia/Shanghai' >/etc/timezone
  11. RUN sed -i 's/dl-cdn.alpinelinux.org/mirrors.ustc.edu.cn/g' /etc/apk/repositories  \
  12.     && apk add --no-cache curl
  13. #将maven目录的jar包拷贝到docker中,并命名为for_docker.jar
  14. COPY target/$JAR_FILE $WORK_PATH/
  15. #设置工作目录
  16. WORKDIR $WORK_PATH
  17. # 指定于外界交互的端口
  18. EXPOSE $EXPOSE_PORT
  19. # 配置容器,使其可执行化
  20. ENTRYPOINT exec java $JAVA_OPTS -jar $JAR_FILE
复制代码
k8s部署模版deployment.yaml
注:经验证,java项目可省略结束回调钩子的配置
此外,若需使用回调钩子,需保证镜像中包含curl工具,且需注意应用管理端口(50000)不能暴露到公网
  1. apiVersion: apps/v1
  2. kind: Deployment
  3. spec:
  4.   template:
  5.     spec:
  6.       containers:
  7.       - name: {APP_NAME}
  8.         image: {IMAGE_URL}
  9.         imagePullPolicy: Always
  10.         ports:
  11.         - containerPort: {APP_PORT}
  12.         - containerPort: 50000
  13.         lifecycle:
  14.           preStop:       # 结束回调钩子
  15.             exec:
  16.               command: ["curl", "-XPOST", "127.0.0.1:50000/actuator/shutdown"]
复制代码
弹性伸缩

为pod设置资源限制后,创建HPA
  1. apiVersion: apps/v1
  2. kind: Deployment
  3. metadata:
  4.   name: {APP_NAME}
  5.   labels:
  6.     app: {APP_NAME}
  7. spec:
  8.   template:
  9.     spec:
  10.       containers:
  11.       - name: {APP_NAME}
  12.         image: {IMAGE_URL}
  13.         imagePullPolicy: Always
  14.         resources:                     # 容器资源管理
  15.           limits:                      # 资源限制(监控使用情况)
  16.             cpu: 0.5
  17.             memory: 1Gi
  18.           requests:                    # 最小可用资源(灵活调度)
  19.             cpu: 0.15
  20.             memory: 300Mi
  21. ---
  22. kind: HorizontalPodAutoscaler            # 弹性伸缩控制器
  23. apiVersion: autoscaling/v2beta2
  24. metadata:
  25.   name: {APP_NAME}
  26. spec:
  27.   scaleTargetRef:
  28.     apiVersion: apps/v1
  29.     kind: Deployment
  30.     name: {APP_NAME}
  31.   minReplicas: {REPLICAS}                # 缩放范围
  32.   maxReplicas: 6
  33.   metrics:
  34.     - type: Resource
  35.       resource:
  36.         name: cpu                        # 指定资源指标
  37.         target:
  38.           type: Utilization
  39.           averageUtilization: 50
复制代码
Prometheus集成

业务层面

项目依赖 pom.xml
  1. <dependency>
  2.     <groupId>org.springframework.boot</groupId>
  3.     <artifactId>spring-boot-starter-actuator</artifactId>
  4. </dependency>    io.micrometer    micrometer-registry-prometheus
复制代码
定义访问端口、路径及权限 application.yaml
  1. management:
  2.   server:
  3.     port: 50000                         # 启用独立运维端口
  4.   metrics:
  5.     tags:
  6.       application: ${spring.application.name}
  7.   endpoints:
  8.     web:
  9.       exposure:
  10.         base-path: /actuator            # 指定上下文路径,启用相应端点
  11.         include: metrics,prometheus
复制代码
将暴露/actuator/metric和/actuator/prometheus接口,访问方式如下:
  1. http://127.0.0.1:50000/actuator/metric
  2. http://127.0.0.1:50000/actuator/prometheus
复制代码
运维层面

deployment.yaml
  1. apiVersion: apps/v1
  2. kind: Deployment
  3. spec:
  4.   template:
  5.     metadata:
  6.       annotations:
  7.         prometheus:io/port: "50000"
  8.         prometheus.io/path: /actuator/prometheus  # 在流水线中赋值
  9.         prometheus.io/scrape: "true"              # 基于pod的服务发现
复制代码
配置分离

方案:通过configmap挂载外部配置文件,并指定激活环境运行
作用:配置分离,避免敏感信息泄露;镜像复用,提高交付效率
通过文件生成configmap
  1. # 通过dry-run的方式生成yaml文件
  2. kubectl create cm -n <namespace> <APP_NAME> --from-file=application-test.yaml --dry-run=1 -oyaml > configmap.yaml
  3. # 更新
  4. kubectl apply -f configmap.yaml
复制代码
挂载configmap并指定激活环境
  1. apiVersion: apps/v1
  2. kind: Deployment
  3. metadata:
  4.   name: {APP_NAME}
  5.   labels:
  6.     app: {APP_NAME}
  7. spec:
  8.   template:
  9.     spec:
  10.       containers:
  11.       - name: {APP_NAME}
  12.         image: {IMAGE_URL}
  13.         imagePullPolicy: Always
  14.         env:
  15.           - name: SPRING_PROFILES_ACTIVE   # 指定激活环境
  16.             value: test
  17.         volumeMounts:                      # 挂载configmap
  18.         - name: conf
  19.           mountPath: "/app/config"         # 与Dockerfile中工作目录一致
  20.           readOnly: true
  21.       volumes:
  22.       - name: conf
  23.         configMap:
  24.           name: {APP_NAME}
复制代码
汇总配置

业务层面

项目依赖 pom.xml
  1. <dependency>
  2.     <groupId>org.springframework.boot</groupId>
  3.     <artifactId>spring-boot-starter-actuator</artifactId>
  4. </dependency>    io.micrometer    micrometer-registry-prometheus
复制代码
定义访问端口、路径及权限 application.yaml
  1. spring:
  2.   application:
  3.     name: project-sample
  4.   profiles:
  5.     active: @profileActive@
  6.   lifecycle:
  7.     timeout-per-shutdown-phase: 30s     # 停机过程超时时长设置30s,超过30s,直接停机
  8. server:
  9.   port: 8080
  10.   shutdown: graceful                    # 默认为IMMEDIATE,表示立即关机;GRACEFUL表示优雅关机
  11. management:
  12.   server:
  13.     port: 50000                         # 启用独立运维端口
  14.   metrics:
  15.     tags:
  16.       application: ${spring.application.name}
  17.   endpoint:                             # 开启shutdown和health端点
  18.     shutdown:
  19.       enabled: true
  20.     health:
  21.       probes:
  22.         enabled: true
  23.   endpoints:
  24.     web:
  25.       exposure:
  26.         base-path: /actuator            # 指定上下文路径,启用相应端点
  27.         include: health,shutdown,metrics,prometheus
复制代码
运维层面

确保dockerfile模版集成curl工具,否则无法使用curl命令
  1. FROM openjdk:8-jdk-alpine
  2. #构建参数
  3. ARG JAR_FILE
  4. ARG WORK_PATH="/app"
  5. ARG EXPOSE_PORT=8080
  6. #环境变量
  7. ENV JAVA_OPTS=""\
  8.     JAR_FILE=${JAR_FILE}
  9. #设置时区
  10. RUN ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime && echo 'Asia/Shanghai' >/etc/timezone
  11. RUN sed -i 's/dl-cdn.alpinelinux.org/mirrors.ustc.edu.cn/g' /etc/apk/repositories  \
  12.     && apk add --no-cache curl
  13. #将maven目录的jar包拷贝到docker中,并命名为for_docker.jar
  14. COPY target/$JAR_FILE $WORK_PATH/
  15. #设置工作目录
  16. WORKDIR $WORK_PATH
  17. # 指定于外界交互的端口
  18. EXPOSE $EXPOSE_PORT
  19. # 配置容器,使其可执行化
  20. ENTRYPOINT exec java $JAVA_OPTS -jar $JAR_FILE
复制代码
k8s部署模版deployment.yaml
  1. apiVersion: apps/v1
  2. kind: Deployment
  3. metadata:
  4.   name: {APP_NAME}
  5.   labels:
  6.     app: {APP_NAME}
  7. spec:
  8.   selector:
  9.     matchLabels:
  10.       app: {APP_NAME}
  11.   replicas: {REPLICAS}                            # Pod副本数
  12.   strategy:
  13.     type: RollingUpdate                           # 滚动更新策略
  14.     rollingUpdate:
  15.       maxSurge: 1
  16.       maxUnavailable: 0
  17.   template:
  18.     metadata:
  19.       name: {APP_NAME}
  20.       labels:
  21.         app: {APP_NAME}
  22.       annotations:
  23.         timestamp: {TIMESTAMP}
  24.         prometheus.io/port: "50000"               # 不能动态赋值
  25.         prometheus.io/path: /actuator/prometheus
  26.         prometheus.io/scrape: "true"              # 基于pod的服务发现
  27.     spec:
  28.       affinity:                                   # 设置调度策略,采取多主机/多可用区部署
  29.         podAntiAffinity:
  30.           preferredDuringSchedulingIgnoredDuringExecution:
  31.           - weight: 100
  32.             podAffinityTerm:
  33.               labelSelector:
  34.                 matchExpressions:
  35.                 - key: app
  36.                   operator: In
  37.                   values:
  38.                   - {APP_NAME}
  39.               topologyKey: "kubernetes.io/hostname" # 多可用区为"topology.kubernetes.io/zone"
  40.       terminationGracePeriodSeconds: 30             # 优雅终止宽限期
  41.       containers:
  42.       - name: {APP_NAME}
  43.         image: {IMAGE_URL}
  44.         imagePullPolicy: Always
  45.         ports:
  46.         - containerPort: {APP_PORT}
  47.         - name: management-port
  48.           containerPort: 50000         # 应用管理端口
  49.         readinessProbe:                # 就绪探针
  50.           httpGet:
  51.             path: /actuator/health/readiness
  52.             port: management-port
  53.           initialDelaySeconds: 30      # 延迟加载时间
  54.           periodSeconds: 10            # 重试时间间隔
  55.           timeoutSeconds: 1            # 超时时间设置
  56.           successThreshold: 1          # 健康阈值
  57.           failureThreshold: 9          # 不健康阈值
  58.         livenessProbe:                 # 存活探针
  59.           httpGet:
  60.             path: /actuator/health/liveness
  61.             port: management-port
  62.           initialDelaySeconds: 30      # 延迟加载时间
  63.           periodSeconds: 10            # 重试时间间隔
  64.           timeoutSeconds: 1            # 超时时间设置
  65.           successThreshold: 1          # 健康阈值
  66.           failureThreshold: 6          # 不健康阈值
  67.         resources:                     # 容器资源管理
  68.           limits:                      # 资源限制(监控使用情况)
  69.             cpu: 0.5
  70.             memory: 1Gi
  71.           requests:                    # 最小可用资源(灵活调度)
  72.             cpu: 0.1
  73.             memory: 200Mi
  74.         env:
  75.           - name: TZ
  76.             value: Asia/Shanghai
  77. ---
  78. kind: HorizontalPodAutoscaler            # 弹性伸缩控制器
  79. apiVersion: autoscaling/v2beta2
  80. metadata:
  81.   name: {APP_NAME}
  82. spec:
  83.   scaleTargetRef:
  84.     apiVersion: apps/v1
  85.     kind: Deployment
  86.     name: {APP_NAME}
  87.   minReplicas: {REPLICAS}                # 缩放范围
  88.   maxReplicas: 6
  89.   metrics:
  90.     - type: Resource
  91.       resource:
  92.         name: cpu                        # 指定资源指标
  93.         target:
  94.           type: Utilization
  95.           averageUtilization: 50
复制代码
近期热文推荐:
1.1,000+ 道 Java面试题及答案整理(2022最新版)
2.劲爆!Java 协程要来了。。。
3.Spring Boot 2.x 教程,太全了!
4.别再写满屏的爆爆爆炸类了,试试装饰器模式,这才是优雅的方式!!
5.《Java开发手册(嵩山版)》最新发布,速速下载!
觉得不错,别忘了随手点赞+转发哦!

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

守听

金牌会员
这个人很懒什么都没写!

标签云

快速回复 返回顶部 返回列表