溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

基于GitLab的CICD流程是怎樣的

發(fā)布時(shí)間:2021-10-19 18:36:19 來(lái)源:億速云 閱讀:153 作者:柒染 欄目:大數(shù)據(jù)

基于GitLab的CICD流程是怎樣的,針對(duì)這個(gè)問(wèn)題,這篇文章詳細(xì)介紹了相對(duì)應(yīng)的分析和解答,希望可以幫助更多想解決這個(gè)問(wèn)題的小伙伴找到更簡(jiǎn)單易行的方法。

最近想把公司基于Jenkins的自動(dòng)化構(gòu)建修改到GitLab上,主要原因是在Jenkins上沒(méi)有做權(quán)限控制,大家使用同一個(gè)賬號(hào),造成不同項(xiàng)目組的源碼泄漏問(wèn)題;另外還有一個(gè)使用Jenkins的獨(dú)立服務(wù)器,感覺(jué)還是資源浪費(fèi)了點(diǎn)。

配置GitLab的runner

從gitlab上獲取Runner注冊(cè)的token。有三種方式
  • 按項(xiàng)目
    項(xiàng)目->設(shè)置->CI/CD->Runner

  • 按分組
    分組->設(shè)置->CI/CD->Runner

  • 全局
    管理中心->概覽->Runner

運(yùn)行Runner
  • 從gitee上下載對(duì)應(yīng)的的helm包,地址

  • 修改values文件的gitlabUrl、runnerRegistrationTokentags

  • 執(zhí)行以下命令

helm package .
helm install --namespace gitlab --name gitlab-runner *.tgz

說(shuō)明:

  • gitlabUrl 就是你gitlab私服地址

  • runnerRegistrationToken 就是從第1步獲取的runner注冊(cè)的token值

  • tags 標(biāo)識(shí)這個(gè)runner,stage的job就是根據(jù)該tag選擇對(duì)應(yīng)的runner的

  • Chart.yaml定義該helm的基本信息,注意里面的name字段必須和當(dāng)前目錄的名稱一致

  • templates/pvc.yaml 定義了一個(gè)Dynamic Provisioning的PVC,使用的storageClassName是阿里云的alicloud-disk-efficiency(我們的k8s是阿里云的容器服務(wù)),它會(huì)自動(dòng)創(chuàng)建對(duì)應(yīng)的PV,并創(chuàng)建一個(gè)云盤實(shí)例。這個(gè)可以用來(lái)處理多個(gè)Job之間的緩存文件

  • templates/configmap.yaml文件的runners.kubernetes.volumes.pvc定義了PVC的名稱,即上一步定義的PVC名稱,如果有修改注意同步

至此,一個(gè)gitlab-runner應(yīng)該就可以注冊(cè)到對(duì)應(yīng)的gitlab server上去了。

配置環(huán)境變量

對(duì)于在構(gòu)建過(guò)程使用到比較私密的信息,應(yīng)該直接配置到gitlab server的環(huán)境變量上,這里我們主要配置一下三個(gè)參數(shù):

  • REGISTRY_PASSWORD Harbor私服的密碼

  • REGISTRY_USERNAME Harbor私服的用戶名

  • KUBE_CONFIG kubectl執(zhí)行所需的賬號(hào)、證書(shū)等信息,該字符串可以使用以下命令獲取

echo $(cat ~/.kube/config | base64) | tr -d " "

這里的環(huán)境變量是配置在group下的CI/CD頁(yè)面的環(huán)境變量

對(duì)于以下容器的配置為了純手工配置,更好的方式應(yīng)該是使用Dockerfile進(jìn)行編寫(xiě)。這里只是為了更好的說(shuō)明基礎(chǔ)鏡像的制作過(guò)程。

配置Node容器

Node容器主要用于編譯前端項(xiàng)目,一般主要使用yarn下載依賴,npm編譯打包。所以Node容器需要包含這兩個(gè)命令。

