K8s容器资源限制

 

在K8s中定义Pod中运行容器有两个维度的限制:
 1. 资源需求:即运行Pod的节点必须知足运行Pod的最基本需求才能运行Pod。
   如: Pod运行至少须要2G内存,1核CPU
    2. 资源限额:即运行Pod期间,可能内存使用量会增长,那最多能使用多少内存,这就是资源限额。前端

  

# kubectl  describe  node   node1.zcf.com
    .......................
   Allocated resources:
      (Total limits may be over 100 percent, i.e., overcommitted.)
      Resource           Requests    Limits             #这里显示的就是 资源的需求 和 限额
      --------           --------    ------
      cpu                250m (12%)  0 (0%)
      memory             0 (0%)      0 (0%)
      ephemeral-storage  0 (0%)      0 (0%)
          
    Requests:  就是需求限制,也叫软限制
    Limits:最大限制,也叫硬限制
    一般来讲:Limits >= Requests
    而且requests 和 limits 一般要一块儿配置,若只配置了requests,而不配置limits,则极可能致使Pod会吃掉全部资源。

须要注意:
  目前k8s在对资源限制方面还有欠缺,特别是Java应用,由于Pod运行起来后,它看到的资源是Node上所有的资源,虽然可经过requests和limits限制,但咱们都知道JVM启动后,它要计算本身的堆内存中不一样区域的大小,而这些大小一般是按比例划分的,倘若JVM启动后,根据Node上实际的内存大小来计算堆内存中老年代,Eden,幸存区那确定会出问题,由于,咱们给它分片的内存确定不够,因此这个要特别注意,而解决办法,只能是在启动Java应用前,配置JVM能使用的最大内存量。


在K8s的资源:
 CPU:
  咱们知道2核2线程的CPU,可被系统识别为4个逻辑CPU,在K8s中对CPU的分配限制是对逻辑CPU作分片限制的。
  也就是说分配给容器一个CPU,实际是分配一个逻辑CPU。
  并且1个逻辑CPU还可被单独划分子单位,即 1个逻辑CPU,还可被划分为1000个millicore(毫核), 简单说就是1个逻辑CPU,继续逻辑分割为1000个豪核心。
  豪核:可简单理解为将CPU的时间片作逻辑分割,每一段时间片就是一个豪核心。
  因此:500m 就是500豪核心,即0.5个逻辑CPU.

 内存:
  K,M,G,T,P,E #一般这些单位是以1000为换算标准的。
  Ki, Mi, Gi, Ti, Pi, Ei #这些一般是以1024为换算标准的。

K8s中资源限制对调度Pod的影响:node

  

   cpu.limits: 是咱们设置Pod运行时,最大可以使用500m个CPU,但要保障Pod能在Node上成功启动起来,就必需能提供cpu.requests个CPU.
  当预选策略在选择备选Node时,会首先考虑当前Pod运行, 其所需资源是否足够, 来作为首要判断条件,假如某Node上已经运行了一些Pod,预选策略会获取当前全部Pod的cpu.requests ,ram.requests等,这里以cpu.requests来讲明,好比说某Node上是2核2线程的CPU,全部容器的cpu.requests所有加起来假如已经3.9个CPU了,那么此Node在预选阶段就会被筛选掉。git

资源限制配置:
  kubectl explain pods.spec.containers.resorces
    limits:<map[string]string>
    requests:<map[string]string>程序员

#如下压测时,若压测内存,可能致使登陆容器都成问题,所以改成仅测试CPU。
apiVersion: v1
kind: Pod
metadata:
  name: pod-cpu-limits
  labels:
    app: test
    tier: frontend
spec:
  containers:
  - name: myapp
    image: ikubernetes/stress-ng
    command: ["/usr/bin/stress-ng","-c 1","--metrics-brief"]
    resources:
      requests:
        cpu: "500m"
        memory: "512Mi"
      limits:
        cpu: "500m"
        memory: "512Mi"

QoS类型:
 Guranteed:
  每一个容器的CPU,RAM资源都设置了相同值的requests 和 limits属性。
  简单说: cpu.limits = cpu.requests
      memory.limits = memory.requests
  这类Pod的运行优先级最高,但凡这样配置了cpu和内存的limits和requests,它会自动被归为此类。
  Burstable:
    每一个容器至少定义了CPU,RAM的requests属性,这里说每一个容器是指:一个Pod中能够运行多个容器。
    那么这类容器就会被自动归为burstable,而此类就属于中等优先级。
  BestEffort:
    没有一个容器设置了requests 或 limits,则会归为此类,而此类别是最低优先级。

QoS类型的做用:
  Node上会运行不少Pod,当运行一段时间后,发现Node上的资源紧张了,这时K8s就会根据QoS类别来选择Kill掉一部分Pod,那些会先被Kill掉?
  固然就是优先级最低的,也就是BestEffort,若BestEffort被Kill完了,仍是紧张,接下来就是Kill中等优先级的,即Burstable,依次类推。

  这里有个问题,BestEffort由于没有设置requests和limits,可根据谁占用资源最多,就kill谁,但Burstable设置了requests和limits,它的kill标准是什么?
  若按照谁占资源多kill谁,那遇到这样的问题,怎么选择?
    PodA: 启动时设置了memory.request=512M , memory.limits=1G
    PodB: 设置为: memory.requests=1G, memory.limits=2G

    PodA: 运行了一段时间后,占用了500M了,它可能还有继续申请内存。
    PodB: 它则占用了512M内存了,但它可能也还须要申请内存。
    想一想,如今Node资源紧张了,会先kill谁?
    其实,会优先kill PodA , 为啥?
    由于它启动时,说本身须要512M内存就够了,但你如今这么积极的申请内存,都快把你需求的内存吃完了,只能说明你太激进了,所以会先kill。
    而PodB,启动时须要1G,但目前才用了1半,说明它比较温和,所以不会先kill它。github

 

