原文 Scaling Kubernetes to 2,500 Nodes
緣起
最近比較忙碌,都只能夜深人靜才能好好的來閱讀一些文章來充實自己.(公司牛人多到像牧場,只好不斷努力 lol )
OpenAI 最近有一篇技術文章,相當的值得一讀.就是他們分享他們如何管理超過 2500 個節點. 當然我們都知道,
Kubernetes 自從 1.6 之後就號稱可以乘載 5000 個節點以上,但是從 數十台到 2500 台的路上,難道不會遇到一些問題嗎? 這篇文章分享了他們遇到的問題,試著要解決與懷疑的地方,最後找到真正的問題.這篇文章適合所有 DevOp 好好的熟讀.
遇到的問題與解決方式
第一次遇到問題: 1 ~ 500 個節點之後
- 問題徵兆:
kubectl
有時候會發生 timeout. (p.s. `kubectl -v=6 可以顯示所有API 細節指令)
- 嘗試解決方式:
- 一開始以為是
kube-apiserver
服務器過分忙碌,試著增加 proxy 來做 replica 來幫忙 load balance - 但是超過 10 個備份 master 的時候,他們發現問題一定不是因為 kube-apiserver 無法承受.因為
GKE 透過一台 32-core VM 就可以乘載 500台
- 一開始以為是
- 原因:
第二次遇到問題: ~1000 個節點的時候
- 問題徵兆:
- 發現
kube-apiserver
每秒需要從 etcd 上面讀取 500Mb
- 發現
- 嘗試解決方式:
- 透過 Prometheus (一種廣泛用於 Kubernetes 上面作為 Container 資料搜集與監控工具) 來查看每個 container 之間的網路流量
- 原因:
- 發現 Fluentd (一個作為資料與 log 轉發的工具) 與 Datadog ,太頻繁來抓取每個節點上面的資料.
- 調低這兩個服務的抓取頻率,網路效率馬上就從 500 Mb/s 到幾乎沒有…
etcd
小技巧: 透過--etcd-servers-overrides
可以將 Kubernetes Event 的資料寫入作為切割,分不同機器處理.範例為 :
--etcd-servers-overrides=/events#https://0.example.com:2381;https://1.example.com:2381;https://2.example.com:2381
第三次問題: 當經營到 1000~2000節點
- 問題徵兆:
- 無法再寫入資料,回報
cascading failure
kubernetes-ec2-autoscaler
在全部的etcd
都爆掉之後才回傳問題,並且關閉所有的etcd
- 無法再寫入資料,回報
- 嘗試解決方式:
- 猜測
etcd
硬碟爆滿,但是檢查 SSD 硬碟空間依舊有許多空間. - 檢查是否有預設設定空間限制,發現有 2GB 大小限制
- 猜測
- 解決方式:
etcd
啟動參數加上--quota-backend-bytes
- 修改
kubernetes-ec2-autoscaler
logic 如果超過 50% 都出問題,預警性的關閉集群.
## 各種服務的優化
除了遇到的問題解決外, OpenAI 也提供他們一些設定方式. 可以幫助你更順利的在大量集群上的運作.
Kube masters 的 HA (High Availability)
一般來說,我們架設都是以一個 kube-master (主要的 Kubernetes 服務提供者,上面有 kube-apiserver
, kube-scheduler
與 kube-control-manager
) 加上多個 slave . 但是要達到 HA 設定,要根據以下的方式:
kube-apiserver
要設置多個服務,並且透過參數--apiserver-count
重啟並且設定.kubernetes-ec2-autoscaler
可以幫你自動關閉 idle 的資源,但是這跟 Kubernetes scheduler 的原則相反. 不過透過這些設定,可以幫助你盡量把資源集中.
{
"kind" : "Policy",
"apiVersion" : "v1",
"predicates" : [
{"name" : "GeneralPredicates"},
{"name" : "MatchInterPodAffinity"},
{"name" : "NoDiskConflict"},
{"name" : "NoVolumeZoneConflict"},
{"name" : "PodToleratesNodeTaints"}
],
"priorities" : [
{"name" : "MostRequestedPriority", "weight" : 1},
{"name" : "InterPodAffinityPriority", "weight" : 2}
]
}
上面是個調整你 Kubernetes scheduler 的範例,這個範例會透過把 InterPodAffinityPriority
的權重調高,達到我們要的調整方向.更多的部分,可以參考原始範例.
不過要注意,目前 Kubernetes Scheduler Policy 並不支援動態切換,需要重起你的 kube-apiserver
(issue: 41600)
參考文件: VF技術部落格: 深入kubernetes调度之原理分析 – 關於 Kubernetes Scheduler 相關介紹文件(中文)
調整 scheduler policy 造成的影響
OpenAI 有使用 KubeDNS: 一個 Kubernetes 內部使用的 DNS ,但是經過不久發現
-
問題徵兆:
- 經常有 DNS 忽然查詢不到的 (隨機發生)
- 超過 ~200QPS domain lookup
-
嘗試解決問題方式:
- 試著察看為何有這種狀態,發現有些 node 上面有跑超過 10+ KubeDNS
-
解決方式:
- 由於 scheduler policy 造成許多 POD 會儘量的集中.
- KubeDNS 相當的 lightweight,所以很容易被分配到同一個節點.造成 domain lookup 集中.
- 需要修改 POD affinity (這邊有更多相關介紹),儘量讓 KubeDNS 不要都分配到同一個節點 (node)
affinity: podAntiAffinity: requiredDuringSchedulingIgnoredDuringExecution: - weight: 100 labelSelector: matchExpressions: - key: k8s-app operator: In values: - kube-dns topologyKey: kubernetes.io/hostname
緩慢的 Docker image pulls (針對新建節點)
- 問題徵兆:
- 每次一個新的節點建立起來,都得花約 30mins 在 docker image pull
- 嘗試解決方式:
- 有一個相當龐大的 container image Dota, 裡面約莫 17GB.他影響了整個節點的 image pulling
- 開始查看
kubelet
是否有其他選項可以讓你 image pull
- 解決方式:
- 在
kubelet
加上選項--serialize-image-pulls=false
來啟動 image pulling 來讓其他服務可以比較早 pull 參考:kubelet 啟動選項- 這個選項需要 docker storage 換到
overlay2
可以參考這篇 docker 教學文章
- 這個選項需要 docker storage 換到
- 並且把 docker image 存放位置放到 SSD ,讓 image pull 更快
- 在
補充: 特地下去把 source trace 了一下
// serializeImagePulls when enabled, tells the Kubelet to pull images one
// at a time. We recommend *not* changing the default value on nodes that
// run docker daemon with version < 1.9 or an Aufs storage backend.
// Issue #10959 has more details.
SerializeImagePulls *bool `json:"serializeImagePulls"`
增加 docker image pull 速度
此外,還可以透過以下方式來增加 pull 速度
kubelet
有個參數--image-pull-progress-deadline
要提高到 30mins- docker daemon 有個參數
max-concurrent-download
要調到 10 才能多線程下載
網路效能的提升
Flannel 效能限制
OpenAI 節點間的網路流量,可以達到 10-15Gbit/s .但是由於 Flannel 所以導致流量會降到 ~2Gbit/s
解決方式就是將 Flannel 拿掉,使用實體網路.
hostNetwork: true
dnsPolicy: ClusterFirstWithHostNet
這裡有一些警告需要詳細閱讀
參考文章 :
kubectl
小技巧:kubectl -v=6
可以顯示所有API 細節指令kube-apiserver
小技巧:kube-apiserver
啟動指令--audit-log-path
與--audit-log-maxbackup
可以查看更詳細的內容etcd
小技巧: 透過--etcd-servers-overrides
可以將 Kubernetes Event 的資料寫入作為切割,分不同機器處理- Fio: 效能評估資料 IOPS
- Datadog: 檢查整個集群效能與監控評比
- Prometheus: Container monitoring tool
- Fluentd (一個作為資料與 log 轉發的工具)
- Kubernetes-ec2-autoscaler 在 AWS EC2 可以自動開機與關閉的 Autoscaler
- Kubernetes scheduler config example
- KubeDNS: 一個 Kubernetes 內部使用的 DNS
- Kubernetes Blog: POD assignment affinity
- VF技術部落格: 深入kubernetes调度之原理分析 – 關於 Kubernetes Scheduler 相關介紹文件(中文)
- kubelet 啟動選項