Choerodon豬齒魚平臺使用微服務架構進行開發,部署在Kubernetes 擴展中,並且服務新功能開發完成後會被依次部署到暫存環境測試,UAT 環境驗收和生產環境使用。在這多個多個環境的部署過程中,豬齒魚平臺只需要一次CI生成的包,便能實現服務部署的“因地制宜”。
需求
豬齒魚平臺集成的GitLab用於進行CI的過程,在微服務程序中經過Gitlab CI的docker_build和chart_build步驟之後,對應一次成功的CI過程,會有一個可以進行部署的Helm的發行包。
一般情況下,不同環境下基礎設施如數據庫的地址是不同。而部署服務的需求是一次打包生成的安裝包可以在不同的環境進行部署而不需要對源代碼重新打包。
spring:
datasource:
url: "jdbc:mysql://localhost/demo_service?useUnicode=true&characterEncoding=utf-8&useSSL=false" # 本地數據庫
username: demo
password: demo
方案基礎
豬齒魚微服務後端環境變量方案的本質上是Springboot的環境變量機制和頭盔環境變量機制的結合。
所以在此之前,先聊一聊SpringBoot 和頭盔所提供的支持。
SpringBoot環境變量支持
SpringBoot支持外部化配置,允許使用者通過屬性文件,YAML文件,環境變量及命令行參數對服務進行外部化配置。同時允許 @Value和@ConfigurationProperties註解的方式對上述變量進行訪問。
@Value方式:
@Value("${JAVA_HOME}")
private String javaHome;
@Value("${spring.application.name}")
private String appName;
@ConfigurationProperties 方式:
@Component
@ConfigurationProperties(prefix = "services.gitlab")
public class GitlabConfigurationProperties {
private String password;
private Integer projectLimit;
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public Integer getProjectLimit() {
return projectLimit;
}
public void setProjectLimit(Integer projectLimit) {
this.projectLimit = projectLimit;
}
}
在SpringBoot官方文檔中,SpringBoot提供了多於十種配置環境變量的方式,並列出他們所配置的環境變量的優先級。從文檔中可以看到,對於應用程序而言,系統環境變量的優先級高於應用內的配置文件所配置的值。
Helm環境變量支持
在豬齒魚微服務中,項目根目錄下會有一個 chart 目錄用於定義此服務如何打包成 Helm Chart 包,這個目錄下就是 helm 的 chart 文件結構:
devops-service/
Chart.yaml # 包含關於chart的的信息的YAML文件
LICENSE # 可選:包含chart的許可證信息的純文本文件
README.md # 可選:chart的README文件
requirements.yaml # 可選:列出依賴信息的YAML文件
values.yaml # 這個chart的默認配置值
charts/ # 包含這個chart所依賴的多個chart
templates/ # 這個目錄下包含了多個模板文件以結合配置值生成有效的Kubernetes manifest文件
templates/NOTES.txt # 可選:包含簡短使用提示的純文本文件
更多關於chart下文件的信息,可點擊這裏
Helm的模板文件主要是使用 Go Template Language 以及一些其他補充函數。所有的模板文件存在於 templates 目錄下,在helm對chart包進行渲染的時候,模板所用到的配置值會有兩個來源:chart包內的values.yaml和Chart.yaml文件及命令行提供的配置值。
chart包內提供的配置值:
.Release # 和release相關的一些屬性值,如當前部署的release的名稱,命名空間
.Files # 一個包含其它沒有被指定(未被上文提到的)的文件的map結構,可以用於訪問其它文件內的內容
.Chart # 訪問 Chart.yaml 文件中的一些值,只能訪問這個文件預定義的值,其它值會被忽視
.Values # 訪問 Values.yaml 文件中定義的配置值
更過關於預定義變量的文檔,可點擊這裏
命令行提供的配置值:
# 命令行直接指定配置值的方式,--set:
$ helm install nginx --repo localhost --name nginx-release-zmf --set deployment.name=zmf-naginx-dep
# 命令行使用--values指定values.yaml文件的方式
# 在命令行的配置文件名稱可以不爲values.yaml
# 命令行指定的文件會和chart包內的values.yaml文件合併
# 且會覆蓋values.yaml內同名配置項的值
# 如下:
$ helm install nginx --repo localhost --values=myvals.yaml
在模板文件中使用模板文件定義的語法和內置函數可以訪問到以上所提供的配置值,下列是一個Kubernetes Deployment文件的模板示例:
apiVersion: apps/v1beta2
kind: Deployment
metadata:
name: {{ .Values.deployment.name }}
labels:
app.kubernetes.io/name: {{ .Values.deployment.name }}
helm.sh/chart: {{ include "nginx.chart" . }}
app.kubernetes.io/instance: {{ .Release.Name }}
app.kubernetes.io/managed-by: {{ .Release.Service }}
spec:
replicas: {{ .Values.replicaCount }}
selector:
matchLabels:
app.kubernetes.io/name: {{ .Values.deployment.name }}
app.kubernetes.io/instance: {{ .Release.Name }}
template:
metadata:
labels:
app.kubernetes.io/name: {{ .Values.deployment.name }}
app.kubernetes.io/instance: {{ .Release.Name }}
spec:
containers:
- name: {{ .Chart.Name }}
image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}"
imagePullPolicy: {{ .Values.image.pullPolicy }}
env:
{{- range $name, $value := .Values.env.open }}
{{- if not (empty $value) }}
- name: {{ $name | quote }}
value: {{ $value | quote }}
{{- end }}
{{- end }}
ports:
- name: http
containerPort: 80
protocol: TCP
livenessProbe:
httpGet:
path: /
port: http
readinessProbe:
httpGet:
path: /
port: http
resources:
{{ toYaml .Values.resources | indent 12 }}
{{- with .Values.nodeSelector }}
nodeSelector:
{{ toYaml . | indent 8 }}
{{- end }}
{{- with .Values.affinity }}
affinity:
{{ toYaml . | indent 8 }}
{{- end }}
{{- with .Values.tolerations }}
tolerations:
{{ toYaml . | indent 8 }}
{{- end }}
在模板文件中可以使用 {{ .Value.property.name }} 的方式直接訪問配置值。
使用模板文件的方式可以使得 Helm 根據命令傳入的參數渲染chart包以部署在不同的環境中。
更多的的模板語法,可點擊這裏
方案實現
在重溫SpringBoot和Helm提供的環境變量方案之後,再來詳細看看豬齒魚微服務是怎麼將它們結合的。
此處以devops-service的0.18.0版本爲例, 說明這個過程。
豬齒魚微服務的打包
打包過程分爲三步:
- maven 打包 SpringBoot 項目爲 JAR 包。在項目被打包生成JAR包後,JAR包中實際上只有 bootstrap.yml 和 application.yml 兩個配置文件,也可以說只有一份配置文件,豬齒魚微服務後端並沒有採用多種配置文件進行切換的方式。resources文件夾下內容如下:
- docker 根據項目根目錄下docker目錄下的配置生成包含 JAR 包的鏡像文件。
- helm 從源代碼中的chart目錄下的文件夾(在下圖中是devops-service目錄)生成 chart 包。
在打包的步驟結束後,一個可以在Kubernetes集羣中進行部署Helm Release就出爐了。
注:以上目錄結構由根目錄下的 .gitlab-ci.yml所定義。
豬齒魚微服務環境變量的設置過程
在/chart/devops-service/values.yaml文件中,有一部分如下圖所示:
這裏定義了一部分由 env.open開頭的配置項。
在/chart/devops-service/templates/deployment.yaml文件中,有一部分如下圖所示:
在圖中的第26行,通過模板的語法訪問了 values.yaml文件中定義的 env.open 的值,而range函數是將 env.open 所代表的 map的鍵值對賦值到 name 和 value 中,並且在內層判斷 value 不爲空就爲模板添加 28 行和29 行所示的結構。
結合文件中上下文,可以發現,這是在Kubernetes的對象文件中,定義docker容器的環境變量的位置。也就是說,這裏通過模板語法讀取helm所提供的配置值,定義kubernetes中部署的Deployment中的容器的系統變量值。而豬齒魚的微服務最終是通過helm部署helm release而運行在Kubernetes的容器中的,此時運行在容器中的SpringBoot應用就能夠讀取到系統環境變量,由於上文提到的SpringBoot配置項優先級的關係,系統環境變量會覆蓋 JAR 包內默認提供的值。
所以,在豬齒魚微服務打包完成之後,即可使用helm install或者 helm upgrade命令在命令行傳入根據環境所配置的values以部署同一個服務於不同的環境中。
最後,再來一起回顧一下整個過程:
從方案看豬齒魚平臺實現多環境部署
在理解豬齒魚如何實現後端一次打包生成的包,可以多環境部署之後,再看看豬齒魚平臺如何運用這個方案實現這個多環境部署的過程。
第一步:豬齒魚平臺使用者選擇一個服務的版本,根據所需部署的環境,填寫對應的values進行部署:
第二步:豬齒魚平臺的 devops-service 收到請求後對參數進行校驗,異步處理部署請求,爲部署的一個release在環境對應的GitLab倉庫中生成一個release開頭的文件,這個文件中存儲這次部署的所對應的版本信息、名稱信息以及values值。
第三步:choerodon-agent會去拉取環境庫解析文件,並根據文件的新增或更新在Kubernetes集羣執行對應的helm install或helm upgrade操作。
經過以上三步,豬齒魚平臺的使用者部署或升級的實例會在對應的Kubernetes集羣中安裝或升級。
至此,豬齒魚平臺支持一個服務在多個環境部署的實現方式也就理清了。
更多關於豬齒魚平臺GitOps運用的詳細情況,可閱讀《Choerodon豬齒魚 Agent——基於GitOps的雲原生持續交付模型》。
更多關於Choerodon豬齒魚的相關文章,點擊藍字閱讀 ▼
關於Choerodon豬齒魚
Choerodon豬齒魚是一個開源多雲技術平臺,是基於開源技術Kubernetes,Istio,knative,Gitlab,Spring Cloud來實現本地和雲端環境的集成,實現企業多雲/混合雲應用環境的一致性。平臺通過提供精益敏捷、持續交付、容器環境、微服務、DevOps等能力來幫助組織團隊來完成軟件的生命週期管理,從而更快、更頻繁地交付更穩定的軟件。
Choerodon豬齒魚已開通官方微信交流羣,歡迎大家添加Choerodon豬齒魚微信(ID:choerodon-c7n)入羣
大家也可以通過以下社區途徑瞭解豬齒魚的最新動態、產品特性,以及參與社區貢獻: