前言
2018年既是微服務架構火爆的一年,也是容器和Kubernetes收獲贊譽盆滿缽滿的一年;在kubernetes的引領下,以容器為中心部署微服務已成為一種事實標准,並不斷加速着微服務架構模式落地,持續地發揮着它的魔力。企業,特別是互聯網公司,為了快速響應前端用戶的需求,縮短產品從需求到交付的周期,常常需要快速地、細膩度地迭代產品,以搶占市場先機;在微服務模式下,可以很好地滿足這個要求,只發布變化的服務,從而最小化單次迭代的風險,實現敏捷開發和部署。
當采用微服務模式后,整個業務流程將被垂直拆分成多個小單元;每個小單元都是一個獨立開發、獨立部署和獨立擴展的微處理服務,這樣的靈活性非常適合敏捷開發模式,但也給開發和運維帶來了固有的復雜性和難度。對於開發者而言,由於微服務應用整體作為一個分布式系統提供服務,需要選擇合適服務通訊協議,並處理潛在的網絡分化瞬時故障等情況,除此之外,還需要建設服務發現、配置中心等基礎設施;對於運維人員,需要利用容器的可移植性,持續地集成和部署微服務到不同的集群環境,這些都要求運維人員具有非常全面的能力,比如:熟悉容器及k8s、能編寫Linux Shell運維腳本、熟練一種持續集成部署工具(比如:gitlab、jenkins)等。
綜上所述,如何搭建一條成熟穩定、且符合微服務特色的高度自動化DevOps管道又成為了另一個難題。
目標
以最小的學習成本,搭建一條成熟穩定、且符合微服務特色的高度自動化DevOps管道,按需地持續集成/部署微服務到kubernetes。
工具 - 最小的學習成本
kubernetes + gitlab + shell
方案 - 願景
1. 持續集成 - CI
在kubernetes的master節點部署gitlab-runner,充當gitlab服務器的客戶端;當提交或合並代碼到指定的分支時,gitlab-runner自動從gitlab拉取代碼,利用master主機提供的邊緣計算能力來執行已編排好的DevOps CI管道=》編譯代碼、運行單元和集成測試、容器化微服務成鏡像,最后上傳到企業鏡像倉庫,這就是持續集成流程,該階段交付的產物為鏡像。
2. 持續部署 - CD
在kubernetes的master節點部署gitlab-runner,充當gitlab服務器的客戶端,當持續集成階段交付了新版本的鏡像后,從企業鏡像倉庫拉取最新版本的鏡像,利用master主機提供的邊緣計算能力執行已編排好的DevOps CD管道=》同步服務配置信息到配置中心(k8s的ConfigMap),並滾動更新kubernetes集群鏡像版本。
部署環境
安裝目錄:/root/gitrunner
工作目錄:/home/devops/gitrunner
> mkdir -p /root/gitrunner && mkdir -p /home/devops/gitrunner;
1. 部署gitlab-runner
在kubernetes的master節點部署gitlab-runner,命令如下:
> wget -O /root/gitrunner/gitlab-runner https://gitlab-runner-downloads.s3.amazonaws.com/latest/binaries/gitlab-runner-linux-amd64;
> cd /root/gitrunner;
> chmod +x gitlab-runner;
> # 注意:建議使用root用戶進行安裝,以避免不必要的權限問題。
> ./gitlab-runner install --user=root --working-directory=/home/devops/gitrunner;
> ./gitlab-runner start;
2. 注冊gitlab-runner
gitlab支持注冊兩種類型的runner:
1. Specific Runners
這是隸屬於特定項目的專有工人,不接受其他項目調遣。
2. Shared Runners
這是隸屬於gitlab-server的工人,可以共享給所有的項目調遣。
這兩種Runner各有千秋,如果為每一個項目都注冊專用Runner,會顯得比較繁瑣和多余,而使用共享Runner就很省事,但是一個工人一次只能做一件事情,當同時調遣一個工人時,那么就會出現競爭等待,故大家還是實際情況來注冊工人吧,只要不延誤工期就行,嘿嘿。
注冊runner
在開發、預生產、生產環境注冊Runner,並貼上標簽:build、staging、prod。
備注:后面搭建DevOps管道時,將根據標簽來調遣工人。
步驟
-
獲取項目地址和注冊token,依次查找路徑:Settings => CI / CD => Runners settings,如下:
-
注冊:
> cd /root/gitrunner; > ./gitlab-runner register > # 回車,根據提示填寫項目地址、注冊Token、標簽、執行器 > # 假如,項目地址為:http://gitlab.justmine.cn:8002/, 項目注冊token為:6iS4GBCh18NR4GPoMyef。 > ## 以開發環境為例(僅供參考) > Please enter the gitlab-ci coordinator URL (e.g. https://gitlab.com/): http://gitlab.justmine.cn:8002/ > Please enter the gitlab-ci token for this runner: 6iS4GBCh18NR4GPoMyef > Please enter the gitlab-ci description for this runner: [justmine.com]: development environment > Please enter the gitlab-ci tags for this runner (comma separated): build > Registering runner... succeeded runner=4iS4GwCh > Please enter the executor: ssh, docker+machine, kubernetes, virtualbox, docker-ssh+machine, docker, docker-ssh, parallels, shell: shell > Runner registered successfully. Feel free to start it, but if it's running already the config should be automatically reloaded! > # 其他環境同理
搭建DevOps管道 - PipeLines
上面的方案僅僅描述了願景,也就是期望達成目標的最后結果,但對於如何落地一條真正的管道而言,還是顯得非常的空洞。其實這正是DevOps的難點,大體流程上都曉得有個持續集成、持續部署,講起來如數家珍,落地時都之乎者也。
同樣,秉承微服務的思想,分而治之,我們將管道分為兩個部分:創建、更新,即先創建一個主板次,然后再基於此主板次進行小版本迭代,不斷地擴展新功能。通過這樣有效的拆分,是不是就不那么的空洞了,就像領域驅動設計的CQRS模式一樣,區別地對待讀寫,從而大大地減少了阻抗,也非常地切合產品的創新迭代,比如將需求拆分為3期,每一期都對應一個主版次,然后再小版本迭代每一期的需求,完成一期,封板一期,彼此隔離,互補影響,同時也方便追溯。
理清了整個管道的脈絡,現在就需要思考一些實際問題了,比如:
1. 如何將持續集成/部署微服務流程腳本化,即如何實現基礎設施代碼化?
2. 如何動態解析git當前變化日志,實現准確地按需發布微服務?
3. 如何保留現場,並以最小的成本重試管道?
4. 在不修改管道腳本的情況下,如何手工控制按需發布、自動伸縮和回滾微服務?
5. 如何兼容新增的微服務?
6. 如何快速調試整個管道腳本?
只有把上面的問題都處理了,才算是一條成熟可用的、企業級別的CI/CD管道,才符合高度自動化、穩定、快速、容錯等特點;在互聯網公司,可能一天要提交好幾個版本到不同的環境,不能因為考慮不周而影響連續部署的進度,管道一旦投入使用就需要對修改閉合,只對擴展開放。
管道一覽圖:
示例項目(AspnetCore)已分享到github,請參考:MicroService.AutoDevOpsPipeLines,歡迎start,歡迎fork,歡迎issue。
為了驗證管道的特性,我特意做了以下測試:
1. 創建環境 - 發布主板本
這是一個從0到1、從無到有的過程,這里一小步,卻是落地DevOps管道的一大步。
版本迭代的第一步就是創建微服務集群環境,那么如何快捷地創建這個環境呢?我將使用kubernetes的包管理器helm來完成這個任務,可能很多同學都沒用過這個工具,平時部署組件都是手工編寫好yaml資源部署文件,雖然這種方式方便快捷,但是對於大量組件,以及需要實現基礎設施代碼化的場景,手工處理這種方式就不能滿足需求了。
模板文件請參考示例項目,下面是創建環境的腳本化命令:
helm install /root/AutoDevOpsPipeLinesCharts \
--name=${releaseName} \
--set environment.upper=${Environment} \
--set environment.lower=${environment} \
--set namespace=${namespace} \
--set image.registryhost=${RegistryHost} \
--set image.username=${registryUserName} \
--set image.version=${version} \
--set replicas=${replicas}
從上面可以看出,實現部署服務腳本化的目的已經達到了。
下面我們在來看看如何腳本化整個創建環境管道線:
# 001 Continuous integration image to registry.
bash ./devops/PipeLines/Creation/001_CI.sh
# 002 Create config information to k8s's configmap.
bash ./devops/PipeLines/Creation/002_CreateConfig.sh
# 003 Release major to k8s's cluster.
bash ./devops/PipeLines/Creation/003_ReleaseMajor.sh
# 004 Create gateway route.
bash ./devops/PipeLines/Creation/Gateways/Kong/004_CreateGatewayRoute.sh
備注:管道線腳本請參考示例項目(AspnetCore):MicroService.AutoDevOpsPipeLines/devops/PipeLines/Creation。
1.1、測試
將剛剛創建的helm模板文件上傳到gitlab-runner所在服務器的/root目錄下,並添加配置,如下:
<Project>
<PropertyGroup>
<Major>1</Major>
<Minor>0</Minor>
<Patch>0</Patch>
</PropertyGroup>
</Project>
然后合並代碼到分支release/staging,如下:
從上面可以,第一個主板次(1.0.0)已經成功發布到預生產環境。
生產環境同理,在預生產環境跑完各種測試后,合並代碼到分支release/production即可。
2. 滾動更新 - 迭代小版本
這個階段將模擬在第一個主板次(1.0.0)上進行小版本迭代需求,距離上次發布已經一周了,開發部門也完成了第一個小版本的開發工作,現在需要發布版本1.0.1到預生產環境進行測試,首先修改文件version.props,如下:
<Project>
<PropertyGroup>
<Major>1</Major>
<Minor>0</Minor>
<Patch>1</Patch>
</PropertyGroup>
</Project>
除了發布本次需求修改的兩個微服務:Identity.API、Marketing.API以外,還需強制發布微服務Basket.API,添加配置,在gitlab倉庫依次查找 (Settings => CI/CD => Secret variables),如下:
最后合並代碼到分支staging。
-
先來看看是否正確解析git變更日志和全局變量,准確地實現自動化和手工控制:
-
再來看看整個管道的執行情況:
-
最后看一下預生產環境的效果
從上面可以看出,第一個小版本(1.0.1)已經按需自動發布到預生產環境,一共滾動更新了三個微服務。如果當管道的某個階段執行異常,只需要點擊重試此階段即可;如果需要重新手工干預,只需要添加配置信息,然后重試analysing-git-changes
階段,再依次重試后面的Job即可,整個過程無需修改CI/CD管道腳本,真正實現高度自動化、快速等特點。
生產環境同理,在預生產環境跑完各種測試后,合並代碼到分支master即可。
3. 自動伸縮
3.1、伸縮單個微服務
經過一段時間的觀察發現預生產環境的購物車(Basket.API)微服務吞吐量頗高,故決定擴容它的實例數量到2個,首先修改項目屬性文件deploy.props,如下:
<Replicas>2</Replicas>
然后添加配置,如下:
最后合並代碼到分支scaling/staging,如下:
3.2、伸縮所有微服務
同理,首先修改項目屬性文件deploy.props,如下:
<Replicas>2</Replicas>
然后添加配置,如下:
最后合並代碼到分支scaling/staging,或者直接重試管道的auto-scaling階段,如下:
從上面測試看到,只需要修改配置,就可以支持不同粒度地伸縮微服務,也不用修改CI/CD管道腳本。
生產環境同理,只需要合並代碼到分支scaling/production。
4. 回滾
4.1、回滾單個微服務
經過一段時間的觀察,發現剛剛發布到預生產環境的版本1.0.1有問題,故決定回滾到上一個版次1.0.0,首先修改項目屬性文件deploy.props,如下:
<!--回滾步長-->
<RollBackStep>1</RollBackStep>
然后添加配置(只回滾購物車微服務),如下:
最后合並代碼到分支rollback/staging,如下:
4.2、回滾所有微服務
同理,首先修改項目屬性文件deploy.props,如下:
<!--回滾步長-->
<RollBackStep>1</RollBackStep>
然后添加配置回滾所有微服務,如下:
最后合並代碼到分支rollback/staging,或者直接重試管道的roll-back階段,如下:
生產環境同理,只需要合並代碼到分支rollback/production。
5. 可擴展性 - 兼容新增微服務
5.1、添加新的搜索微服務
經過一段時間的迭代,一期已經完工,二期新增了搜索微服務,這時修改helm模板文件支持部署搜索微服務,然后合並代碼到release/staging,測試如下:
-
k8s
-
網關路由
從上面可以看到,新增的搜索微服務已經成功發布到第二個主版次了。除了修改helm模板文件以外,整個過程並沒有修改CI/CD管道腳本,圓滿完成了兼容新增微服務的特性。
備注:我們可以將helm模板看成服務編排文件。
運維說明
1、分支
-
build
構建和編譯代碼。
-
release/staging
創建預生產環境。
-
staging
滾動更新預生產環境。
-
release/production
創建生產環境。
-
master
滾動更新生產環境。
-
scaling/staging
伸縮預生產環境
-
scaling/production
伸縮生產環境
-
rollback/staging
回滾預生產環境
-
rollback/production
回滾生產環境
2、配置文件
-
應用程序配置 - app.props
<!-- k8s命名空間前綴,比如:microservice-autodevopspipeline-v1 --> <NameSpace>microservice-autodevopspipeline</NameSpace> <!-- 應用程序名稱,主要用於Tips --> <AppName>MicroService.AutoDevOpsPipeLine</AppName> <!-- 解決方案名稱,用於生成項目 --> <SolutionName>MicroService.AutoDevOpsPipeLines.sln</SolutionName>
-
版本配置 - version.props
<!-- 主板次,不兼容升級 --> <Major>1</Major> <!-- 次板次,兼容升級 --> <Minor>0</Minor> <!-- 補丁版次,靜默修復接口 --> <Patch>1</Patch>
-
部署配置 - deploy.props
<!-- Auto-scaling 實例數量 --> <Replicas>1</Replicas> <!-- Rollback 步長 --> <RollBackStep>1</RollBackStep> <!-- 鏡像倉庫用戶名 --> <ImageUserName>devopspipelines</ImageUserName>
特定環境配置,如:deploy.staging.props
<!-- 鏡像倉庫主機域名 --> <RegistryHost>registry.staging.com:8100</RegistryHost> <!-- k8s restful地址 --> <K8sApiServer>https://192.168.2.110:6443</K8sApiServer> <!-- k8s 接口訪問令牌 --> <AccessToken>utyeyerye.ytryeryeryyyyyyr.jhddghdhdhdhd</AccessToken> <!-- kong restful地址 --> <KongApiServer>http://192.168.2.110:81</KongApiServer> <!-- kong 域名綁定 --> <KongRouteDomain>staging.devops.com</KongRouteDomain>
-
分支環境配置 - branch.env.props
<!-- 解耦,目前用於滾動更新 --> <!-- key: branch name(last keyword), value: environment --> <staging>Staging</staging> <master>Production</master>
總結
上面的測試幾乎涵蓋了結合k8s管理應用生命周期的所有流程(部署、伸縮、回滾、發布),大家可以放心地運用或者擴展這個管道到自己的微服務項目中,比如:目前僅支持自動創建路由到kong網關,建議大家fork項目后,自行擴展,測試完成后,也可以提取PR。如果你采用示例一樣的項目結構,只需要修改配置信息,然后開箱即用。
如果你有什么需求無法實現,歡迎加入QQ群:564095699,一起探討k8s實踐微服務的方方面面。
最后
如果有什么疑問和見解,歡迎評論區交流。
如果你覺得本篇文章對您有幫助的話,感謝您的【推薦】。
如果你對微服務實踐感興趣的話可以關注我,我會定期的在博客分享我的學習心得。
歡迎轉載,請在明顯位置給出出處及鏈接。