目錄html
2018年既是微服務架構火爆的一年,也是容器和Kubernetes收穫讚譽盆滿鉢滿的一年;在kubernetes的引領下,以容器爲中心部署微服務已成爲一種事實標準,並不斷加速着微服務架構模式落地,持續地發揮着它的魔力。企業,特別是互聯網公司,爲了快速響應前端用戶的需求,縮短產品從需求到交付的週期,經常須要快速地、細膩度地迭代產品,以搶佔市場先機;在微服務模式下,能夠很好地知足這個要求,只發布變化的服務,從而最小化單次迭代的風險,實現敏捷開發和部署。前端
當採用微服務模式後,整個業務流程將被垂直拆分紅多個小單元;每一個小單元都是一個獨立開發、獨立部署和獨立擴展的微處理服務,這樣的靈活性很是適合敏捷開發模式,但也給開發和運維帶來了固有的複雜性和難度。對於開發者而言,因爲微服務應用總體做爲一個分佈式系統提供服務,須要選擇合適服務通信協議,並處理潛在的網絡分化瞬時故障等狀況,除此以外,還須要建設服務發現、配置中心等基礎設施;對於運維人員,須要利用容器的可移植性,持續地集成和部署微服務到不一樣的集羣環境,這些都要求運維人員具備很是全面的能力,好比:熟悉容器及k8s、能編寫Linux Shell運維腳本、熟練一種持續集成部署工具(好比:gitlab、jenkins)等。linux
綜上所述,如何搭建一條成熟穩定、且符合微服務特點的高度自動化DevOps管道又成爲了另外一個難題。git
以最小的學習成本,搭建一條成熟穩定、且符合微服務特點的高度自動化DevOps管道,按需地持續集成/部署微服務到kubernetes。github
kubernetes + gitlab + shelldocker
在kubernetes的master節點部署gitlab-runner,充當gitlab服務器的客戶端;當提交或合併代碼到指定的分支時,gitlab-runner自動從gitlab拉取代碼,利用master主機提供的邊緣計算能力來執行已編排好的DevOps CI管道=》編譯代碼、運行單元和集成測試、容器化微服務成鏡像,最後上傳到企業鏡像倉庫,這就是持續集成流程,該階段交付的產物爲鏡像。shell
在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;
在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;
gitlab支持註冊兩種類型的runner:
1. Specific Runners
這是隸屬於特定項目的專有工人,不接受其餘項目調遣。
2. Shared Runners
這是隸屬於gitlab-server的工人,能夠共享給全部的項目調遣。
這兩種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的難點,大致流程上都曉得有個持續集成、持續部署,講起來如數家珍,落地時都之乎者也。
一樣,秉承微服務的思想,分而治之,咱們將管道分爲兩個部分:建立、更新,即先建立一個主板次,而後再基於此主板次進行小版本迭代,不斷地擴展新功能。經過這樣有效的拆分,是否是就不那麼的空洞了,就像領域驅動設計的CQRS模式同樣,區別地對待讀寫,從而大大地減小了阻抗,也很是地切合產品的創新迭代,好比將需求拆分爲3期,每一期都對應一個主版次,而後再小版本迭代每一期的需求,完成一期,封板一期,彼此隔離,互補影響,同時也方便追溯。
理清了整個管道的脈絡,如今就須要思考一些實際問題了,好比:
1. 如何將持續集成/部署微服務流程腳本化,即如何實現基礎設施代碼化?
2. 如何動態解析git當前變化日誌,實現準確地按需發佈微服務?
3. 如何保留現場,並以最小的成本重試管道?
4. 在不修改管道腳本的狀況下,如何手工控制按需發佈、自動伸縮和回滾微服務?
5. 如何兼容新增的微服務?
6. 如何快速調試整個管道腳本?
只有把上面的問題都處理了,纔算是一條成熟可用的、企業級別的CI/CD管道,才符合高度自動化、穩定、快速、容錯等特色;在互聯網公司,可能一天要提交好幾個版本到不一樣的環境,不能由於考慮不周而影響連續部署的進度,管道一旦投入使用就須要對修改閉合,只對擴展開放。
管道一覽圖:
示例項目(AspnetCore)已分享到github,請參考:MicroService.AutoDevOpsPipeLines,歡迎start,歡迎fork,歡迎issue。
爲了驗證管道的特性,我特地作了如下測試:
這是一個從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。
將剛剛建立的helm模板文件上傳到gitlab-runner所在服務器的/root目錄下,並添加配置,以下:
<Project> <PropertyGroup> <Major>1</Major> <Minor>0</Minor> <Patch>0</Patch> </PropertyGroup> </Project>
而後合併代碼到分支release/staging,以下:
從上面能夠,第一個主板次(1.0.0)已經成功發佈到預生產環境。
生產環境同理,在預生產環境跑完各類測試後,合併代碼到分支release/production便可。
這個階段將模擬在第一個主板次(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便可。
通過一段時間的觀察發現預生產環境的購物車(Basket.API)微服務吞吐量頗高,故決定擴容它的實例數量到2個,首先修改項目屬性文件deploy.props,以下:
<Replicas>2</Replicas>
而後添加配置,以下:
最後合併代碼到分支scaling/staging,以下:
同理,首先修改項目屬性文件deploy.props,以下:
<Replicas>2</Replicas>
而後添加配置,以下:
最後合併代碼到分支scaling/staging,或者直接重試管道的auto-scaling階段,以下:
從上面測試看到,只須要修改配置,就能夠支持不一樣粒度地伸縮微服務,也不用修改CI/CD管道腳本。
生產環境同理,只須要合併代碼到分支scaling/production。
通過一段時間的觀察,發現剛剛發佈到預生產環境的版本1.0.1有問題,故決定回滾到上一個版次1.0.0,首先修改項目屬性文件deploy.props,以下:
<!--回滾步長--> <RollBackStep>1</RollBackStep>
而後添加配置(只回滾購物車微服務),以下:
最後合併代碼到分支rollback/staging,以下:
同理,首先修改項目屬性文件deploy.props,以下:
<!--回滾步長--> <RollBackStep>1</RollBackStep>
而後添加配置回滾全部微服務,以下:
最後合併代碼到分支rollback/staging,或者直接重試管道的roll-back階段,以下:
生產環境同理,只須要合併代碼到分支rollback/production。
通過一段時間的迭代,一期已經完工,二期新增了搜索微服務,這時修改helm模板文件支持部署搜索微服務,而後合併代碼到release/staging,測試以下:
k8s
網關路由
從上面能夠看到,新增的搜索微服務已經成功發佈到第二個主版次了。除了修改helm模板文件之外,整個過程並無修改CI/CD管道腳本,圓滿完成了兼容新增微服務的特性。
備註:咱們能夠將helm模板當作服務編排文件。
build
構建和編譯代碼。
release/staging
建立預生產環境。
staging
滾動更新預生產環境。
release/production
建立生產環境。
master
滾動更新生產環境。
scaling/staging
伸縮預生產環境
scaling/production
伸縮生產環境
rollback/staging
回滾預生產環境
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實踐微服務的方方面面。
若是有什麼疑問和看法,歡迎評論區交流。
若是你以爲本篇文章對您有幫助的話,感謝您的【推薦】。
若是你對微服務實踐感興趣的話能夠關注我,我會按期的在博客分享個人學習心得。
歡迎轉載,請在明顯位置給出出處及連接。