千家信息网

基于GitLab的CICD流程是怎样的

发表于:2024-09-22 作者:千家信息网编辑
千家信息网最后更新 2024年09月22日,基于GitLab的CICD流程是怎样的,针对这个问题,这篇文章详细介绍了相对应的分析和解答,希望可以帮助更多想解决这个问题的小伙伴找到更简单易行的方法。最近想把公司基于Jenkins的自动化构建修改到
千家信息网最后更新 2024年09月22日基于GitLab的CICD流程是怎样的

基于GitLab的CICD流程是怎样的,针对这个问题,这篇文章详细介绍了相对应的分析和解答,希望可以帮助更多想解决这个问题的小伙伴找到更简单易行的方法。

最近想把公司基于Jenkins的自动化构建修改到GitLab上,主要原因是在Jenkins上没有做权限控制,大家使用同一个账号,造成不同项目组的源码泄漏问题;另外还有一个使用Jenkins的独立服务器,感觉还是资源浪费了点。

配置GitLab的runner

从gitlab上获取Runner注册的token。有三种方式
  • 按项目
    项目->设置->CI/CD->Runner

  • 按分组
    分组->设置->CI/CD->Runner

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

运行Runner
  • 从gitee上下载对应的的helm包,地址

  • 修改values文件的gitlabUrlrunnerRegistrationTokentags

  • 执行以下命令

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

说明:

  • gitlabUrl 就是你gitlab私服地址

  • runnerRegistrationToken 就是从第1步获取的runner注册的token值

  • tags 标识这个runner,stage的job就是根据该tag选择对应的runner的

  • Chart.yaml定义该helm的基本信息,注意里面的name字段必须和当前目录的名称一致

  • templates/pvc.yaml 定义了一个Dynamic Provisioning的PVC,使用的storageClassName是阿里云的alicloud-disk-efficiency(我们的k8s是阿里云的容器服务),它会自动创建对应的PV,并创建一个云盘实例。这个可以用来处理多个Job之间的缓存文件

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

至此,一个gitlab-runner应该就可以注册到对应的gitlab server上去了。

配置环境变量

对于在构建过程使用到比较私密的信息,应该直接配置到gitlab server的环境变量上,这里我们主要配置一下三个参数:

  • REGISTRY_PASSWORD Harbor私服的密码

  • REGISTRY_USERNAME Harbor私服的用户名

  • KUBE_CONFIG kubectl执行所需的账号、证书等信息,该字符串可以使用以下命令获取

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

这里的环境变量是配置在group下的CI/CD页面的环境变量

对于以下容器的配置为了纯手工配置,更好的方式应该是使用Dockerfile进行编写。这里只是为了更好的说明基础镜像的制作过程。

配置Node容器

Node容器主要用于编译前端项目,一般主要使用yarn下载依赖,npm编译打包。所以Node容器需要包含这两个命令。

$ docker pull node //拉取最新的node镜像$ docker run -it --rm --name node node /bin/sh //运行node镜像,并且进入$ 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 //另外打开一个窗口,提交修改后的node镜像$ docker push harbor_url/tools/node-taobao //推送镜像到Harbor私服

配置Java容器

Java容器主要用于编译Java项目,主要用到JDKMAVEN

$ docker pull alpine // 拉取最新的alpine镜像$ docker run -it --rm --name java alpine //进入镜像$ mkdir -p /opt/java // 创建java目录$ mkdir -p /opt/maven //创建maven目录$ docker cp jdk-8u211-linux-x64.tar.gz java:/opt/java/    //从主机上拷贝JDK到容器内部 $ docker cp apache-maven-3.6.1-bin.tar.gz java:/opt/maven/   //从主机上拷贝MAVEN到容器内部/opt/maven $ tar -xzvf apache-maven-3.6.1-bin.tar.gz  //在容器内解压MAVEN/opt/maven $ rm -rf apache-maven-3.6.1-bin.tar.gz     //删除MAVEN压缩包/opt/java $ tar -xzvf jdk-8u211-linux-x64.tar.gz      //在容器内解压JDK/opt/java $ rm -rf jdk-8u211-linux-x64.tar.gz         //删除JDK压缩包$ vi /etc/profile     //配置环境变量--------------------------------export JAVA_HOME=/opt/java/jdk1.8.0_211export M2_HOME=/opt/maven/apache-maven-3.6.1export 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库// 参考地址: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库安装完毕$ source /etc/profile  //生效环境变量$ 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.1Java version: 1.8.0_211, vendor: Oracle Corporation, runtime: /opt/java/jdk1.8.0_211/jreDefault locale: en_US, platform encoding: ANSI_X3.4-1968OS name: "linux", version: "4.9.125-linuxkit", arch: "amd64", family: "unix"--------------------------------$ docker commit java harbor_url/tools/java:1.8  //在另外一个窗口,提交镜像$ docker push harbor_url/tools/java:1.8   //将镜像推送到Harbor私服

