馬松林 分布式實驗室
Kubernetes的出現讓容器的排程管理變的簡單,但是Kubernetes本身的“部署難”又讓很多人止步,對該技術的普及也有一定的影響。文章首先,從Kubernetes的架構角度,為大家講解一下從零部署一個生産可用的Kubernetes叢集,并對Kubelet TLS Bootstrapping的原理進行講解。
先說一下我們生産環境Kubernets叢集部署,為友善後期維護及減少一層Docker封裝,我們選擇采用二進制方式部署Kubernetes叢集。(kubeadm方式部署全部運作在Docker容器中、證書時長限制等;雖然降低部署門檻,但屏蔽了很多細節,遇到問題很難排查等。)
Kubernets叢集部署流程:
網絡、主機等規劃
規劃叢集網絡
規劃主機叢集架構(如節點多機房災備等)
主機系統初始化
主機名
軟體源
關閉swap
關閉防火牆
關閉SELinux
配置Chrony
安裝依賴軟體包
加載相關核心子產品
核心優化
配置資料盤
簽發叢集證書
簽發ca證書
簽發etcd證書
簽發admin證書
簽發apiserver證書
簽發metrics-server證書
簽發controller-manager證書
簽發scheduler證書
簽發kube-proxy證書
部署etcd高可用叢集
etcd叢集部署
etcd資料備份
apiserver的高可用配置
HAProxy+Keepalived
部署Master節點
生成kuberctl kubeconfig,配置kubectl
安裝配置kube-apiserver
安裝配置kube-controller-mannager
安裝配置kube-scheduler
部署Node節點
安裝配置Docker
安裝配置kubelet
安裝配置kube-proxy
部署Calico
Kubernetes叢集部署要點:
關閉非安全端口,通過--anonymous-auth=false關閉匿名請求,所有通信使用證書認證,防止請求被篡改;通過證書認證和授權政策(x509、token、RBAC)。
開啟bootstrap token認證,動态建立token,而不是在apiserver中靜态配置。
使用TLS bootstrap機制自動生成kubelet client和server證書,過期自動輪轉(部分叢集部署使用admin證書簽發kubelet.kubeconfig,這樣叢集非常不安全)。
etcd、master證書指定節點IP,限制通路,即便某個節點證書洩漏,在其他機器上也無法使用。
網絡使用calico ipip
我已經将Kubernetes叢集安裝過程寫成ansible-playbook,實作一鍵部署、擴容Kubernets高可用叢集[1]。Playbook包含了系統初始化、簽發證書、部署etcd、部署Kubernetes、替換叢集證書等。
我們DevOps平台對接了Ansible Playbook,可在DevOps平台上操作部署、擴容,配合工單系統,完成全自動化流程。
DevOps平台操作部署、擴容Kubernetes叢集流程:
填寫申請機器工單
選擇用途為Kubernetes建立或者擴容
選擇對應角色
工單審批通過後,自動申請機器
調用Ansible Playbook開始進行系統初始化
調用Ansible Playbook開始進行證書簽發
調用Ansible Playbook開始進行etcd叢集部署
調用Ansible Playbook開始進行節點擴容
同時也可以使用以下指令進行操作:
通過以下指令即可将一批剛剛安裝好系統、配置好網絡的機器部署為一套生産可用的Kubernetes叢集:

擴容Master節點:
擴容Node節點:
通過Playbook部署叢集,可以在很短的時間内完成叢集擴容。生産上使用本Playbook最高一次性擴容過50個Node節點。
這裡先簡單介紹下Kubelet TLS Bootstrapping和etcd的自動備份,其他部分就不再進一步講解,具體詳細部署大家可參考《Kubernetes高可用叢集之二進制部署[2]》。
在Kubernetes叢集中,工作節點上的元件(kubelet和kube-proxy)需要與Kubernetes主元件通信,特别是kube-apiserver。為了確定通信保持私密,不受幹擾,并確定群集的每個元件與另一個受信任元件通信,我們強烈建議在節點上使用用戶端TLS證書。
引導這些元件的正常過程,特别是需要證書的工作節點,是以它們可以與kube-apiserver安全地通信,這可能是一個具有挑戰性的過程,因為它通常超出了Kubernetes的範圍,需要大量的額外工作。反過來,這可能會使初始化或擴充叢集變得具有挑戰性。
為了簡化流程,從版本1.4開始,Kubernetes引入了證書請求和簽名API以簡化流程。
Kubernetes開啟TLS認證後,每個N ode節點的kubelet都要使用由kube-apiserver的CA簽發證書,才能與kube-apiserver進行通信,如果接入比較多的節點,為每個節點生成證書不太現實,Bootstrapping就是讓kubelet先使用一個低權限使用者連接配接到kube-apiserver,然後由kube-controller-manager為kubelet動态簽發證書。再配合RBAC指定使用者擁有通路哪些API的權限。
kubelet啟動後會發起CSR請求,kube-apiserver收到CSR請求後,對其中的Token進行認證,認證通過後将請求的user設定為 system:bootstrap:<TokenID>,group設定為 system:bootstrappers,這一過程稱為Bootstrap Token Auth。
kubelet發起的CSR請求都是由kube-controller-manager來做實際簽發的,對于kube-controller-manager來說,TLS bootstrapping下kubelet發起的CSR請求大緻分為以下三種:
nodeclient:kubelet以 O=system:nodes和 CN=system:node:(node name)形式發起的CSR請求
selfnodeclient:kubelet client renew自己的證書發起的CSR請求(與上一個證書就有相同的O和CN)
selfnodeserver:kubelet server renew自己的證書發起的CSR請求
使用Bootstrap Token時整個啟動引導過程:
配置apiserver使用 BootstrapTokenSecret,替換以前使用 token.csv檔案
在叢集内建立首次TLS Bootstrap申請證書的ClusterRole、後續renew Kubelet client/server的ClusterRole,以及其相關對應的ClusterRoleBinding;并綁定到對應的組或使用者
配置controller-manager,使其可以自動簽發相關證書和自動清理過期的TLS Bootstrapping Token
生成特定的包含TLS Bootstrapping Token的 bootstrap.kubeconfig以供kubelet啟動時使用
配置kubelet,使其首次啟動加載 bootstrap.kubeconfig 并使用其中的 TLS Bootstrapping Token 完成首次證書申請
controller-manager簽發證書,并生成kubelet.kubeconfig,kubelet自動重載完成引導流程
後續kubelet自動renew相關證書
叢集搭建成功後立即清除 BootstrapTokenSecret,或等待Controller Manager待其過期後删除,以防止被惡意利用
下面講一下etcd備份。
etcd是Kubernetes叢集中的一個十分重要的元件,用于儲存叢集所有的網絡配置和對象的狀态資訊。一旦出現問題或者資料丢失,影響将無法估計。是以,我們一定要做好etcd的資料備份。
這裡利用Kubernetes的cronjob對etcd進行備份,并挂載外部存儲,将資料備份在外部存儲上。
以下是使用cronjob備份的yaml:
下面來講一下,我們的CI/CD是如何實作的。
先給大家看下我們大概的架構圖:
我們業務主要的開發語言包含Java、PHP、Golang、NodeJs以及少部分Python,涉及開發語言較廣,CI、CD需求各種各樣等原因,我們選擇使用Jenkins Pipeline來完成CI、CD的相關工作,全部邏輯通過Groovy語言編寫。并通過Jenkins Agent的方式适配公司所有開發語言代碼的CICD。同時支援虛拟機和Kubernetes部署。
Jenkins Master及所有agent都部署在Kubernetes叢集,并使用PVC挂載一塊極速NAS作為資料同步。下面給大家看下我們部分部署yaml:
agent-go.yaml
下圖是我們目前Jenkins在使用的節點:
我們CI/CD的流程:
---> 在DevOps平台建立項目(DevOps平台提供項目管理、配置管理、JOB處理、日志檢視、監控資訊、Kubernetes容器Web Terminal等管理功能,CICD後續流程全部為Jenkins處理)
--->選擇是容器部署or虛機部署
--->按照提示填寫相關配置(包含開發語言、GIT倉庫、編譯指令、域名、容器内可寫目錄、運作指令、運作端口、資源限制、健康檢查等)
--->儲存配置
--->觸發JOB
--->釋出前檢查/拉取項目配置(同時對項目配置進行校驗是否符合規範)
--->拉取業務代碼
--->漏洞掃描
--->編譯建構
--->根據配置選擇對應語言的編譯節點
--->判斷虛機還是容器部署,選擇不同的部署流程
---> 容器部署會根據項目配置生成Dockerfile并建構上傳鏡像(适配所有業務Dockerfile自動生成,并支援自定義)
--->選擇環境(prd or pre or qa or dev )
--->helm使用模版替換項目配置進行部署(Helm Chart模版适配了所有業務需求,并支援自定義。預設部署Deployment、Service、Ingress、HPA)
--->部署結束後發送部署詳情通知
以下是CI/CD的流程圖:
Jenkins Pipeline測試環境階段視圖:
一些亮點功能:
有很多案例使用gitlab-ci實作的CI/CD,我們通過調研發現gitlab-ci有一定的侵入性,而且Pipeline支援比較弱。我們使用Jenkins Pipeline完成了公司全部的CI/CD需求,其中還包含了運維相關系統的部署、安卓打包及管道包打包、IOS打包,并提供了二維碼展示,友善測試或營運人員快速下載下傳安裝。
使用Groovy完成整套流程,友善、易用便于維護,但是其中處理邏輯相對複雜,需要對業務非常了解,并且掌握Groovy語言。同時選擇使用Helm部署也遇到不少問題,Release名稱在不同namespace不能重用(helm3已經支援),模版使用APIVersion與實際部署資源對象APIVersion不一緻(影響不大),同版本代碼部署不更新(通過添加自定義annotation實作支援)等等。另外,我也測試了Helm 3,前期bug太多,屬于完全不可用狀态,最近新出了alpha2版本,修複了很多bug,可以考慮測試使用了。
目前Kubernetes配置建議使用yaml配置檔案進行配置,參數形式即将删除,後期逐漸一一替換。
apiserver的健康檢查問題,目前使用4層代理,無法對服務狀态進行校驗,後續需要對服務健康狀态進行校驗。
拆分CI/CD,增加制品庫;改造編譯節點動态建立Pod進行編譯,任務完成後删除Pod,提高資源使用率,提高編譯建構的并發量。
使用helm repo,将chart儲存在repo,讓部署更簡潔。