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
相關文章
相關標籤/搜索