K8s中Pod监控的指标有如下几类:
  1. Kubernetes系统指标
  2. 容器指标,即:容器使用的CPU,内存,存储等资源的统计用量的
  3. 应用指标,即业务应用的指标,如:接收了多少用户请求,正在处理的用户请求等等。docker

K8s中获取Node资源用量,Pod资源用量要如何实现?
  其实早期K8s中kubelet内封装了一个组件叫cAdvisor,它启动后,会监听在14041端口上,来对外提供单节点上Node和Pod的资源统计用量,可是因为安全性问题,后期就将kubelet上的cAdvisor改成不监听,而是会经过配置HeapSter Pod的访问cAdvisor的地址,将本身的统计数据发送给它,由它来负责存储这些统计数据,但HeapSter它默认是将数据存储在缓存中,不能持久存储,所以它须要借助InfluxDB来实现数据的持久化,这些资源统计用量被发给HeapSter后,若经过命令行工具来获取指定Node上的资源使用统计,以及Pod的资源使用统计时,能够用kubectl top   [node |pod] 来查看,但若想查看历史数据,就不能实现了,由于命令行工具只能从HeapSter来获取实时数据,而没法获取历史数据,若要获取历史数据,就必须借助另外一个组件叫Grafana,它能够从InfluxDB中读取时序存储的数据,并经过图形界面来展现给用户。数据库

  

   HeapSter 因为从Kubernetes1.11.1之后将被废弃,从11.2后将被完全废弃。
  它被废弃的缘由是,由于它自身的设计架构上,会去整合不少第三方开发的后端存储组件,其中InfluxDB就是其中之一,因为是第三方组织研发的,因此这就致使了一个问题,若那天第三方对此不感兴趣了,就会放弃对这些后端存储组件的维护,致使没法继续支持K8s后期版本的。另外一个缘由是在HeapSter中这些第三方存储组件也是做为其核心代码的一部分存在的,所以它带来的问题是,HeapSter的代码会愈来愈臃肿,并且配置也会愈来愈复杂,于是K8s才决定放弃HeapSter。

apache

下面部署中使用了这样的版本组合:

 HeapSter-amd64:v1.5.4 + heapster-influxdb-amd64:v1.5 + heapster-grafana-amd64:v5.0.4
  #测试发现,不能正常工做,查看日志一切正常,可是没法正常获取监控指标数据。
使用下面这个旧版本的组合,是能够正常工做的,这个须要注意:
 HeapSter-amd64:v1.5.1 + heapster-influxdb-amd64:v1.3.3 + heapster-grafana-amd64:v4.4.3
  #这个组合中,grafana配置NodePort后,从外部访问,Grafana没有Web图像接口,但从日志上能够看到外部访问记录,也没有报错,怀疑其可能没有图像界面。
  #因此这个grafana组件能够不安装。另外,我测试将5.0.4的Grafana部署上,它能够链接到InfluxDB,应该是能获取数据,但由于没有默认面板,因此若想测试,须要自行到grafana官网去找一些模板测试。vim


构建上面三个组件的顺序:
后端

  1. 先部署InfluxDB,由于它被HeapSter所依赖
    wget -c https://raw.githubusercontent.com/kubernetes-retired/heapster/master/deploy/kube-config/influxdb/influxdb.yaml

  2. 接着就能够直接应用此清单
    kubectl  apply  -f  influxdb.yaml
    若镜像下载失败,可尝试阿里云镜像的谷歌镜像仓库下载:
    docker pull registry.cn-hangzhou.aliyuncs.com/google_containers/heapster-influxdb-amd64:v1.5.2

  3. 验证
    # kubectl  get  pod  -n  kube-system

      #kubectl describe pod  -n kube-system  monitoring-influxdb-xxxxx
    #从输出的信息中能够看到默认influxdb使用HTTP协议来对对外提供服务,你能够经过它的一些专用客户端工具来登入它,查看它所提供的服务。

 

   4. 接下来建立HeapSter,但建立HeapSter前须要先建立它全部依赖的RBAC配置,由于默认使用kubeasz部署的K8s集群是启用了RBAC的,所以须要先建立HeapSter所需的RBAC配置.
   wget -c https://raw.githubusercontent.com/kubernetes-retired/heapster/master/deploy/kube-config/rbac/heapster-rbac.yaml

     kubectl  apply   heapster-rbac.yaml

    #建立完RBAC后,就能够建立heapster Pod了。
    wget https://raw.githubusercontent.com/kubernetes-retired/heapster/master/deploy/kube-config/influxdb/heapster.yaml

#须要注意:
apiVersion: v1
kind: ServiceAccount     #heapSter须要使用一个服务账户,由于它须要能从全部Node上获取Pod的资源统计信息,所以它必须被受权.
metadata:
  name: heapster
  namespace: kube-system