注意source /etc/profile这个命令只是当前有效,在提交镜像后,使用镜像重新运行容器还需要在执行一次该命令。具体如何永久生效,还不知道。如果大佬知道可以告知下。

配置Curl&Git容器

该容器只是适应我们公司的状况,我们公司的前端打包其实并不需要Node容器。前端打包过程是在本地打包编译后生成dist目录下的文件,然后压缩上传到内网的oss上。接着在Jenkins上执行脚本,其实是从内网的oss下载并解压,然后根据Dockerfile在制作业务镜像。这个过程就需要使用到Curl和Git命令。整个过程是为了解决线上打包环境可能跟开发本地不一致,以及前端打包需要下载依赖和编译耗时的问题,通过这样的一个流程,前端每次构建的时间就非常短,几秒钟就能搞定。

$ 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.2Release-Date: 2018-09-05Protocols: dict file ftp ftps gopher http https imap imaps pop3 pop3s rtsp scp sftp smb smbs smtp smtps telnet tftpFeatures: 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  //在另外一个窗口,提交镜像$ docker push harbor_url/tools/curl-git   //将镜像推送到Harbor私服

配置kubectl容器

kubectl容器是用于部署应用到k8s集群,需要用到config的配置信息。但是这个信息一般比较私密,不会直接打到容器里面,容器里面只会放一个kubectl客户端,然后具体的配置文件在运行期间在放到~/.kube/config文件内。

$ docker run -it --rm --name kubectl alpine  //运行并且进入容器$ docker cp kubectl kubectl:/usr/bin/  //拷贝kubectl客户端到容器内部,kubectl客户端可以直接在k8s的master节点找到,或者直接在github上下载到对应版本的客户端$ chmod +x /usr/bin/kubectl //设置为可执行文件$ kubectl version //查看版本,因为没有配置服务的证书,所以服务端的信息打印不出来--------------------------------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  //在另外一个窗口,提交镜像$ docker push  harbor_url/tools/kubectl:1.12.6   //将镜像推送到Harbor私服

配置.gitlab-ci.yml

# 如果各个stage没有使用镜像,则使用默认镜像image: $HARBOR_URL/tools/alpinestages:  - build  - deploy# 全局变量定义variables:  # 镜像名,tag默认使用pipeline_id  IMAGE_NAME: //  # 定义应用名称,即deployment_name、container_name、service_name等  APP_NAME:   # 应用端口,一般应用端口和service的端口一致  APP_PORT: 80  # 定义命名空间,需要根据不同的打包命令替换为真实命名空间  NAMESPACE: dev  # HARBOR_URL  HARBOR_URL: docker_build_job:  # 包含curl 和 git 工具的镜像  image: $HARBOR_URL/tools/curl-git  stage: build  # 定义只有dev分支push或者merge事件触发Job  only:    refs:      - dev  tags:    -   # 使用dind模式,连接到一个有启动docker的容器  services:    - $HARBOR_URL/tools/docker-dind:18.09.7  variables:    # docker daemon 启动的参数    DOCKER_DRIVER: overlay    DOCKER_HOST: tcp://localhost:2375  # 该 stage 执行的脚本命令  # 1. 执行构建脚本build.sh  # 2. 登录Harbor私服  # 3. 根据Dockerfile构建image  # 4. push image 到Harbor  script:      # build.sh脚本为公司内部脚本,根据后面的参数配置不同的环境    # 主要流程是下载开发打包好的压缩文件,然后解压,接着根据不同环境替换变量    - 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_IDk8s_deploy_job:  # 包含kubectl 工具的镜像  image: $HARBOR_URL/tools/kubectl:1.12.6  stage: deploy  only:    refs:      - dev  tags:    -   # 该 stage 执行的脚本命令  # 1. 创建/etc/deploy/config文件  # 2. 将k8s的证书信息写入/etc/deploy/config  # 3. 替换deployment.yaml文件中的各个变量  # 4. 部署到k8s集群环境中  script:    - mkdir -p ~/.kube    - touch ~/.kube/config    # KUBE_CONFIG这个环境变量是在gitlab server中配置的    - echo $KUBE_CONFIG | base64 -d > ~/.kube/config    # 对deployment.yaml进行对应的变量替换    - 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

