[dotnet]以最小的成本,落地微服務特點的DevOps管道,持續集成/部署到kubernetes。

前言

2018年既是微服務架構火爆的一年,也是容器和Kubernetes收穫讚譽盆滿鉢滿的一年;在kubernetes的引領下,以容器爲中心部署微服務已成爲一種事實標準,並不斷加速着微服務架構模式落地,持續地發揮着它的魔力。企業,特別是互聯網公司,爲了快速響應前端用戶的需求,縮短產品從需求到交付的週期,經常須要快速地、細膩度地迭代產品,以搶佔市場先機;在微服務模式下,能夠很好地知足這個要求,只發布變化的服務,從而最小化單次迭代的風險,實現敏捷開發和部署。前端

當採用微服務模式後,整個業務流程將被垂直拆分紅多個小單元;每一個小單元都是一個獨立開發、獨立部署和獨立擴展的微處理服務,這樣的靈活性很是適合敏捷開發模式,但也給開發和運維帶來了固有的複雜性和難度。對於開發者而言,因爲微服務應用總體做爲一個分佈式系統提供服務,須要選擇合適服務通信協議,並處理潛在的網絡分化瞬時故障等狀況,除此以外,還須要建設服務發現、配置中心等基礎設施;對於運維人員,須要利用容器的可移植性,持續地集成和部署微服務到不一樣的集羣環境,這些都要求運維人員具備很是全面的能力,好比:熟悉容器及k8s、能編寫Linux Shell運維腳本、熟練一種持續集成部署工具(好比:gitlab、jenkins)等。linux

綜上所述,如何搭建一條成熟穩定、且符合微服務特點的高度自動化DevOps管道又成爲了另外一個難題。git

目標

以最小的學習成本,搭建一條成熟穩定、且符合微服務特點的高度自動化DevOps管道,按需地持續集成/部署微服務到kubernetes。github

工具 - 最小的學習成本

kubernetes + gitlab + shelldocker

方案 - 願景

1. 持續集成 - CI

在kubernetes的master節點部署gitlab-runner,充當gitlab服務器的客戶端;當提交或合併代碼到指定的分支時,gitlab-runner自動從gitlab拉取代碼,利用master主機提供的邊緣計算能力來執行已編排好的DevOps CI管道=》編譯代碼、運行單元和集成測試、容器化微服務成鏡像,最後上傳到企業鏡像倉庫,這就是持續集成流程,該階段交付的產物爲鏡像。shell

2. 持續部署 - CD

在kubernetes的master節點部署gitlab-runner,充當gitlab服務器的客戶端,當持續集成階段交付了新版本的鏡像後,從企業鏡像倉庫拉取最新版本的鏡像,利用master主機提供的邊緣計算能力執行已編排好的DevOps CD管道=》同步服務配置信息到配置中心(k8s的ConfigMap),並滾動更新kubernetes集羣鏡像版本。bash

部署環境

安裝目錄:/root/gitrunner服務器

工做目錄:/home/devops/gitrunnerrestful

> 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;

詳情請參考: Install GitLab Runner manually on GNU/Linux

2. 註冊gitlab-runner

gitlab支持註冊兩種類型的runner:

1. Specific Runners

這是隸屬於特定項目的專有工人,不接受其餘項目調遣。

2. Shared Runners

這是隸屬於gitlab-server的工人,能夠共享給全部的項目調遣。

這兩種Runner各有千秋,若是爲每個項目都註冊專用Runner,會顯得比較繁瑣和多餘,而使用共享Runner就很省事,可是一個工人一次只能作一件事情,當同時調遣一個工人時,那麼就會出現競爭等待,故你們仍是實際狀況來註冊工人吧,只要不延誤工期就行,嘿嘿。

註冊runner

在開發、預生產、生產環境註冊Runner,並貼上標籤:build、staging、prod。

備註:後面搭建DevOps管道時,將根據標籤來調遣工人。

步驟
  1. 獲取項目地址和註冊token,依次查找路徑:Settings => CI / CD => Runners settings,以下:

  2. 註冊:

    > 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到一、從無到有的過程,這裏一小步,倒是落地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.一、測試

將剛剛建立的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.一、伸縮單個微服務

通過一段時間的觀察發現預生產環境的購物車(Basket.API)微服務吞吐量頗高,故決定擴容它的實例數量到2個,首先修改項目屬性文件deploy.props,以下:

<Replicas>2</Replicas>

而後添加配置,以下:

最後合併代碼到分支scaling/staging,以下:

3.二、伸縮全部微服務

同理,首先修改項目屬性文件deploy.props,以下:

<Replicas>2</Replicas>

而後添加配置,以下:

最後合併代碼到分支scaling/staging,或者直接重試管道的auto-scaling階段,以下:

從上面測試看到,只須要修改配置,就能夠支持不一樣粒度地伸縮微服務,也不用修改CI/CD管道腳本。

生產環境同理,只須要合併代碼到分支scaling/production。

4. 回滾

4.一、回滾單個微服務

通過一段時間的觀察,發現剛剛發佈到預生產環境的版本1.0.1有問題,故決定回滾到上一個版次1.0.0,首先修改項目屬性文件deploy.props,以下:

<!--回滾步長-->
<RollBackStep>1</RollBackStep>

而後添加配置(只回滾購物車微服務),以下:

最後合併代碼到分支rollback/staging,以下:

4.二、回滾全部微服務

同理,首先修改項目屬性文件deploy.props,以下:

<!--回滾步長-->
<RollBackStep>1</RollBackStep>

而後添加配置回滾全部微服務,以下:

最後合併代碼到分支rollback/staging,或者直接重試管道的roll-back階段,以下:

生產環境同理,只須要合併代碼到分支rollback/production。

5. 可擴展性 - 兼容新增微服務

5.一、添加新的搜索微服務

通過一段時間的迭代,一期已經完工,二期新增了搜索微服務,這時修改helm模板文件支持部署搜索微服務,而後合併代碼到release/staging,測試以下:

  • k8s

  • 網關路由

從上面能夠看到,新增的搜索微服務已經成功發佈到第二個主版次了。除了修改helm模板文件之外,整個過程並無修改CI/CD管道腳本,圓滿完成了兼容新增微服務的特性。

備註:咱們能夠將helm模板當作服務編排文件。

運維說明

一、分支

  1. build

    構建和編譯代碼。

  2. release/staging

    建立預生產環境。

  3. staging

    滾動更新預生產環境。

  4. release/production

    建立生產環境。

  5. master

    滾動更新生產環境。

  6. scaling/staging

    伸縮預生產環境

  7. scaling/production

    伸縮生產環境

  8. rollback/staging

    回滾預生產環境

  9. rollback/production

    回滾生產環境

二、配置文件

  • 應用程序配置 - 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實踐微服務的方方面面。

最後

若是有什麼疑問和看法,歡迎評論區交流。
若是你以爲本篇文章對您有幫助的話,感謝您的【推薦】。
若是你對微服務實踐感興趣的話能夠關注我,我會按期的在博客分享個人學習心得。
歡迎轉載,請在明顯位置給出出處及連接

相關文章
相關標籤/搜索