k8s springboot 生产实践(高可用部署、基于qps动态扩缩容、prometheus监控)

以下均为亲自实践并应用

概要

1、k8s sprintboot eureka高可用配置、部署、优化
2、k8s sprintboot 微服务高可用配置、部署、优化
3、springboot安装prometheus依赖并获取metric
4、helm安装prometheus operator、prometheus adapter(custom metric)
5、配置prometheus及adapter获取应用qps
6、配置k8s hpa(HorizontalPodAutoscaler)
7、配置grafana展示监控数据

效果展示

1、k8s sprintboot eureka高可用配置、部署、优化

简介:eureka做集群,需要eureka互相注册,为方便注册,使用statefulSet方式部署
eureka server配置:

eureka:
  server:
    enable-self-preservation: false
    eviction-interval-timer-in-ms: 5000
  client:
    fetch-registry: true  
    register-with-eureka: true #互相注册
    serviceUrl:
      defaultZone: ${EUREKA_URL}
  instance:
    prefer-ip-address: true
    lease-renewal-interval-in-seconds: 3
    lease-expiration-duration-in-seconds: 10

eureka_url:将多实例地址均填写,方便配置

EUREKA_URL="http://eureka-0.eureka.default.svc.cluster.local:8761/eureka/,http://eureka-1.eureka.default.svc.cluster.local:8761/eureka/"

eureka statefulSet配置:

apiVersion:  apps/v1
kind: StatefulSet
metadata:
  labels:
    app: eureka
  name: eureka
  namespace: default
spec:
  replicas: 2
  serviceName: eureka
  podManagementPolicy: "Parallel"
  revisionHistoryLimit: 3
  selector:
    matchLabels:
      app: eureka
  template:
    metadata:
      labels:
        app: eureka
      annotations:   #用于prometheus收集数据,需micrometer-registry-prometheus插件
        prometheus.io/path: "/actuator/prometheus"
        prometheus.io/port: "8761"
        prometheus.io/scrape: "true"
    spec:
      containers:
      - image: eureka:latest              #镜像名
        imagePullPolicy: IfNotPresent
        name: eureka
        envFrom:
        - configMapRef:
            name: app-configmap           #环境变量
        env:
        - name: MEMORY
          value: "800"
        resources:
          limits:
            cpu: "0"
            memory: 1000Mi
          requests:
            cpu: "0"
            memory: 1000Mi
        readinessProbe:
          tcpSocket:
            port: 8761
          failureThreshold: 1
          initialDelaySeconds: 20
        livenessProbe:
          tcpSocket:
            port: 8761
          failureThreshold: 1
          initialDelaySeconds: 60
        volumeMounts:
        - mountPath: /logs
          name: log-vol
      volumes:
      - name: log-vol
        nfs:
          path: /logs/eureka         #多实例日志可统一在此次查看
          server: 127.0.0.1           #nfs地址
      dnsPolicy: ClusterFirst
      imagePullSecrets:
      - name: registry-harbor
      restartPolicy: Always

2、k8s sprintboot 微服务高可用配置、部署、优化

这边有思考点,client以什么地址注册eureka?
a、以deployment直接部署,默认情况会将容器名称注册到eureka,k8s不识别deployment方式容器名称域名,导致无法访问
b、使用statefulSet部署,通过pod名称注册,并且可以识别域名,以pod名称注册并使用,感觉完美,然而需要弹性扩缩容时候,pod缩容,注册信息不会立马从eureka server去除,有延迟,会导致请求到这个销毁的pod上,error!(如果不考虑hpa这方式ok)
c、使用service注册,通过endpoint分发请求,pod销毁后pod ip会里面从endpoint里去除,不会出现缩容时候请求到销毁pod上,扩容时候,服务没完全起来请求转发到此pod上会出现问题,不过可以通过健康检查解决
最终选择c方案:
client配置如下:
HOSTNAME即k8s service名称,注册时候会将service注册到eureka

#服务注册相关配置
eureka:
  client:
    serviceUrl:
      defaultZone: ${EUREKA_URL}
  instance:
    prefer-ip-address: true
    instance-id: ${HOSTNAME}:${server.port}
    ip-address: ${HOSTNAME}

deployment和service配置