这个.gitlab-ci.yml文件少了基于node和java镜像的配置。不过都是大同小异,就不在复述。对于node镜像打包后一般会生成dist目录,这个时候可以加个步骤把dist目录压缩,然后定义artifacts,这样当前的stage执行完后就会上传该压缩包到gitlab-server。接着下一个stage就会自动下载这个压缩包,这样我们就可以解压这个压缩包,然后再根据Dockerfile进行打包了,同样是使用dind的模式。对于java镜像同样可以使用这个原理,mvn编译打包出一个jar包或者war包,然后传递到下一个stage,再进行构建镜像;不过如果使用maven的docker插件的话,那就不用分两个stage了,直接在java的那个镜像加个services的定义,这样就可以使用mvn docker:build docker:push命令了。不过要注意,使用maven的docker插件,镜像是定义在pom.xml文件的,这个需要和外部的.gitlab-ci.yml文件定义的镜像名称同步

node镜像部分定义
node_build_job:  image: $HARBOR_URL/tools/node-taobao  stage: package  only:    refs:      - dev  tags:    -   script:      # 下载依赖    - yarn    # 编译打包    - npm run build --qa    # 压缩dist目录    - tar -czvf dist.tar.gz dist/  # 定义artifacts,会上传到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模式,其实就是通过link指令把docker容器链接到java镜像,使得java镜像可以使用docker命令  services:    - $HARBOR_URL/tools/docker-dind:18.09.7  variables:    DOCKER_DRIVER: overlay    DOCKER_HOST: tcp://localhost:2375  tags:    -   script:    # 重新使得JAVA_HOME、M2_HOME环境变量生效    - source /etc/profile    - mvn -P$NAMESPACE clean package    - cd     - mvn -P$NAMESPACE docker:build docker:push

配置deployment.yaml

deployment.yaml文件中包含2部分,k8s的deployment对象和service对象。

apiVersion: apps/v1beta2kind: Deploymentmetadata:  labels:    app: APP_NAME  name: APP_NAME  namespace: NAMESPACEspec:  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          # 前端项目,使用的是nginx基础镜像,一般使用内存都比较低          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: v1kind: Servicemetadata:  name: APP_NAME  namespace: NAMESPACEspec:  ports:    - port: APP_PORT      protocol: TCP      targetPort: APP_PORT  selector:    app: APP_NAME  sessionAffinity: None  type: ClusterIP

结束

至此,一个完整的基于gitlab的CICD流程可以跑起来了。因为是配合k8s运行的,在整个搭建的过程还是坎坷。例如使用javaj镜像但是需要运行docker命令,services那块的定义如果不去看文档就稀里糊涂的;然后前端的yarnmvn install等命令都会涉及到从公网下载依赖包,这些依赖包如何缓存才能使得下一次构建可以直接使用,这个就涉及到k8s的PV和PVC的相关概念和使用。

另外,对于.gitlab-ci.yml的变量还是有写死的内容,例如namespace,还需要另外一个脚本根据打包命令来替换对应的变量。还有待优化。

这个整套流程跑下来,感觉又学到了一些东西。


关于基于GitLab的CICD流程是怎样的问题的解答就分享到这里了,希望以上内容可以对大家有一定的帮助,如果你还有很多疑惑没有解开,可以关注行业资讯频道了解更多相关知识。

0