解讀與部署(二):基於 Kubernetes 的 CICD 基礎設施即代碼

在上一篇基於Kubernetes的基礎設施即代碼一文中,我概要地介紹了基於 Kubernetes 的 .NET Core 微服務和 CI/CD 動手實踐工做坊使用的基礎設施是如何使用代碼描述的,以及它的自動化執行過程。 git

若是要查看基於Kubernetes的基礎設施即代碼架構全圖,以及實現代碼,請回到文章基於 Kubernetes 的基礎設施即代碼。 sql

本文,咱們深刻探討其中 CI/CD 軟件部分的「基礎設施即代碼」的實現原理。 數據庫

PIC1.png

變量模板引擎 編程

在工做坊中,因爲全部與會者使用的都是同一個 Kubernetes 集羣,所以咱們須要一種方法來標識當前用戶。Kubernetes的命名空間提供的邏輯隔離功能能夠很輕鬆地實現這個效果。所以,咱們要爲每一個工做坊與會者建立他的一批命名空間: 安全

•cicd-<suffix> 用於部署 CI/CD 軟件 服務器

•dev-<suffix> 做爲「開發環境」,部署微服務 架構

•stage-<suffix> 做爲「預生產環境」,部署微服務 app

顯然,對於每個與會者來講,這裏的 suffix 會有所不一樣,所以它是一個變量。除了在啓動安裝 CI/CD 軟件時須要使用,這個變量還須要以某種形式保存到 Jenkins 上,由於當 Jenkins 運行部署任務時,它也須要知道目標命名空間的名字。 微服務

爲了處理變量,咱們本身發明了一個小型的「模板引擎」。其做用是,使用變量文件中指定的值,替換各個文件中的變量,輸出最終的內容。這個模板引擎以雙美圓符號 $$ 做爲變量起始字符。打開 cicd-infra/jenkins.yaml 並搜索 $$ 就能夠發現其中大量地引用了各個變量。 工具

模板引擎的實現位於 ./tmpl.sh 腳本文件,它能從指定的變量文件和環境變量讀入各個變量的值,並將待處理文件中的變量佔位符替換爲對應的值,最後向標準輸出(stdout)打印最終的文件內容。藉助流水線指令 |,這些內容隨後被 kubectl apply -f - 命令讀取,用於安裝配置對應的 Kubernetes資源。

在 kubelet 1.14 及以上的版本中,新增長了 kustomize 子命令。它提供更多編寫模板化、嵌套式 Yaml 文件的方法。在工做坊中,咱們須要兼容支持低一些版本的 kubelet,就不得不借助這樣的模板引擎。

自動化安裝Jenkins

打開 cicd-infra/jenkins.yaml 會發現接近 600 行,能夠說不短了。其中包含以下幾個關鍵的Kubernetes資源:
•ServiceAccount jenkins 是 Jenkins 自己,以及 Jenkins 用於生成容器鏡像並部署微服務時所用的 Pod 要使用的集羣帳號;

•RoleBinding jenkins_edit 爲上述集羣帳號賦予相應權限;

•Service jenkins-jnlp 供 Jenkins 構建運行器(Slave)啓動期間鏈接 Jenkins 主機(Master)時用的集羣 Service;

•Service jenkins 是供 Ingress 用於把 Jenkins Web 界面暴露給用戶用的集羣 Service;

•Ingress jenkins-ingress 是負責把用戶請求轉發到集羣 Service 的流量入口處理規則;

•ConfigMap jenkins-jobs 可掛載爲 Jenkins 內置任務的配置;

•ConfigMap jenkins 一系列用於初始化 Jenkins 的配置;

•Deployment jenkins 用於部署 Jenkins Web 服務。

這裏須要重點介紹的是 configmap/jenkins,以及 deployment/jenkins。後者掛載前者,以文件的方式讀入內容並完成 Jenkins 的初始化配置工做。具體來講,deployment/jenkins 聲明瞭兩個容器,在這兩個容器上共享多個存儲卷,以實現共享文件的目的:

1.在 Jenkins 啓動以前運行的初始化容器 installer,它按照 plugins.txt 先將插件安裝到磁盤上,併爲工做坊的全部微服務建立內置 Jenkins 任務

2.在 installer 運行完成以後才啓動的容器 jenkins,它就是 Jenkins Web 服務自己所在的容器

PIC2.png

從 deployment/jenkins 的 yaml 配置中,咱們不難發現,installer 運行的具體過程位於腳本文件 /var/jenkins_config/apply_config.sh 中,它的內容是從 configmap/jenkins 掛載而來的。這個腳本中還將用到不少其餘文件,好比安裝插件用的 plugins.txt,它們都是從這個 configmap/jenkins 掛載而來。爲了加速 Jenkins 插件的安裝過程,咱們在 installer 容器裏使用 JENKINS_UC、JENKINS_UC_DOWNLOAD 這兩個環境變量來讓它從國內的服務器源下載插件。

configmap/jenkins/plugins.txt 定義了工做坊中咱們須要用到的插件列表:

•git

•dashboard-view

•pipeline-stage-view

•workflow-aggregator

•kubernetes:1.20.0

其中的kubernetes插件讓咱們的 Jenkins 能夠與它所在的 Kubernetes 集羣集成,從而實現幾乎能把任何容器鏡像做爲構建運行器(Slave)節點來使用,而且這些節點將以獨立的 Pod 的方式「按需」在 Kubernetes 集羣中運行,並自動鏈接到 Jenkins。這大大簡化了 Jenkins 的運行器節點的維護工做。若是進一步研讀 configmap/jenkins/config.xml 配置內容能夠發現,咱們的 Jenkins 將內置支持 dotnet 和 image-builder 兩種 Slave 節點。
閱讀 configmap/jenkins/apply_config.sh 能夠看到,它使用了 Jenkins 支持的多種自動化配置功能:

