摘要:近期在按照業(yè)務(wù)劃分項目時,我們組被分了好多的項目過來,大量的是基于的,也是我們組持續(xù)在使用的語言。部署環(huán)境強依賴本地,因為需要在本地建立倉庫的臨時目錄,并經(jīng)過多次的方式完成部署上線的操作。
近期在按照業(yè)務(wù)劃分項目時,我們組被分了好多的項目過來,大量的是基于 Node.js 的,也是我們組持續(xù)在使用的語言。現(xiàn)有流程中的一些問題
在維護多個項目的時候,會暴露出一些問題:
如何有效的使用 測試用例
如何有效的使用 ESLint
部署上線還能再快一些嗎
使用了 TypeScript 以后帶來的額外成本
測試用例首先是測試用例,最初我們設(shè)計在了 git hooks 里邊,在執(zhí)行 git commit 之前會進行檢查,在本地運行測試用例。
這會帶來一個時間上的問題,如果是日常開發(fā),這么操作還是沒什么問題的,但如果是線上 bug 修復(fù),執(zhí)行測試用例的時間依據(jù)項目大小可能會持續(xù)幾分鐘。
而為了修復(fù) bug,可能會采用 commit 的時候添加 -n 選項來跳過 hooks ,在修復(fù) bug 時這么做無可厚非,但是即使大家在日常開發(fā)中都采用commit -n 的方式來跳過繁瑣的測試過程,這個也是沒有辦法管控的,畢竟是在本地做的這個校驗,是否遵循這個規(guī)則,全靠大家自覺。
所以一段時間后發(fā)現(xiàn),通過這種方式執(zhí)行測試用例來規(guī)避一些風(fēng)險的作用可能并不是很有效。
ESLint然后就是 ESLint,我們團隊基于airbnb的 ESLint 規(guī)則自定義了一套更符合團隊習(xí)慣的規(guī)則,我們會在編輯器中引入插件用來幫助高亮一些錯誤,以及進行一些自動格式化的操作。
同時我們也在 git hooks 中添加了對應(yīng)的處理,也是在 git commit 的時候進行檢查,如果不符合規(guī)范則不允許提交。
不過這個與測試用例是相同的問題:
編輯器是否安裝 ESLint 插件無從得知,即使安裝插件、是否人肉忽略錯誤提示也無從得知。
git hooks 可以被繞過
部署上線的方式之前團隊的部署上線是使用shipit周邊套件進行部署的。
部署環(huán)境強依賴本地,因為需要在本地建立倉庫的臨時目錄,并經(jīng)過多次ssh XXX "command"的方式完成 部署 + 上線 的操作。
shipit提供了一個有效的回滾方案,就是在部署后的路徑添加多個歷史部署版本的記錄,回滾時將當(dāng)前運行的項目目錄指向之前的某個版本即可。_不過有一點兒坑的是,很難去選擇我要回滾到那個節(jié)點,以及保存歷史記錄需要占用額外的磁盤空間_
不過正因為如此,shipit在部署多臺服務(wù)器時會遇到一些令人不太舒服的地方。
如果是多臺新增的服務(wù)器,那么可以通過在shipit配置文件中傳入多個目標服務(wù)器地址來進行批量部署。
但是假設(shè)某天需要上線一些小流量(比如四臺機器中的一臺),因為前邊提到的shipit回滾策略,這會導(dǎo)致單臺機器與其他三臺機器的歷史版本時間戳不一致(因為這幾臺機器不是同一時間上線的)
提到了這個時間戳就另外提一嘴,這個時間戳的生成是基于執(zhí)行上線操作的那臺機器的本地時間,之前有遇到過同事在本地測試代碼,將時間調(diào)整為了幾天前的時間,后時間沒有改回正確的時間時進行了一次部署操作,代碼出現(xiàn)問題后卻發(fā)現(xiàn)回滾失敗了,原因是該同事部署的版本時間戳太小,shipit 找不到之前的版本(shipit 可以設(shè)置保留歷史版本的數(shù)量,當(dāng)時最早的一次時間戳也是大于本次出問題的時間戳的)
也就是說,哪怕有一次進行過小流量上線,那么以后就用不了批量上線的功能了 (沒有去仔細研究shipit官方文檔,不知道會不會有類似--force之類的忽略歷史版本的操作)
基于上述的情況,我們的部署上線耗時變?yōu)榱耍?(__機器數(shù)量__)X(__基于本地網(wǎng)速的倉庫克隆、多次 ssh 操作的耗時總和__)。 P.S. 為了保證倉庫的有效性,每次執(zhí)行 shipit 部署,它都會刪除之前的副本,重新克隆
尤其是服務(wù)端項目,有時緊急的 bug 修復(fù)可能是在非工作時間,這意味著可能當(dāng)時你所處的網(wǎng)絡(luò)環(huán)境并不是很穩(wěn)定。
我曾經(jīng)晚上接到過同事的微信,讓我?guī)退暇€項目,他家的 Wi-Fi 是某博士的,下載項目依賴的時候出了些問題。
還有過使用移動設(shè)備開熱點的方式進行上線操作,有一次非前后分離的項目上線后,直接就收到了聯(lián)通的短信:「您本月流量已超出XXX」(當(dāng)時還在用合約套餐,一月就800M流量)。
在去年下半年開始,我們團隊就一直在推動 TypeScript 的應(yīng)用,因為在大型項目中,擁有明確類型的 TypeScript 顯然維護性會更高一些。
但是大家都知道的, TypeScript 最終需要編譯轉(zhuǎn)換為 JavaScript(也有 tsc 那種的不生成 JS 文件,直接運行,不過這個更多的是在本地開發(fā)時使用,線上代碼的運行我們還是希望變量越少越好)。
所以之前的上線流程還需要額外的增加一步,編譯 TS。
而且因為shipit是在本地克隆的倉庫并完成部署的,所以這就意味著我們必須要把生成后的 JS 文件也放入到倉庫中,最直觀的,從倉庫的概覽上看著就很丑(50% TS、50% JS),同時這進一步增加了上線的成本。
總結(jié)來說,現(xiàn)有的部署上線流程過于依賴本地環(huán)境,因為每個人的環(huán)境不同,這相當(dāng)于給部署流程增加了很多不可控因素。如何解決這些問題
上邊我們所遇到的一些問題,其實可以分為兩塊:
有效的約束代碼質(zhì)量
快速的部署上線
所以我們就開始尋找解決方案,因為我們的源碼是使用自建的 GitLab 倉庫來進行管理的,首先就找到了 GitLab CI/CD。
在研究了一番文檔以后發(fā)現(xiàn),它能夠很好的解決我們現(xiàn)在遇到的這些問題。
要使用 GitLab CI/CD 是非常簡單的,只需要額外的使用一臺服務(wù)器安裝 gitlab-runner,并將要使用 CI/CD 的項目注冊到該服務(wù)上就可以了。
GitLab 官方文檔中有非常詳細的安裝注冊流程:
install | runner
register | runner
group register | repo 注冊 Group 項目時的一些操作
上邊的注冊選擇的是注冊 group ,也就是整個 GitLab 某個分組下所有的項目。安裝時需要注意的地方
主要目的是因為我們這邊項目數(shù)量太多,單個注冊太過繁瑣(還要登錄到 runner 服務(wù)器去執(zhí)行命令才能夠注冊)
官網(wǎng)的流程已經(jīng)很詳細了,不過還是有一些地方可以做一些小提示,避免踩坑
sudo gitlab-runner install --user=gitlab-runner --working-directory=/home/gitlab-runner
這是 Linux 版本的安裝命令,安裝需要 root (管理員) 權(quán)限,后邊跟的兩個參數(shù):
--user 是 CI/CD 執(zhí)行 job (后續(xù)所有的流程都是基于 job 的)時所使用的用戶名
--working-directory 是 CI/CD 執(zhí)行時的根目錄路徑 個人的踩坑經(jīng)驗是將目錄設(shè)置為一個空間大的磁盤上,因為 CI/CD 會生成大量的文件,尤其是如果使用 CI/CD 進行編譯 TS 文件并且將其生成后的 JS 文件緩存;這樣的操作會導(dǎo)致 innode 不足產(chǎn)生一些問題
--user 的意思就是 CI/CD 執(zhí)行使用該用戶進行執(zhí)行,所以如果要編寫腳本之類的,建議在該用戶登錄的狀態(tài)下編寫,避免出現(xiàn)無權(quán)限執(zhí)行 sudo su gitlab-runner注冊時需要注意的地方
在按照官網(wǎng)的流程執(zhí)行時,我們的 tag 是留空的,暫時沒有找到什么用途。。
以及 executor 這個比較重要了,因為我們是從手動部署上線還是往這邊靠攏的,所以穩(wěn)妥的方式是一步步來,也就是說我們選擇的是 shell ,最常規(guī)的一種執(zhí)行方式,對項目的影響也是比較小的(官網(wǎng)示例給的是 docker )
上邊的環(huán)境已經(jīng)全部裝好了,接下來就是需要讓 CI/CD 真正的跑起來
runner 以哪種方式運行,就靠這個配置文件來描述了,按照約定需要將文件放置到 repo 倉庫的根路徑下。
當(dāng)該文件存在于倉庫中,執(zhí)行 git push 命令后就會自動按照配置文件中所描述的動作進行執(zhí)行了。
quick start
configuration
上邊的兩個鏈接里邊信息非常完整,包含各種可以配置的選項。
一般來講,配置文件的結(jié)構(gòu)是這樣的:
stages: - stage1 - stage2 - stage3 job 1: stage: stage1 script: echo job1 job 2: stage: stage2 script: echo job2 job 3: stage: stage2 script: - echo job3-1 - echo job3-2 job 4: stage: stage3 script: echo job4
stages 用來聲明有效的可被執(zhí)行的 stage,按照聲明的順序執(zhí)行。
下邊的那些 job XXX 名字不重要,這個名字是在 GitLab CI/CD Pipeline 界面上展示時使用的,重要的是那個 stage 屬性,他用來指定當(dāng)前的這一塊 job 隸屬于哪個 stage。
script 則是具體執(zhí)行的腳本內(nèi)容,如果要執(zhí)行多行命令,就像job 3那種寫法就好了。
如果我們將上述的 stage、job 之類的換成我們項目中的一些操作install_dependencies、test、eslint之類的,然后將script字段中的值換成類似npx eslint之類的,當(dāng)你把這個文件推送到遠端服務(wù)器后,你的項目就已經(jīng)開始自動運行這些腳本了。
并且可以在Pipelines界面看到每一步執(zhí)行的狀態(tài)。
P.S. 默認情況下,上一個 stage 沒有執(zhí)行完時不會執(zhí)行下一個 stage 的,不過也可以通過額外的配置來修改:設(shè)置僅在特定的情況下觸發(fā) CI/CD
allow failure
when
上邊的配置文件存在一個問題,因為在配置文件中并沒有指定哪些分支的提交會觸發(fā) CI/CD 流程,所以默認的所有分支上的提交都會觸發(fā),這必然不是我們想要的結(jié)果。
CI/CD 的執(zhí)行會占用系統(tǒng)的資源,如果因為一些開發(fā)分支的執(zhí)行影響到了主干分支的執(zhí)行,這是一件得不償失的事情。
所以我們需要限定哪些分支才會觸發(fā)這些流程,也就是要用到了配置中的 only 屬性。
使用only可以用來設(shè)置哪些情況才會觸發(fā) CI/CD,一般我們這邊常用的就是用來指定分支,這個是要寫在具體的 job 上的,也就是大致是這樣的操作:
具體的配置文檔
job 1: stage: stage1 script: echo job1 only: - master - dev
單個的配置是可以這樣寫的,不過如果 job 的數(shù)量變多,這么寫就意味著我們需要在配置文件中大量的重復(fù)這幾行代碼,也不是一個很好看的事情。
所以這里可能會用到一個yaml的語法:
這是一步可選的操作,只是想在配置文件中減少一些重復(fù)代碼的出現(xiàn)
.access_branch_template: &access_branch only: - master - dev job 1: <<: *access_branch stage: stage1 script: echo job1 job 2: <<: *access_branch stage: stage2 script: echo job2
一個類似模版繼承的操作,官方文檔中也沒有提到,這個只是一個減少冗余代碼的方式,可有可無。
緩存必要的文件因為默認情況下,CI/CD在執(zhí)行每一步(job)時都會清理一下當(dāng)前的工作目錄,保證工作目錄是干凈的、不包含一些之前任務(wù)留下的數(shù)據(jù)、文件。
不過這在我們的 Node.js 項目中就會帶來一個問題。
因為我們的 ESLint、單元測試 都是基于 node_modules 下邊的各種依賴來執(zhí)行的。
而目前的情況就相當(dāng)于我們每一步都需要執(zhí)行npm install,這顯然是一個不必要的浪費。
所以就提到了另一個配置文件中的選項:cache
用來指定某些文件、文件夾是需要被緩存的,而不能清除:
cache: key: ${CI_BUILD_REF_NAME} paths: - node_modules/
大致是這樣的一個操作,CI_BUILD_REF_NAME是一個 CI/CD 提供的環(huán)境變量,該變量的內(nèi)容為執(zhí)行 CI/CD 時所使用的分支名,通過這種方式讓兩個分支之間的緩存互不影響。
部署項目如果基于上邊的一些配置,我們將 單元測試、ESLint 對應(yīng)的腳本放進去,他就已經(jīng)能夠完成我們想要的結(jié)果了,如果某一步執(zhí)行出錯,那么任務(wù)就會停在那里不會繼續(xù)向后執(zhí)行。
不過目前來看,后邊已經(jīng)沒有多余的任務(wù)供我們執(zhí)行了,所以是時候?qū)?部署 這一步操作接過來了。
部署的話,我們目前選擇的是通過 rsync 來進行同步多臺服務(wù)器上的數(shù)據(jù),一個比較簡單高效的部署方式。
P.S. 部署需要額外的做一件事情,就是建立從gitlab runner所在機器gitlab-runner用戶到目標部署服務(wù)器對應(yīng)用戶下的機器信任關(guān)系。
有 N 多種方法可以實現(xiàn),最簡單的就是在runner機器上執(zhí)行 ssh-copy-id 將公鑰寫入到目標機器。
或者可以像我一樣,提前將 runner 機器的公鑰拿出來,需要與機器建立信任關(guān)系時就將這個字符串寫入到目標機器的配置文件中。
類似這樣的操作:ssh 10.0.0.1 "echo "XXX" >> ~/.ssh/authorized_keys"
大致的配置如下:
variables: DEPLOY_TO: /home/XXX/repo # 要部署的目標服務(wù)器項目路徑 deploy: stage: deploy script: - rsync -e "ssh -o StrictHostKeyChecking=no" -arc --exclude-from="./exclude.list" --delete . 10.0.0.1:$DEPLOY_TO - ssh 10.0.0.1 "cd $DEPLOY_TO; npm i --only=production" - ssh 10.0.0.1 "pm2 start $DEPLOY_TO/pm2/$CI_ENVIRONMENT_NAME.json;"
同時用到的還有variables,用來提出一些變量,在下邊使用。
ssh 10.0.0.1 "pm2 start $DEPLOY_TO/pm2/$CI_ENVIRONMENT_NAME.json;",這行腳本的用途就是重啟服務(wù)了,我們使用pm2來管理進程,默認的約定項目路徑下的pm2文件夾存放著個個環(huán)境啟動時所需的參數(shù)。
當(dāng)然了,目前我們在用的沒有這么簡單,下邊會統(tǒng)一提到
并且在部署的這一步,我們會有一些額外的處理
這是比較重要的一點,因為我們可能會更想要對上線的時機有主動權(quán),所以 deploy 的任務(wù)并不是自動執(zhí)行的,我們會將其修改為手動操作還會觸發(fā),這用到了另一個配置參數(shù):
deploy: stage: deploy script: XXX when: manual # 設(shè)置該任務(wù)只能通過手動觸發(fā)的方式運行
當(dāng)然了,如果不需要,這個移除就好了,比如說我們在測試環(huán)境就沒有配置這個選項,僅在線上環(huán)境使用了這樣的操作
更方便的管理 CI/CD 流程如果按照上述的配置文件進行編寫,實際上已經(jīng)有了一個可用的、包含完整流程的 CI/CD 操作了。
不過它的維護性并不是很高,尤其是如果 CI/CD 被應(yīng)用在多個項目中,想做出某項改動則意味著所有的項目都需要重新修改配置文件并上傳到倉庫中才能生效。
所以我們選擇了一個更靈活的方式,最終我們的 CI/CD 配置文件是大致這樣子的(省略了部分不相干的配置):
variables: SCRIPTS_STORAGE: /home/gitlab-runner/runner-scripts DEPLOY_TO: /home/XXX/repo # 要部署的目標服務(wù)器項目路徑 stages: - install - test - build - deploy_development - deploy_production install_dependencies: stage: install script: bash $SCRIPTS_STORAGE/install.sh unit_test: stage: test script: bash $SCRIPTS_STORAGE/test.sh eslint: stage: test script: bash $SCRIPTS_STORAGE/eslint.sh # 編譯 TS 文件 build: stage: build script: bash $SCRIPTS_STORAGE/build.sh deploy_development: stage: deploy_development script: bash $SCRIPTS_STORAGE/deploy.sh 10.0.0.1 only: dev # 多帶帶指定生效分支 deploy_production: stage: deploy_production script: bash $SCRIPTS_STORAGE/deploy.sh 10.0.0.2 only: master # 多帶帶指定生效分支
我們將每一步 CI/CD 所需要執(zhí)行的腳本都放到了 runner 那臺服務(wù)器上,在配置文件中只是執(zhí)行了那個腳本文件。
這樣當(dāng)我們有什么策略上的調(diào)整,比如說 ESLint 規(guī)則的變更、部署方式之類的。
這些都完全與項目之間進行解耦,后續(xù)的操作基本都不會讓正在使用 CI/CD 的項目重新修改才能夠支持(部分需要新增環(huán)境變量的導(dǎo)入之類的確實需要項目的支持)。
實際上,當(dāng) CI/CD 執(zhí)行成功或者失敗,我們可以在 Pipeline 頁面中看到,也可以設(shè)置一些郵件通知,但這些都不是時效性很強的。
鑒于我們目前在使用釘釘進行工作溝通,所以就研究了一波釘釘機器人。
發(fā)現(xiàn)有支持 GitLab 機器人,不過功能并不適用,只能處理一些 issues 之類的, CI/CD 的一些通知是缺失的,所以只好自己基于釘釘?shù)南⒛0鎸崿F(xiàn)一下了。
因為上邊我們已經(jīng)將各個步驟的操作封裝了起來,所以這個修改對同事們是無感知的,我們只需要修改對應(yīng)的腳本文件,添加釘釘?shù)南嚓P(guān)操作即可完成,封裝了一個簡單的函數(shù):
function sendDingText() { local text="$1" curl -X POST "$DINGTALK_HOOKS_URL" -H "Content-Type: application/json" -d "{ "msgtype": "text", "text": { "content": """$text""" } }" } # 具體發(fā)送時傳入的參數(shù) sendDingText "proj: $CI_PROJECT_NAME[$CI_JOB_NAME] env: $CI_ENVIRONMENT_NAME deploy success $CI_PIPELINE_URL created by: $GITLAB_USER_NAME message: $CI_COMMIT_MESSAGE" # 某些 case 失敗的情況下 是否需要更多的信息就看自己自定義咯 sendDingText "error: $CI_PROJECT_NAME[$CI_JOB_NAME] env: $CI_ENVIRONMENT_NAME"
上述用到的環(huán)境變量,除了DINGTALK_HOOKS_URL是我們自定義的機器人通知地址以外,其他的變量都是有 GitLab runenr所提供的。
各種變量可以從這里找到:predefined variables
回滾處理聊完了正常的流程,那么也該提一下出問題時候的操作了。
人非圣賢孰能無過,很有可能某次上線一些沒有考慮到的地方就會導(dǎo)致服務(wù)出現(xiàn)異常,這時候首要任務(wù)就是讓用戶還可以照常訪問,所以我們會選擇回滾到上一個有效的版本去。
在項目中的 Pipeline 頁面 或者 Enviroment 頁面(這個需要在配置文件中某些 job 中手動添加這個屬性,一般會寫在 deploy 的那一步去),可以在頁面上選擇想要回滾的節(jié)點,然后重新執(zhí)行 CI/CD 任務(wù),即可完成回滾。
不過這在 TypeScript 項目中會有一些問題,因為我們回滾一般來講是重新執(zhí)行上一個版本 CI/CD 中的 deploy 任務(wù),在 TS 項目中,我們在 runner 中緩存了 TS 轉(zhuǎn)換 JS 之后的 dist 文件夾,并且部署的時候也是直接將該文件夾推送到服務(wù)器的(TS項目的源碼就沒有再往服務(wù)器上推過了)。
而如果我們直接點擊 retry 就會帶來一個問題,因為我們的 dist 文件夾是緩存的,而 deploy 并不會管這種事兒,他只會把對應(yīng)的要推送的文件發(fā)送到服務(wù)器上,并重啟服務(wù)。
而實際上 dist 還是最后一次(也就是出錯的那次)編譯出來的 JS 文件,所以解決這個問題有兩種方法:
在 deploy 之前執(zhí)行一下 build
在 deploy 的時候進行判斷
第一個方案肯定是不可行的,因為嚴重依賴于操作上線的人是否知道有這個流程。
所以我們主要是通過第二種方案來解決這個問題。
我們需要讓腳本在執(zhí)行的時候知道,dist 文件夾里邊的內(nèi)容是不是自己想要的。
所以就需要有一個 __標識__,而做這個標識最簡單有效唾手可得的就是,git commit id。
每一個 commit 都會有一個唯一的標識符號,而且我們的 CI/CD 執(zhí)行也是依靠于新代碼的提交(也就意味著一定有 commit)。
所以我們在 build 環(huán)節(jié)將當(dāng)前的commit id也緩存了下來:
git rev-parse --short HEAD > git_version
同時在 deploy 腳本中添加額外的判斷邏輯:
currentVersion=`git rev-parse --short HEAD` tagVersion=`touch git_version; cat git_version` if [ "$currentVersion" = "$tagVersion" ] then echo "git version match" else echo "git version not match, rebuild dist" bash ~/runner-scripts/build.sh # 額外的執(zhí)行 build 腳本 fi
這樣一來,就避免了回滾時還是部署了錯誤代碼的風(fēng)險。
關(guān)于為什么不將 build 這一步操作與 deploy 合并的原因是這樣的:hot fix 的處理
因為我們會有很多臺機器,同時 job 會寫很多個,類似 deploy_1、deploy_2、deploy_all,如果我們將 build 的這一步放到 deploy 中
那就意味著我們每次 deploy,即使是一次部署,但因為我們選擇一臺臺機器多帶帶操作,它也會重新生成多次,這也會帶來額外的時間成本
在 CI/CD 運行了一段時間后,我們發(fā)現(xiàn)偶爾解決線上 bug 還是會比較慢,因為我們提交代碼后要等待完整的 CI/CD 流程走完。
所以在研究后我們決定,針對某些特定情況hot fix,我們需要跳過ESLint、單元測試這些流程,快速的修復(fù)代碼并完成上線。
CI/CD 提供了針對某些 Tag 可以進行不同的操作,不過我并不想這么搞了,原因有兩點:
這需要修改配置文件(所有項目)
這需要開發(fā)人員熟悉對應(yīng)的規(guī)則(打 Tag)
所以我們采用了另一種取巧的方式來實現(xiàn),因為我們的分支都是只接收Merge Request那種方式上線的,所以他們的commit title實際上是固定的:Merge branch "XXX"。
同時 CI/CD 會有環(huán)境變量告訴我們當(dāng)前執(zhí)行 CI/CD 的 commit message。
我們通過匹配這個字符串來檢查是否符合某種規(guī)則來決定是否跳過這些job:
function checkHotFix() { local count=`echo $CI_COMMIT_TITLE | grep -E "^Merge branch "(hot)?fix/w+" | wc -l` if [ $count -eq 0 ] then return 0 else return 1 fi } # 使用方法 checkHotFix if [ $? -eq 0 ] then echo "start eslint" npx eslint --ext .js,.ts . else # 跳過該步驟 echo "match hotfix, ignore eslint" fi
這樣能夠保證如果我們的分支名為 hotfix/XXX 或者 fix/XXX 在進行代碼合并時, CI/CD 會跳過多余的代碼檢查,直接進行部署上線。 沒有跳過安裝依賴的那一步,因為 TS 編譯還是需要這些工具的
小結(jié)目前團隊已經(jīng)有超過一半的項目接入了 CI/CD 流程,為了方便同事接入(主要是編輯 .gitlab-ci.yml 文件),我們還提供了一個腳手架用于快速生成配置文件(包括自動建立機器之間的信任關(guān)系)。
相較之前,部署的速度明顯的有提升,并且不再對本地網(wǎng)絡(luò)有各種依賴,只要是能夠?qū)⒋a push 到遠程倉庫中,后續(xù)的事情就和自己沒有什么關(guān)系了,并且可以方便的進行小流量上線(部署單臺驗證有效性)。
以及在回滾方面則是更靈活了一些,可在多個版本之間快速切換,并且通過界面的方式,操作起來也更加直觀。
最終可以說,如果沒有 CI/CD,實際上開發(fā)模式也是可以忍受的,不過當(dāng)使用了 CI/CD 以后,再去使用之前的部署方式,則會明顯的感覺到不舒適。(沒有對比,就沒有傷害
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://m.specialneedsforspecialkids.com/yun/104282.html
摘要:內(nèi)部長期使用來管理代碼。審核通過并且成功后,觸發(fā)靜態(tài)測試單元測試鏡像構(gòu)建鏡像部署集成測試等測試通過后,創(chuàng)建一個從到的,由負責(zé)人進行審核。從圖中我們可以看到,部分是一個單元測試,預(yù)發(fā)布部署,集成測試,,提交代碼的循環(huán)過程。UCloud內(nèi)部長期使用 Gitlab 來管理代碼。雖然Gitlab作為一套開源平臺已很優(yōu)秀,但我們對于其能為CI/CD提供的敏捷性并不十分滿意,內(nèi)部實踐中的代碼發(fā)布周期仍需...
摘要:只要的項目有提交,相關(guān)就根據(jù)來決定是否跑自動部署的命令。項目的自動部署添加執(zhí)行的注冊命令,按照說明進行參數(shù)配置。至此,和服務(wù)都已經(jīng)自動部署完成。 準備工作 說明 公司最近準備了一臺新的開發(fā)服務(wù)器,正好用以實踐docker的基本應(yīng)用。docker的好處不再贅述,詳情可參考阮一峰的這篇入門。(關(guān)于Docker最好的中文介紹,沒有之一)。 公司目前主要使用了EggJs + ReactJS的技...
摘要:在貓屎氤氳的霧氣里角仰望天花板,手機微信提醒這次構(gòu)建成功或失敗,并附帶污言穢語。這時他可以開始往工位走,坐下時,微信又會提醒本次部署到成功或失敗。與企業(yè)微信的集成在決定使用之前,需要知道的是,是一個高度依賴社區(qū)的項目。 前言 相信我,一切事情的發(fā)生都是趕鴨子上架,沒有例外。人類所有偉大的變革都是迫不得已,可又是那么順其自然。比如容器(docker)技術(shù)的誕生,比如箭在弦上的創(chuàng)業(yè),比如野...
摘要:集成測試完成后,由運維同學(xué)從發(fā)起一個到分支,此時會會運行單元測試,構(gòu)建鏡像,并發(fā)布到預(yù)發(fā)布環(huán)境測試人員在預(yù)發(fā)布環(huán)境下再次驗證功能,團隊做上線前的其他準備工作運維同學(xué)合并,將為本次發(fā)布的代碼及鏡像自動打上版本號并書寫,同時發(fā)布到生產(chǎn)環(huán)境。 云原生 (Cloud Native) 是伴隨的容器技術(shù)發(fā)展出現(xiàn)的的一個詞,最早出自 Pivotal 公司(即開發(fā)了 Spring 的公司)的一本技術(shù)小...
摘要:集成測試完成后,由運維同學(xué)從發(fā)起一個到分支,此時會會運行單元測試,構(gòu)建鏡像,并發(fā)布到預(yù)發(fā)布環(huán)境測試人員在預(yù)發(fā)布環(huán)境下再次驗證功能,團隊做上線前的其他準備工作運維同學(xué)合并,將為本次發(fā)布的代碼及鏡像自動打上版本號并書寫,同時發(fā)布到生產(chǎn)環(huán)境。 云原生 (Cloud Native) 是伴隨的容器技術(shù)發(fā)展出現(xiàn)的的一個詞,最早出自 Pivotal 公司(即開發(fā)了 Spring 的公司)的一本技術(shù)小...
閱讀 3117·2021-11-24 09:39
閱讀 979·2021-09-07 10:20
閱讀 2400·2021-08-23 09:45
閱讀 2272·2021-08-05 10:00
閱讀 575·2019-08-29 16:36
閱讀 840·2019-08-29 11:12
閱讀 2824·2019-08-26 11:34
閱讀 1844·2019-08-26 10:56