#在HeapSter容器定义部分能够看到它引用了上面建立的SA账户
spec:
  serviceAccountName: heapster
  containers:
  - name: heapster
    image: k8s.gcr.io/heapster-amd64:v1.5.4
    imagePullPolicy: IfNotPresent
    command:
        - /heapster
        - --source=kubernetes:https://kubernetes.default        #这里是定义HeapSter从K8s内部访问APIServer的地址.
        - --sink=influxdb:http://monitoring-influxdb.kube-system.svc:8086     
             #这是指明HeapSter访问InfluxDB的地址,由于InfluxDB是Pod,不能直接访问Pod的IP,所以这里访问的是InfluxDB前端的SerivseIP。

#另外还有注意,HeapSter也须要Serivce
apiVersion: v1
kind: Service
.....
  name: heapster
  namespace: kube-system
spec:
  ports:
  - port: 80           #这里能够看到它在Node上暴露的端口是80
    targetPort: 8082   #HeapSter在Pod内部启动的端口为8082
 type: NodePort        #若须要K8s外部访问HeapSter,可修改端口类型为NodePort
  selector:
    k8s-app: heapster

  #接着执行应用此清单
    kubectl  apply  -f   heapster.yaml

  #查看heapster的日志:

   kubectl  logs  -n kube-system   heapster-xxxxx

  

  5. 最后来部署Grafana
    wget https://raw.githubusercontent.com/kubernetes-retired/heapster/master/deploy/kube-config/influxdb/grafana.yaml

#另外还有须要注意:
volumeMounts:
    - mountPath: /etc/ssl/certs #它会自动挂载Node上的/etc/ssl/certs目录到容器中,并自动生成证书,由于它使用的HTTPS.
      name: ca-certificates
      readOnly: true
      
#Grafana启动时,会去链接数据源,默认是InfluxDB,这个配置是经过环境变量来传入的
env:
 - name: INFLUXDB_HOST
   value: monitoring-influxdb  #这里可看到,它将InfluxDB的Service名传递给Grafana了。
 - name: GF_SERVER_HTTP_PORT
   value: "3000"       #默认Grafara在Pod内启动时,监听的端口也是经过环境变量传入的,默认是3000端口.

#在一个是,咱们须要配置Grafana能够被外部直接访问
  ports:
    - port: 80
      targetPort: 3000
    selector:
      k8s-app: grafana
    type:  NodePort

  部署完成后,可登陆Dashboard查看资源状态统计信息

  

      

 

 

自定义资源:
  在K8s中支持用户根据本身业务的特殊需求去自定义服务组件,来扩展K8s原始的Service,headless等,这种被称为 自制资源定义(CRD)。
  另外在K8s中也可本身开发一个新的APIServer,它里面可提供本身所须要的API接口,而后在经过K8s 中的所谓的API聚合器将本身开发的APIServer和K8s本身的APIServer聚合在一块儿来使用它;在否则就是本身修改K8s源码,来新增须要的功能定义。

  K8s从1.8开始引入资源指标API,它将资源的内容也看成API接口中的数据直接进行获取,而不像早期HeapSter,须要先部署HeapSter,而后从HeapSter中获取资源指标数据,这样带来的不即是,咱们获取数据就须要经过两个地方获取,当获取API资源(Pod, Service,...)是经过APIServer获取,而获取监控资源指标时,就必须从HeapSter中获取,而在新版的K8s中,引入资源指标API就是想避免这种麻烦,让用户再来获取数据时,所有从APIServer来获取,而要实现这个功能,它引入了一个API聚合器,由于资源监控指标API是容许用户自定义开发的,而开发出来的资源指标API经过一个相似代理层的API聚合器 将这些用户开发的资源指标API 和 原始的APIServer联合起来,用户经过访问API聚合器,来获取本身须要的数据,而API聚合器会根据用户的请求,自动将请求转发给APIServer或资源指标API。
  须要说明的是 资源指标API 分为两类,一类是核心指标,另外一类是非核心指标,核心指标是metrics-server提供的,它也是一个Pod。
  HPA:它是水平Pod自动伸缩器,它也是须要获取资源指标来判断,并做出一些预约义动做,如:判断CPU使用率已经80%了,则会自动增长一个Pod,若发现某个Pod的资源使用率很低,一直维持在好比说5%,它能够自动关闭几个该Pod,以便腾出资源供其它Pod使用等。
  kubectl top .... 这个命令 和 HPA功能在早期都是须要依赖HeapSter来工做的,可是HeapSter有个不少的缺陷,它只能统计CPU,内存,磁盘等的资源用量,但没法获取其它更多资源指标,这就限制了咱们想获取更多信息的途径,另外也使得HPA的功能受到了限制,例若有时候,Pod的CPU,内存等占有率不高,但其访问量却很是高,这时咱们也但愿能自动建立Pod来分担并发压力,但HeapSter就没法帮咱们作的,所以才致使新的资源指标API的出现,以及后来又引入了自定义资源指标的模型。


Prometheus:它能够收集基本指标,同时还能够收集网络报文的收发速率,网络链接的数量,内存,包括进程的新建和回收的速率等等,而这些K8s早期是不支持的,它让咱们可使用这些功能来加强咱们的HPA能力。它即做为监控组件使用,也做为一些特殊指标的资源提供者来提供,但这些不是内建的标准核心指标,这些咱们统称为自定义指标。
须要注意Prometheus要想将它监控采集到的数据,转化为指标格式,须要一个特殊的组件,它叫 k8s-prometheus-adapter