$ docker pull node //拉取最新的node鏡像
$ docker run -it --rm --name node node /bin/sh //運(yùn)行node鏡像,并且進(jìn)入
$ yarn config set registry https://registry.npm.taobao.org //配置yarn的源為淘寶源
$ yarn config list //查看配置
--------------------------------
info yarn config
{
  'version-tag-prefix': 'v',
  'version-git-tag': true,
  'version-commit-hooks': true,
  'version-git-sign': false,
  'version-git-message': 'v%s',
  'init-version': '1.0.0',
  'init-license': 'MIT',
  'save-prefix': '^',
  'bin-links': true,
  'ignore-scripts': false,
  'ignore-optional': false,
  registry: 'https://registry.yarnpkg.com',
  'strict-ssl': true,
  'user-agent': 'yarn/1.16.0 npm/? node/v12.5.0 linux x64',
  version: '1.16.0'
}
info npm config
{
  version: '1.16.0'
}
Done in 0.07s.
--------------------------------
$ docker commit node harbor_url/tools/node-taobao //另外打開(kāi)一個(gè)窗口,提交修改后的node鏡像
$ docker push harbor_url/tools/node-taobao //推送鏡像到Harbor私服

配置Java容器

Java容器主要用于編譯Java項(xiàng)目,主要用到JDKMAVEN

$ docker pull alpine // 拉取最新的alpine鏡像
$ docker run -it --rm --name java alpine //進(jìn)入鏡像
$ mkdir -p /opt/java // 創(chuàng)建java目錄
$ mkdir -p /opt/maven //創(chuàng)建maven目錄
$ docker cp jdk-8u211-linux-x64.tar.gz java:/opt/java/    //從主機(jī)上拷貝JDK到容器內(nèi)部 
$ docker cp apache-maven-3.6.1-bin.tar.gz java:/opt/maven/   //從主機(jī)上拷貝MAVEN到容器內(nèi)部
/opt/maven $ tar -xzvf apache-maven-3.6.1-bin.tar.gz  //在容器內(nèi)解壓MAVEN
/opt/maven $ rm -rf apache-maven-3.6.1-bin.tar.gz     //刪除MAVEN壓縮包
/opt/java $ tar -xzvf jdk-8u211-linux-x64.tar.gz      //在容器內(nèi)解壓JDK
/opt/java $ rm -rf jdk-8u211-linux-x64.tar.gz         //刪除JDK壓縮包
$ vi /etc/profile	//配置環(huán)境變量
--------------------------------
export JAVA_HOME=/opt/java/jdk1.8.0_211
export M2_HOME=/opt/maven/apache-maven-3.6.1
export PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:$JAVA_HOME/bin:$M2_HOME/bin
--------------------------------
//Java是基于GUN Standard C library(glibc),Alpine是基于MUSL libc(mini libc),所以需要安裝glibc庫(kù)
// 參考地址:https://blog.csdn.net/Dannyvon/article/details/80092834
$ echo http://mirrors.ustc.edu.cn/alpine/v3.10/main > /etc/apk/repositories
$ echo http://mirrors.ustc.edu.cn/alpine/v3.10/community >> /etc/apk/repositories
$ apk update
$ apk --no-cache add ca-certificates
$ wget https://github.com/sgerrand/alpine-pkg-glibc/releases/download/2.27-r0/glibc-2.27-r0.apk
$ wget -q -O /etc/apk/keys/sgerrand.rsa.pub https://alpine-pkgs.sgerrand.com/sgerrand.rsa.pub
$ apk add glibc-2.27-r0.apk  // 至此glibc庫(kù)安裝完畢
$ source /etc/profile  //生效環(huán)境變量
$ java -version  //查看JAVA版本
--------------------------------
java version "1.8.0_211"
Java(TM) SE Runtime Environment (build 1.8.0_211-b12)
Java HotSpot(TM) 64-Bit Server VM (build 25.211-b12, mixed mode)
--------------------------------
$ mvn -v  //查看MAVEN版本
--------------------------------
Apache Maven 3.6.1 (d66c9c0b3152b2e69ee9bac180bb8fcc8e6af555; 2019-04-04T19:00:29Z)
Maven home: /opt/maven/apache-maven-3.6.1
Java version: 1.8.0_211, vendor: Oracle Corporation, runtime: /opt/java/jdk1.8.0_211/jre
Default locale: en_US, platform encoding: ANSI_X3.4-1968
OS name: "linux", version: "4.9.125-linuxkit", arch: "amd64", family: "unix"
--------------------------------
$ docker commit java harbor_url/tools/java:1.8  //在另外一個(gè)窗口,提交鏡像
$ docker push harbor_url/tools/java:1.8   //將鏡像推送到Harbor私服

注意source /etc/profile這個(gè)命令只是當(dāng)前有效,在提交鏡像后,使用鏡像重新運(yùn)行容器還需要在執(zhí)行一次該命令。具體如何永久生效,還不知道。如果大佬知道可以告知下。

