基于 Kubernetes 的 CICD 基础设施即代码
在上一篇基于 Kubernetes 的基礎設施即代碼一文中,我概要地介紹了基于 Kubernetes 的 .NET Core 微服務和 CI/CD 動手實踐工作坊?使用的基礎設施是如何使用代碼描述的,以及它的自動化執行過程。
如果要查看基于 Kubernetes 的基礎設施即代碼架構全圖,以及實現代碼,請回到文章基于 Kubernetes 的基礎設施即代碼。
本文,我們深入探討其中 CI/CD 軟件部分的“基礎設施即代碼”的實現原理。
變量模板引擎
在工作坊中,由于所有與會者使用的都是同一個 Kubernetes 集群,因此我們需要一種方法來標識當前用戶。Kubernetes 的命名空間提供的邏輯隔離功能可以很輕松地實現這個效果。因此,我們要為每個工作坊與會者創建他的一批命名空間:
cicd-<suffix>?用于部署 CI/CD 軟件
dev-<suffix>?作為“開發環境”,部署微服務
stage-<suffix>?作為“預生產環境”,部署微服務
顯然,對于每一個與會者來說,這里的?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?聲明了兩個容器,在這兩個容器上共享多個存儲卷,以實現共享文件的目的:
在 Jenkins 啟動之前運行的初始化容器?installer,它按照?plugins.txt?先將插件安裝到磁盤上,并為工作坊的所有微服務創建內置 Jenkins 任務
在?installer?運行完成之后才啟動的容器?jenkins,它就是 Jenkins Web 服務本身所在的容器
從?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 的配置存儲機制而預先寫入配置來達到內置配置和任務的目的。
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?命令行工具。接著執行以下工作:
等待?gogs-postgresql?和?gogs?部署完成,調用?Gogs 的 RESTful API 接口,完成用戶注冊和代碼庫導入工作
等待?nexus?部署完成,調用 Nexus 的?Scripting API(腳本編程)接口,完成管理員密碼的修改
不難發現,雖然都是自動化配置,卻使用了不同的技術。比起 RESTful API 接口,Nexus 的腳本編程接口由于是直接注入腳本,似乎功能會更靈活和強大。不過,過于強大的功能也通常會帶來額外的安全風險。
總結
簡單總結一下,在上面的講解中,用到過的自動化技術有:
基于 Deployment 實現容器應用自動化部署(自動化部署 Jenkins、Gogs、Nexus 和 Sonarqube 等軟件)
借助 Pod 的初始化容器(initContainer)實現提前運行自動化任務(在 Jenkins 主容器啟動之前,在 initContainer 中安裝插件)
借助 Pod 多容器共享存儲卷來跨容器共享文件(在 initContainer 中安裝插件后,由 Jenkins 主容器直接使用)
借助 Pod 環境變量向應用注入預置的配置(為 Jenkins 指定插件下載源)
借助 ConfigMap 向應用中直接掛載預置的配置文件(為 Jenkins 預設配置)
借助 Pod 就緒探針和存活探針,配合?kubectl rollout status?跟蹤檢測應用部署狀態(等待 Gogs、Nexus 部署完成)
借助 Job 執行一次性任務(cicd-installer)
使用 Dockerfile 構建容器鏡像(Jenkins 上的自定義 Slave 節點)
調用應用準備好的腳本自動完成配置(使用 Jenkins 提供的?install-plubins.sh?安裝插件)
調用應用的 RESTful API 接口導入數據(為 Gogs 注冊用戶并自動導入代碼庫)
調用應用的 Script API 編程接口自動配置(向 Jenkins 和 Nexus 設置登錄憑據)
使用模板引擎替換變量引用
到目前,我們詳細地解讀了如何有機地結合使用各種自動化技術,讓工作坊的各個 CI/CD 軟件在 Kubernetes 上完成啟動之后,自動地完成各項自動化配置。由于 Kubernetes 部署 Yaml 文件以及各類自動化配置腳本都是文本文件,因此我們上一篇文章基于 Kubernetes 的基礎設施即代碼中關于“基礎設施即代碼”的兩個要求仍然成立。
最后,工作坊的自動化腳本還沒有提供存儲支持,在實際的項目中應該會有對應的需求;基本上,只要在你的 Kubernetes 集群中配置好集群的存儲類和自動存儲供給支持,要支持存儲并不困難。
相關文章:
基于 Kubernetes 的基礎設施即代碼
(譯)An introduction to Kubernetes
程序員修神之路--kubernetes是微服務發展的必然產物
深入探究Kubernetes - 初識容器
使用Helm將ASP.NET Core應用程序部署到Kubernetes容器集群
Kubernetes攻略之新手上路
Hello Kubernetes快速交互實驗手冊
十分鐘了解Kubernetes
原文鏈接:https://blog.jijiechen.com/post/cicd-infra-as-code-on-kubernetes/
.NET社區新聞,深度好文,歡迎訪問公眾號文章匯總?http://www.csharpkit.com?
總結
以上是生活随笔為你收集整理的基于 Kubernetes 的 CICD 基础设施即代码的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Blazor 机制初探以及什么是前后端分
- 下一篇: Azure Arc:微软是怎么玩多云游戏