GitLab 容器化 CI 流程填坑記(一)
本文以SpringBoot專案的部署構建為例,對基於GItLab的CI流程進行簡要介紹。
環境準備:
1. 系統環境:
作業系統:CentOS 7.2 1511
GitLab:v11.1.4
GitLab-runner:v11.2.0
Docker:17.03.2 ce
2. 應用環境:
應用框架:Spring boot v2.0.x
專案構建管理:Maven v3.5.x
CI整合流程:
關於證書(HTTPS需要,HTTP請忽略):
注:下述 "hostname.com" 請自行替換為GitLab域名
1. 完整自簽證書:
sudo openssl genrsa -des3 -out /etc/gitlab/ssl/hostname.com.key 2048 sudo openssl req -new -key /etc/gitlab/ssl/hostname.com.key -out /etc/gitlab/ssl/hostname.com.csr sudo openssl x509 -req -days 3650 -in /etc/gitlab/ssl/hostname.com.csr -signkey /etc/gitlab/ssl/hostname.com.key -out /etc/gitlab/ssl/hostname.com.crt
2. 服務端已有證書:
可直接通過瀏覽器匯出證書,並將檔案存為hostname.com.crt, 存於/etc/gitlab/ssl/(預設)目錄下。
完成證書的獲取後,可使用:
openssl s_client -connect hostname.com:443 -CAfile hostname.com.crt -state
進行證書的校驗。
若返回0則表示無問題,如下圖所示:
具體實現:
1. 安裝GitLab:略(直接容器部署即可)
2. 在GitLab中建立專案:略
3. 安裝runner:
gitlab-runner有多種安裝方式,具體詳見
docker run -d --name bala-runner --restart always \
-v /etc/gitlab-runner/certs/hostname.com.crt:/usr/local/share/ca-certificates/hostname.com.crt \
-v /etc/gitlab-runner/certs/hostname.com.crt:/etc/gitlab-runner/certs/hostname.com.crt \
-v /var/run/docker.sock:/var/run/docker.sock \
-v /root/build_cache:/cache \
gitlab/gitlab-runner:latest
注:
1. 第一和第二個 -v 實現證書目錄內容的掛載;
2. 第三個 -v 實現docker.sock的掛載(因為後續要實現docker in docker的使用,即 docker executor);
3. 第四個 -v 實現gitlab-runner cache目錄的掛載(可選),cache相關請參考 docker executor 下的cache部分。
4. 進入runner更新證書:
docker-enter <name>
update-ca-certificates
沒有 docker-enter 可使用 docker exec -it /bin/bash 進入容器。
docker-enter配置方式請參考這裡。
5. 註冊runner:
runner註冊的引數很多,可通過下述命令進行檢視(config文件地址):
gitlab-runner register --help
這裡,本文使用如下命令進行runner註冊:
gitlab-runner register -n \
--url https://hostname.com/ \
--registration-token Bz7bb9xxxxxxxxxYxf91 \
--tls-cert-file /etc/gitlab-runner/certs/hostname.com.crt \
--executor docker \
--pre-clone-script "git config --global http.sslVerify false" \
--output-limit 81920 \
--description "BalaBalaYi Runner" \
--docker-image "balabalayi/maven-plus-docker:jdk-8-maven-3.5.4-docker-17.03" \
--docker-volumes /var/run/docker.sock:/var/run/docker.sock
注:
1.url 為 gitlab的地址;
2. registration-token 為專案下的token,可通過 gitlab -> project -> settings -> ci/cd 下獲得,如圖所示:
3. tls-cert-file 為證書目錄,注意與啟動runner容器時的掛載目錄要一致;
4. executor,使用 docker 作為 executor;
5. pre-clone-script 表示 git clone 倉庫程式碼前執行的命令,本文這裡簡化了git的過程,直接禁用了sslVerify,若對環境安全性要求高,請自行配置git ssl;
6. output-limit 為日誌輸出的大小限制,預設為4096 (4MB);
7. description 為 runner 的描述資訊,請自定義;
8. docker-image 為 executor 所採用的預設 docker 映象(會被gitlab-ci.yml中的配置覆蓋)。這裡,因為本文要使用mvn docker:build命令,因此採用了自己封裝的映象(包括 java8+maven3+docker17.03 環境);
9. docker-volumes ,因採用 "docker executor" ,必須掛載宿主機的docker.sock,
10. 如果需要掛載cache到宿主機,docker-volumes 還需新增宿主機目錄到容器內cache目錄(預設為/cache)的對映(可選)。
6. 編寫.gitlab-ci.yml
.gitlab-ci.yml 是控制整個ci流程的核心配置檔案,本文僅針對SpringBoot應用構建的幾個要點進行闡述,其它請具體參考 gitlab-ci.yml 指導文件。
maven環境的引用:
在企業內部,實際專案的構建過程大多依賴私有倉庫等設定,因此預設的maven環境是不能滿足需要的。但是因為在本篇文章所涉及的CI流程中,無論是executor還是runner,都是以容器化的方式託管給GitLab進行操作,所以介紹下如何在該場景下便捷地引用maven的配置,方法有三:
1. 通過自定義官方的maven映象的dockerfile,重新配置指定目錄下的settings.xml,並在內部實現變數,方便後續在CI流程中通過外部定義變數的方式,實現maven自定義動態配置的匯入。
結論:此方法可行。但是maven的配置較多,如果企業內部依賴maven的配置較多,此方法依舊較複雜。何況還要涉及dockerfile的修改及映象的構建。
2. 如果配置極少,可直接在 before_script 通過sed等命令,新增配置內容至settings.xml(以預設的settings.xml為基準) 。
結論:此方法在自定義配置專案較少時可用,配置項若較多,則異常繁瑣。
3. 將maven的settings.xml拷貝一份,置於專案根目錄下(與pom檔案一起),作為專案本身的配置檔案之一。在.gitlab-ci.yml中定義新的maven變數引用(mvn-setting.xml是自定義的名稱):
variables:
MAVEN_CLI_OPTS: "-s ./mvn-settings.xml --batch-mode"
然後,在每個stage下對應的指令碼命令中,都可通過引用此變數來執行maven命令:
- mvn $MAVEN_CLI_OPTS clean deploy docker:build -DpushImage
結論:此方法最為簡單粗暴,無須擔心自定義的maven配置是否複雜。缺點是專案多維護了一個配置檔案(其實都多了.gitlab-ci.yml了,也不在乎多這一個)。
docker構建所需環境:
如果要實現 docker build 及其它 docker 命令,需要對應的docker環境,上述 /var/run/docker.sock 的掛載就是為此服務的。
除了與宿主機的docker.sock的共享,另外還需要當前環境下的docker安裝。在此針對SpringBoot應用構建,有兩種方式如下:
1. 使用 maven 的 dockerbuild 外掛,通過 mvn 命令在一個 stage 中完成打包以及 docker 的映象構建:
此方法需要使用者自行構建一個包含 JDK+MAVEN+DOCKER 環境的容器映象,然後使用此映象作為 executor 的映象執行CI流程。採用此方法一個命令即可完成打包,推送jar至倉庫,構建docker映象,推動docker映象至倉庫:
mvn $MAVEN_CLI_OPTS clean deploy docker:build -DskipTests -DpushImage
2. 分為兩個stage,分別完成打包和映象構建:
此方法,需要使用 cache 或是 artifact 在 package stage 步驟中保留打包後的jar及相關目標檔案,然後在 build stage 步驟中引用 cache 或是 artifact 儲存下來的目標內容進行後續的映象構建。大致的指令碼流程如下:
image: docker:latest
services:
- docker:dind
stages:
- package
- build
# 打包
package:
image: maven:3-jdk-8
stage: package
script:
- docker login ip:port -u xxx -p xxxx
- mvn clean deploy
cache:
key: target
paths:
- target/*
# 構建
deploy:
stage: deploy
script:
- docker login ip:port -u xxx -p xxxx
- docker build xxx xxx
- docker push xxx
上述程式碼只是一個示例,cache 和 artifacts 的使用還請參考 這裡,具體語法還請參考 gitlab-ci.yml 指導文件 。
docker的部署執行:
目前,部署執行環境主要為兩種,傳統的宿主機環境(物理機或是虛擬機器)以及kubernetes叢集。
1. 宿主機:
此方法大多需要通過ssh實現遠端命令控制,在此給出一個簡單的方法,使用sshpass:
deploy:
stage: deploy
script:
- apt-get install -y sshpass
- sshpass -p "$DEPLOY_HOST_PASSWORD" ssh -o StrictHostKeyChecking=no -tt [email protected]$DEPLOY_HOST_IP 'if [ -n "`docker ps -qa --filter name=xxx`" ];then docker rm -f xxx;fi'
- sshpass -p "$DEPLOY_HOST_PASSWORD" ssh -o StrictHostKeyChecking=no -tt [email protected]$DEPLOY_HOST_IP "docker login $REGISTRY_HOST:$REGISTRY_PUBLIC_PORT -u $REGISTRY_ADMIN_USER -p $REGISTRY_ADMIN_USER_PASSWORD"
- sshpass -p "$DEPLOY_HOST_PASSWORD" ssh -o StrictHostKeyChecking=no -tt [email protected]$DEPLOY_HOST_IP "docker run --name xxx -d $REGISTRY_HOST:$REGISTRY_PUBLIC_PORT/xx/xxx"
上述四行命令分別為:
1. 安裝sshpass;
2. 根據名稱清除已有的正在執行的容器;
3. 登入docker倉庫;
4. 部署執行容器。
官方使用ssh免密的方法:Using SSH keys with GitLab CI/CD
2. kubernetes叢集:
需要使用者自定義應用的k8s宣告檔案,配置k8s叢集訪問,然後在 .gitlab-ci.yml 中實現部署流程:
k8s-deploy:
image: xxx
stage: deploy
script:
- kubectl create secret docker-registry xxx --docker-server=https://registry.gitlab.com --docker-username=xxx --docker-password=xxx
- kubectl apply -f deployment.yml
其它詳細請參考 k8s整合。
7. 完成CI整合並測試
完成 .gitlab-ci.yml 檔案的編寫後,可通過 GitLab 的 CI Lint 對該檔案進行檢查,確認語法等是否有問題。
確認無問題後可提交併推送專案至 GitLab 即可觸發CI流程。具體過程可通過project -> ci/cd -> pipelines 進行檢視:
相關內容及文章引用:
結語:
最後感謝 Du Wenkai 小夥伴的技術和環境支援。