最近揮霍青春、沉淪于學習科學文化知識,摸了些旁門左道,故而在此想做一些分享,同時也是小弟我第一次編寫文章。以下都是一些僅代表個人的一些觀點和心得,本人盡量使用比較通俗易懂的話語來闡述,希望能給各位少俠一些啟發和幫助。若有解釋不當的地方,還請各位大鍋指點一二。
CI/CD介紹
對與Gitlab 提供的 CI/CD, 其稱之為持續集成服務、通俗點就是自動化(打包、測試、部署 ...)
CI (持續構建) --> 代碼提交后觸發自動化的單元測試,代碼預編譯,構建鏡像,上傳鏡像等.
CD (持續發布) --> 將構建好的程序發布到各種環境,如預發布環境,正式環境.
為什么要使用持續集成?
我們都知道,項目開發最基本的流程不過于 "開發" -> "打包" -> "測試" -> "部署",在一個完整項目的生命周期中,避免不了多次以上這樣的流程。傳統的模式可能會讓我們覺得厭煩,原因不外乎于下面幾點:
1、開發和打包都在同一臺機器上運作,可能導致打包的過程中,影響開發的進度
2、一天天的都是手動打包、測試、部署、日復一日的工作使我們厭倦
3、每個開發者都在自己的機器打包項目,不同的環境配置可能會有各種千奇百怪的問題
除以上問題,當然還有其他不盡人意的缺點,就不一 一描述了,上面的問題足以讓人腦殼深疼。在這個時候,我相信強大的持續集成方案一定能解決你對開發流程不滿的地方
1、提供后臺集成服務,開發、打包,互不影響
2、減少人工編譯部署過程中的低級錯誤
3、解決不同環境下構建項目產生不一致的問題
還有各種好處。。。(具體還是根據大家不同的場景需求定制自己的自動化方案吧)
特別說明
本人使用的系統環境都是 ubuntu、使用docker,項目語言是node.js
不熟悉docker基礎的仁兄們需要先看看docker的一些基礎知識
個人建議使用兩臺以上的服務器, 一臺開發+測試, 一臺部署發布項目 (筆者認為,如果只使用一臺服務器,實際上發揮不出 CI/CD 的威力)
對與網上現有的各大分享gitlab ci/cd 的文章,使用 shell 來搭建ci/cd服務的太多了,在此我就不介紹這種方案了。但是基于docker 方案的文章,也看了不少,對與我個人而言并不是太友好,有些說的比較高深,難以理解,有些過于簡單,不夠詳細。所以決定寫下這篇文章希望能和大家互相探討。該文章主要是基于docker 的持續集成方案。
認識Gitlab-CI/CD流程
該小節適于初步認識gitlab持續集成服務的讀者閱讀、對于已經理解基本流程的可以直接跳過本小節(這一節已經不能教你什么了)
GitLab8.0之后,GitLab CI/CD 就已經集成在GitLab里了。給我幾分鐘,你會發現,其實流程很簡單。
pipeline
每次代碼提交就會觸發一次pipeline。如上去所示,每一行就是一個集成服務,我們稱之為流水線。一次pipeline可以看成一次構建任務。
stage
stage就是上述構建任務中的各個構建階段。一般會包含:安裝依賴,測試,編譯,部署服務等多個階段。
job
job表示構建工作,是每個stage構建階段里具體執行的工作。
我們可以點擊進去看看,你會發現整個流程就像工廠車間里面的任務一樣,一個任務完成后接著執行下一個(或多個)任務,不難看出來,以上的任務順序為 build ->test -> deploy。
(并且如果有其中一個任務失敗了,我們可以選擇后面的任務是否能繼續下去,這對我們很有用,而這些任務都是我們可以預先設定好的,并按照我們的規則來進行)
通過上面這些概念上的東西,你應該對 Gitlab-CI/CD 的工作 流程有了初步的了解,但是這些任務都是交給誰來托管呢? 沒錯,它就是 GitLab runner。下面就開始我們的主題吧。
啟動GitLab runner服務
1、首先要安裝docker、已經安裝的可跳過此步驟:
(附上docker 安裝的官方文檔 Get Docker CE for Ubuntu | Docker Documentation)
sudo apt-get update
sudo apt-get install docker-ce
2、創建gitlab-runner容器:
sudo docker pull gitlab/gitlab-runner:latest
sudo docker stop gitlab-runner && docker rm gitlab-runner
sudo docker run -d --name gitlab-runner --restart always \
-v /srv/gitlab-runner/config:/etc/gitlab-runner \
-v /var/run/docker.sock:/var/run/docker.sock \
gitlab/gitlab-runner:latest
3、注冊runner(綁定gitlab項目):
首先我們需要打開自己gitlab的項目,打開一下紅色指示的地方
注冊runner:
sudo docker exec -it gitlab-runner gitlab-ci-multi-runner register -n \
--url 這里填寫上圖中的url \
--registration-token 這里填寫上圖中的token \
--executor docker \
--description "gitlab-runner in docker" \
--tag-list "ci-cd" \
--docker-privileged=false \
--docker-pull-policy="if-not-present" \
--docker-image "docker:latest" \
--docker-volumes /var/run/docker.sock:/var/run/docker.sock
成功后如下圖所示(該步驟有可能會出現網絡異常的情況,可以嘗試多次重試)
上面的命令將注冊一個新的 Runner 來使用 Docker 所提供的特殊docker:latest鏡像。這里使用的是官方提供的 Use Docker socket binding 模式,是將/var/run/docker.sock綁定裝載到容器中,以便 docker 在該鏡像的上下文中可用。(請注意,它正在使用 宿主機 本身的 Docker 守護進程,docker 命令產生的任何容器都將是 一開始我們創建gitlab-runner容器的兄弟,而不是所運行程序的子進程)有興趣可自行閱讀官方文檔,看看具體參數的用法。
這里需要說明的是 docker-pull-policy,設置gitlab是否從遠程拉去image, 如果iamge是本地的,需要配置該屬性的值為 if-not-present,這樣可以避免docker 鏡像每次都pull
4、提升gitlab-runner用戶權限:
由于runner執行過程中,是通過一個叫做 gitlab-runner 的用戶來進行操作的,因為不是root用戶,所以免不了會有權限問題,這里我們將其添加到docker組中,并驗證gitlab-runner是否可以訪問Docker
sudo usermod -aG docker gitlab-runner
sudo -u gitlab-runner -H docker info
配置.gitlab-ci.yml
好了,通過上一節,我們已經成功注冊runner了,是時候定制我們的持續集成服務了,在項目根目錄中創建.gitlab-ci.yml文件。(附上官方的文檔說明 配置gitlab-ci.yml規則)
先附上完整版的yml,里面均有注釋,后面再針對特殊的地方做些解釋
# 使用docker鏡像
image: docker:latest
# 設置變量
variables:
# 鏡像倉庫地址
REGISTRY: registry.cn-shenzhen.aliyuncs.com
# 鏡像版本
REGISTRY_IMAGE_TAG: registry.cn-shenzhen.aliyuncs.com/jieyufeng/gitlab-ci-cd:master
# 鏡像啟動后的容器名
CONTAINER_NAME: gitlab-ci-cd
stages:
- build
- test
- deploy
# ----------------構建-----------------
build:
stage: build
script:
# 停止并刪除正在使用當前鏡像的容器
- if [ "$(docker ps -a | grep $CONTAINER_NAME)" ]; then
- docker stop $CONTAINER_NAME && docker rm $CONTAINER_NAME
- fi
# 刪除當前已存在的鏡像
- if [ "$(docker images | grep $REGISTRY_IMAGE_TAG)" ]; then
- docker rmi $REGISTRY_IMAGE_TAG
- fi
# 登錄鏡像倉庫
- docker login -u $REGISTRY_USER -p $REGISTRY_PASSWORD $REGISTRY
# 構建新的鏡像
- docker build -t $REGISTRY_IMAGE_TAG .
# 上傳鏡像
- docker push $REGISTRY_IMAGE_TAG
only:
- master
tags:
- ci-cd
# ----------------測試-----------------
test:
stage: test
script:
# 本地啟動容器進行測試
- docker run -d --name $CONTAINER_NAME -p 3000:3000 $REGISTRY_IMAGE_TAG
when: on_success
only:
- master
tags:
- ci-cd
# ----------------部署-----------------
deploy:
# 切換ubuntu作為deploy任務的鏡像
image: ubuntu:latest
stage: deploy
script:
# 給runner配置私鑰
- 'which ssh-agent || ( apt-get update -y && apt-get install openssh-client -y )'
- eval $(ssh-agent -s)
- echo "$SSH_PRIVATE_KEY" | tr -d '\r' | ssh-add - > /dev/null
- mkdir -p ~/.ssh
- chmod 700 ~/.ssh
# 給runner配置ssh登錄不驗證HostKey
- '[[ -f /.dockerenv ]] && echo -e "Host *\\n\\tStrictHostKeyChecking no\\n\\n" > ~/.ssh/config'
# 使用ssh遠程登錄正式服務器,并拉取之前build上傳好的鏡像進行部署
- ssh root@$DEPLOY_HOST "
docker images;
docker login -u $REGISTRY_USER -p $REGISTRY_PASSWORD $REGISTRY;
docker pull $REGISTRY_IMAGE_TAG;
docker run -d --name $CONTAINER_NAME -p 3000:3000 $REGISTRY_IMAGE_TAG;"
when: manual
allow_failure: false
only:
- master
tags:
- ci-cd
部分說明:
1、這里會涉及一個概念,叫做docker in docker的概念,針對這個我個人也沒能很好的解釋是個什么東西,以免誤導大家,因此提供官方的文檔 docker socket binding 給大家參考
2、既然要使用自動化部署,那就免不了要使用ssh免密登錄策略,此處就關于免密的就不做詳細介紹了,可以參考該文檔 ssh免密登錄
3、試想一下,有些敏感的參數我們是不希望明文暴露在.gitlab-ci.yml 中的,比如密碼、私鑰等,那怎么辦才好呢?對此,官方提供了很好的方案 GitLab CI/CD Variables,設置后,我們可以直接使用參數來代替銘感信息
如上圖所示,我們需要在我們gitlab項目中設置對應的參數:
REGISTRY_USER: 登錄你個人的docker鏡像倉庫用戶名
REGISTRY_PASSWORD: 登錄你個人的docker鏡像倉庫密碼
DEPLOY_HOST: 你正式服務器的地址
SSH_PRIVATE_KEY: gitlab-runner所在的服務器的ssh私鑰
如下圖所示,我們在.gitlab-ci.yml只需要使用對應的參數即可,很高大上的有木有
對與不敏感的信息,我們也可以.gitlab-ci.yml設置參數 (其實就跟我們平常寫代碼,聲明一個全局的參數是一個道理的)
4、各流程簡單描述
build: 因為我們runner所在的服務器就是測試服務器,所以我們在構建鏡像之前,需要先將使用了該鏡像的容器給刪除,并刪除舊的鏡像。刪除后我們構建新的鏡像,并登陸個人鏡像倉庫進行上傳。(由于網絡沒辦法翻墻,這里推薦使用 阿里云容器鏡像服務,也可以使用你們自己搭載的個人鏡像倉庫。 如果你們可以翻墻,也可以使用gitlab配套的容器鏡像倉庫,如下圖,沒有翻墻請慎用,可能會導致上傳鏡像失敗的情況)
test: 正如剛才我們說的 runner所在的服務器就是測試服務器,所以test的任務比較簡單,就是使用docker啟動我們剛才編譯的鏡像即可
deploy: 因為docker:latest 鏡像中沒有ssh服務,我們可以換一種思路,切換ubuntu:latest 鏡像,大家都知道,使用ssh遠程登錄肯定免不了登錄驗證, 這里一定要先打通服務器之間的ssh免密登錄,也就是上面的第2點說明,否則登錄不成功,接著就是給runner配置私鑰了。針對這個,官方也有方案文檔 ssh-keys-when-using-the-docker-executor。需要注意的地方是,一般我們不希望每一次構建一次流水線就部署一次,因此我們可以在deploy中設置when: manual,它讓我們可以通過手動來控制是否需要執行部署的操作
如圖所示,我們可以根據前面的任務狀態來確定是否需要進行部署任務,只需點一下紅色標注的地方即可
總結
雞湯:可能對于像我這樣的新手一開始接觸這個,會有很多很多困惑,也會遇到各種各樣的問題。但是勇于嘗試,總能成功的,畢竟羅馬也不是一天建成的不是嗎?
最后,由于這個Gitlab-CI/CD太過強大,還有很多高大上的方案本人也還在學習中,文章中出現的文檔鏈接都很有用,都是官方文檔的,每個人可能都會遇到各種不同的問題,本文只是做一個總結分享,并不一定能解決大家所遇到的問題,大家可以多閱讀資料,互相探討一下
附上本人簡單的demo: gitlab-ci-cd