•運行 /usr/local/bin/install-plugins.sh 腳本文件能夠預先安裝指定的插件

•在 /var/jenkins_home/init.groovy.d 目錄中建立的 groovy 腳本將在 Jenkins 啓動後自動運行,咱們這裏用來向 Jenkins 中植入容器鏡像註冊表的登陸信息

•經過預先定義 /var/jenkins_home/config.xml 及其餘 xml 文件能夠定製 Jenkins 的各種全局系統設置

•/var/jenkins_jobs 目錄下的子目錄將自動被視爲內置任務自動被 Jenkins 加載

上面第一種自動化功能,是內置在 Jenkins 安裝包中的一個實用工具,它的源代碼位於 GitHub 上。第二種自動化功能是 Jenkins 的初始化腳本,它支持以 Groovy 語言爲 Jenkins 開發自動運行的腳本鉤子。後面兩種自動化功能則是根據 Jenkins 的配置存儲機制而預先寫入配置來達到內置配置和任務的目的。

PIC3.png

deployment/jenkins 還讓這兩個容器共享 jenkins-home 和 plugin-dir 這兩個存儲卷,這樣就可讓 jenkins 容器從 installer 容器繼承已經初始化完成的 Jenkins 配置和插件。這樣就確保 Jenkins 主容器運行起來時,就已經具有了已經下載好的插件,以及正確的全局配置。

自動化安裝 Gogs 和 Nexus

比起 Jenkins 自動化的過程,Gogs 和 Nexus 的自動化安裝就簡單得多了。雖然 Gogs 須要 Postgre 數據庫的支持,咱們在工做坊環境中,仍是爲數據庫配置了 emptyDir 類型的臨時存儲。所以並不提供持久化存儲的支持。給 Nexus 提供的存儲也同樣用的是 emptyDir 臨時存儲

值得一提的是這兩個軟件啓動後的初始化操做。在工做坊的自動化腳本中,分別對這兩個軟件執行了以下自動化初始化:

•在 Gogs 中自動建立帳號,從 GitHub 導入各個微服務的源代碼庫,並配置 WebHook

•修改 Nexus 的默認登陸信息爲 admin/admin

這些過程,都是藉助獨立的集羣任務 cicd-installer 完成的。在該任務中,它首先讀入當前 Kubernetes 環境給定的 Service Account 憑據,配置好 kubectl 命令行工具。接着執行如下工做:

1.等待 gogs-postgresql 和 gogs 部署完成,調用 Gogs 的 RESTful API 接口,完成用戶註冊和代碼庫導入工做

2.等待 nexus 部署完成,調用 Nexus 的 Scripting API(腳本編程)接口,完成管理員密碼的修改

不難發現,雖然都是自動化配置,卻使用了不一樣的技術。比起 RESTful API 接口,Nexus 的腳本編程接口因爲是直接注入腳本,彷佛功能會更靈活和強大。不過,過於強大的功能也一般會帶來額外的安全風險。

總結

簡單總結一下,在上面的講解中,用到過的自動化技術有:

1.基於 Deployment 實現容器應用自動化部署(自動化部署 Jenkins、Gogs、Nexus 和 Sonarqube 等軟件);

2.藉助 Pod 的初始化容器(initContainer)實現提早運行自動化任務(在 Jenkins 主容器啓動以前,在 initContainer 中安裝插件);

3.藉助 Pod 多容器共享存儲捲來跨容器共享文件(在 initContainer 中安裝插件後,由 Jenkins 主容器直接使用);

4.藉助 Pod 環境變量嚮應用注入預置的配置(爲 Jenkins 指定插件下載源);

5.藉助 ConfigMap 嚮應用中直接掛載預置的配置文件(爲 Jenkins 預設配置);

6.藉助 Pod 就緒探針和存活探針,配合 kubectl rollout status 跟蹤檢測應用部署狀態(等待 Gogs、Nexus 部署完成);

7.藉助 Job 執行一次性任務(cicd-installer);

8.使用 Dockerfile 構建容器鏡像(Jenkins 上的自定義 Slave 節點);

9.調用應用準備好的腳本自動完成配置(使用 Jenkins 提供的 install-plubins.sh 安裝插件);

10.調用應用的 RESTful API 接口導入數據(爲 Gogs 註冊用戶並自動導入代碼庫);

11.調用應用的 Script API 編程接口自動配置(向 Jenkins 和 Nexus 設置登陸憑據);

12.使用模板引擎替換變量引用。

到目前,咱們詳細地解讀了如何有機地結合使用各類自動化技術,讓工做坊的各個 CI/CD 軟件在 Kubernetes 上完成啓動以後,自動地完成各項自動化配置。因爲 Kubernetes 部署 Yaml 文件以及各種自動化配置腳本都是文本文件,所以咱們上一篇文章基於 Kubernetes 的基礎設施即代碼中關於「基礎設施即代碼」的兩個要求仍然成立。

最後,工做坊的自動化腳本尚未提供存儲支持,在實際的項目中應該會有對應的需求;基本上,只要在你的Kubernetes集羣中配置好集羣的存儲類和自動存儲供給支持,要支持存儲並不困難。

相關文章
相關標籤/搜索