K8s新一代监控指标架构由两部分组成:

  • 核心指标流水线:由Kubelet资源评估器,metrics-server,以及由APIServer提供的API组成,它里面主要提供最核心的监控指标。主要是经过它让Kubernetes自身的组件来了解内部组件和核心使用程序的指标,目前主要包含,CPU(CPU的累积使用率),内存的实时使用率,Pod的资源占用率和容器的磁盘占用率。【累积使用率:指一个进程累积使用CPU的总时长比例】
  • 监控流水线:用于从系统收集各类指标数据并提供给用户,存储,系统以及HPA来使用。 它包含核心指标,同时也包含许多非核心指标;非核心指标不必定能被K8s所理解,简单说:prometheus采集的数据,k8s可能不理解,由于这些数据定义只有在Prometheus的语境中才有定义,所以才须要一个中间组件叫 k8s-prometheus-adapter来将其转化为k8s能理解的监控指标定义。


metrics-server:
  它主要用于提供监控指标API,但它一般是由用户提供的API服务,它自己不是k8s的核心组件,它仅是K8s上的一个Pod,所以为了能让用户无缝的使用metrics-server上提供的API,所以就必须使用kube-aggregator。固然kube-aggregator不只仅能够聚合传统APIServer和metrics-server,它还能够聚合不少用户自定义的API服务。

/apps/metrics.k8s.io/v1beta1:
  这个群组默认是不包含在建立API Server中的,所以你经过 kubectl api-versions 查看,是没有这个群组的,这个群组实际是由 metrics-server 来提供的,而咱们须要作的是使用kube-aggregator将这个API群组合并到API Server中去,这样用户再去访问API Server时,就能够访问到此API群组了。

#须要修改两个文件:
#第一个文件: metrics-server-deployment.yaml
  #此清单文件定义了metrics-server镜像和metrics-server-nanny容器启动的参数,这些参数有些须要修改
  #metrics-server容器:
    command:
        - /metrics-server
        - --metric-resolution=30s
        #- --kubelet-insecure-tls    
                #网上不少文章都说必须加上此参数, 此参数含义: 
                #若不能作TLS加密认证,使用不安全的通讯也能够.但我测试时,不加也能正常工做,仅作借鉴
        # These are needed for GKE, which doesn't support secure communication yet.
        # Remove these lines for non-GKE clusters, and when GKE supports token-based auth.
        - --kubelet-port=10255
        - --deprecated-kubelet-completely-insecure=true
        - --kubelet-preferred-address-types=InternalIP,Hostname,InternalDNS,ExternalDNS,ExternalIP
                
  #metrics-server-nanny容器: 
    command:
      - /pod_nanny
      - --config-dir=/etc/config                         
      #下面这些{{....}} 这些若不替换,启动metrics-server-nanny容器时会报错,但从报错日志中能够到它们的简单说明
      - --cpu={{ base_metrics_server_cpu }}       #设置metrics-server基本运行可用CPU豪核数量,测试设置100m
      - --extra-cpu=0.5m
      - --memory={{ base_metrics_server_memory }} #分配给metrics-server基本运行的内存大小, 测试设置 150Mi
      - --extra-memory={{ metrics_server_memory_per_node }}Mi  #每一个节点上的metrics-server额外分配内存大小,测试50Mi
      - --threshold=5
      - --deployment=metrics-server-v0.3.3
      - --container=metrics-server
      - --poll-period=300000
      - --estimator=exponential
      # Specifies the smallest cluster (defined in number of nodes)
      # resources will be scaled to.
      #- --minClusterSize={{ metrics_server_min_cluster_size }}               
      #这里字面意思彷佛是 设置启动几组Metrics-server,选项说明提示默认是16组. 但这我注释掉了。

#第二个文件:resource-reader.yaml
    rules:
    - apiGroups:
      - ""
      resources:
      - pods
      - nodes
      - nodes/stats  
          #这里须要注意:默认是没有添加的,若只添加nodes,它是获取不到nodes/stats的状态信息的,
          #      由于nodes/stats和nodes是两个不一样的资源. nodes/stats是获取节点监控数据的专用资源. 
      - namespaces
    
#以上两个文件修改好后,就可执行应用了
    kubectl  apply  -f  ./
    
#在应用使用,可查看kube-system名称空间中 metrics-server pod的建立
    kubectl  get  pod  -n  kube-system  -w        #会发现metrics-server先建立一组,等第二组启动为running后,第一组就会自动终止。目前尚未弄明白是什么逻辑。

#上面修改好后,测试发现仍是会报错,但已经不报参数无效的错误了
# kubectl get pod -n kube-system 
        NAME                                       READY   STATUS    RESTARTS   AGE
        ................
        metrics-server-v0.3.3-7d598d5c9d-qngp7     2/2     Running   0          49s

