- Kubernetes 自從1.6起便號稱可以承載 5000 個以上的節點,但是從數十到 5000 的路上,難免會遇到問題。
- 在 kubernetes 5000 之路上的經驗,包括遇到的問題、嘗試解決問題以及找到真正的問題。
1、
問題一:1 ~ 500 個節點之后
問題:kubectl 有時會出現 timeout ( p.s. kubectl -v=6 可以顯示所有 API 細節指令)
嘗試解決:
一開始以為是 kube-apiserver 服務器負載的問題,嘗試增加 proxy 做 replica 協助進行負載均衡
但是超過 10 個備份 master 的時候,發現問題不是因為 kube-apiserver 無法承受負載,GKE 通過一台 32-core VM 就可以承載 500 個節點
原因:
排除以上原因,開始排查 master 上剩下的幾個服務(etcd、kube-proxy)
開始嘗試調整 etcd
通過使用datadog查看 etcd 吞吐量,發現有異常延遲(latency spiking ~100 ms)
通過Fio工具做性能評估,發現只用到 10%的 IOPS(Input/Output Per Second),由於寫入延遲(write latency 2ms)降低了性能
嘗試把 SSD 從網絡硬盤變為每台機器有個 local temp drive ( SSD )
結果從~100ms —> 200us
2、
問題二:~1000 個節點的時候
問題:發現 kube-apiserver 每秒從 etcd 上讀取 500mb
嘗試解決:
通過Prometheus查看 container 之間的網絡流量
原因:
發現Fluentd和 Datadog 抓取每個節點上資料過於頻繁
調低兩個服務的抓取頻率,網絡性能從 500mb/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
3、
問題三:1000 ~ 2000 個節點
問題:無法再寫入數據,報錯 cascading failure
kubernetes-ec2-autoscaler 在全部的 etcd 都停掉以后才回傳問題,並且關閉所有的 etcd
嘗試解決:
猜測是 etcd 硬盤滿了,但是檢查 SSD 依舊有很多空間
檢查是否有預設的空間限制,發現有 2GB 大小限制
解決方法:
在 etcd 啟動參數中加入--quota-backend-bytes
修改 kubernetes-ec2-autoscaler 邏輯——如果超過 50%出現問題,關閉集群
各種服務的優化
Kube masters 的高可用
一般來說,我們的架構是一個 kube-master (主要的 Kubernetes 服務提供組件,上面有 kube-apiserver、kube-scheduler 和 kube-control-manager )加上多個 slave。但是要達到高可用,要參考一下方式實現:
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)
4、
調整 scheduler policy 造成的影響
OpenAI 使用了KubeDNS ,但不久后發現
問題:
經常出現 DNS 查詢不到的情況(隨機發生)
超過 ~200QPS domain lookup
嘗試解決:
嘗試查看為何有這種狀態,發現有些 node 上跑了超過 10 個 KuberDNS
解決方法:
由於 scheduler policy 造成了許多 POD 的集中
KubeDNS很輕量,容易被分配到同一節點上,造成 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
- kube-dns
- key: k8s-app
5、
新建節點時 Docker image pulls 緩慢的問題
問題:
每次新節點建立起來,docker image pull 都要花 30 分鍾
嘗試解決:
有一個很大的 container image Dota,差不多 17GB,影響了整個節點的 image pulling
開始檢查 kubelet 是否有其他 image pull 選項
解決方法:
在 kubelet 增加選項--serialize-image-pulls=false來啟動 image pulling,讓其他服務可以更早地 pull (參考:kubelet啟動選項)
這個選項需要 docker storgae 切換到 overlay2 (可以參考docker 教學文章)
並且把 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 才能多線程下載
6、
網絡性能提升
Flannel 性能限制
問題:
OpenAI 節點間的網絡流量,可以達到 10-15GBit/s,但是由於 Flannel 所以導致流量會降到 ~ 2GBit/s
解決方式是拿掉 Flannel,使用實際的網絡
hostNetwork: true
dnsPolicy: ClusterFirstWithHostNet