【轉】Kubernetes容器資源限制 resources:cpu memory


 

在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的影響:

  

   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在預選階段就會被篩選掉。

資源限制配置:
  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它。

 

K8s中Pod監控的指標有以下幾類:
  1. Kubernetes系統指標
  2. 容器指標,即:容器使用的CPU,內存,存儲等資源的統計用量的
  3. 應用指標,即業務應用的指標,如:接收了多少用戶請求,正在處理的用戶請求等等。

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。

下面部署中使用了這樣的版本組合:

 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官網去找一些模板測試。


構建上面三個組件的順序:

  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
復制代碼

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM