天天看點

基于Kubernetes的DevOps平台實戰

馬松林 分布式實驗室

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叢集:

基于Kubernetes的DevOps平台實戰

擴容Master節點:

基于Kubernetes的DevOps平台實戰

擴容Node節點:

基于Kubernetes的DevOps平台實戰

通過Playbook部署叢集,可以在很短的時間内完成叢集擴容。生産上使用本Playbook最高一次性擴容過50個Node節點。

這裡先簡單介紹下Kubelet TLS Bootstrapping和etcd的自動備份,其他部分就不再進一步講解,具體詳細部署大家可參考《Kubernetes高可用叢集之二進制部署[2]》。

基于Kubernetes的DevOps平台實戰

在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的權限。

基于Kubernetes的DevOps平台實戰

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備份。

基于Kubernetes的DevOps平台實戰

etcd是Kubernetes叢集中的一個十分重要的元件,用于儲存叢集所有的網絡配置和對象的狀态資訊。一旦出現問題或者資料丢失,影響将無法估計。是以,我們一定要做好etcd的資料備份。

這裡利用Kubernetes的cronjob對etcd進行備份,并挂載外部存儲,将資料備份在外部存儲上。

以下是使用cronjob備份的yaml:

基于Kubernetes的DevOps平台實戰
基于Kubernetes的DevOps平台實戰

下面來講一下,我們的CI/CD是如何實作的。

先給大家看下我們大概的架構圖:

基于Kubernetes的DevOps平台實戰

我們業務主要的開發語言包含Java、PHP、Golang、NodeJs以及少部分Python,涉及開發語言較廣,CI、CD需求各種各樣等原因,我們選擇使用Jenkins Pipeline來完成CI、CD的相關工作,全部邏輯通過Groovy語言編寫。并通過Jenkins Agent的方式适配公司所有開發語言代碼的CICD。同時支援虛拟機和Kubernetes部署。

Jenkins Master及所有agent都部署在Kubernetes叢集,并使用PVC挂載一塊極速NAS作為資料同步。下面給大家看下我們部分部署yaml:

基于Kubernetes的DevOps平台實戰
基于Kubernetes的DevOps平台實戰
基于Kubernetes的DevOps平台實戰
基于Kubernetes的DevOps平台實戰

agent-go.yaml

基于Kubernetes的DevOps平台實戰
基于Kubernetes的DevOps平台實戰

下圖是我們目前Jenkins在使用的節點:

基于Kubernetes的DevOps平台實戰

我們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的流程圖:

基于Kubernetes的DevOps平台實戰

Jenkins Pipeline測試環境階段視圖:

基于Kubernetes的DevOps平台實戰

一些亮點功能:

基于Kubernetes的DevOps平台實戰

有很多案例使用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的DevOps平台實戰

目前Kubernetes配置建議使用yaml配置檔案進行配置,參數形式即将删除,後期逐漸一一替換。

apiserver的健康檢查問題,目前使用4層代理,無法對服務狀态進行校驗,後續需要對服務健康狀态進行校驗。

拆分CI/CD,增加制品庫;改造編譯節點動态建立Pod進行編譯,任務完成後删除Pod,提高資源使用率,提高編譯建構的并發量。

使用helm repo,将chart儲存在repo,讓部署更簡潔。