本文是kubelet源碼閱讀的先導片,先了解kubelet的主要配置和功能以及一些注意事項,後面走讀源碼的時候纔會更加順暢,否則一堆 config 的初始化和chan處理,不知道支持哪些新特性,啥場景會用到,看了也沒啥意思。php
k8s 迭代速度很快,幾個月一個大版本,kubelet 的啓動參數也在不斷變化,一切配置以官方文檔爲準,或者拿二進制直接--help 看,否則忙活一圈才發現某個特性在當前版本不支持。下面是一份基礎可用的kubelet配置,版本 1.8html
./kubelet \ --address=192.168.5.228 \ --allow-privileged=true \ --client-ca-file=/etc/kubernetes/pki/ca.pem \ --cloud-config=/etc/kubernetes/cloud.config \ --cloud-provider=external \ --cluster-dns=172.16.0.10 \ --cluster-domain=cluster.local \ --docker-root=/data/docker \ --fail-swap-on=false \ --feature-gates=VolumeSnapshotDataSource=true,CSINodeInfo=true,CSIDriverRegistry=true \ --hostname-override=192.168.5.228 \ --kubeconfig=/etc/kubernetes/kubelet.conf \ --logtostderr=true \ --network-plugin=kubenet \ --max-pods=256 \ --non-masquerade-cidr=172.26.0.0/16 \ --pod-infra-container-image=hub.docker.com/public/pause:2.0 \ --pod-manifest-path=/etc/kubernetes/manifests \ --root-dir=/data/kubelet \ --tls-cipher-suites=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305,TLS_RSA_WITH_AES_128_CBC_SHA,TLS_RSA_WITH_AES_256_CBC_SHA,TLS_RSA_WITH_AES_128_GCM_SHA256,TLS_RSA_WITH_AES_256_GCM_SHA384,TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA \ --anonymous-auth=false \ --v=5 \ --enforce-node-allocatable=pods,kube-reserved,system-reserved \ --kube-reserved-cgroup=/system.slice/kubelet.service \ --system-reserved-cgroup=/system.slice \ --kube-reserved=cpu=50m \ --system-reserved=cpu=50m \ --eviction-hard=memory.available<5%,nodefs.available<10%,imagefs.available<10%% \ --eviction-soft=memory.available<10%,nodefs.available<15%,imagefs.available<15%% \ --eviction-soft-grace-period=memory.available=2m,nodefs.available=2m,imagefs.available=2m \ --eviction-max-pod-grace-period=30 \ --eviction-minimum-reclaim=memory.available=0Mi,nodefs.available=500Mi,imagefs.available=500Mi
上面的配置文件是老版本 kubelet(1.10 之前),啓動參數都是用 flag 來聲明的,簡單粗暴,在 1.10 之後,kubelet 支持了KubeletConfiguration的方式來聲明參數,如 kubeadm 部署的集羣配置以下:java
# Note: This dropin only works with kubeadm and kubelet v1.11+ [Service] Environment="KUBELET_KUBECONFIG_ARGS=--bootstrap-kubeconfig=/etc/kubernetes/bootstrap-kubelet.conf --kubeconfig=/etc/kubernetes/kubelet.conf" Environment="KUBELET_CONFIG_ARGS=--config=/var/lib/kubelet/config.yaml" # This is a file that "kubeadm init" and "kubeadm join" generates at runtime, populating the KUBELET_KUBEADM_ARGS variable dynamically EnvironmentFile=-/var/lib/kubelet/kubeadm-flags.env # This is a file that the user can use for overrides of the kubelet args as a last resort. Preferably, the user should use # the .NodeRegistration.KubeletExtraArgs object in the configuration files instead. KUBELET_EXTRA_ARGS should be sourced from this file. EnvironmentFile=-/etc/sysconfig/kubelet ExecStart= ExecStart=/usr/bin/kubelet $KUBELET_KUBECONFIG_ARGS $KUBELET_CONFIG_ARGS $KUBELET_KUBEADM_ARGS $KUBELET_EXTRA_ARGS ~
kubelet 的--config配置採用了本地文件KubeletConfiguration資源作參數node
本地文件/var/lib/kubelet/config.yaml內容爲:mysql
apiVersion: kubelet.config.k8s.io/v1beta1 authentication: anonymous: enabled: false webhook: cacheTTL: 0s enabled: true x509: clientCAFile: /etc/kubernetes/pki/ca.crt authorization: mode: Webhook webhook: cacheAuthorizedTTL: 0s cacheUnauthorizedTTL: 0s clusterDNS: - 10.96.0.10 clusterDomain: cluster.local cpuManagerReconcilePeriod: 0s evictionPressureTransitionPeriod: 0s fileCheckFrequency: 0s healthzBindAddress: 127.0.0.1 healthzPort: 10248 httpCheckFrequency: 0s imageMinimumGCAge: 0s kind: KubeletConfiguration nodeStatusReportFrequency: 0s nodeStatusUpdateFrequency: 0s rotateCertificates: true runtimeRequestTimeout: 0s staticPodPath: /etc/kubernetes/manifests streamingConnectionIdleTimeout: 0s syncFrequency: 0s volumeStatsAggPeriod: 0s
爲何要這麼改呢?git
--max-pods int32 Number of Pods that can run on this Kubelet. (default 110) (DEPRECATED: This parameter should be set via the config file specified by the Kubelet's --config flag. See https://kubernetes.io/docs/tasks/administer-cluster/kubelet-config-file/ for more information.)
以上面的max-pods配置爲例,你運行kubelet --help你會發現,kubelet的絕大多數命令行flag參數都被DEPRECATED了,後面一句就是官方推薦咱們使用--config文件來指定這些配置,具體內容能夠查看這裏Set Kubelet parameters via a config file,一來是區分出什麼是機器特有配置,什麼是機器能夠共享的配置,二來是爲了支持以後更高級的動態Kubelet配置Dynamic Kubelet Configuration,即把能夠共享的配置作成一種資源,節點共享一份配置github
kubelet 的支持動態 kubelet 配置,即dynamic-config,在1.11版本開始支持,原理以下:golang
參考:https://kubernetes.io/docs/ta...web
config 文件的概念出來以後,kubelet 的配置就劃分爲了兩部分:算法
動態配置在 1.17仍然處於 beta 狀態,其中有幾個關鍵點還沒解決:
沒有提供原生的集羣灰度能力,須要用戶本身實現自動化灰度節點配置。若是全部Node引用同一個Kubelet ConfigMap,當該ConfigMap發生錯誤變動後,可能會致使集羣短期不可用。
不管是flag 參數仍是 config 參數,都是kubelet 運行的必備條件,這裏對一些關鍵指標進行解釋,如下內容大量引用官方文檔
所有 config:https://kubernetes.io/zh/docs...
config 文件中的參數列表爲:https://github.com/kubernetes...
剩下的就是 flag參數,參數的示例值見上文。
cloud-config
: 雲服務商的配置文件路徑,cloud-provider開啓時使用cloud-provider
: 雲服務商,爲空表示沒有云服務商,用於肯定節點名稱。hostname-override
: 若是爲非空,將使用此字符串而不是實際的主機名做爲節點標識config
: 用於聲明 config 文件的路徑container-runtime
: 容器運行時,默認爲 docker,還支持remote、rkt(已棄用)docker-root
: docker 根目錄的路徑,默認值:/var/lib/dockerkubeconfig
: kubeconfig 配置文件的路徑,指定如何鏈接到 API 服務器。提供 --kubeconfig 將啓用 API 服務器模式,而省略 --kubeconfig 將啓用獨立模式。logtostderr
: 日誌輸出到 stderr 而不是文件(默認值爲 true)network-plugin
: 僅當容器運行環境設置爲 docker 時生效,如 kubenetnon-masquerade-cidr
: kubelet 向該 IP 段以外的 IP 地址發送的流量將使用 IP 假裝技術,該參數將在將來版本中刪除 ?pod-infra-container-image
: 僅當容器運行環境設置爲 docker 時生效,指定pause鏡像root-dir
: 設置用於管理 kubelet 文件的根目錄(例如掛載卷的相關文件),默認/var/lib/kubelettls-cipher-suites
: 服務器端加密算法列表,以逗號分隔,若是不設置,則使用 Go 語言加密包的默認算法列表v
: 設置 kubelet 日誌級別詳細程度的數值address
: kubelet綁定的主機IP地址,默認爲0.0.0.0表示綁定所有網絡接口allow-privileged
: 是否容許以特權模式啓動容器。當前默認值爲false,已廢棄client-ca-file
: 基礎 ca證書,即 ca.pemcluster-dns
: 集羣內DNS服務的IP地址,僅當 Pod 設置了 「dnsPolicy=ClusterFirst」 屬性時可用cluster-domain
: 集羣的域名fail-swap-on
: 設置爲 true 表示若是主機啓用了交換分區,kubelet 將沒法使用。(默認值爲 true)max-pods
: kubelet 能運行的 Pod 最大數量。(默認值爲 110)feature-gates
: 用於 alpha 實驗性質的特性開關組,每一個開關以 key=value 形式表示pod-manifest-path
: 設置包含要運行的static Pod 的文件的路徑,或單個靜態 Pod 文件的路徑anonymous-auth
: 設置爲 true 表示 kubelet 服務器能夠接受匿名請求。enforce-node-allocatable
: 包含由 kubelet 強制執行的節點可分配資源級別。可選配置爲:‘none’、‘pods’、‘system-reserved’ 和 ‘kube-reserved’kube-reserved-cgroup
: 頂層kube cgroup 的名稱system-reserved-cgroup
: 頂層system cgroup 的名稱kube-reserved
: kube 組件資源預留system-reserved
: 系統組件組件預留eviction-hard
: 硬驅逐策略eviction-soft
: 軟驅逐策略eviction-soft-grace-period
: 軟驅逐寬限期eviction-max-pod-grace-period
: 響應知足軟驅逐閾值(soft eviction threshold)而終止 Pod 時使用的最長寬限期(以秒爲單位)eviction-minimum-reclaim
: 當本節點壓力過大時,kubelet 執行軟性驅逐操做。此參數設置軟性驅逐操做須要回收的資源的最小數量(例如:imagefs.available=2Gi)。詳細內容參考:k8s節點資源預留與 pod 驅逐
驅逐:經過--eviction-hard標誌預留一些內存後,當節點上的可用內存降至保留值如下時,kubelet 將會對pod進行驅逐。驅逐有軟硬兩種,並且軟驅逐能夠細化到持續多久才觸發。
預留:能夠給系統核心進程、k8s 核心進程配置資源預留,總數-預留數剩下的纔是給 pod 分配的量,資源預留建議使用階梯式,機器配置越高,預留越多
如,對於內存資源:
設計文檔:node-heartbeat
目的:
API Server 很高的 CPU 消耗,node 節點很是龐大,序列化/反序列化開銷很大,處理心跳請求的 CPU 開銷超過 API Server CPU 時間佔用的 80%。
方法:
具體參考:https://kubernetes.io/docs/co...
設計文檔:watch-bookmark
目的:
方法:
kubernetes 從v1.15開始 支持 bookmark 機制,bookmark 主要做用是隻將特定的事件發送給客戶端,從而避免增長 apiserver 的負載。bookmark 的核心思想歸納起來就是在 client 與 server 之間保持一個「心跳」,即便隊列中無 client 須要感知的更新,reflector 內部的版本號也須要及時的更新。
好比:每一個節點上的 kubelet 僅關注 和本身節點相關的 pods,pod storage 隊列是有限的(FIFO),當 pods 的隊列更新時,舊的變動就會從隊列中淘汰,當隊列中的更新與某個 kubelet client 無關時,kubelet client watch 的 resourceVersion 仍然保持不變,若此時 kubelet client 重連 apiserver 後,這時候 apiserver 沒法判斷當前隊列的最小值與 kubelet client 之間是否存在須要感知的變動,所以返回 client too old version err 觸發 kubelet client 從新 list 全部的數據。
EventType多了一種枚舉值:Bookmark
Added EventType = "ADDED" Modified EventType = "MODIFIED" Deleted EventType = "DELETED" Error EventType = "ERROR" Bookmark EventType = "BOOKMARK"
設計文檔: hugepages
目的:
HugePages是Linux內核的一個特性,使用hugepage能夠用更大的內存頁來取代傳統的4K頁面。能夠提升內存的性能,下降CPU負載,做用詳情參考hugepage的優點與使用
對於大內存工做集或者對內存訪問延遲很敏感的應用來講,開啓hugepages的效果比較顯著,如 mysql、java 程序、dpdk等,默認狀況下 kubelet啓動的 pod 是沒有開啓hugepages的。
方法:
從 k8s1.8 開始就開始支持hugepage,kubelet中經過--feature-gates=HugePages=true來開啓,hugepage 建議謹慎使用,由管理員來分配,由於預分配的大頁面會減小節點上可分配的內存量。該節點將像對待其餘系統保留同樣對待預分配的大頁面,可分配 mem 的公式就變成了:
[Allocatable] = [Node Capacity] - [Kube-Reserved] - [System-Reserved] - [Pre-Allocated-HugePages * HugePageSize] - [Hard-Eviction-Threshold]
如開了 hugepage 的 node 狀態爲:
apiVersion: v1 kind: Node metadata: name: node1 ... status: capacity: memory: 10Gi hugepages-2Mi: 1Gi allocatable: memory: 9Gi hugepages-2Mi: 1Gi
在建立 pod 時能夠聲明使用這些頁內存,
apiVersion: v1 kind: Pod metadata: name: example spec: containers: ... volumeMounts: - mountPath: /hugepages-2Mi name: hugepage-2Mi - mountPath: /hugepages-1Gi name: hugepage-1Gi resources: requests: hugepages-2Mi: 1Gi hugepages-1Gi: 2Gi limits: hugepages-2Mi: 1Gi hugepages-1Gi: 2Gi volumes: - name: hugepage-2Mi emptyDir: medium: HugePages-2Mi - name: hugepage-1Gi emptyDir: medium: HugePages-1Gi
設計文檔:[https://github.com/kubernetes...]
目的:
健康檢查的基礎內容參考:[K8S 中的健康檢查機制
](https://www.jianshu.com/p/5de...
kubelet 中有 health check 相關的邏輯來判斷 pod 啓動後狀態是否正常,若是檢查不經過會殺死 pod 重啓,直到檢查經過,但對於慢啓動容器 來講現有的健康檢查機制不太好用
慢啓動容器:指須要大量時間(一到幾分鐘)啓動的容器。啓動緩慢的緣由可能有多種:
這種容器的主要問題在於,在livenessProbe失敗以前,應該給它們足夠的時間來啓動它們。對於這種問題,現有的機制的處理方式爲:
延遲初始時間initialDelaySeconds
設置的很長,以容許容器啓動(即initialDelaySeconds大於平均啓動時間)。雖然這樣能夠確保livenessProbe不會檢測失敗,可是不知道initialDelaySeconds應該配置爲多少,啓動時間不是一個固定值。另外,由於livenessProbe在啓動過程還沒運行,所以pod 得不到反饋,events 看不到內容,若是你initialDelaySeconds是 10 分鐘,那這 10 分鐘內你不知道在發生什麼。方法二能夠解決這個問題,但不夠優雅。
由於livenessProbe的設計是爲了在 pod 啓動成功後進行健康探測,最好前提是 pod 已經啓動成功,不然啓動階段的屢次失敗是沒有意義的,所以官方提出了一種新的探針:即startupProbe,startupProbe並非一種新的數據結構,他徹底複用了livenessProbe,只是名字改了下,多了一種概念,關於這個 probe 的提議討論能夠參考issue
使用方式:startup-probes
ports: - name: liveness-port containerPort: 8080 hostPort: 8080 livenessProbe: httpGet: path: /healthz port: liveness-port failureThreshold: 1 periodSeconds: 10 startupProbe: httpGet: path: /healthz port: liveness-port failureThreshold: 30 periodSeconds: 10
這個配置的含義是:
startupProbe首先檢測,該應用程序最多有5分鐘(30 * 10 = 300s)完成啓動。一旦startupProbe成功一次,livenessProbe將接管,以對後續運行過程當中容器死鎖提供快速響應。若是startupProbe從未成功,則容器將在300秒後被殺死。
k8s 1.16 纔開始支持startupProbe這個特性