gitlab?ci?cd?命令的使用不完全指南
gitlab 可能大家很常用,CI、CD 也應(yīng)該早有耳聞,但是可能還沒有去真正地了解過,這篇文章就是我對 gitlab CI、CD 的一些理解,以及踩過的一些坑,希望能幫助到大家。
什么是 CI、CD
CI(Continuous Integration)持續(xù)集成,CD(Continuous Deployment)持續(xù)部署(也包含了持續(xù)交付的意思)。
CI 指的是一種開發(fā)過程的的自動化流程,在我們提交代碼的時候,一般會做以下操作:
lint
檢查,檢查代碼是否符合規(guī)范- 自動運行測試,檢查代碼是否能通過測試
這個過程我們可以稱之為 CI,也就是持續(xù)集成,這個過程是自動化的,也就是說我們不需要手動去執(zhí)行這些操作,只需要提交代碼,這些操作就會自動執(zhí)行。
CD 指的是在我們 CI 流程通過之后,將代碼自動發(fā)布到服務(wù)器的過程,這個過程也是自動化的。 在有了前面 CI 的一些操作之后,說明我們的代碼是可以安全發(fā)布到服務(wù)器的,所以就可以進(jìn)行發(fā)布的操作。
為什么要使用 CI、CD
實際上,就算沒有 CI、CD 的這些花里胡哨的概念,對于一些重復(fù)的操作,我們也會盡量想辦法會讓它們可以自動化實現(xiàn)的,只不過可能效率上沒有這么高,但是也是可以的。
CI、CD 相比其他方式的優(yōu)勢在于:
- 一次配置,多次使用:我們需要做的所有操作都通過配置固定下來了,每次提交代碼我們都可以執(zhí)行相同的操作。
- 可觀測性:我們可以通過 CI、CD 的日志來查看每次操作的執(zhí)行情況,而且每一次的 CI、CD 執(zhí)行的日志都會保留下來,這樣我們就可以很方便地查看每一次操作的執(zhí)行情況。
- 自動化:我們不需要手動去執(zhí)行 CI、CD 的操作,只需要提交代碼,CI、CD 就會自動執(zhí)行。
- 少量配置:一般的代碼托管平臺都會提供 CI、CD 的功能,我們只需要簡單的配置一下就可以使用了。同時其實不同平臺的 CI、CD 配置也是有很多相似之處的,所以我們只需要學(xué)習(xí)一種配置方式,就可以在不同平臺上使用了。
gitlab CI、CD
在開始之前,我們可以通過下圖來了解一下 CI、CD 的整體流程:
- 在開發(fā)人員提交代碼之后,會觸發(fā) gitlab 的 CI 流水線。也就是上圖的
CI PIPELINE
,也就是中間的部分。 - 在 CI 流水線中,我們可以配置多個任務(wù)。比如上圖的
build
、unit test
、integration tests
等,也就是構(gòu)建、單元測試、集成測試等。 - 在 CI 流水線都通過之后,會觸發(fā) CD 流水線。也就是上圖的
CD PIPELINE
,也就是右邊的部分。 - 在 CD 流水線中,我們可以配置多個任務(wù)。比如上圖的
staging
、production
等,也就是部署到測試環(huán)境、部署到生產(chǎn)環(huán)境等。
在 CD 流程結(jié)束之后,我們就可以在服務(wù)器上看到我們的代碼了。
gitlab CI、CD 中的一些基本概念
在開始之前,我們先來了解一下 gitlab CI、CD 中的一些基本概念:
pipeline
:流水線,也就是 CI、CD 的整個流程,包含了多個stage
,每個stage
又包含了多個job
。stage
: 一個階段,一個階段中可以包含多個任務(wù)(job
),這些任務(wù)會并行執(zhí)行,但是下一個stage
的job
只有在上一個stage
的job
執(zhí)行通過之后才會執(zhí)行。job
:一個任務(wù),這是 CI、CD 中最基本的概念,也是最小的執(zhí)行單元。一個stage
中可以包含多個job
,同時這些job
會并行執(zhí)行。runner
:執(zhí)行器,也就是執(zhí)行job
的機器,runner
跟 gitlab 是分離的,runner
需要我們自己去安裝,然后注冊到 gitlab 上(不需要跟 gitlab 在同一個服務(wù)器上,這樣有個好處就是可以很方便實現(xiàn)多個機器來同時處理 gitlab 的 CI、CD 的任務(wù))。tag
:runner
和job
都需要指定標(biāo)簽,job
可以指定一個或多個標(biāo)簽(必須指定,否則job
不會被執(zhí)行),這樣job
就只會在指定標(biāo)簽的runner
上執(zhí)行。cache
: 緩存,可以緩存一些文件,這樣下次流水線執(zhí)行的時候就不需要重新下載了,可以提高執(zhí)行效率。artifacts
: 這代表這構(gòu)建過程中所產(chǎn)生的一些文件,比如打包好的文件,這些文件可以在下一個stage
中使用,也可以在pipeline
執(zhí)行結(jié)束之后下載下來。variables
:變量,可以在pipeline
中定義一些變量,這些變量可以在pipeline
的所有stage
和job
中使用。services
:服務(wù),可以在pipeline
中啟動一些服務(wù),比如mysql
、redis
等,這樣我們就可以在pipeline
中使用這些服務(wù)了(常常用在測試的時候模擬一個服務(wù))。script
: 腳本,可以在job
中定義一些腳本,這些腳本會在job
執(zhí)行的時候執(zhí)行。
CI、CD 的工作模型
我們以下面的配置為例子,簡單說明一下 pipeline
、stage
、job
的工作模型,以及 cache
和 artifacts
的作用:
ci
配置文件(也就是一個 pipeline
的所有任務(wù)):
# 定義一個 `pipeline` 的所有階段,一個 `pipeline` 可以包含多個 `stage`,每個 `stage` 又包含多個 `job`。 # stage 的順序是按照數(shù)組的順序來執(zhí)行的,也就是說 stage1 會先執(zhí)行,然后才會執(zhí)行 stage2。 stages: - stage1 # stage 的名稱 - stage2 # 定義一個 `job`,一個 `job` 就是一個任務(wù),也是最小的執(zhí)行單元。 job1: stage: stage1 # 指定這個 `job` 所屬的 `stage`,這個 `job` 只會在 `stage1` 執(zhí)行。 script: # 指定這個 `job` 的腳本,這個腳本會在 `job` 執(zhí)行的時候執(zhí)行。 - echo "hello world" > "test.txt" tags: # 指定這個 `job` 所屬的 `runner` 的標(biāo)簽,這個 `job` 只會在標(biāo)簽為 `tag1` 的 `runner` 上執(zhí)行。 - tag1 # cache 可以在當(dāng)前 `pipeline` 后續(xù)的 `job` 中使用,也可以在后續(xù)的 `pipeline` 中使用。 cache: # 指定這個 `job` 的緩存,這個緩存會在 `job` 執(zhí)行結(jié)束之后保存起來,下次執(zhí)行的時候會先從緩存中讀取,如果沒有緩存,就會重新下載。 key: $CI_COMMIT_REF_SLUG # 緩存的 key paths: # 緩存的路徑 - node_modules/ artifacts: # 指定這個 `job` 的構(gòu)建產(chǎn)物,這個構(gòu)建產(chǎn)物會在 `job` 執(zhí)行結(jié)束之后保存起來??梢栽谙乱粋€ stage 中使用,也可以在 pipeline 執(zhí)行結(jié)束之后下載下來。 paths: - test.txt job2: stage: stage1 script: - cat test.txt tags: - tag1 cache: key: $CI_COMMIT_REF_SLUG paths: - node_modules/ # 指定這個 `job` 的緩存策略,只會讀取緩存,不會寫入緩存。默認(rèn)是既讀取又寫入,在 job 開始的時候讀取,在 job 結(jié)束的時候?qū)懭搿? # 但是實際上,只有在安裝依賴的時候是需要寫入緩存的,其他 job 都使用 pull 即可。 policy: pull # job3 和 job4 都屬于 stage2,所以 job3 和 job4 會并行執(zhí)行。 # job3 和 job4 都指定了 tag2 標(biāo)簽,所以 job3 和 job4 只會在標(biāo)簽為 tag2 的 runner 上執(zhí)行。 # 同時,在 job1 中,我們指定了 test.txt 作為構(gòu)建產(chǎn)物,所以 job3 和 job4 都可以使用 test.txt 這個文件。 job3: stage: stage2 script: - cat test.txt tags: - tag1 cache: key: $CI_COMMIT_REF_SLUG paths: - node_modules/ policy: pull job4: stage: stage2 script: - cat test.txt tags: - tag1 cache: key: $CI_COMMIT_REF_SLUG paths: - node_modules/ policy: pull
上面的配置文件的 pipeline
執(zhí)行過程可以用下面的圖來表示:
說明:
- 上面的圖有兩個
pipeline
被執(zhí)行了,但是pipeline2
沒有全部畫出來 - 其中,在
pipeline 1
中,stage1
中的job
會先被執(zhí)行,然后才會執(zhí)行stage2
中的job
。 stage1
中的job1
和job2
是可以并行執(zhí)行的,這也就是stage
的本質(zhì)上的含義,表示了一個階段中不同的任務(wù),比如我們做測試的時候,可以同時對不同模塊做測試。job1
和job2
都指定了tag1
標(biāo)簽,所以job1
和job2
只會在標(biāo)簽為tag1
的runner
上執(zhí)行。job1
中,我們創(chuàng)建了一個test.txt
文件,這個文件會作為stage1
的構(gòu)建產(chǎn)物,它可以在stage2
中被使用,也就是job3
和job4
都可以讀取到這個文件。一種實際的場景是,前端部署的時候,build 之后會生成可以部署的靜態(tài)文件,這些靜態(tài)文件就會被保留到部署相關(guān)的 stage 中。需要注意的是,artifacts
只會在當(dāng)前pipeline
后續(xù)的stage
中共享,不會在pipeline
之間共享。- 同時,在
job1
中,我們也指定了cache
,這個cache
會在job1
執(zhí)行結(jié)束之后保存起來,不同于artifacts
,cache
是可以在不同的pipeline
之間共享的。一種很常見的使用場景就是我們代碼的依賴,比如node_modules
文件夾,它可以加快后續(xù)pipeline
的執(zhí)行流程,因為避免了重復(fù)的依賴安裝。
需要特別注意的是:cache
是跨流水線共享的,而 artifacts
只會在當(dāng)前流水線的后續(xù) stage 共享。
其他一些在個人實踐中的一些經(jīng)驗
gitlab 的 CI、CD 是一個很龐大的話題,同時很多內(nèi)容可能比較少用,所以本文只是介紹個人在實踐中用到的一些內(nèi)容,其他的東西如果有需要,可以自行查閱官方文檔。
指定特定分支才會執(zhí)行的 job
這個算是基本操作了,我們可以通過 only
來指定特定分支才會執(zhí)行的 job
,也有其他方法可以實現(xiàn),比如 rules
,具體請參考官方文檔。
deploy-job: stage: deploy # 當(dāng)前的這個 job 只會在 master 分支代碼更新的時候會執(zhí)行 only: - "master"
不同 job 之間的依賴
這個也是基本操作,我們可以通過 needs
來指定不同 job
之間的依賴關(guān)系,比如 job1
依賴 job2
,那么 job1
就會在 job2
執(zhí)行完畢之后才會執(zhí)行。
job1: stage: deploy needs: - job2
指定執(zhí)行 job 的 runner
我們可以通過 tags
來指定 job
執(zhí)行的 runner
,比如我們可以指定 job
只能在 api
標(biāo)簽的 runner
上執(zhí)行。
build-job: stage: build tags: - api
如果我們沒有標(biāo)簽為 api
的 runner
,那么這個 job
就會一直不會被執(zhí)行,所以需要確保我們配置的 tag
有對應(yīng)的 runner
。
指定 job 的 docker image
注意:這個只在我們的 runner
的 executor
為 docker
的時候才會生效。也就是我們的 runner
是一個 docker
容器。
有時候,我們需要執(zhí)行一些特定命令,但是我們?nèi)值?docker
鏡像里面沒有,可能只需要一個特定的 docker
鏡像,這個時候我們可以通過 image
來指定 job
的 docker
鏡像。
deploy-job: stage: deploy tags: - api # 指定 runner 的 docker image image: eleven26/rsync:1.3.0 script: # 下面這個命令只在上面指定的 docker 鏡像中存在 - rsync . root@example.com:/home/www/foo
為我們的集成測試指定一個 service
在我們的 CI 流程中,可能會有一些集成測試需要使用到一些服務(wù),比如我們的 mysql
,這個時候我們可以通過 services
來指定我們需要的服務(wù)。
test_rabbitmq: # 這會啟動一個 rabbitmq 3.8 的 docker 容器,我們的 job 就可以使用這個容器了。 # 我們的 job 可以連接到一個 rabbitmq 的服務(wù),然后進(jìn)行測試。 # 需要注意的是,這個容器只會在當(dāng)前 job 執(zhí)行的時候存在,執(zhí)行完畢之后就會被刪除。所以產(chǎn)生的數(shù)據(jù)不會被保留。 services: - rabbitmq:3.8 stage: test only: - master tags: - go script: # 下面的測試命令會連接到上面啟動的 rabbitmq 服務(wù) - "go test -v -cover ./pkg/rabbitmq"
復(fù)用 yaml 配置片段
在 yaml
中,有一種機制可以讓我們復(fù)用 yaml
配置片段,比如:
# 發(fā)布代碼的 job .deploy-job: &release-job tags: - api image: eleven26/rsync:1.3.0 script: - rsync . root@example.com:/home/www/foo deploy-release: <<: *release-job stage: deploy only: - "release" deploy-master: <<: *release-job stage: deploy only: - "master"
上面的代碼中,我們定義了一個 release-job
的配置片段,然后在 deploy-release
和 deploy-master
中,我們都引用了這個配置片段,這樣我們就可以復(fù)用這個配置片段了。 等同于下面的代碼:
# 發(fā)布代碼的 job .deploy-job: &release-job tags: - api image: eleven26/rsync:1.3.0 script: - rsync . root@example.com:/home/www/foo deploy-release: tags: - api image: eleven26/rsync:1.3.0 script: - rsync . root@example.com:/home/www/foo stage: deploy only: - "release" deploy-master: tags: - api image: eleven26/rsync:1.3.0 script: - rsync . root@example.com:/home/www/foo stage: deploy only: - "master"
在 yaml
的術(shù)語中,這一種機制叫做 anchor
。
cache vs artifacts
初次使用的人,可能會對這個東西有點迷惑,因為它們好像都是緩存,但是實際上,它們的用途是不一樣的。
cache
是用來緩存依賴的,比如node_modules
文件夾,它可以加快后續(xù)pipeline
的執(zhí)行流程,因為避免了重復(fù)的依賴安裝。artifacts
是用來緩存構(gòu)建產(chǎn)物的,比如build
之后生成的靜態(tài)文件,它可以在后續(xù)的stage
中使用。表示的是單個 pipeline 中的不同 stage 之間的共享。
指定 artifacts 的過期時間
我們可以通過 expire_in
來指定 artifacts
的過期時間,比如:
job1: stage: build only: - "release" image: eleven26/apidoc:1.0.0 tags: - api artifacts: paths: - public expire_in: 1 hour
因為我們的 artifacts
有時候只是生成一些需要部署到服務(wù)器的東西,然后在下一個 stage
使用,所以是不需要長期保留的。所以我們可以通過 expire_in
來指定一個比較短的 artifacts
的過期時間。
cache 只 pull 不 push
gitlab CI 的 cache
有一個 policy
屬性,它的值默認(rèn)是 pull-push
,也就是在 job
開始執(zhí)行的時候會拉取緩存,在 job
執(zhí)行結(jié)束的時候會將緩存指定文件夾的內(nèi)容上傳到 gitlab 中。
但是在實際使用中,我們其實只需要在安裝依賴的時候上傳這些緩存,其他時候都只是讀取緩存的。所以我們在安裝依賴的 job 中使用默認(rèn)的 policy
,而在后續(xù)的 job
中,我們可以通過 policy: pull
來指定只拉取緩存,不上傳緩存。
job: tags: - api image: eleven26/rsync:1.3.0 cache: key: files: - composer.json - composer.lock paths: - "vendor/" policy: pull # 只拉取 vendor,在 job 執(zhí)行完畢之后不上傳 vendor
cache 的 key 使用文件
這一個特性是非常有用的,在現(xiàn)代軟件工程的實踐中,往往通過 *.lock
文件來記錄我們使用的額依賴的具體版本,以保證在不同環(huán)境中使用的時候保持一致的行為。
所以,相應(yīng)的,我們的緩存也可以在 *.lock
這類文件發(fā)生變化的時候,重新生成緩存。上面的例子就使用了這種機制。
script 中使用多行命令
在 script
中,我們可以使用多行命令,比如:
job: script: # 我們可以通過下面這種方式來寫多行的 shell 命令,也就是以一個豎線開始,然后換行 - | if [ "$release_host" != "" ]; then host=$release_host fi
CD - 如何同步代碼到服務(wù)器
如果我們的項目需要部署到服務(wù)器上,那么我們還需要做一些額外的操作,比如同步代碼到服務(wù)器上。 如果我們的 gitlab 是通過容器執(zhí)行的,或者我們的 runner 的 executor 是 docker,那么有一種比較常見的方法是通過 ssh 私鑰來進(jìn)行部署。
我們可以通過以下流程來實現(xiàn):
- 新建一對 ssh key,比如
id_rsa
和id_rsa.pub
。 - 將
id_rsa.pub
的內(nèi)容添加到服務(wù)器的authorized_keys
文件中。 - 將
id_rsa
上傳到 gitlab 中(在項目的 CI/CD 配置中,配置一個變量,變量名為PRIVATE_KEY
,內(nèi)容為id_rsa
的內(nèi)容,類型為file
)。 - 在我們的
ci
配置文件中,添加如下配置即可:
before_script: - chmod 600 $PRIVATE_KEY deploy: stage: deploy image: eleven26/rsync:1.3.0 script: # $user 是 ssh 的用戶 # $host 是 ssh 的主機 # $port 是 ssh 的端口 # $PRIVATE_KEY 是我們在 gitlab 中配置的私鑰 - rsync -az -e "ssh -o StrictHostKeyChecking=no -p $port -i $PRIVATE_KEY" --delete --exclude='.git' . $user@$host:/home/www
這里的 rsync
命令中,我們使用了 -o StrictHostKeyChecking=no
參數(shù),這是為了避免每次都需要手動輸入 yes
來確認(rèn)服務(wù)器的指紋。
安全最佳實踐:
- 為每一個 project 配置 ssh key 變量,如果是全局變量的話,其他 project 可以在未授權(quán)的情況下,訪問到這個私鑰,這是非常危險的。
- 使用單獨的倉庫來保存 ci 配置文件,防止其他人未經(jīng)授權(quán)就修改 ci 配置文件,這也是非常危險的。
必須嚴(yán)格遵循以上兩步,否則會造成嚴(yán)重的安全問題。
總結(jié)
最后,總結(jié)一下本文中一些比較關(guān)鍵的內(nèi)容:
- gitlab 中的一些基本概念:
pipeline
:代表了一次 CI 的執(zhí)行過程,它包含了多個stage
。stage
:代表了一組job
的集合,stage
會按照順序執(zhí)行。job
:代表了一個具體的任務(wù),比如build
、test
、deploy
等。
- 一個
stage
中的多個job
是可以并行執(zhí)行的。但是下一個stage
的job
必須要等到上一個stage
的所有job
都執(zhí)行完畢之后才會執(zhí)行。 cache
和artifacts
的區(qū)別:cache
是用來緩存依賴的,比如node_modules
文件夾,它可以加快后續(xù)pipeline
的執(zhí)行流程,因為避免了重復(fù)的依賴安裝。artifacts
是用來緩存構(gòu)建產(chǎn)物的,比如build
之后生成的靜態(tài)文件,它可以在后續(xù)的stage
中使用。表示的是單個 pipeline 中的不同 stage 之間的共享。
cache
在安裝依賴的job
中才需要使用默認(rèn)的policy
,也就是pull-push
,在其他不需要安裝依賴的job
中使用pull
就可以了,不需要上傳緩存。cache
的key
可以指定多個文件,這樣在指定的文件變動的時候,緩存會失效,這往往用在依賴相關(guān)的文件中。- 可以使用
services
關(guān)鍵字來指定需要啟動的服務(wù),比如mysql
、redis
等,在 job 中可以連接到這些 services,從而方便進(jìn)行測試。 - 可以使用
yaml
的anchor
機制來復(fù)用一些配置片段,可以少寫很多重復(fù)的配置。 - 一個
job
必須運行在某個runner
上,job
和runner
的關(guān)聯(lián)是通過tag
來指定的。
以上就是gitlab ci cd 不完全指南的詳細(xì)內(nèi)容,更多關(guān)于gitlab ci cd 的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
一個SSL證書在線轉(zhuǎn)換工具以及IIS7環(huán)境下開通https的方法
公司只能提供 Nginx 下的 SSL 證書,卻要在 IIS 里面開啟 https 這個問題,那么就需要將pem轉(zhuǎn)換為pfx,這里為大家分享一下幾種方法2024-02-02網(wǎng)站控制臺directadmin中文手冊 Linux下虛擬主機管理
特別注意:本站所有轉(zhuǎn)載文章言論不代表本站觀點,本站所提供的攝影照片,插畫,設(shè)計作品,如需使用,請與原作者聯(lián)系2009-11-11git標(biāo)簽管理_動力節(jié)點Java學(xué)院整理
這篇文章主要為大家詳細(xì)介紹了git標(biāo)簽管理的相關(guān)資料,具有一定的參考價值,感興趣的小伙伴們可以參考一下2017-08-08理解web服務(wù)器和數(shù)據(jù)庫的負(fù)載均衡以及反向代理
這里的“負(fù)載均衡”是指在網(wǎng)站建設(shè)中應(yīng)該考慮的“負(fù)載均衡”。假設(shè)我們要搭建一個網(wǎng)站:aaa.me,我們使用的web服務(wù)器每秒能處理100條請求,而aaa.me這個網(wǎng)站最火的時候也只是每秒99條請求,那么我們使用一個服務(wù)器是完全可以的2014-04-04centos6.4+nginx+mysql+php+phpmyadmin整合過程詳解
這篇文章主要介紹了centos6.4+nginx+mysql+php+phpmyadmin整合過程,較為詳細(xì)的分析了centos6.4+nginx+mysql+php+phpmyadmin整合的具體步驟、操作指令與相關(guān)實現(xiàn)技巧,需要的朋友可以參考下2016-11-11HTTP與HTTP協(xié)作的Web服務(wù)器訪問流程圖解
記得以前剛接觸網(wǎng)站的時候,很奇怪一臺服務(wù)器上可以放很多個網(wǎng)站,不用的域名就可以訪問不同的目錄,今天看起來的理所當(dāng)然以前真是不可思議,今天剛好看到了這篇文章就為大家分享一下2018-10-10MSXML2.XMLHTTP 800401F3 錯誤的解決方法
今天ASP調(diào)用Web Service報錯,錯誤代碼為800401F3,錯誤提示為:Server.CreateObject失敗。2009-08-08