沪江基于容器编排的Dev/Ops流程
生活随笔
收集整理的這篇文章主要介紹了
沪江基于容器编排的Dev/Ops流程
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
【編者的話】我們整個 DevOps 流程是建立在容器編排的基礎上的,目的是簡化流程和實現自動化 CI/CD 和自動化運維。當中會有很多沒有想到的地方,可能也不太適用于復雜場景。
本文講的是滬江基于容器編排的Dev/Ops流程隨著 DevOps 和 SRE 概念的流行,越來越多的 developer 和 operater 們摒棄傳統的開發部署流程,轉向了如下圖所示的無線循環模式:
在我理解 DevOps 包含三個大塊:敏捷開發(Agile)、持續集成與交付(CI/CD)、自動運維(ITSM)。?
在容器化的時代,我們是如何實現 DepOps 或者 SRE 的呢?下面我就來分享一下滬江學習產品線團隊基于容器編排的 DevOps 流程。
FROM?java:8-jre-alpine
使用上述 Dockerfile 生成的鏡像平均只有 80 多 MB,啟動時間幾乎在 5 秒內。使用 Alpine 鏡像雖然減小了體積,但缺少一些工具命令,例如 curl 等,可以根據需要酌情安裝。另外遇到的一個坑是時區問題:由于 Docker 鏡像內的時區是 UTC 時間,和宿主機的東 8 區不一致,所以必須安裝 timezone 工具并設置 TZ,才能使容器內時間和宿主機保持一致,對數據庫的寫入和日志的輸出都是非常必要的一環。
這里我們還要介紹一個概念,要讓制作的鏡像,能在所有安裝了 Docker 的服務器上運行,而不在乎宿主機的操作系統及環境。借用 Java 的一句話來說:一次制作,多平臺運行。所以,我們還會把所有環境的配置文件,以不同的文件名全部放入鏡像中,通過參數來選擇 Docker 啟動時使用的環境配置文件。
值得注意的是,如果開發的應用是基于 Spring 框架的話,這個功能很好實現。但如果是其他語言開發,會有一定的開發量。
本文以默認 Java 開發當所有的開發工作完成后,推薦程序目錄結構是這樣的:
│???├──?main │???│???├──?java │???│???├──?resources │???│???│???├──?application.yaml │???│???│???├──?application-dev.yaml │???│???│???├──?application-qa.yaml │???│???│???├──?application-yz.yaml │???│???│???├──?application-prod.yaml │???│???│???├──?logback.xml │???├──?test ├──?scripts │???├──?Dockerfile │???├──?InitDB.sql ├──?pom.xml?
如何減少人工參與到持續集成與持續交付呢?我們最希望的開發過程是:對著計算機說出我們的想要的功能,計算機按照套路,自動編碼,自動發布到測試環境,自動運行測試腳本,自動上線。當然,目前時代要實現自動編碼的過程還需要發明那只「貓」。
但只要對測試有足夠信心,我們完全可以實現一種境界:在炎熱的下午,輕松地提交自己編寫的代碼,去休息室喝杯咖啡,回來后看見自己的代碼已經被應用在生產環境上了。在容器時代,我們可以很快速的實現這一夢想,其具體步驟如下圖:
Gitflow 給我們展示了復雜團隊在處理不通代碼版本的優雅解決方案,它需要feature、develop、release、hotfix、master 5 條分支來處理不同時段的并行開發。但這真的合適于一個不超過 20 人的本地合作團隊開發嗎?我們的開發團隊不足 6 人,每個人負責 3 個以上的微服務,幾乎不可能在同個項目上安排兩個以上的同學并行開發。
在初期我們準守規定并使用標準的 Gitflow 流程,開發人員立刻發現一個問題,他們需要在至少 3 條分支上來回的 merge 代碼,且不會有任何代碼沖突(因為就一個人開發),降低了開發的效率。這讓我意識到,Gitflow 模式也許并不適合于小團隊微服務的世界,一種反 Gitflow 模式的想法出現在腦海中。我決定對Gitflow 進行瘦身,化繁至簡。
我們把 5 條分支簡化為 3 條分支,其中 Master 分支的作用只是維護了最新的線上版本的作用,Dev 分支為開發的主要分支,所有的鏡像是以此分支的代碼為源頭生成的。這時開發的過程變為:
如此一來,只有從 Feature 把代碼 merge 到 Dev 分支的一次 merge 動作,大大提升可開發效率。
工欲善其事必先利其器,首先我們必須要在 Jenkins 上安裝插件 :
Pipeline Plugin(如果使用Jenkins2.0默認安裝) Git Sonar Scaner Docker Pipeline Plugin Marathon
如果你第一次接觸 Jenkins Pipeline,可以從https://github.com/jenkinsci/p ... AL.md找到幫助。
現在,我們開始編寫 Groove 代碼。基于容器編排的 Pipeline 分為如下幾個步驟:
1、檢出代碼
這個步驟使用 Git 插件,把開發好的代碼檢出。
stage('Check?out') gitUrl?=?"git@gitlab.xxxx.com:xxx.git" git?branch:?"dev",?changelog:?false,?credentialsId:?"deploy-key",?url:?gitUrl?
2、Maven 構建 Java 代碼
由于我們使用的是 Spring Boot 框架,生成物應該是一個可執行的 jar 包。
stage('Build') sh?"${mvnHome}/bin/mvn?-U?clean?install"
3、靜態代碼分析
通過 Sonar Scaner 插件,通知 Sonar 對代碼庫進行靜態掃描。
stage('SonarQube?analysis') //?requires?SonarQube?Scanner?2.8+ def?scannerHome?=?tool?'SonarQube.Scanner-2.8'; withSonarQubeEnv('SonarQube-Prod')?{sh?"${scannerHome}/bin/sonar-scanner?-e?-Dsonar.links.scm=${gitUrl}?-Dsonar.sources=.?-Dsonar.test.exclusions=file:**/src/test/java/**?-Dsonar.exclusions=file:**/src/test/java/**?-Dsonar.language=java?-Dsonar.projectVersion=1.${BUILD_NUMBER}?-Dsonar.projectKey=lms-barrages?-Dsonar.projectDescription=0000000-00000?-Dsonar.java.source=8?-Dsonar.projectName=xxx" }?
4、制作 Docker 鏡像
此步驟會調用 Docker Pipeline 插件通過預先寫好的 Dockerfile,把 jar 包和配置文件、三方依賴包一起打入 Docker 鏡像中,并上傳到私有 Docker 鏡像倉庫中。
stage('Build?image') docker.withRegistry('https://dockerhub.xxx.com',?'dockerhub-login')?{ docker.build('dockerhub.xxx.com/xxxx').push('test')?//test是tag名稱 }?
5、部署測試環境
通過事先寫好的部署文件,用 Marathon 插件通知 Marathon 集群,在測試環境中部署生成好的鏡像。
stage('Deploy?on?Test') sh?"mkdir?-pv?deploy" dir("./deploy")?{git?branch:?'dev',?changelog:?false,?credentialsId:?'deploy-key',?url:?'git@gitlab.xxx.com:lms/xxx-deploy.git'//Get?the?right?marathon?urlmarathon_url="http://marathon-qa"marathon?docker:?imageName,?dockerForcePull:?true,?forceUpdate:?true,?url:?marathon_url,?filename:?"qa-deploy.json" }?
6、自動化測試
運行事先測試人員寫好的自動化測試腳本來檢驗程序是否運行正常。
stage('Test') //?下載測試用例代碼 git?branch:?'dev',?changelog:?false,?credentialsId:?'deploy-key',?url:?'git@gitlab.xxx.com:lms/xxx-test.git' parallel(autoTests:?{//?使用nosetests?運行測試用例sh?"docker?run?-it?--rm?-v?$PWD:/code?nosetests?nosetests?-s?-v?-c?conf\run\api_test.cfg?--attr?safeControl=1" },manualTests:{sleep?30000 })?
7、人工測試
如果對自動化測試不放心,此時可選擇結束 Pipeline,進行人工測試。為了說明整個流程,我們這里選擇跳過人工測試環節。
8、部署生產環境
當所有測試通過后,Pipeline 自動發布生產環境。
stage('Deploy?on?Prod') input?"Do?tests?OK?" dir("./deploy")?{//Get?the?right?marathon?urlmarathon_url="http://marathon-prod"marathon?docker:?imageName,?dockerForcePull:?true,?forceUpdate:?true,?url:?marathon_url,?filename:?"prod-deploy.json" }?
最后我們來看看整個 Pipeline 的過程:
下面我們就來介紹一下容器編排的配置文件。由于我們使用 Mesos+Marathon的容器編排方式,部署的重任從以前的寫部署腳本變成了寫一個 Marathon 的配置,其內容如下:
{ "id":?"/appName", "cpus":?2, "mem":?2048.0, "instances":?2, "args":?[ "--spring.profiles.active=qa" ], "labels":?{ "HAPROXY_GROUP":?"external", "HAPROXY_0_VHOST":?"xxx.hujiang.com" }, "container":?{ "type":?"DOCKER", "docker":?{"image":?"imageName","network":?"USER","forcePullImage":?true,"portMappings":?[{"containerPort":?12345,"hostPort":?0,"protocol":?"tcp","servicePort":?12345}] }, "volumes":?[{"containerPath":?"/app/log","hostPath":?"/home/logs/appName","mode":?"RW"} ] }, "ipAddress":?{ "networkName":?"calico-net" }, "healthChecks":?[ {"gracePeriodSeconds":?300,"ignoreHttp1xx":?true,"intervalSeconds":?20,"maxConsecutiveFailures":?3,"path":?"/health_check","portIndex":?0,"protocol":?"HTTP","timeoutSeconds":?20 } ], "uris":?[ "file:///etc/docker.tar.gz" ] }?
我們把這個配置內容保存為不同的 Json 文件,每個對應的環境都有一套配置文件。例如 Marathon-qa.json,Marathon-prod.json。當 Pipeline 部署時,可以通過Jenkins Marathon 插件,根據選擇不同的環境,調用部署配置,從而達到自動部署的目的。
但風險過大,我們并不是每個人都能像 Rambo 一樣 bug 的存在,大多數的情況還需要使用規范和流程來約束。就像自動化測試取代不了人工黑盒測試一樣,部署測試后也不能直接上生產環境,在測試通過后還是需要有個人工確認和部署生產的過程。
所以我們需要把自動化流程和最后的部署上線工作分開來,分別變成兩個 Job,并給后者單獨分配權限,讓有權限的人來做最后的部署工作。這個人可以是 Team leader、開發經理,也可以是運維伙伴,取決于公司的組織結構。
那這個部署的 Job 具體干什么呢?在容器編排時代,結合鏡像既構建物的思想,部署 Job 不會從代碼編譯開始工作,而是把一個充分測試且通過的鏡像版本,通過 Marathon Plugin 部署到產線環境中去。這里是 Deploy_only 的例子:
node('docker-qa'){ if?(ReleaseVersion?==""){echo?"發布版本不能為空"return } stage?"Prepare?image"def?moduleName?=?"${ApplicationModule}".toLowerCase()def?resDockerImage?=?imageName?+?":latest"def?desDockerImage?=?imageName?+?":${ReleaseVersion}"if?(GenDockerVersion?=="true"){sh?"docker?pull?${resDockerImage}"sh?"docker?tag?${resDockerImage}?${desDockerImage}"sh?"docker?push?${desDockerImage}"sh?"docker?rmi?-f?${resDockerImage}?${desDockerImage}"}stage?"Deploy?on?Mesos"git?branch:?'dev',?changelog:?false,?credentialsId:?'deploy-key',?url:?'git@gitlab.xxx.com:lms/xxx-test.git'??//Get?the?right?marathon?urlecho?"DeployDC:?"?+?DeployDCmarathon_url?=?""if?(DeployDC=="AA")?{if?(DeployEnv?==?"prod"){input?"Are?you?sure?to?deploy?to?production?"marathon_url?=?"${marathon_AA_prod}"}else?if?(DeployEnv?==?"yz")?{marathon_url?=?"${marathon_AA_yz}"}}else?if?("${DeployDC}"=="BB"){if?("${DeployEnv}"?==?"prod"){input?"Are?you?sure?to?deploy?to?production?"marathon_url?=?"${marathon_BB_prod}"}else?if?("${DeployEnv}"?==?"yz")?{marathon_url?=?"${marathon_BB_yz}"}}marathon?docker:?imageName,?dockerForcePull:?true,?forceUpdate:?true,?url:?marathon_url,?filename:?"${DeployEnv}-deploy.json" }?
為什么不把這個文件跟隨應用項目一起放到 scripts 下呢?因為把部署和應用分開后,可以由兩撥人進行維護,兼顧公司的組織架構。
在我們團隊目前使用 cAdvisor + InfluxDB + Grafana 的組合套件實現對容器的監控。
首先需要在 Mesos 集群中所有的 Agent 安裝 cAdvisor 。他負責把宿主機上所有運行中的容器數據以數據點(data point)形式發送給時序數據庫(InfluxDB),下面是 cAdvisor 監控的一些數據點:
這些數據點經過 Grafana 整理,展示在界面上,這樣我們就能掌握具體容器的性能指標了。下面是一個 Grafana 的截圖:
除了對容器本身的監控,宿主機的監控也是必不可少的。由于監控的點有很多,這里不一一例舉。
本文講的是滬江基于容器編排的Dev/Ops流程隨著 DevOps 和 SRE 概念的流行,越來越多的 developer 和 operater 們摒棄傳統的開發部署流程,轉向了如下圖所示的無線循環模式:
在我理解 DevOps 包含三個大塊:敏捷開發(Agile)、持續集成與交付(CI/CD)、自動運維(ITSM)。?
在容器化的時代,我們是如何實現 DepOps 或者 SRE 的呢?下面我就來分享一下滬江學習產品線團隊基于容器編排的 DevOps 流程。
敏捷開發
大道至簡,所有血的教訓告訴我們,不要把簡單的事情復雜化。換句話說,不要用復雜的方法處理簡單的事情。我對敏捷的理解是「快」和「微」。快指迭代快,開發快,上線快,性能快。微指微服務、微鏡像。圍繞這兩點,在開發階段我們需要做以下幾件事:應用微服務化
這是個比較大的概念,不在這里討論,有興趣可以參考我的其他文章。但只有應用小了,才有可能快起來。給 Docker 鏡像瘦身
為了讓 Docker 啟動和運行得快,首先就是要對 Docker 瘦身。由于所有的應用全部會統一為 Java 語言開發,所以我們以 Java 為例,選用了 jre-alpine 作為我們的基礎鏡像,下面是 Dockerfile 的例子:FROM?java:8-jre-alpine
add timezone and default it to Shanghai
RUN?apk?--update?add?--no-cache?tzdata ENV?TZ=Asia/Shanghai RUN?mkdir?-p?/app/log COPY??./target/xxx.jar??/app/xxx.jar EXPOSE?9999 VOLUME?["/app/log"] WORKDIR?/app/ ENTRYPOINT?["java","-Xms2048m",?"-Xmx2048m",?"-Xss512k",?"-jar","xxx.jar"] CMD?[]?使用上述 Dockerfile 生成的鏡像平均只有 80 多 MB,啟動時間幾乎在 5 秒內。使用 Alpine 鏡像雖然減小了體積,但缺少一些工具命令,例如 curl 等,可以根據需要酌情安裝。另外遇到的一個坑是時區問題:由于 Docker 鏡像內的時區是 UTC 時間,和宿主機的東 8 區不一致,所以必須安裝 timezone 工具并設置 TZ,才能使容器內時間和宿主機保持一致,對數據庫的寫入和日志的輸出都是非常必要的一環。
把所有環境配置包含在鏡像中
早在虛擬機時代,我們已經做到了使用包含依賴的虛擬機鏡像來加速部署,那么為什么要止步于此呢?我們可以更進一步,把服務本身也包含在鏡像中,Docker 用了更輕量的方式已經實現了這一點。這里我們還要介紹一個概念,要讓制作的鏡像,能在所有安裝了 Docker 的服務器上運行,而不在乎宿主機的操作系統及環境。借用 Java 的一句話來說:一次制作,多平臺運行。所以,我們還會把所有環境的配置文件,以不同的文件名全部放入鏡像中,通過參數來選擇 Docker 啟動時使用的環境配置文件。
值得注意的是,如果開發的應用是基于 Spring 框架的話,這個功能很好實現。但如果是其他語言開發,會有一定的開發量。
本文以默認 Java 開發當所有的開發工作完成后,推薦程序目錄結構是這樣的:
│???├──?main │???│???├──?java │???│???├──?resources │???│???│???├──?application.yaml │???│???│???├──?application-dev.yaml │???│???│???├──?application-qa.yaml │???│???│???├──?application-yz.yaml │???│???│???├──?application-prod.yaml │???│???│???├──?logback.xml │???├──?test ├──?scripts │???├──?Dockerfile │???├──?InitDB.sql ├──?pom.xml?
持續集成與交付
自動化的持續集成和交付在整個 DevOps 流中起了重要的角色,他是銜接開發和運維的橋梁。如果這一環做的不好,無法支撐大量微服務的快速的迭代和高效運維。在這一環節,我們需要靈活的運用工具,盡量減少人參與,當然仍然需要圍繞「快」和「微」做文章。如何減少人工參與到持續集成與持續交付呢?我們最希望的開發過程是:對著計算機說出我們的想要的功能,計算機按照套路,自動編碼,自動發布到測試環境,自動運行測試腳本,自動上線。當然,目前時代要實現自動編碼的過程還需要發明那只「貓」。
但只要對測試有足夠信心,我們完全可以實現一種境界:在炎熱的下午,輕松地提交自己編寫的代碼,去休息室喝杯咖啡,回來后看見自己的代碼已經被應用在生產環境上了。在容器時代,我們可以很快速的實現這一夢想,其具體步驟如下圖:
Gitfolw 與 Anti-Gitflown
持續集成的第一步是提交代碼(Code Commit),VCS 也由 CVS,SVN 進化到如今的 Git,自然不得不說一下 Gitflow。談起無人不曉的 Gitflow,大家一定會大談其優點:支持多團隊,設置多國家的開發人員并行開發,減小代碼沖突或臟代碼的上線概率。它的大致流程如下:Gitflow 給我們展示了復雜團隊在處理不通代碼版本的優雅解決方案,它需要feature、develop、release、hotfix、master 5 條分支來處理不同時段的并行開發。但這真的合適于一個不超過 20 人的本地合作團隊開發嗎?我們的開發團隊不足 6 人,每個人負責 3 個以上的微服務,幾乎不可能在同個項目上安排兩個以上的同學并行開發。
在初期我們準守規定并使用標準的 Gitflow 流程,開發人員立刻發現一個問題,他們需要在至少 3 條分支上來回的 merge 代碼,且不會有任何代碼沖突(因為就一個人開發),降低了開發的效率。這讓我意識到,Gitflow 模式也許并不適合于小團隊微服務的世界,一種反 Gitflow 模式的想法出現在腦海中。我決定對Gitflow 進行瘦身,化繁至簡。
我們把 5 條分支簡化為 3 條分支,其中 Master 分支的作用只是維護了最新的線上版本的作用,Dev 分支為開發的主要分支,所有的鏡像是以此分支的代碼為源頭生成的。這時開發的過程變為:
- 開發人員從 Dev 分支中 checkout 新的 feature 分支,在 feature 分支上進行開發
- 當開發完成后 merge 回 Dev 分支中,根據 Dev 分支的代碼打成鏡像,部署 QA 環境交給 QA 人員測試
- 測試中如有 bug 便在新分支中修復問題循環步驟 2
- 測試完成 merge 回 Master 分支
如此一來,只有從 Feature 把代碼 merge 到 Dev 分支的一次 merge 動作,大大提升可開發效率。
使用Jenkins Pipeline
Jenkins 作為老牌 CI/CD 工具,能夠幫我們自動化完成代碼編譯、上傳靜態代碼分析、制作鏡像、部署測試環境、冒煙測試、部署上線等步驟。尤其是Jenkins 2.0 引入 Pipeline 概念后,以上步驟變的如此行云流水。它讓我們從步驟 3 開始,完全可以無人值守完成整個集成和發布過程。工欲善其事必先利其器,首先我們必須要在 Jenkins 上安裝插件 :
如果你第一次接觸 Jenkins Pipeline,可以從https://github.com/jenkinsci/p ... AL.md找到幫助。
現在,我們開始編寫 Groove 代碼。基于容器編排的 Pipeline 分為如下幾個步驟:
1、檢出代碼
這個步驟使用 Git 插件,把開發好的代碼檢出。
stage('Check?out') gitUrl?=?"git@gitlab.xxxx.com:xxx.git" git?branch:?"dev",?changelog:?false,?credentialsId:?"deploy-key",?url:?gitUrl?
2、Maven 構建 Java 代碼
由于我們使用的是 Spring Boot 框架,生成物應該是一個可執行的 jar 包。
stage('Build') sh?"${mvnHome}/bin/mvn?-U?clean?install"
3、靜態代碼分析
通過 Sonar Scaner 插件,通知 Sonar 對代碼庫進行靜態掃描。
stage('SonarQube?analysis') //?requires?SonarQube?Scanner?2.8+ def?scannerHome?=?tool?'SonarQube.Scanner-2.8'; withSonarQubeEnv('SonarQube-Prod')?{sh?"${scannerHome}/bin/sonar-scanner?-e?-Dsonar.links.scm=${gitUrl}?-Dsonar.sources=.?-Dsonar.test.exclusions=file:**/src/test/java/**?-Dsonar.exclusions=file:**/src/test/java/**?-Dsonar.language=java?-Dsonar.projectVersion=1.${BUILD_NUMBER}?-Dsonar.projectKey=lms-barrages?-Dsonar.projectDescription=0000000-00000?-Dsonar.java.source=8?-Dsonar.projectName=xxx" }?
4、制作 Docker 鏡像
此步驟會調用 Docker Pipeline 插件通過預先寫好的 Dockerfile,把 jar 包和配置文件、三方依賴包一起打入 Docker 鏡像中,并上傳到私有 Docker 鏡像倉庫中。
stage('Build?image') docker.withRegistry('https://dockerhub.xxx.com',?'dockerhub-login')?{ docker.build('dockerhub.xxx.com/xxxx').push('test')?//test是tag名稱 }?
5、部署測試環境
通過事先寫好的部署文件,用 Marathon 插件通知 Marathon 集群,在測試環境中部署生成好的鏡像。
stage('Deploy?on?Test') sh?"mkdir?-pv?deploy" dir("./deploy")?{git?branch:?'dev',?changelog:?false,?credentialsId:?'deploy-key',?url:?'git@gitlab.xxx.com:lms/xxx-deploy.git'//Get?the?right?marathon?urlmarathon_url="http://marathon-qa"marathon?docker:?imageName,?dockerForcePull:?true,?forceUpdate:?true,?url:?marathon_url,?filename:?"qa-deploy.json" }?
6、自動化測試
運行事先測試人員寫好的自動化測試腳本來檢驗程序是否運行正常。
stage('Test') //?下載測試用例代碼 git?branch:?'dev',?changelog:?false,?credentialsId:?'deploy-key',?url:?'git@gitlab.xxx.com:lms/xxx-test.git' parallel(autoTests:?{//?使用nosetests?運行測試用例sh?"docker?run?-it?--rm?-v?$PWD:/code?nosetests?nosetests?-s?-v?-c?conf\run\api_test.cfg?--attr?safeControl=1" },manualTests:{sleep?30000 })?
7、人工測試
如果對自動化測試不放心,此時可選擇結束 Pipeline,進行人工測試。為了說明整個流程,我們這里選擇跳過人工測試環節。
8、部署生產環境
當所有測試通過后,Pipeline 自動發布生產環境。
stage('Deploy?on?Prod') input?"Do?tests?OK?" dir("./deploy")?{//Get?the?right?marathon?urlmarathon_url="http://marathon-prod"marathon?docker:?imageName,?dockerForcePull:?true,?forceUpdate:?true,?url:?marathon_url,?filename:?"prod-deploy.json" }?
最后我們來看看整個 Pipeline 的過程:
容器編排配置文檔化
在介紹敏捷開發時,曾介紹過根據不同環境的配置參數部署到不同的環境。如何告知部署程序用什么樣的配置文件啟動服務,每個環境又用多少 CPU,內存和 instance 呢?下面我們就來介紹一下容器編排的配置文件。由于我們使用 Mesos+Marathon的容器編排方式,部署的重任從以前的寫部署腳本變成了寫一個 Marathon 的配置,其內容如下:
{ "id":?"/appName", "cpus":?2, "mem":?2048.0, "instances":?2, "args":?[ "--spring.profiles.active=qa" ], "labels":?{ "HAPROXY_GROUP":?"external", "HAPROXY_0_VHOST":?"xxx.hujiang.com" }, "container":?{ "type":?"DOCKER", "docker":?{"image":?"imageName","network":?"USER","forcePullImage":?true,"portMappings":?[{"containerPort":?12345,"hostPort":?0,"protocol":?"tcp","servicePort":?12345}] }, "volumes":?[{"containerPath":?"/app/log","hostPath":?"/home/logs/appName","mode":?"RW"} ] }, "ipAddress":?{ "networkName":?"calico-net" }, "healthChecks":?[ {"gracePeriodSeconds":?300,"ignoreHttp1xx":?true,"intervalSeconds":?20,"maxConsecutiveFailures":?3,"path":?"/health_check","portIndex":?0,"protocol":?"HTTP","timeoutSeconds":?20 } ], "uris":?[ "file:///etc/docker.tar.gz" ] }?
我們把這個配置內容保存為不同的 Json 文件,每個對應的環境都有一套配置文件。例如 Marathon-qa.json,Marathon-prod.json。當 Pipeline 部署時,可以通過Jenkins Marathon 插件,根據選擇不同的環境,調用部署配置,從而達到自動部署的目的。
自動化流程和部署上線分離與管理
開發部署如此的簡單快捷,是不是每個人都能方便的使用呢?答案是否定的,并不是因為技術上有難度,而是在于權限。在理想的情況下,通過這套流程的確可以做到在提交代碼后,喝杯咖啡的時間就能看見自己的代碼已經被千萬用戶使用了。但風險過大,我們并不是每個人都能像 Rambo 一樣 bug 的存在,大多數的情況還需要使用規范和流程來約束。就像自動化測試取代不了人工黑盒測試一樣,部署測試后也不能直接上生產環境,在測試通過后還是需要有個人工確認和部署生產的過程。
所以我們需要把自動化流程和最后的部署上線工作分開來,分別變成兩個 Job,并給后者單獨分配權限,讓有權限的人來做最后的部署工作。這個人可以是 Team leader、開發經理,也可以是運維伙伴,取決于公司的組織結構。
那這個部署的 Job 具體干什么呢?在容器編排時代,結合鏡像既構建物的思想,部署 Job 不會從代碼編譯開始工作,而是把一個充分測試且通過的鏡像版本,通過 Marathon Plugin 部署到產線環境中去。這里是 Deploy_only 的例子:
node('docker-qa'){ if?(ReleaseVersion?==""){echo?"發布版本不能為空"return } stage?"Prepare?image"def?moduleName?=?"${ApplicationModule}".toLowerCase()def?resDockerImage?=?imageName?+?":latest"def?desDockerImage?=?imageName?+?":${ReleaseVersion}"if?(GenDockerVersion?=="true"){sh?"docker?pull?${resDockerImage}"sh?"docker?tag?${resDockerImage}?${desDockerImage}"sh?"docker?push?${desDockerImage}"sh?"docker?rmi?-f?${resDockerImage}?${desDockerImage}"}stage?"Deploy?on?Mesos"git?branch:?'dev',?changelog:?false,?credentialsId:?'deploy-key',?url:?'git@gitlab.xxx.com:lms/xxx-test.git'??//Get?the?right?marathon?urlecho?"DeployDC:?"?+?DeployDCmarathon_url?=?""if?(DeployDC=="AA")?{if?(DeployEnv?==?"prod"){input?"Are?you?sure?to?deploy?to?production?"marathon_url?=?"${marathon_AA_prod}"}else?if?(DeployEnv?==?"yz")?{marathon_url?=?"${marathon_AA_yz}"}}else?if?("${DeployDC}"=="BB"){if?("${DeployEnv}"?==?"prod"){input?"Are?you?sure?to?deploy?to?production?"marathon_url?=?"${marathon_BB_prod}"}else?if?("${DeployEnv}"?==?"yz")?{marathon_url?=?"${marathon_BB_yz}"}}marathon?docker:?imageName,?dockerForcePull:?true,?forceUpdate:?true,?url:?marathon_url,?filename:?"${DeployEnv}-deploy.json" }?
為什么不把這個文件跟隨應用項目一起放到 scripts 下呢?因為把部署和應用分開后,可以由兩撥人進行維護,兼顧公司的組織架構。
自動化運維
在 DevOps 的最后階段是運維階段。在容器時代,如何對龐大的鏡像制品進行運維呢?我們的目標是盡量實現自動化運維,這里主要講述兩點:容器的監控
容器的監控大致有兩種方式:物理機上安裝其他服務監控本機上的所有容器;通過 Mesos 或 Kubernates 自帶 API 監控容器狀態。兩種方式其實都需要在物理機上安裝相應的監控軟件或 Agent。在我們團隊目前使用 cAdvisor + InfluxDB + Grafana 的組合套件實現對容器的監控。
首先需要在 Mesos 集群中所有的 Agent 安裝 cAdvisor 。他負責把宿主機上所有運行中的容器數據以數據點(data point)形式發送給時序數據庫(InfluxDB),下面是 cAdvisor 監控的一些數據點:
這些數據點經過 Grafana 整理,展示在界面上,這樣我們就能掌握具體容器的性能指標了。下面是一個 Grafana 的截圖:
除了對容器本身的監控,宿主機的監控也是必不可少的。由于監控的點有很多,這里不一一例舉。
自動伸縮
有了監控指標只是實現了自動化運維的第一步,當業務請求發生大量增加或減少,通過人工監測是不能及時的進行相應的,況且還不一定有那么多的人,7×24 小時的監控。一定需要有一套根據監控數據自行伸縮容的機制。在學習產品線,我們針對容器編排的 Mesos+Marathon 框架,開發了一套針對應用本身的自動擴容微服務。其原理如下:- 通過 Restful 的接口通知 AutoScaler 程序需要監控的應用服務。
- AutoScaler 程序開始讀取每臺 Agent 上部署相關應用的 Metrics 數據,其中包括 CPU,內存的使用狀況。
- 當發現有應用過于繁忙(其表現形式大多是 CPU 占用過高或內存占用過大)時調用 Marathon API 將其擴容
- Marathon 收到消息后,立刻通知 Mesos 集群發布新的應用,從而緩解當前的繁忙狀況。
結束語
DevOps 和 SRE 并不是一個渴望而不可及的概念,它們需要在不同的環境中落地。我們整個 DevOps 流程是建立在容器編排的基礎上的,目的是簡化流程和實現自動化 CI/CD 和自動化運維。當中會有很多沒有想到的地方,可能也不太適用于復雜場景。其次,本文中的例子也做了相應的隱私處理,可能無法直接使用。希望大家能通過我們在實踐中產生的成功和遇到的問題,提煉出適合自己的 DevOps 流程。原文鏈接:基于容器編排的Dev/Ops流程(作者:黃凱)
原文發布時間為:2017-10-01
本文作者:黃凱
本文來自云棲社區合作伙伴Dockerone.io,了解相關信息可以關注Dockerone.io。
原文標題:滬江基于容器編排的Dev/Ops流程
總結
以上是生活随笔為你收集整理的沪江基于容器编排的Dev/Ops流程的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 保证java的jar包在后台运行
- 下一篇: Java NIO系列教程(三) Buff