apiVersion:  apps/v1
kind: Deployment
metadata:
  labels:
    app: client 
  name: client 
  namespace: default
spec:
  replicas: 2
  revisionHistoryLimit: 3
  selector:
    matchLabels:
      app: client 
  template:
    metadata:
      labels:
        app: client 
      annotations:
        prometheus.io/path: "/actuator/prometheus"
        prometheus.io/port: "8024"
        prometheus.io/scrape: "true"
    spec:
      containers:
      - image: client:latest
        imagePullPolicy: IfNotPresent
        name: client 
        envFrom:
        - configMapRef:
            name: client-configmap
        env:
        - name: MEMORY
          value: "1300"
        - name: HOSTNAME
          value: client 
        resources:
          limits:
            cpu: "0"
            memory: 1500Mi
          requests:
            cpu: "0"
            memory: 1500Mi
        readinessProbe:
          tcpSocket:
            port: 8024
          failureThreshold: 1
          initialDelaySeconds: 60
        livenessProbe:
          tcpSocket:
            port: 8024
          failureThreshold: 1
          initialDelaySeconds: 90
      dnsPolicy: ClusterFirst
      imagePullSecrets:
      - name: registry-harbor
      restartPolicy: Always
---
apiVersion: v1
kind: Service
metadata:
  name: client 
  namespace: default
  labels:
    app: client  
spec:
  ports:
  - name: http-8024
    port: 8024
    protocol: TCP
    targetPort: 8024
  selector:
    app: client  

3、springboot安装prometheus依赖并获取metric

高可用部署完成后就需要弹性扩缩容, 需要获取qps数据,这里用的是prometheus,直接贴配置

增加pom依赖:

        <dependency>
            <groupId>io.micrometer</groupId>
            <artifactId>micrometer-registry-prometheus</artifactId>
        </dependency>

增加配置文件:

management:
  endpoints:
    web:
      exposure:
        include: '*'
  metrics:
    tags:
      application: ${spring.application.name}

主函数增加bean

import io.micrometer.core.instrument.MeterRegistry;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.actuate.autoconfigure.metrics.MeterRegistryCustomizer;
import org.springframework.context.annotation.Bean;

public class Application {
    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
    @Bean
    MeterRegistryCustomizer<MeterRegistry> configurer(
            @Value("${spring.application.name}") String applicationName) {
        return (registry) -> registry.config().commonTags("application", applicationName);
    }
}

配置完成后访问:http:localhost:8024/actuator/prometheus,返回数据如下(重点关注下http_server_requests_seconds_count,后面会用到)

# HELP jvm_memory_max_bytes The maximum amount of memory in bytes that can be used for memory management
# TYPE jvm_memory_max_bytes gauge
jvm_memory_max_bytes{application="portal-eureka",area="heap",id="Par Survivor Space",} 2.7918336E7
jvm_memory_max_bytes{application="portal-eureka",area="nonheap",id="Compressed Class Space",} 1.073741824E9
jvm_memory_max_bytes{application="portal-eureka",area="heap",id="Tenured Gen",} 5.59284224E8
jvm_memory_max_bytes{application="portal-eureka",area="nonheap",id="Metaspace",} -1.0
jvm_memory_max_bytes{application="portal-eureka",area="heap",id="Par Eden Space",} 2.23739904E8
jvm_memory_max_bytes{application="portal-eureka",area="nonheap",id="Code Cache",} 2.5165824E8
# HELP logback_events_total Number of error level events that made it to the logs
# TYPE logback_events_total counter
logback_events_total{application="portal-eureka",level="info",} 804.0
http_server_requests_seconds_count{application="portal-eureka",exception="None",method="POST",outcome="SUCCESS",status="204",uri="root",} 8.0
http_server_requests_seconds_sum{application="portal-eureka",exception="None",method="POST",outcome="SUCCESS",status="204",uri="root",} 0.29997471
http_server_requests_seconds_count{application="portal-eureka",exception="None",method="GET",outcome="SUCCESS",status="200",uri="/actuator/prometheus",} 114.0
...

4、helm安装prometheus operator、prometheus adapter(custom metric)

a、下载prometheus-operator

helm fetch stable/prometheus-operator --version 8.13.0