# kubectl logs -n kube-system metrics-server-v0.3.3-7d598d5c9d-qngp7 -c metrics-server-nanny 
   ERROR: logging before flag.Parse: I0729 13:06:42.923342       1 pod_nanny.go:65] Invoked by [/pod_nanny --config-dir=/etc/config --cpu=100m --extra-cpu=0.5m --memory=300Mi --extra-memory=50Mi --threshold=5 --deployment=metrics-server-v0.3.3 --container=metrics-server --poll-period=300000 --estimator=exponential]
   ERROR: logging before flag.Parse: I0729 13:06:42.923611       1 pod_nanny.go:81] Watching namespace: kube-system, pod: metrics-server-v0.3.3-7d598d5c9d-qngp7, container: metrics-server.
   ERROR: logging before flag.Parse: I0729 13:06:42.923642       1 pod_nanny.go:82] storage: MISSING, extra_storage: 0Gi
   ERROR: logging before flag.Parse: I0729 13:06:42.927214       1 pod_nanny.go:109] cpu: 100m, extra_cpu: 0.5m, memory: 300Mi, extra_memory: 50Mi
   ERROR: logging before flag.Parse: I0729 13:06:42.927362       1 pod_nanny.go:138] Resources: [{Base:{i:{value:100 scale:-3} d:{Dec:<nil>} s:100m Format:DecimalSI} ExtraPerNode:{i:{value:5 scale:-4} d:{Dec:<nil>} s: Format:DecimalSI} Name:cpu} {Base:{i:{value:314572800 scale:0} d:{Dec:<nil>} s:300Mi Format:BinarySI} ExtraPerNode:{i:{value:52428800 scale:0} d:{Dec:<nil>} s:50Mi Format:BinarySI} Name:memory}]



  #上面准备就绪后,就可作如下测试   
    1. 查看api-versions是否多出了一个 metrics.k8s.io/v1beta1
        # kubectl  api-versions
           .............
            metrics.k8s.io/v1beta1
         
    2. 若以上验证都经过了,则可作如下测试
          kubectl  proxy  --ports=8080
          
    3. 在另外一个终端访问8080
       curl   http://localhost:8080/apis/metrics.k8s.io/v1beta1
            {
              "kind": "APIResourceList",
              "apiVersion": "v1",
              "groupVersion": "metrics.k8s.io/v1beta1",
              "resources": [
                {
                  "name": "nodes",
                  "singularName": "",
                  "namespaced": false,
                  "kind": "NodeMetrics",
                  "verbs": [
                    "get",
                    "list"
            ........................
            }
               
   #查看收集到的Pods 和 node监控数据
    curl  http://localhost:8080/apis/metrics.k8s.io/v1beta1/node

 

   #查看是否能获取Node 和 Pod的资源使用状况:

  

  经过上面部署metrics-server,咱们能够获取到核心资源信息了,可是若想获取更多监控资源数据,就必须借助另外一个Addons组件来获取,而这个Addons就是prometheus

 

prometheus

  它自己就是一个监控系统,它相似于Zabbix,它也须要在Node上安装Agent,而prometheus将本身的Agent称为node_exporter, 但这个node_exporter它仅是用于给Prometheus提供Node的系统级监控指标数据的,所以,若你想采集MySQL的监控数据,你还须要本身部署一个MySQL_exporter,才能采集mySQL的监控数据,并且Prometheus还有不少其它重量级的应用exporter,可在用到时自行学习。

  咱们须要知道,若你能获取一个node上的监控指标数据,那么去获取该node上运行的Pod的指标数据就很是容易了。所以Prometheus,就是经过metrics URL来获取node上的监控指标数据的,固然咱们还能够经过在Pod上定义一些监控指标数据,而后,定义annotations中定义容许 Prometheus来抓取监控指标数据,它就能够直接获取Pod上的监控指标数据了。

PromQL:
  这是Prometheus提供的一个RESTful风格的,强大的查询接口,这也是它对外提供的访问本身采集数据的接口。
  可是Prometheus采集的数据接口与k8s API Server资源指标数据格式不兼容,所以API Server是不能直接使用Prometheus采集的数据的,须要借助一个第三方开发的k8s-prometheus-adapter来解析prometheus采集到的数据, 这个第三方插件就是经过PromQL接口,获取Prometheus采集的监控数据,而后,将其转化为API Server能识别的监控指标数据格式,可是咱们要想经过kubectl来查看这些转化后的Prometheus监控数据,还须要将k8s-prometheus-adpater聚合到API Server中,才能实现直接经过kubectl获取数据 。

#接下来部署Prometheus的步骤大体为:
  1. 部署Prometheus
  2. 配置Prometheus可以获取Pod的监控指标数据
  3. 在K8s上部署一个k8s-prometheus-adpater Pod
  4. 此Pod部署成功后,还须要将其聚合到APIServer中

  

  说明:
  Prometheus它自己就是一个时序数据库,由于它内建了一个存储 全部eporter 或 主动上报监控指标数据给Prometheus的Push Gateway的数据 存储到本身的内建时序数据库中,所以它不须要想InfluxDB这种外部数据库来存数据。
  Prometheus在K8s中经过Service Discovery来找到须要监控的目标主机,而后经过想Grafana来展现本身收集到的全部监控指标数据,另外它还能够经过Web UI 或 APIClients(PromQL)来获取其中的数据。
  Prometheus自身没有提供报警功能,它会将本身的报警需求专给另外一个组件Alertmanger来实现报警功能。

#在K8s上部署Prometheus须要注意,由于Prometheus自己是一个有状态数据集,所以建议使用statefulSet来部署并控制它,可是若你只打算部署一个副本,那么使用deployment和statefulSet就不重要了。可是你若须要后期进行纵向或横向扩展它,那你就只能使用StatefulSet来部署了。

部署K8s Prometheus
须要注意,这是马哥本身作的简版Prometheus,他没有使用PVC,若须要部署使用PVC的Prometheus,可以使用kubernetes官方的Addons中的清单来建立。
官方地址:https://github.com/kubernetes/kubernetes/tree/master/cluster/addons/prometheus
马哥版的地址:https://github.com/iKubernetes/k8s-prom

下面以马哥版原本作说明:
1. 先部署名称空间:
  kubectl  apply  -f   namespace.yaml
    ---
    apiVersion: v1
    kind: Namespace
    metadata:
      name: prom       #这里须要注意: 他是先建立了一个prom的名称空间,而后,将全部Prometheus的应用都放到这个名称空间了。
              
2. 先建立node_exporter:
cd  node_exporter
  #须要注意:
   apiVersion: apps/v1
    kind: DaemonSet
    metadata:
      name: prometheus-node-exporter
      namespace: prom
   .......
       spec:
          tolerations:   #这里须要注意:你要保障此Pod运行起来后,它能容忍Master上的污点.这里仅容忍了默认Master的污点.这里须要根据实际状况作确认。
          - effect: NoSchedule
            key: node-role.kubernetes.io/master 
         containers:
              - image: prom/node-exporter:v0.15.2  #这里使用的node-exporter的镜像版本。
                name: prometheus-node-exporter

#应用这些清单
 kubectl  apply  -f   ./

  #应用完成后,查看Pod

  

#接着进入Prometheus的清单目录
cd  prometheus

#prometheus-deploy.yaml 它须要的镜像文件可从hub.docker.com中下载,若网速慢的话。

#prometheus-rbac.yaml
    apiVersion: rbac.authorization.k8s.io/v1beta1
    kind: ClusterRole
    metadata:
      name: prometheus
    rules:
    - apiGroups: [""]
      resources:
      - nodes
      - nodes/proxy
      - services
      - endpoints
      - pods
      verbs: ["get", "list", "watch"]
    - apiGroups:
      - extensions
      resources:
      - ingresses
      verbs: ["get", "list", "watch"]
    - nonResourceURLs: ["/metrics"]
      verbs: ["get"]


#prometheus-deploy.yaml
    resources:         
    #这里作了一个资源使用限制,须要确认你每一个节点上要能知足2G的可用内存的需求,若你的Node上不能知足这个limits,就将这部分删除,而后作测试。   
      limits:
        memory: 2Gi

#接着开始应用这些清单:
   kubectl  apply  -f   ./

   #应用完成后查看:

  kubectl  get  all  -n  prom

#如今来部署,让K8s能获取Prometheus的监控数据
 cd  kube-state-metrics
 #此清单中的镜像若不能从google仓库中获取,可到hub.docker.com中搜索镜像名,下载其余人作的测试
 
 #K8s须要经过kube-state-metrics这个组件来进行格式转化,实现将Prometheus的监控数据转换为K8s API Server能识别的格式。
 #可是kube-state-metrics转化后,仍是不能直接被K8s所使用,它还须要借助k8s-prometheus-adpater来将kube-state-metrics聚合到k8s的API Server里面,这样才能经过K8s API Server来访问这些资源数据。
 
#应用kube-state-metrics的清单文件   kubectl apply
-f ./
#应用完成后,再次验证

  

 

 

#以上建立好之后,可先到k8s-prometheus-adapter的开发者github上下载最新的k8s-prometheus-adapter的清单文件
  https://github.com/DirectXMan12/k8s-prometheus-adapter/tree/master/deploy/manifests
 #注意:
# !!!!!!!!!
# 使用上面新版本的k8s-prometheus-adapter的话,而且是和马哥版的metrics-
server结合使用,须要修改清单文件中的名称空间为prom
# !!!!!!!!!!!!!!!
# 但下面这个文件要特别注意: custom
-metrics-apiserver-auth-reader-role-binding.yaml piVersion: rbac.authorization.k8s.io/v1 kind: RoleBinding metadata: name: custom-metrics-auth-reader namespace: kube-system #这个custom-metrics-auth-reader必须建立在kube-system名称空间中,由于它要绑到这个名称空间中的Role上 roleRef: apiGroup: rbac.authorization.k8s.io kind: Role #此角色是用于外部APIServer认证读的角色 name: extension-apiserver-authentication-reader subjects: - kind: ServiceAccount name: custom-metrics-apiserver #这是咱们本身建立的SA帐号 namespace: prom #这些须要注意:要修改成prom #以上清单文件下载完成后,须要先修改这些清单文件中的namespace为prom,由于咱们要部署的Prometheus都在prom这个名称空间中. 以后就能够正常直接应用了   kubectl apply -f ./

   # 应用完成后,须要检查
  kubectl get all -n prom #查看全部Pod都已经正常运行后。。

  # 查看api-versions中是否已经包含了 custom.metrics.k8s.io/v1beta1, 若包含,则说明部署成功
  kubectl api-versions

  # 测试获取custom.metrics.k8s.io/v1beta1的监控数据
  curl   http://localhost:8080/custom.metrics.k8s.io/v1beta1/

下面测试将Grafana部署起来,而且让Grafana从Prometheus中获取数据
    
#部署Grafana,这里部署方法和上面部署HeapSter同样,只是这里仅部署Grafana
wget  https://raw.githubusercontent.com/kubernetes-retired/heapster/master/deploy/kube-config/influxdb/grafana.yaml

#此清单若须要修改apiVersion,也要向上面修改同样,配置其seletor。
 
#另外还有须要注意:
   volumeMounts:
    - mountPath: /etc/ssl/certs  #它会自动挂载Node上的/etc/ssl/certs目录到容器中,并自动生成证书,由于它使用的HTTPS.
      name: ca-certificates
      readOnly: true
              
#Grafana启动时,会去链接数据源,默认是InfluxDB,这个配置是经过环境变量来传入的
   env:
    #- name: INFLUXDB_HOST
    # value: monitoring-influxdb              
        #这里可看到,它将InfluxDB的Service名传递给Grafana了。
        #须要特别注意:由于这里要将Grafana的数据源指定为Prometheus,因此这里须要将InfluxDB作为数据源给关闭,若你知道如何定义prometheus的配置,
        #也可直接修改,不修改也能够,那就直接注释掉,而后部署完成后,登陆Grafana后,在修改它的数据源获取地址。
    - name: GF_SERVER_HTTP_PORT
      value: "3000" 
      #默认Grafara在Pod内启动时,监听的端口也是经过环境变量传入的,默认是3000端口.
    
 #在一个是,咱们须要配置Grafana能够被外部直接访问
  ports:
      - port: 80
        targetPort: 3000
      selector:
        k8s-app: grafana
      type:  NodePort
                

#配置完成后,进行apply
  kubectl  apply  -f   grafana.yaml
  
#而后查看service对集群外暴露的访问端口
  kubectl   get   svc   -n  prom

  #随后打开浏览器,作如下修改

  

  #接着,你能够查找一个,如何导入第三方作好的模板,而后,从grafana官网下载一个模板,导入就能够获取一个漂亮的监控界面了。
  #获取Prometheus的模板文件,可从这个网站获取
  https://grafana.com/grafana/dashboards?search=kubernetes

  

 

 

HPA功能:
  正如前面所说,它可根据咱们所设定的规则,监控当前Pod总体使用率是否超过咱们设置的规则,若超过则设置的根据比例动态增长Pod数量。
  举个简单的例子:
  假若有3个Pod,咱们规定其最大使用率不能高于60%,但如今三个Pod每一个CPU使用率都到达90%了,那该增长几个Pod的?
  HPA的计算方式是:
    90% × 3 = 270% , 那在除以60,就是须要增长的Pod数量, 270 / 60 = 4.5 ,也就是5个Pod

#HPA示例:
  kubectl run myapp --image=harbor.zcf.com/k8s/myapp:v1 --replicas=1 \
    --requests='cpu=50m,memory=256Mi' --limits='cpu=50m,memory=256Mi' \
    --labels='app=myapp' --expose --port=50

#修改myapp的svcPort类型为NodePort,让K8s集群外部能够访问myapp,这样方便压力测试,让Pod的CPU使用率上升,而后,查看HPA自动建立Pod.
  kubectl patch svc myapp -p '{"spec":{"type":"NodePort"}}'

  # kubectl get pods

  

  #这里目前只有一个Pod!!

  kubectl describe pod myapp-xxxx    #可查看到它当前的QoS类别为: Guranteed

#建立HPA,根据CPU利用率来自动伸缩Pod
  kubectl autoscale deployment myapp --min=1 --max=8 --cpu-percent=40

  

#查看当前Pod是Service:
# kubectl get svc
    NAME         TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)        AGE
    ..................
    myapp        NodePort    172.30.162.48   <none>        80:50113/TCP   103m

#建立成功后,就能够经过ab等压测工具来测试自动伸缩
#apt-get install  apache2-utils
#
# ab  -c 1000  -n 3000   http://192.168.111.84:50113

#查看HPA自动伸缩状况
   # kubectl describe hpa
    Name:                                                  myapp
    Namespace:                                             default
   ............................
      resource cpu on pods  (as a percentage of request):  76% (38m) / 40%
    Min replicas:                                                                        1
    Max replicas:                                                                        8
    Deployment pods:                                       6 current / 8 desired   #这里可看到如今已经启动6个Pod

        
   
#建立一个HPA v2版本的自动伸缩其
#完整配置清单:
vim  hpa-pod-demo-v2.yaml 
    apiVersion: v1
    kind: Service
    metadata:
      labels:
        app: myapp
      name: myapp-v2
    spec:
      clusterIP: 172.30.10.98
      ports:
      - port: 80
        protocol: TCP
        targetPort: 80
      type: NodePort
      selector:
        app: myapp
    ---
    apiVersion: apps/v1
    kind: Deployment
    metadata:
      labels:
        app: myapp
      name: myapp-v2
    spec:
      replicas: 1
      selector:
        matchLabels:
          app: myapp
      strategy: {}
      template:
        metadata:
          labels:
            app: myapp
        spec:
          containers:
          - image: harbor.zcf.com/k8s/myapp:v1
            name: myapp-v2
            ports:
            - containerPort: 80
            resources:
              limits:
                cpu: 50m
                memory: 256Mi
              requests:
                cpu: 50m
                memory: 256Mi

    ---
    apiVersion: autoscaling/v2beta1
    kind: HorizontalPodAutoscaler
    metadata:
      name: myapp-v2
    spec:
      maxReplicas: 8
      minReplicas: 1
      scaleTargetRef:
        apiVersion: extensions/v1beta1
        kind: Deployment
        name: myapp
      metrics:
       - type: Resource
         resource:
           name: cpu
           targetAverageUtilization: 55
       - type: Resource
         resource:
           name: memory
           targetAverageValue: 50Mi

  #压测方便和上面同样。这个配置清单中定义了CPU和内存的资源监控指标,V2是支持内存监控指标的,但V1是不支持的。

  

  #若之后本身程序员开发的Pod,能经过Prometheus导出Pod的资源指标,好比:HTTP的访问量,链接数,咱们就能够根据HTTP的访问量或者链接数来作自动伸缩。
 在那个Pod上的那些指标可用,是取决于你的Prometheus可以从你的Pod的应用程序中获取到什么样的指标的,可是Prometheus能获取的指标是由必定语法要求的,开发要依据  Prometheus支持的RESTful风格的接口,去输出一些指标数据,这指标记录当前系统上Web应用程序所承载的最大访问数等一些指标数据,那咱们就可基于这些输出的指标数据,来完成HPA自动伸缩的扩展。

#自定义资源指标来建立HPA,实现根据Pod中输出的最大链接数来自动扩缩容Pod
#下面是一个HPA的定义,你还须要建立一个能输出http_requests这个自定义资源指标的Pod,而后才能使用下面的HPA的清单。

下面清单是使用自定义资源监控指标 http_requests 来实现自动扩缩容:
  docker pull ikubernetes/metrics-app   #可从这里获取metrics-app镜像

vim  hpa-http-requests.yaml
apiVersion: v1
kind: Service
metadata:
  labels:
    app: myapp
  name: myapp-hpa-http-requests
spec:
  clusterIP: 172.30.10.99    #要根据实际状况修改成其集群IP
  ports:
  - port: 80
    protocol: TCP
    targetPort: 80
  type: NodePort             #若须要集群外访问,可添加
  selector:
    app: myapp
---
apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    app: myapp
  name: myapp-hpa-http-requests
spec:
  replicas: 1      #这里指定Pod副本数量为1
  selector:
    matchLabels:
      app: myapp
  strategy: {}
  template:
    metadata:
      labels:
        app: myapp
      annotations:         #annotations必定要,而且要定义在容器中!!
        prometheus.io/scrape: "true"     #这是容许Prometheus到容器中抓取监控指标数据
        prometheus.io/port: "80"                 
        prometheus.io/path: "/metrics"   #这是指定从那个URL路径中获取监控指标数据
    spec:
      containers:
      - image: harbor.zcf.com/k8s/metrics-app  #此镜像中包含了作好的,能输出符合Prometheus监控指标格式的数据定义。
        name: myapp-metrics
        ports:
        - containerPort: 80
        resources:
          limits:
            cpu: 50m
            memory: 256Mi
          requests:
            cpu: 50m
            memory: 256Mi

---
apiVersion: autoscaling/v2beta1
kind: HorizontalPodAutoscaler
metadata:
  name: myapp-hpa-http-requests
spec:
  maxReplicas: 8
  minReplicas: 1
  scaleTargetRef:       #这指定要伸缩那些类型的Pod。
    apiVersion: extensions/v1beta1
    kind: Deployment    #这里指定对名为 myapp-hpa-http-requests这个 Deployment控制器 下的全部Pod作自动伸缩.
    name: myapp-hpa-http-requests
  metrics:
   - type: Pods    #设置监控指标是从那种类型的资源上获取:它支持Resource,Object,Pods ;
                   #resource:核心指标如:cpu,内存可指定此类型,若监控的资源指标是从Pod中获取,那类型就是Pods
     pods:
       metricName: http_requests   #http_requests就是自定义的监控指标,它是Prometheus中Pod中获取的。
       targetAverageValue: 800m    #800m:是800个并发请求,由于一个并发请求,就须要一个CPU核心来处理,因此是800个豪核,就是800个并发请求。
     
     
#  curl http://192.168.111.84:55066/metrics
   #注意:Prometheus抓取数据时,它要求获取资源指标的数据格式以下:
    # HELP   http_requests_total The amount of requests in total   #HELP:告诉Prometheus这个数据的描述信息
    # TYPE   http_requests_total   counter     #TYPE: 告诉Prometheus这个数据的类型
    http_requests_total   1078                 #告诉Prometheus这个数据的值是多少。

    # HELP http_requests_per_second The amount of requests per second the latest ten seconds
    # TYPE http_requests_per_second gauge
    http_requests_per_second   0.1

                      
# 测试方法:
1. 先在一个终端上执行:
   for  i  in  `seq  10000`;  do   curl  http://K8S_CLUSTER_NODE_IP:SERVER_NODE_PORT/ ;  done

2. 查看hpa的状态
  # kubectl   describe   hpa 
    Name:                       myapp-hpa-http-requests
    Namespace:                  default
    .........
    Reference:                  Deployment/myapp-hpa-http-requests
    Metrics:                    ( current / target )
      "http_requests" on pods:  4366m / 800m
    Min replicas:                                1
    Max replicas:                               8
    Deployment pods:            8 current / 8 desired
    ........................
    Events:
      Type     Reason                        Age   From                       Message
      ----     ------                        ----  ----                       -------
      .....................
      Normal   SuccessfulRescale             51s   horizontal-pod-autoscaler  New size: 4; reason: pods metric http_requests above target
      Normal   SuccessfulRescale             36s   horizontal-pod-autoscaler  New size: 8; reason: pods metric http_requests above target

3. 查看Pod
   # kubectl   get   pod
    NAME                                       READY   STATUS    RESTARTS   AGE
    myapp-hpa-http-requests-69c9968cdf-844lb   1/1     Running   0          24s
    myapp-hpa-http-requests-69c9968cdf-8hcjl   1/1     Running   0          24s
    myapp-hpa-http-requests-69c9968cdf-8lx9t   1/1     Running   0          39s
    myapp-hpa-http-requests-69c9968cdf-d4xdr   1/1     Running   0          24s
    myapp-hpa-http-requests-69c9968cdf-k4v6h   1/1     Running   0          114s
    myapp-hpa-http-requests-69c9968cdf-px2rl   1/1     Running   0          39s
    myapp-hpa-http-requests-69c9968cdf-t52xr   1/1     Running   0          39s
    myapp-hpa-http-requests-69c9968cdf-whjl6   1/1     Running   0          24s
相关文章
相关标签/搜索