Kubernetes微服務(wù)自動(dòng)化發(fā)布系統(tǒng)

實(shí)施微服務(wù)架構(gòu)后,原先單一的系統(tǒng)結(jié)構(gòu)統(tǒng)變成了數(shù)量眾多的微服務(wù)應(yīng)用,開(kāi)發(fā)、測(cè)試、運(yùn)維部署等都會(huì)面臨不少挑戰(zhàn)。在微服務(wù)架構(gòu)下如何提高工程研發(fā)效率,確保開(kāi)發(fā)、測(cè)試、運(yùn)維部署等流程上的順暢,是微服務(wù)技術(shù)體系能夠真正落地產(chǎn)生效益的關(guān)鍵。
要實(shí)現(xiàn)上述目標(biāo)就需要基于DevOps(開(kāi)發(fā)運(yùn)維)思想構(gòu)建一套高度自動(dòng)化的發(fā)布系統(tǒng),在該系統(tǒng)中開(kāi)發(fā)人員可以隨時(shí)隨地構(gòu)建代碼并將其發(fā)布至指定的運(yùn)行環(huán)境中,這個(gè)過(guò)程也就是我們通常所說(shuō)的CI/CD(持續(xù)集成/持續(xù)交付)流程。
關(guān)于DevOps的具體實(shí)踐,不同的公司一般會(huì)根據(jù)自身的發(fā)展階段和實(shí)際需要來(lái)選擇具體落地的方案。具備條件的公司可以研發(fā)功能豐富的可視化發(fā)布系統(tǒng),而條件有限的創(chuàng)業(yè)公司則可以通過(guò)開(kāi)源或現(xiàn)有的技術(shù)組件(如GitLab、Jenkins等)來(lái)實(shí)現(xiàn)操作相對(duì)簡(jiǎn)陋但功能完備的自動(dòng)化發(fā)布系統(tǒng)。
在本篇文章中我將以Spring Cloud微服務(wù)技術(shù)體系為背景,通過(guò)GitLab自帶的CI/CD機(jī)制并基于Kubernetes容器化技術(shù)來(lái)實(shí)現(xiàn)一套具備相對(duì)完整CI/CD流程的自動(dòng)化發(fā)布系統(tǒng)。
CI/CD流程概述

實(shí)際上DevOps并不是微服務(wù)架構(gòu)流行之后才產(chǎn)生的概念,而是業(yè)界在多年軟件開(kāi)發(fā)實(shí)踐中積累的理論、工具的集合。本文所要討論的自動(dòng)化發(fā)布系統(tǒng)實(shí)際上是要通過(guò)搭建CI/CD流水線來(lái)建立一套應(yīng)用程序構(gòu)建、測(cè)試、打包及發(fā)布的高效自動(dòng)化方法。關(guān)于CI(持續(xù)集成)/CD(持續(xù)交付)的概念并不是指某一種具體的技術(shù),而是一種軟件工程文化加一系列操作原則和具體實(shí)踐的集合。
其中CI(持續(xù)集成)的主要目標(biāo)是通過(guò)建立一致的自動(dòng)化構(gòu)建方法來(lái)打包程序代碼,使得團(tuán)隊(duì)成員能夠以更頻繁地動(dòng)作提交代碼、更早地進(jìn)行代碼集成,以及時(shí)發(fā)現(xiàn)和解決代碼中的問(wèn)題、提高協(xié)作開(kāi)發(fā)效率及軟件交付質(zhì)量。可持續(xù)集成(CI)的基本流程如圖所示:

從實(shí)現(xiàn)流程上來(lái)說(shuō)CI的主要過(guò)程就是將開(kāi)發(fā)人員提交的代碼以高度自動(dòng)化的方式打包成可以在具體基礎(chǔ)架構(gòu)環(huán)境運(yùn)行的程序包(例如Docker鏡像)。而這個(gè)過(guò)程可以由一組工具如GitLab Runner(CI Pipeline)、Sonar(代碼檢測(cè)工具)等去完成,具體構(gòu)建CI流程時(shí)根據(jù)實(shí)際需要集成運(yùn)用即可。
持續(xù)交付(CD)的主要邏輯則是將CI流程中構(gòu)建的程序鏡像從鏡像倉(cāng)庫(kù)自動(dòng)發(fā)布到具體的基礎(chǔ)架構(gòu)環(huán)境(如測(cè)試/生產(chǎn)Kubernetes集群),實(shí)現(xiàn)CD的工具主要有GitLab Runner(CD Pipeline)、Helm(Kubernetes軟件包管理工具)等。
實(shí)際上CD的核心就是通過(guò)輸入的各種用戶參數(shù)(如yaml文件、環(huán)境配置參數(shù)等)最終自動(dòng)生成具體的發(fā)布指令(如Helm指令),并根據(jù)參數(shù)中設(shè)置的相應(yīng)信息來(lái)配置程序的具體運(yùn)行環(huán)境。可持續(xù)交付(CD)的基本運(yùn)行流程如下圖所示:

以上就是CI/CD的基本概念及流程,也是自動(dòng)化發(fā)布系統(tǒng)的實(shí)現(xiàn)的依據(jù)。在后面的內(nèi)容中將主要圍繞這兩個(gè)階段來(lái)實(shí)現(xiàn)自動(dòng)化發(fā)布系統(tǒng)的基本流程邏輯。
系統(tǒng)的基本組成

本文所要描述的自動(dòng)化發(fā)布系統(tǒng)主要是利用GitLab提供的GitLab CI機(jī)制,實(shí)現(xiàn)當(dāng)代碼發(fā)生提交或合并等事件時(shí)自動(dòng)觸發(fā)預(yù)設(shè)的CI/CD流程。其中CI流程主要包括基本的代碼編譯、構(gòu)建、打包等階段,并在完成上述步驟后將打包好的應(yīng)用Docker鏡像發(fā)布至鏡像倉(cāng)庫(kù)。
而CD階段則是從鏡像倉(cāng)庫(kù)拉取應(yīng)用Docker鏡像,并根據(jù)設(shè)置的CD流程將應(yīng)用發(fā)布至指定的Kubernetes集群。具體系統(tǒng)結(jié)構(gòu)如下圖所示:

如上圖所示,該自動(dòng)化發(fā)布系統(tǒng)主要由GitLab、Harbor鏡像倉(cāng)庫(kù)及Kubernetes集群組成。其中GitLab主要承擔(dān)代碼版本的管理,以及CI/CD流程定義和觸發(fā), Harbor負(fù)責(zé)應(yīng)用Docker鏡像的存儲(chǔ)和分發(fā),而Kubernetes集群則是應(yīng)用容器運(yùn)行的基礎(chǔ)架構(gòu)環(huán)境。
GitLab-CI自動(dòng)化發(fā)布系統(tǒng)的關(guān)鍵實(shí)現(xiàn)

