原文鏈接:https://hands-on-tech.github.io/2020/03/15/k8s-jenkins-example.html
讓我們在 Kubernetes 上創(chuàng)建一個(gè)CI/CD(持續(xù)集成和持續(xù)部署)解決方案,使用 Jenkins 作為構(gòu)建工具,并使用 Traefik 作為用于靈活應(yīng)用程序部署和路由的入口。
目標(biāo)
主要目標(biāo)是在 Kubernetes 之上提供一種靈活的 CI/CD解決方案,并在每個(gè)環(huán)境中自動(dòng)部署應(yīng)用程序,定義主機(jī)和路由。為了使此過程易于理解,將詳細(xì)介紹并描述以下步驟:- 設(shè)置 Kubernetes 并了解其基本概念;
- 使用 Helm 安裝 Traefik,Dashboard 和 Jenkins;
- 創(chuàng)建 Kotlin 應(yīng)用程序以展示如何使用 CI/CD;
- 實(shí)施 Jenkins 管道以自動(dòng)構(gòu)建和部署應(yīng)用程序。
為了完成上述步驟并驗(yàn)證提出的 CI/CD解決方案,提出了具有以下組件的體系結(jié)構(gòu):- Traefik:作為訪問服務(wù)的代理和負(fù)載平衡器;
- Kubernetes 儀表板:通過基于Web的界面管理Kubernetes;
- Jenkins:作為自動(dòng)化服務(wù)器來自動(dòng)構(gòu)建和部署應(yīng)用程序;
- DockerHub:作為用于使用示例應(yīng)用程序管理Docker映像的注冊表;
- 應(yīng)用程序說明:出于開發(fā)和測試目的的示例應(yīng)用程序部署;
- 應(yīng)用程序生產(chǎn):將在生產(chǎn)中使用的示例應(yīng)用程序部署。
在幕后并作為支持工具,還使用了以下技術(shù):- Docker:用于服務(wù)和應(yīng)用程序容器化;
- Helm:用于在Kubernetes上簡化服務(wù)的部署和配置;
- Kotlin:開發(fā)示例應(yīng)用程序,它將自動(dòng)構(gòu)建并部署到Kubernetes
關(guān)于CI/CD解決方案,本文將重點(diǎn)介紹兩個(gè)主要的交互工作流程,如下圖所示:- 構(gòu)建和部署應(yīng)用程序:簽出最新的源代碼版本以構(gòu)建應(yīng)用程序并將其部署在Kubernetes集群上;
- 訪問應(yīng)用程序:使用代理對特定主機(jī)名上的已部署應(yīng)用程序進(jìn)行標(biāo)準(zhǔn)化訪問。
Kubernetes
Kubernetes,也稱為K8s,是容器編排的當(dāng)前標(biāo)準(zhǔn)解決方案,可以輕松地在云中以高可伸縮性,可用性和自動(dòng)化級別部署和管理大規(guī)模應(yīng)用程序。Kubernetes最初是由Google開發(fā)的,受到了開源社區(qū)的廣泛關(guān)注。 它是 Cloud Native Computing Foundation 的主要項(xiàng)目,一些最大的支持者也支持它,例如 Google,Amazon,Microsoft 和 IBM。Kubernetes 目前是頂級的開源項(xiàng)目之一,也是 Linux 之前活動(dòng)最多的項(xiàng)目。如今,已有多家公司提供了可用于生產(chǎn)的 Kubernetes 集群,例如亞馬遜的 AWS,微軟的 Azure 和 Google 的 GCE。Kubernetes文檔中提供了現(xiàn)有云提供商的正式列表。術(shù)語
為了理解如何部署應(yīng)用程序,基本介紹一些核心概念,下面將對其進(jìn)行介紹和簡要介紹:- 命名空間:一個(gè)虛擬集群,可以位于同一物理集群硬件之上,從而使各個(gè)開發(fā)團(tuán)隊(duì)之間的關(guān)注點(diǎn)分離;
- Pod:是最小的可部署單元,具有一組共享相同資源(例如內(nèi)存,CPU和IP)的容器;
- 副本集:確保在任何給定時(shí)間正在運(yùn)行指定數(shù)量的Pod副本;
- 部署:一組多個(gè)相同的Pod,定義如何運(yùn)行應(yīng)用程序的多個(gè)副本,如何自動(dòng)替換任何失敗或無響應(yīng)的實(shí)例以及如何執(zhí)行更新;
- 服務(wù):邏輯Pod集的抽象,這是其他應(yīng)用程序用來與之交互的唯一接口;
- 持久卷:用于在Pod生命周期內(nèi)持久保存數(shù)據(jù)的一塊存儲(chǔ)。
架構(gòu)
在開始安裝和配置Kubernetes之前,了解正確設(shè)置集群所需的軟件和硬件組件非常重要。下圖總結(jié)了必需的組件體系結(jié)構(gòu),并簡要描述了每個(gè)組件的角色:- Master:負(fù)責(zé)維護(hù)所需的群集狀態(tài),是管理員管理各個(gè)節(jié)點(diǎn)的入口點(diǎn)。以下軟件組件在主機(jī)中運(yùn)行:
- API服務(wù)器:REST API,它公開了可以在群集上執(zhí)行的所有操作,例如創(chuàng)建,配置和刪除Pod和服務(wù);
- 調(diào)度程序:負(fù)責(zé)將任務(wù)分配給各個(gè)群集節(jié)點(diǎn);
- Controller-Manager:確保集群狀態(tài)按預(yù)期運(yùn)行,對整個(gè)集群中控制器觸發(fā)的事件做出反應(yīng);
- etcd:分布式鍵值存儲(chǔ),用于共享有關(guān)集群狀態(tài)的信息,所有集群節(jié)點(diǎn)均可訪問;
- 節(jié)點(diǎn):執(zhí)行給定任務(wù)并運(yùn)行以下組件的物理或虛擬機(jī):
- Docker:負(fù)責(zé)啟動(dòng)和管理容器的容器運(yùn)行時(shí);
- Kubelet:跟蹤Pod的狀態(tài),以確保所有容器都按預(yù)期運(yùn)行;
- Kube-proxy:路由從服務(wù)進(jìn)入節(jié)點(diǎn)的流量;
- UI:用于管理集群配置和應(yīng)用程序的用戶界面應(yīng)用程序。Kubernetes儀表板將在本文中使用;
- CLI:命令行界面,用于管理集群配置和應(yīng)用程序。Kubectl將在本文中使用;

