在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