配置Curl&Git容器

該容器只是適應(yīng)我們公司的狀況,我們公司的前端打包其實(shí)并不需要Node容器。前端打包過(guò)程是在本地打包編譯后生成dist目錄下的文件,然后壓縮上傳到內(nèi)網(wǎng)的oss上。接著在Jenkins上執(zhí)行腳本,其實(shí)是從內(nèi)網(wǎng)的oss下載并解壓,然后根據(jù)Dockerfile在制作業(yè)務(wù)鏡像。這個(gè)過(guò)程就需要使用到Curl和Git命令。整個(gè)過(guò)程是為了解決線上打包環(huán)境可能跟開(kāi)發(fā)本地不一致,以及前端打包需要下載依賴和編譯耗時(shí)的問(wèn)題,通過(guò)這樣的一個(gè)流程,前端每次構(gòu)建的時(shí)間就非常短,幾秒鐘就能搞定。

$ docker run -it --rm --name curl-git alpine
$ echo http://mirrors.ustc.edu.cn/alpine/v3.10/main > /etc/apk/repositories
$ echo http://mirrors.ustc.edu.cn/alpine/v3.10/community >> /etc/apk/repositories
$ apk update
$ apk add curl
$ apk add git
$ curl -V
--------------------------------
curl 7.61.1 (x86_64-alpine-linux-musl) libcurl/7.61.1 LibreSSL/2.6.5 zlib/1.2.11 libssh3/1.8.2
Release-Date: 2018-09-05
Protocols: dict file ftp ftps gopher http https imap imaps pop3 pop3s rtsp scp sftp smb smbs smtp smtps telnet tftp
Features: AsynchDNS IPv6 Largefile NTLM NTLM_WB SSL libz UnixSockets HTTPS-proxy
--------------------------------
$ git version
--------------------------------
git version 2.15.3
--------------------------------
$ docker commit curl-git harbor_url/tools/curl-git  //在另外一個(gè)窗口,提交鏡像
$ docker push harbor_url/tools/curl-git   //將鏡像推送到Harbor私服

配置kubectl容器

kubectl容器是用于部署應(yīng)用到k8s集群,需要用到config的配置信息。但是這個(gè)信息一般比較私密,不會(huì)直接打到容器里面,容器里面只會(huì)放一個(gè)kubectl客戶端,然后具體的配置文件在運(yùn)行期間在放到~/.kube/config文件內(nèi)。

$ docker run -it --rm --name kubectl alpine  //運(yùn)行并且進(jìn)入容器
$ docker cp kubectl kubectl:/usr/bin/  //拷貝kubectl客戶端到容器內(nèi)部,kubectl客戶端可以直接在k8s的master節(jié)點(diǎn)找到,或者直接在github上下載到對(duì)應(yīng)版本的客戶端
$ chmod +x /usr/bin/kubectl //設(shè)置為可執(zhí)行文件
$ kubectl version //查看版本,因?yàn)闆](méi)有配置服務(wù)的證書(shū),所以服務(wù)端的信息打印不出來(lái)
--------------------------------
Client Version: version.Info{Major:"1", Minor:"12+", GitVersion:"v1.12.6-aliyun.1", GitCommit:"4304b26", GitTreeState:"", BuildDate:"2019-04-08T08:50:29Z", GoVersion:"go1.10.8", Compiler:"gc", Platform:"linux/amd64"}
The connection to the server localhost:8080 was refused - did you specify the right host or port?
--------------------------------
$ docker commit kubectl harbor_url/tools/kubectl:1.12.6  //在另外一個(gè)窗口,提交鏡像
$ docker push  harbor_url/tools/kubectl:1.12.6   //將鏡像推送到Harbor私服

配置.gitlab-ci.yml

# 如果各個(gè)stage沒(méi)有使用鏡像,則使用默認(rèn)鏡像
image: $HARBOR_URL/tools/alpine
stages:
  - build
  - deploy
# 全局變量定義
variables:
  # 鏡像名,tag默認(rèn)使用pipeline_id
  IMAGE_NAME: <harbor_url>/<image_path>/<image_name>
  # 定義應(yīng)用名稱,即deployment_name、container_name、service_name等
  APP_NAME: <application_name>
  # 應(yīng)用端口,一般應(yīng)用端口和service的端口一致
  APP_PORT: 80
  # 定義命名空間,需要根據(jù)不同的打包命令替換為真實(shí)命名空間
  NAMESPACE: dev
  # HARBOR_URL
  HARBOR_URL: <harbor_url>