前面我們描述了基于GitLab-CI機(jī)制實(shí)現(xiàn)自動(dòng)化發(fā)布系統(tǒng)的基本組成,要具體實(shí)現(xiàn)這套系統(tǒng)你需要安裝部署GitLab服務(wù)器并配置GItLab Runner功能,私有鏡像倉(cāng)庫(kù)服務(wù)(Harbor或JFrog)以及Kubernetes集群(具體可參見(jiàn)本專(zhuān)欄的其他文章)。
由于GitLab服務(wù)器是CI/CD流程執(zhí)行的主要承載點(diǎn),如果你的服務(wù)是基于Maven構(gòu)建的Java服務(wù),那么還需要在GitLab服務(wù)器中安裝Maven客戶端,并配置Maven私服的地址,以提高構(gòu)建速度。此外GitLab服務(wù)器在CI/CD流程執(zhí)行中還會(huì)運(yùn)行Docker鏡像打包構(gòu)建,將鏡像push到Docker鏡像倉(cāng)庫(kù)以及將Docker鏡像從私有倉(cāng)庫(kù)發(fā)布至Kubernetes集群等邏輯,所以GitLab服務(wù)器還需要安裝Docker環(huán)境及kubelet客戶端。
如果環(huán)境都OK,那么我們就可以在Gitlab項(xiàng)目根目錄代碼中創(chuàng)建“.gitlab-ci.yml”文件并定義具體的CI/CD流程了。但在具體定義之前,我們需要在Maven項(xiàng)目中添加應(yīng)用Docker鏡像打包的插件配置及Dockerfile文件定義,具體如下:
<plugin>
????<groupId>com.spotifygroupId>
????<artifactId>dockerfile-maven-pluginartifactId>
????<version>1.4.13version>
????<executions>
????????<execution>
????????????<id>build-imageid>
????????????<phase>packagephase>
????????????<goals>
????????????????<goal>buildgoal>
????????????goals>
????????execution>
????executions>
????<configuration>
????????
????????<dockerfile>docker/Dockerfiledockerfile>
????????
????????<repository>${docker.repository}/springcloud-action/${app.name}repository>
????????<buildArgs>
????????????
????????????<JAR_FILE>target/${project.build.finalName}.jarJAR_FILE>
????????buildArgs>
????configuration>
plugin>
在項(xiàng)目工程pom.xml文件中添加“dockerfile-maven-plugin”插件,該插件是早期“docker-maven-plugin”插件的替代品,支持將Maven項(xiàng)目構(gòu)建打包為Docker鏡像。上述配置中,針對(duì)Docker鏡像的具體構(gòu)建方式,是通過(guò)在
FROM?openjdk:8u191-jre-alpine3.9
ENTRYPOINT?["/usr/bin/java",?"-jar",?"/app.jar"]
ARG?JAR_FILE
ADD?${JAR_FILE}?/app.jar
EXPOSE?8080
配置好Maven打包插件后,就能支持通過(guò)Maven打包命令,將應(yīng)用代碼打包成Docker鏡像了。此時(shí)我們?cè)?.gitlab-ci.yml"文件中定義具體的CI/CD構(gòu)建Stages,示例如下:
#環(huán)境參數(shù)信息
variables:
??#Docker鏡像倉(cāng)庫(kù)地址&賬號(hào)密碼信息
??DOCKER_REPO_URL:?"10.211.55.11:8088"
??DOCKER_REPO_USERNAME:?admin
??DOCKER_REPO_PASSWORD:?Harbor12345
??#Kubernetes相關(guān)信息配置(空間與服務(wù)端口)
??K8S_NAMESPACE:?"wudimanong"
??PORT:?"8080"
#定義CI/CD階段
stages:
??-?test
??-?build
??-?push
??-?deploy
#執(zhí)行單元測(cè)試階段
maven-test:
??stage:?test
??script:
????-?mvn?clean?test
#代碼編譯打包鏡像階段
maven-build:
??stage:?build
??script:
????-?mvn?clean?package?-DskipTests
#將打包的Docker鏡像上傳至私有鏡像倉(cāng)庫(kù)
docker-push:
??stage:?push
??script:
????#對(duì)打包的鏡像進(jìn)行tag
????-?docker?tag?$DOCKER_REPO_URL/$CI_PROJECT_PATH?$DOCKER_REPO_URL/$CI_PROJECT_PATH/$CI_BUILD_REF_NAME:${CI_COMMIT_SHA:0:8}
????#登錄私有鏡像倉(cāng)庫(kù)
????-?docker?login?$DOCKER_REPO_URL?-u?$DOCKER_REPO_USERNAME?-p?$DOCKER_REPO_PASSWORD
????#上傳應(yīng)用鏡像至鏡像倉(cāng)庫(kù)
????-?docker?push?$DOCKER_REPO_URL/$CI_PROJECT_PATH/$CI_BUILD_REF_NAME:${CI_COMMIT_SHA:0:8}
????-?docker?rmi?$DOCKER_REPO_URL/$CI_PROJECT_PATH/$CI_BUILD_REF_NAME:${CI_COMMIT_SHA:0:8}
????-?docker?rmi?$DOCKER_REPO_URL/$CI_PROJECT_PATH
#將應(yīng)用發(fā)布至Kubernetes測(cè)試集群(這里指定為手動(dòng)確認(rèn)方式)
deploy-test:
??stage:?deploy
??when:?manual
??script:
????-?kubectl?config?use-context?kubernetes-admin@kubernetes
????-?sed?-e??"s/__REPLICAS__/1/;?s/__PORT__/$PORT/;?s/__APP_NAME__/$CI_PROJECT_NAME/;?s/__PROFILE__/test/;??s/__IMAGE__/$DOCKER_REPO_URL\/${CI_PROJECT_PATH//\//\\/}\/${CI_BUILD_REF_NAME//\//\\/}:${CI_COMMIT_SHA:0:8}/"?kubernetes/deploy.yaml?|?kubectl?-n?${K8S_NAMESPACE}??apply?-f??-
如上所述,我們?cè)凇?gitlab-ci.yml”文件中定義了”test、build、push、deploy”這4個(gè)stages階段。這幾個(gè)stages的具體說(shuō)明如下:
test:執(zhí)行單元測(cè)試代碼;
build:執(zhí)行構(gòu)建打包指令,將應(yīng)用構(gòu)建打包為Docker鏡像;
push:該階段主要是將build構(gòu)建的本地Docker鏡像經(jīng)過(guò)tag處理后上傳至Harbor鏡像倉(cāng)庫(kù),并在成功后清理掉本地鏡像文件;
deploy:該階段主要是執(zhí)行Kubernetes指令,根據(jù)Kubernetes發(fā)布部署文件的配置,將容器鏡像部署發(fā)布至Kubernetes集群;
在deploy階段,是將Docker鏡像發(fā)布運(yùn)行至Kubernetes集群,其中涉及編寫(xiě)Kubernetes部署發(fā)布yaml文件,具體示例如下:
---
apiVersion:?apps/v1
kind:?Deployment
metadata:
??name:?__APP_NAME__
spec:
??replicas:?__REPLICAS__
??selector:
????matchLabels:
??????app:?__APP_NAME__
??strategy:
????type:?RollingUpdate
??template:
????metadata:
??????labels:
????????app:?__APP_NAME__
????spec:
??????imagePullSecrets:
????????-?name:?wudimanong-ecr
??????containers:
????????-?name:?__APP_NAME__
??????????image:?__IMAGE__
??????????resources:
????????????requests:
??????????????memory:?"1000M"
????????????limits:
??????????????memory:?"1000M"
??????????volumeMounts:
????????????-?name:?time-zone
??????????????mountPath:?/etc/localtime
????????????-?name:?java-logs
??????????????mountPath:?/opt/logs
??????????ports:
????????????-?containerPort:?__PORT__
??????????env:
????????????-?name:?SPRING_PROFILES_ACTIVE
??????????????value:?__PROFILE__
????????????-?name:?JAVA_OPTS
??????????????value:?-Xms1G?-Xmx1G?-Dapp.home=/opt/
??????volumes:
????????-?name:?time-zone
??????????hostPath:
????????????path:?/etc/localtime
????????-?name:?java-logs
??????????hostPath:
????????????path:?/data/app/deployment/logs
如果一切準(zhǔn)備妥當(dāng),此時(shí)你向GitLab倉(cāng)庫(kù)提交代碼將自動(dòng)觸發(fā)構(gòu)建Pipeline,而Pipeline將自動(dòng)運(yùn)行你在“.gitlab-ci.yml”文件中定義的具體CI/CD流水線邏輯,從而實(shí)現(xiàn)應(yīng)用的自動(dòng)化發(fā)布效果。
基于GitLab-CI機(jī)制的自動(dòng)化發(fā)布系統(tǒng)由于其構(gòu)建方式比較簡(jiǎn)單,不需要太多的開(kāi)發(fā)工作,因此目前不少創(chuàng)業(yè)公司中都采用了此類(lèi)方案來(lái)實(shí)現(xiàn)微服務(wù)的自動(dòng)化構(gòu)建和交付。
以上就是本文所要表達(dá)的全部?jī)?nèi)容,希望能對(duì)你理解自動(dòng)化發(fā)布系統(tǒng)的實(shí)現(xiàn)原理有所幫助!
—————END—————