要了解有關(guān) Kubernetes 體系結(jié)構(gòu)和術(shù)語的更多信息,已經(jīng)有幾頁提供了深入的描述,例如 Kubernetes 官方文檔,Digital Ocean 的介紹和 Daniel Sanche 的術(shù)語介紹。
安裝
由于安裝和配置每個(gè)組件都可能是一項(xiàng)耗時(shí)的任務(wù),因此有多個(gè)選項(xiàng)可以使安裝Kubernetes 的過程更加簡單。Ramit Surana 提供了此類安裝程序的詳盡列表。特別強(qiáng)調(diào) kubeadm,kops,minikube 和 k3,它們一直受到開源社區(qū)的支持和更新。由于我使用 MacOS 并想在單個(gè)節(jié)點(diǎn)上本地運(yùn)行 Kubernetes,因此我決定利用 Docker Desktop,該桌面已經(jīng)在單個(gè)工具中提供了 Docker 和 Kubernetes 的安裝。安裝后,可以檢查系統(tǒng)托盤菜單,以確保 Kubernetes 按預(yù)期運(yùn)行:Kubectl
Kubectl是用于完全管理Kubernetes集群的官方CLI工具,可用于部署應(yīng)用程序,檢查和管理集群資源以及查看日志。由于Docker Desktop已經(jīng)安裝了kubectl,因此我們只需執(zhí)行kubectl版本來檢查其運(yùn)行是否正常,該版本提供的輸出類似于: ~ kubectl versionClient Version: version.Info{Major:"1", Minor:"15", GitVersion:"v1.15.5", GitCommit:"20c265fef0741dd71a66480e35bd69f18351daea", GitTreeState:"clean", BuildDate:"2019-10-15T19:16:51Z", GoVersion:"go1.12.10", Compiler:"gc", Platform:"darwin/amd64"}Server Version: version.Info{Major:"1", Minor:"15", GitVersion:"v1.15.5", GitCommit:"20c265fef0741dd71a66480e35bd69f18351daea", GitTreeState:"clean", BuildDate:"2019-10-15T19:07:57Z", GoVersion:"go1.12.10", Compiler:"gc", Platform:"linux/amd64"}
為了了解可用的命令和內(nèi)在邏輯,我建議對官方的kubectl備忘單進(jìn)行快速概述。例如,可以通過執(zhí)行kubectl get pod來獲取正在運(yùn)行的列表pod。
最后但并非最不重要的一點(diǎn)是,如果您使用ZSH Shell,請記住使用kubectl插件,以便獲得適當(dāng)?shù)耐怀鲲@示和自動(dòng)完成功能。為此,只需添加kubectl插件即可更改ZSH?/ .zshrc初始化腳本:Helm
Helm是Kubernetes的軟件包管理器,它有助于創(chuàng)建模板,以準(zhǔn)確描述如何安裝應(yīng)用程序。此類模板可以與社區(qū)共享,并可以針對特定安裝進(jìn)行自定義。每個(gè)模板稱為舵圖。檢查Helm集線器以了解是否已經(jīng)有想要運(yùn)行的應(yīng)用程序的圖表。如果您好奇并想了解圖表的實(shí)現(xiàn)方式,則還可以檢查帶有正式穩(wěn)定和孵化圖表源代碼的GitHub存儲(chǔ)庫。此外,如果您想擁有一個(gè)掌舵圖表的存儲(chǔ)庫,則可以使用Harbor和JFrog Artifactory之類的解決方案來存儲(chǔ)和提供自己的圖表。最后,要安裝 Helm 并檢查其是否正確安裝,只需運(yùn)行:brew install helmhelm version
Which should give you something like: ~ helm versionversion.BuildInfo{Version:"v3.1.1", GitCommit:"afe70585407b420d0097d07b21c47dc511525ac8", GitTreeState:"clean", GoVersion:"go1.13.8"}
?
Traefik
Traefik是HTTP和TCP應(yīng)用程序的一種廣泛使用的代理和負(fù)載平衡器,本機(jī)兼容并針對基于云的解決方案進(jìn)行了優(yōu)化。總而言之,Traefik分析基礎(chǔ)架構(gòu)和服務(wù)配置,并自動(dòng)發(fā)現(xiàn)每一項(xiàng)的正確配置,從而實(shí)現(xiàn)自動(dòng)應(yīng)用程序部署和路由。最重要的是,Traefik還支持收集詳細(xì)的指標(biāo),日志和可追溯性。Traefik提供了一個(gè)穩(wěn)定且正式的Helm圖表,可用于在Kubernetes上進(jìn)行簡單的安裝和配置。以下配置值提供給圖表,以便進(jìn)行配置:- 使用管理員作為用戶名和密碼,通過域“ traefik.localhost”訪問Traefik儀表板;
- 對所有代理服務(wù)強(qiáng)制實(shí)施SSL,并自動(dòng)為“ * .localhost”域生成通配符SSL證書。

將配置值保存在文件“ traefik-values.yml”中后,可以通過執(zhí)行以下命令來安裝Traefik:helm install stable/traefik
如果要?jiǎng)h除Traefik,以下命令應(yīng)有幫助:通過檢查部署和Pod的狀態(tài)來檢查安裝進(jìn)度:kubectl get deploymentskubectl get pods
當(dāng)部署就緒狀態(tài)為“ 1/1”(必須在1中準(zhǔn)備1)時(shí),訪問http://traefik.localhost/以訪問Traefik儀表板并使用先前定義的用戶名和密碼登錄。在儀表板中,可以檢查可用于訪問已部署服務(wù)(后端)的入口點(diǎn)(前端)。Kubernetes儀表板
Kubernetes Dashboard是一個(gè)開放源代碼的Web界面,用于快速管理Kubernetes集群,并提供用戶友好的功能來管理已部署的應(yīng)用程序并進(jìn)行故障排除。就個(gè)人而言,我更喜歡Portainer的界面和組織,但是它仍然不支持Kubernetes。因此,提供了以下配置以啟用Traefik入口并通過http://dashboard.localhost使儀表板可用。
與Traefik相似,可以使用Kubernetes Dashboard Helm官方圖表通過以下命令安裝Dashboard:helm install stable/kubernetes-dashboard
為了登錄,頭盔圖表已經(jīng)創(chuàng)建了具有適當(dāng)權(quán)限的服務(wù)帳戶。使用這種服務(wù)帳戶登錄的令牌在kubernetes機(jī)密中可用。要獲取可用機(jī)密列表,只需運(yùn)行kubectl get secrets:為了登錄,頭盔圖表已經(jīng)創(chuàng)建了具有適當(dāng)權(quán)限的服務(wù)帳戶。使用這種服務(wù)帳戶登錄的令牌在 kubernetes 機(jī)密中可用。要獲取可用機(jī)密列表,只需運(yùn)行kubectl get secrets:要獲取機(jī)密值,請使用kubectl描述包含儀表板令牌的機(jī)密:kubectl describe secrets dashboard-kubernetes-dashboard-token-sk68z:最后,轉(zhuǎn)到http://dashboard.localhost,并使用先前的令牌值登錄Kubernetes儀表板:Jenkins
Jenkins 是使用最廣泛的開源工具,可自動(dòng)構(gòu)建,測試和部署軟件應(yīng)用程序。因此,使用 Jenkins,我們可以指定一個(gè)處理管道,準(zhǔn)確描述每次提交后如何自動(dòng)構(gòu)建和部署我們的應(yīng)用程序。要安裝 Jenkins,我們將利用官方的 Jenkins Helm 圖表,提供以下配置以指定登錄憑據(jù)并安裝插件以與 GitHub 和 Kubernetes 集成:
要執(zhí)行安裝,請執(zhí)行以下命令并檢查 kubectl get 部署的進(jìn)度:helm install stable/jenkins
當(dāng)所需的 Pod 運(yùn)行時(shí),請?jiān)L問 http://jenkins.localhost 以訪問 Jenkins 并使用先前提供的憑據(jù)登錄:
應(yīng)用
由于所有必需的工具都已成功安裝并運(yùn)行,因此我們現(xiàn)在可以創(chuàng)建要自動(dòng)構(gòu)建和部署的示例應(yīng)用程序。此類應(yīng)用程序?qū)⑹褂?Spring Boot 框架在 Kotlin 中開發(fā)。Spring Initializr 用于通過以下配置創(chuàng)建初始應(yīng)用程序:核心功能將在 GreetingController 中,后者僅提供 GET REST 端點(diǎn)即可根據(jù)輸入?yún)?shù),提供的環(huán)境變量和總體計(jì)數(shù)器提供問候,以區(qū)分不同的調(diào)用。
?
此外,請記住添加執(zhí)行器依賴項(xiàng)以在 /actuator/health 上啟用運(yùn)行狀況端點(diǎn),該端點(diǎn)將用于向 Kubernetes 提供應(yīng)用程序運(yùn)行狀況信息:

Dockerfile
要在 Kubernetes 中運(yùn)行該應(yīng)用程序,需要該應(yīng)用程序的 Docker 映像,該映像可通過以下 Dockerfile 描述:
Helm chart
要為示例應(yīng)用程序創(chuàng)建舵圖,可以利用舵機(jī)CLI工具創(chuàng)建一個(gè)基準(zhǔn),使我們可以適應(yīng)示例應(yīng)用程序。可以通過在終端上運(yùn)行helm create helm來創(chuàng)建這樣的基準(zhǔn),helm create helm將創(chuàng)建必需的Kubernetes組件的模板以運(yùn)行并正確配置應(yīng)用程序??紤]到我們的目標(biāo),以下文件是最需要注意的文件:- Chart.yaml:圖表屬性,例如名稱,描述和版本;
- values.yaml:提供給圖表的默認(rèn)配置值;
- template / deplyment.yaml:Kubernetes部署規(guī)范的模板,用于配置應(yīng)用程序pod和復(fù)制特性;
- template / service.yaml:Kubernetes服務(wù)規(guī)范的模板,用于配置其他應(yīng)用程序的應(yīng)用程序接口;
- templates / ingress.yaml:Kubernetes入口規(guī)范的模板,以公開服務(wù)以供外部訪問。
舵圖使用{{}}
用于模板,這意味著將解釋內(nèi)部的內(nèi)容以提供輸出值。官方指南中有關(guān)多個(gè)模板選項(xiàng)的更多詳細(xì)信息。對于我們正在創(chuàng)建的模板,以下是最重要的示例:{{.Values.replicaCount}}從提供的值文件中獲取配置副本計(jì)數(shù);{{-toYaml. | nindent 8}}:將引用的Yaml樹(點(diǎn)指向當(dāng)前結(jié)構(gòu)引用)復(fù)制到帶有8個(gè)空格的縮進(jìn)的結(jié)果中。
定義了以下值來配置應(yīng)用程序,這些值將在圖表模板中使用。重要的是要參考提供的docker映像參考,服務(wù)端口和入口配置以使用Traefik:
?
為了檢查 Helm 圖表是否正常工作,我們可以安裝它并檢查幾個(gè)組件是否正確部署:helm install example ./helmkubectl get deploymentkubectl get podkubectl get servicekubectl get ingress
?
Pipeline
目標(biāo)是建立充分利用Kubernetes的管道,在按需執(zhí)行的專用代理上構(gòu)建所需的工件。這種方法為開發(fā)人員提供了高度的靈活性和獨(dú)立性,他們可以完全控制他們的構(gòu)建管道,并且不依賴于Jenkins主機(jī)上安裝的任何軟件。結(jié)果,Jenkins機(jī)器不會(huì)被許多不同的工具和版本污染。例如,如果一個(gè)團(tuán)隊(duì)需要Java 8,而另一個(gè)團(tuán)隊(duì)則需要Java 13,則Jenkins主機(jī)不需要同時(shí)安裝兩者,因?yàn)槊總€(gè)團(tuán)隊(duì)管道都將在自己的Jenkins代理上運(yùn)行,并且每次運(yùn)行都按需部署。為此,我們使用了Kubernetes Jenkins插件,該插件允許使用所需工具定義帶有容器的容器。然后,我們僅需提及,我們想通過引用其名稱在特定容器內(nèi)運(yùn)行特定步驟。請記住,工作空間卷是自動(dòng)創(chuàng)建的,并且在容器中的容器之間共享,這意味著工作空間上的任何更改將可用于其他容器。例如,如果我們使用maven容器創(chuàng)建打包的jar文件,則docker容器將可以使用它來創(chuàng)建docker映像。此外,為了加快構(gòu)建過程,不要忘記為maven?/ .m2文件夾創(chuàng)建一個(gè)卷,以便在作業(yè)運(yùn)行之間共享下載的依賴項(xiàng)。由于需要maven,docker和helm工具才能正確構(gòu)建和部署示例應(yīng)用程序,因此build.yaml文件中提供了以下pod規(guī)范:
對于管道,我決定使用聲明性語法而不是腳本,這更適合簡單的管道,并且更易于閱讀和理解。但是,如果我們要執(zhí)行更高級的任務(wù),那么限制性更強(qiáng)的語法可能會(huì)成為限制。對于此類情況,可以在聲明性管道中定義腳本塊??偠灾?,示例應(yīng)用程序的CI / CD聲明性管道將分為以下階段:- 構(gòu)建:使用maven構(gòu)建應(yīng)用程序包;
- Docker Build:使用先前創(chuàng)建的Dockerfile構(gòu)建docker鏡像;
- Docker Publish:將構(gòu)建的Docker映像發(fā)布到Docker Hub;
- Kubernetes部署:通過安裝或升級相應(yīng)的Kubernetes組件,使用先前創(chuàng)建的頭盔圖來部署應(yīng)用程序。
在這些階段的頂部,將創(chuàng)建兩個(gè)不同的部署環(huán)境:生產(chǎn)(https://example.localhost)和登臺(tái)(https://example-staging.localhost),它們分別與master和develop分支相關(guān)。因此,如果分支不是master或developer,則不會(huì)構(gòu)建docker映像,并且不會(huì)將應(yīng)用程序部署到Kubernetes。此外,所有應(yīng)用程序工件都具有相同的版本,可以使用Pipeline Utility步驟Jenkins庫從POM文件加載該版本。在示例應(yīng)用程序的Jenkins聲明性管道下面找到該管道,該管道還使用build.yaml文件中所述的pod設(shè)置代理,并在每次運(yùn)行作業(yè)時(shí)自動(dòng)從GitHub簽出源代碼:
Job
最后,讓我們創(chuàng)建 Jenkins 作業(yè)以使用示例應(yīng)用程序源代碼運(yùn)行管道。為此,請轉(zhuǎn)到Jenkins并使用以下配置創(chuàng)建一個(gè)新的 Multibranch Pipeline 作業(yè):保存 Jenkins 作業(yè)后,您應(yīng)該能夠在列表中看到它,瀏覽它的幾個(gè)分支,并檢查為每個(gè)分支執(zhí)行的管道:驗(yàn)證
現(xiàn)在所有部分都運(yùn)行在一起,并且我們檢查了核心功能,讓我們驗(yàn)證該解決方案是否適合典型的GitFlow開發(fā)流程:檢查生產(chǎn)部署是否正在運(yùn)行并提供期望的值:~ curl -k -w '\n' --request GET 'https://example.localhost/greeting'{"id":1,"content":"Hello, World","env":"default_value"}
創(chuàng)建開發(fā)部門并建立各自的 Jenkins 工作; ~ curl -k -w '\n' --request GET 'https://example-staging.localhost/greeting'{"id":1,"content":"Hello, World","env":"default_value"}
Checkout開發(fā)分支,并將問候語方法的默認(rèn)名稱參數(shù)值從“ World”更改為“ World!”;
提交并等待Jenkins作業(yè)完成,以更新登臺(tái)部署;
檢查分段部署上的默認(rèn)值是否已更改: ~ curl -k -w '\n' --request GET 'https://example-staging.localhost/greeting'{"id":1,"content":"Hello, World!","env":"default_value"}
- 等待Jenkins主工作完成并更新生產(chǎn)部署;
~ curl -k -w '\n' --request GET 'https://example.localhost/greeting'{"id":1,"content":"Hello, World!","env":"default_value"}
- END -
公眾號(hào)后臺(tái)回復(fù)「加群」加入一線高級工程師技術(shù)交流群,一起交流進(jìn)步。
點(diǎn)亮,服務(wù)器三年不宕機(jī)