docker_build_job:
  # 包含curl 和 git 工具的鏡像
  image: $HARBOR_URL/tools/curl-git
  stage: build
  # 定義只有dev分支push或者merge事件觸發(fā)Job
  only:
    refs:
      - dev
  tags:
    - <runner_tag>
  # 使用dind模式,連接到一個(gè)有啟動(dòng)docker的容器
  services:
    - $HARBOR_URL/tools/docker-dind:18.09.7
  variables:
    # docker daemon 啟動(dòng)的參數(shù)
    DOCKER_DRIVER: overlay
    DOCKER_HOST: tcp://localhost:2375
  # 該 stage 執(zhí)行的腳本命令
  # 1. 執(zhí)行構(gòu)建腳本build.sh
  # 2. 登錄Harbor私服
  # 3. 根據(jù)Dockerfile構(gòu)建image
  # 4. push image 到Harbor
  script:
  	# build.sh腳本為公司內(nèi)部腳本,根據(jù)后面的參數(shù)配置不同的環(huán)境
    # 主要流程是下載開(kāi)發(fā)打包好的壓縮文件,然后解壓,接著根據(jù)不同環(huán)境替換變量
    - sh ./build.sh -b development
    - docker login -u $REGISTRY_USERNAME -p $REGISTRY_PASSWORD $HARBOR_URL
    - docker build -t $IMAGE_NAME:$CI_PIPELINE_ID .
    - docker push $IMAGE_NAME:$CI_PIPELINE_ID
k8s_deploy_job:
  # 包含kubectl 工具的鏡像
  image: $HARBOR_URL/tools/kubectl:1.12.6
  stage: deploy
  only:
    refs:
      - dev
  tags:
    - <runner_tag>
  # 該 stage 執(zhí)行的腳本命令
  # 1. 創(chuàng)建/etc/deploy/config文件
  # 2. 將k8s的證書(shū)信息寫(xiě)入/etc/deploy/config
  # 3. 替換deployment.yaml文件中的各個(gè)變量
  # 4. 部署到k8s集群環(huán)境中
  script:
    - mkdir -p ~/.kube
    - touch ~/.kube/config
    # KUBE_CONFIG這個(gè)環(huán)境變量是在gitlab server中配置的
    - echo $KUBE_CONFIG | base64 -d > ~/.kube/config
    # 對(duì)deployment.yaml進(jìn)行對(duì)應(yīng)的變量替換
    - sed -i "s?IMAGE_TAG?$CI_PIPELINE_ID?g" deployment.yaml
    - sed -i "s?IMAGE_NAME?$IMAGE_NAME?g" deployment.yaml
    - sed -i "s?APP_NAME?$APP_NAME?g" deployment.yaml
    - sed -i "s?NAMESPACE?$NAMESPACE?g" deployment.yaml
    - sed -i "s?APP_PORT?$APP_PORT?g" deployment.yaml
    - kubectl apply -f deployment.yaml

這個(gè).gitlab-ci.yml文件少了基于node和java鏡像的配置。不過(guò)都是大同小異,就不在復(fù)述。對(duì)于node鏡像打包后一般會(huì)生成dist目錄,這個(gè)時(shí)候可以加個(gè)步驟把dist目錄壓縮,然后定義artifacts,這樣當(dāng)前的stage執(zhí)行完后就會(huì)上傳該壓縮包到gitlab-server。接著下一個(gè)stage就會(huì)自動(dòng)下載這個(gè)壓縮包,這樣我們就可以解壓這個(gè)壓縮包,然后再根據(jù)Dockerfile進(jìn)行打包了,同樣是使用dind的模式。對(duì)于java鏡像同樣可以使用這個(gè)原理,mvn編譯打包出一個(gè)jar包或者war包,然后傳遞到下一個(gè)stage,再進(jìn)行構(gòu)建鏡像;不過(guò)如果使用maven的docker插件的話,那就不用分兩個(gè)stage了,直接在java的那個(gè)鏡像加個(gè)services的定義,這樣就可以使用mvn docker:build docker:push命令了。不過(guò)要注意,使用maven的docker插件,鏡像是定義在pom.xml文件的,這個(gè)需要和外部的.gitlab-ci.yml文件定義的鏡像名稱同步

