Gitlab是企業常用的代碼托管平台。
除了管理代碼外,Gitlab還可以做持續集成和持續發布,這一點就需要依賴Gitlab-CI/CD的功能了。
首先要想使用該功能,就需要先安裝gitlab-runner。gitlab-runner的下載 可以看這里
gitlab-runner的注冊可以看這里。gitlab-runner 就是指某一台服務器(或docker容器,或k8s的節點)用來跑ci任務,當某台服務器安裝了gitlab-runner,那么他就是gitlab-runner了。比如說,我們的倉庫里有java后端項目 和vue的前端項目,那么我們就可以搞兩台服務器跑ci任務,一台跑maven的,一台跑vue的
這里主要注意的兩點就是
1.gitlab-runner Executor的選擇,一般選擇 Docker executor 或者 Kubernetes executor,選擇Kubernetes executor 可以參照
2.runner 的TAG 設置(這個設置在gitlab上進行設置)
這里TAG設置,不能為純數字,否則會提示.gitlab-ci.yml 文件語法錯誤(這一點需要注意) ,建議TAG的名字可以設置為構建的名稱和ip。如果我這台機器 是跑maven的,服務器ip尾數為151,因此該Runner可以設置為maven-151。同樣的,如果機器夠多 同類型得也可以多搞幾個,這樣可以並發構建了。
本篇選擇的是 Docker executor 。
安裝完gitlab-runner 。可以查看gitlab-runner的配置文件。
[root@app01 ~]# cat /etc/gitlab-runner/config.toml
concurrent = 1 check_interval = 0 [[runners]] "name = "jie #這個url 是git的url url = "http://127.0.65.51:90/" #這個url是下載代碼的url,如果發現無法下載代碼,就手手動添加這個配置 clone_url = "http://127.0.65.51:90" # gitlab的token,這個是在注冊時就配置加上的,該token是gitlab提供的 token = "bb21ebd38b0985b95fdada9024bb8e8" executor = "docker" [runners.docker] tls_verify = false image = "harbor.local/library/centos:centos7.5.1804" privileged = false disable_cache = false #這個配置很重要,我的這個runner是用來構建maven項目的,又因為使用的executor是docker,因此每次構建,都需要下載鏡像,如果每次都去下載那會麻煩,因此做一個磁盤映射,/home/gitlab-runner/.m2 是宿主機的目錄,該目錄下 是所有的maven依賴 volumes = ["/cache","/home/gitlab-runner/.m2:/root/.m2"] shm_size = 0 [runners.cache]
上面的gitlab-runner配置文件中,有幾個很重要的配置 一個是 clone_url 一個是 executor 最后一個是 volumes。
可以查看一下 我的 /home/gitlab-runner/.m2 路徑下都是什么
其中repository文件夾下就是存放的各種jar依賴 ,而 settings.xml 則是 maven的配置文件,因此當我們在構建的時候就可以指定配置了。
下面就是.gitlab-ci.yml的配置信息了。
# 這個鏡像很重要,因為我們是在docker內部使用docker命名,因此必須要能使用該鏡像,最好runner上就存在該鏡像 image: harbor.local/library/docker variables: #這個指的是生成的docker鏡像放在那里,當然選擇放在宿主機上了,此處需要注意,如果runner機器跟要放docker的機器不一樣的話,需要做互信 DOCKER_HOST: tcp://172.98.60.152:2375 DOCKER_DRIVER: overlay2 #指定maven本地倉庫地址 MAVEN_OPTS: "-Dmaven.repo.local=/root/.m2/repository" # 定義build shell BUILD_SHELL: "mvn clean package -Dmaven.test.skip=true $MAVEN_OPTS --settings=/root/.m2/settings.xml" stages: - package - build - test - deploy job-package: stage: package image: harbor.local/library/maven:3.6.3-ibmjava-8-alpine tags: #注意這里的tag,如果是純數字,可能回報語法異常 - runner-151 script: - echo $CI_COMMIT_MESSAGE - echo `mvn --version` - echo $BUILD_SHELL - $BUILD_SHELL # 由於下一個job我們要使用該job打好的jar文件,因此加入artifacts artifacts: paths: - node-a1/target/*.jar - node-a2/target/*.jar - node-b1/target/*.jar - node-b2/target/*.jar job-build: stage: build image: harbor.local/library/docker dependencies: - job-package tags: #注意這里的tag,如果是純數字,可能回報語法異常 - runner-151 script: #打印git提交信息 - echo $CI_COMMIT_MESSAGE - echo "###################" # 注意下面這一段script ,他是多行的。這里面做的事,就是判斷提交信息是什么,然后選擇性的就行ci。在docker build的時候 加入了一個參數DOCKER_JAVA_FILE_PATH,這是一個在Dockerfile中定義的一個參數 - if [ "$CI_COMMIT_MESSAGE" == "node-a1" ]; then pwd; ls; echo "======="; ls node-a1/target/ ; java_file_src=$(ls node-a1/target/ | sed "s:^:`pwd`/:"); echo $java_file_src;
# 這里的node-a1/target/*.jar 就是上一個job中定義的 docker build --build-arg DOCKER_JAVA_FILE_PATH=node-a1/target/*.jar -t node-a1 . ; echo 'build imgage as node-a1'; fi - if [ "$CI_COMMIT_MESSAGE" == "node-b1" ]; then pwd; ls; echo "======="; ls node-b1/target/ ; java_file_src=$(ls node-b1/target/ | sed "s:^:`pwd`/:") echo $java_file_src; docker build --build-arg DOCKER_JAVA_FILE_PATH=node-b1/target/*.jar -t node-b1 . ; echo 'build imgage as node-b1'; fi # after_script: # - docker rm jdk_temp job-test: stage: test tags: - runner-151 script: # https://blog.csdn.net/github_35631540/article/details/107864258 # 完整的提交消息 - echo $CI_COMMIT_MESSAGE # 構建項目的分支或標記名稱 - echo $CI_COMMIT_REF_NAME # 提交分支名稱。僅在建立分支時顯示 - echo $CI_COMMIT_BRANCH # 提交標記名稱。僅在構建標簽時顯示 - echo $CI_COMMIT_TAG
# 當前的Git CommitId
- ccho $CI_COMMIT_SHA
# 當前的Git CommitId 短ID 一般使用該值作為build鏡像的TAG
- echo $CI_COMMIT_SHORT_SHA
# 上一次的commitid
- echo $CI_COMMIT_BEFORE_SHA
job-deploy: stage: deploy tags: - runner-151 script: # 發布 - echo $CI_COMMIT_MESSAGE - echo "###################" - if [ "$CI_COMMIT_MESSAGE" == "node-a1" ] ;then docker stop nodea1 || true; docker rm nodea1 || true; echo 'start nodea1 image'; docker run -d -p 9090:9090 --name nodea1 -d node-a1:latest java -jar app.jar; fi - if [ "$CI_COMMIT_MESSAGE" == "node-b1" ] ;then docker stop nodeb1 || true; docker rm nodeb1 || true; echo 'start nodeb1 image'; docker run -p 8080:8080 --name nodeb1 -d node-b1:latest java -jar app.jar; fi
上面有幾點是需要注意的。
1.是要自定義maven構建參數。指定 maven本地倉庫地址,指定配置文件 settings.xml。這樣可以在本地沒有依賴的情況下,通過settings.xml中配置的中央倉庫的地址去拉取依賴。
2.docker鏡像。不要懷疑,鏡像名字就是docker,要在docker中進行docker操作,需要docker in docker 也就是 dind
3.artifacts 的配置,在job中傳遞構建物,使用artifacts是比較方便的,這里需要注意的就是在任務中取artifacts時的路徑問題。
4.Dockerfile 在構建鏡像的時候我們使用if判斷,因此說明Dockerfile中有一個是變量,具體導本例就是Dockerfile 中的ADD 操作,就是ADD什么到鏡像里,因此我們需要在Dockerfile中設置變量,同時在docker build 是設置該變量的值。
5.關於部署。本例中runner 和實際應用服務器其實是一台服務器,因為我們可以直接進行部署,如果運行服務器是其他服務器,那么我們還需要將構建好的鏡像進行推送,然后一個簡單的方案是使用watchtower 來動態更新服務
一些常見問題:
運行 提示:This job does not have a trace
這個問題,花了很久時間才找到原因,之前是可用的,后來發現是docker hub的地址改變了,雖然本地有對應的鏡像,但是runner服務器對應的docker hub中卻沒有鏡像。因此解決方案就是將本地鏡像push到docker hub中