b、解压

tar -zxvf prometheus-operator-8.13.3.tgz

c、修改values.yaml文件,增加采集pod job(operator默认没有搜集kubernetes-pod的配置)

vim prometheus-operator/values.yaml

增加

    additionalScrapeConfigs: 
      - job_name: 'kubernetes-pods'
        honor_labels: false
        kubernetes_sd_configs:
        - role: pod
        tls_config:
          insecure_skip_verify: true
        relabel_configs:
        - source_labels: [__meta_kubernetes_namespace]
          action: replace
          target_label: namespace
        - source_labels: [__meta_kubernetes_pod_name]
          action: replace
          target_label: pod
        - source_labels: [__meta_kubernetes_pod_annotation_prometheus_io_scrape]
          action: keep
          regex: true
        - source_labels: [__meta_kubernetes_pod_annotation_prometheus_io_path]
          action: replace
          target_label: __metrics_path__
          regex: (.+)
        - source_labels: [__address__, __meta_kubernetes_pod_annotation_prometheus_io_port]
          action: replace
          regex: ([^:]+)(?::\d+)?;(\d+)
          replacement: $1:$2
          target_label: __address__
        - source_labels: [__meta_kubernetes_pod_annotation_prometheus_io_scheme]
          action: replace
          target_label: __scheme__
          regex: (.+)

d、安装

helm install -n prometheus-operator prometheus-operator --namespace monitor

e、暴露端口

kubectl edit svc prometheus-operator-prometheus -nmonitor #增加externalIPs或者nodeport

f、安装stable/prometheus-adapter

helm fetch stable/prometheus-adapter --version 2.3.1

解压

tar -zxvf prometheus-adapter-2.3.1.tgz

修改prometheus server配置

vim prometheus-adapter/values.yaml #将prometheus.url替换为http://prometheus-operator-prometheus.monitor.svc

安装

helm install -n prometheus-adapter prometheus-adapter   --namespace monitor

查看api

kubectl get --raw /apis/custom.metrics.k8s.io/v1beta1

5、配置prometheus及adapter获取应用qps

a、增加adapter规则

kubectl edit cm -nmonitor prometheus-adapter

增加规则,将http_server_requests_seconds_count以每5分钟为时间段计算为qps,metric名称为http_server_requests_seconds

    - seriesQuery: '{namespace!="",__name__!~"^container_.*"}'
      seriesFilters:
      - isNot: .*_seconds_total
      resources:
        template: <<.Resource>>
      name:
        matches: ^(.*)_count$
        as: ""
      metricsQuery: sum(rate(<<.Series>>{<<.LabelMatchers>>}[5m])) by (<<.GroupBy>>)

b、重启adapter

kubectl -nmonitor delete pod prometheus-adapter-...

c、查看自定义metric qps

kubectl get --raw "/apis/custom.metrics.k8s.io/v1beta1/namespaces/default/pods/*/http_server_requests_seconds"

6、配置k8s hpa(HorizontalPodAutoscaler)

直接贴配置:

apiVersion: autoscaling/v2beta2
kind: HorizontalPodAutoscaler
metadata:
  name: client
  namespace: default
spec:
  scaleTargetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: client
  minReplicas: 2
  maxReplicas: 10
  metrics:
  - type: Pods
    pods:
      metric:
        name: http_server_requests_seconds
      target:
        type: AverageValue
        averageValue: 50
kubectl get hpa #查看hpa是否获取到metric

7、配置grafana展示监控数据

展示应用qps sql(不包含/actuator/prometheus地址)

sum(rate(http_server_requests_seconds_count{job="kubernetes-pods",uri!="/actuator/prometheus"  }[5m])) by (application)
image.png

dashboard模板地址:https://grafana.com/grafana/dashboards?dataSource=prometheus&direction=asc&orderBy=name&search=spring

推荐Spring Boot 2.1 Statistics模板,导入方法如下图,复制id或者json即可


image.png
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,445评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,889评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,047评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,760评论 1 276
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,745评论 5 367
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,638评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,011评论 3 398
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,669评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,923评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,655评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,740评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,406评论 4 320
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,995评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,961评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,197评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,023评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,483评论 2 342

推荐阅读更多精彩内容