node鏡像部分定義
node_build_job:
  image: $HARBOR_URL/tools/node-taobao
  stage: package
  only:
    refs:
      - dev
  tags:
    - <runner_tag>
  script:
  	# 下載依賴
    - yarn
    # 編譯打包
    - npm run build --qa
    # 壓縮dist目錄
    - tar -czvf dist.tar.gz dist/
  # 定義artifacts,會(huì)上傳到gitlab-server
  artifacts:
    paths:
    - dist.tar.gz
java鏡像部分定義
java_build_job:
  image: $HARBOR_URL/tools/java:1.8
  stage: package
  only:
    refs:
      - dev
  # services定義,使用dind模式,其實(shí)就是通過(guò)link指令把docker容器鏈接到j(luò)ava鏡像,使得java鏡像可以使用docker命令
  services:
    - $HARBOR_URL/tools/docker-dind:18.09.7
  variables:
    DOCKER_DRIVER: overlay
    DOCKER_HOST: tcp://localhost:2375
  tags:
    - <runner_tag>
  script:
    # 重新使得JAVA_HOME、M2_HOME環(huán)境變量生效
    - source /etc/profile
    - mvn -P$NAMESPACE clean package
    - cd <module_dir>
    - mvn -P$NAMESPACE docker:build docker:push

配置deployment.yaml

deployment.yaml文件中包含2部分,k8s的deployment對(duì)象和service對(duì)象。

apiVersion: apps/v1beta2
kind: Deployment
metadata:
  labels:
    app: APP_NAME
  name: APP_NAME
  namespace: NAMESPACE
spec:
  progressDeadlineSeconds: 600
  replicas: 1
  revisionHistoryLimit: 10
  selector:
    matchLabels:
      app: APP_NAME
  strategy:
    rollingUpdate:
      maxSurge: 25%
      maxUnavailable: 25%
    type: RollingUpdate
  template:
    metadata:
      labels:
        app: APP_NAME
    spec:
      affinity: {}
      containers:
        - image: 'IMAGE_NAME:IMAGE_TAG'
          imagePullPolicy: Always
          name: APP_NAME
          # 前端項(xiàng)目,使用的是nginx基礎(chǔ)鏡像,一般使用內(nèi)存都比較低
          resources:
            limits:
              cpu: '1'
              memory: 64Mi
            requests:
              cpu: '0'
              memory: 32Mi
          terminationMessagePath: /dev/termination-log
          terminationMessagePolicy: File
      dnsPolicy: ClusterFirst
      restartPolicy: Always
      schedulerName: default-scheduler
      securityContext: {}
      terminationGracePeriodSeconds: 30

---

apiVersion: v1
kind: Service
metadata:
  name: APP_NAME
  namespace: NAMESPACE
spec:
  ports:
    - port: APP_PORT
      protocol: TCP
      targetPort: APP_PORT
  selector:
    app: APP_NAME
  sessionAffinity: None
  type: ClusterIP

結(jié)束

至此,一個(gè)完整的基于gitlab的CICD流程可以跑起來(lái)了。因?yàn)槭桥浜蟢8s運(yùn)行的,在整個(gè)搭建的過(guò)程還是坎坷。例如使用javaj鏡像但是需要運(yùn)行docker命令,services那塊的定義如果不去看文檔就稀里糊涂的;然后前端的yarnmvn install等命令都會(huì)涉及到從公網(wǎng)下載依賴包,這些依賴包如何緩存才能使得下一次構(gòu)建可以直接使用,這個(gè)就涉及到k8s的PV和PVC的相關(guān)概念和使用。

另外,對(duì)于.gitlab-ci.yml的變量還是有寫(xiě)死的內(nèi)容,例如namespace,還需要另外一個(gè)腳本根據(jù)打包命令來(lái)替換對(duì)應(yīng)的變量。還有待優(yōu)化。

這個(gè)整套流程跑下來(lái),感覺(jué)又學(xué)到了一些東西。


關(guān)于基于GitLab的CICD流程是怎樣的問(wèn)題的解答就分享到這里了,希望以上內(nèi)容可以對(duì)大家有一定的幫助,如果你還有很多疑惑沒(méi)有解開(kāi),可以關(guān)注億速云行業(yè)資訊頻道了解更多相關(guān)知識(shí)。

向AI問(wèn)一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI