基于GitLab的CICD流程是怎样的,针对这个问题,这篇文章详细介绍了相对应的分析和解答,希望可以帮助更多想解决这个问题的小伙伴找到更简单易行的方法。
最近想把公司基于Jenkins的自动化构建修改到GitLab上,主要原因是在Jenkins上没有做权限控制,大家使用同一个账号,造成不同项目组的源码泄漏问题;另外还有一个使用Jenkins的独立服务器,感觉还是资源浪费了点。
按项目
项目
->设置
->CI/CD
->Runner
按分组
分组
->设置
->CI/CD
->Runner
全局
管理中心
->概览
->Runner
从gitee上下载对应的的helm包,地址
修改values文件的gitlabUrl
、runnerRegistrationToken
、tags
执行以下命令
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容器主要用于编译前端项目,一般主要使用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项目,主要用到JDK
和MAVEN
$ 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_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库 // 参考地址: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.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 //在另外一个窗口,提交镜像 $ docker push harbor_url/tools/java:1.8 //将镜像推送到Harbor私服
注意
source /etc/profile
这个命令只是当前有效,在提交镜像后,使用镜像重新运行容器还需要在执行一次该命令。具体如何永久生效,还不知道。如果大佬知道可以告知下。
该容器只是适应我们公司的状况,我们公司的前端打包其实并不需要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.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 //在另外一个窗口,提交镜像 $ docker push harbor_url/tools/curl-git //将镜像推送到Harbor私服
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私服
# 如果各个stage没有使用镜像,则使用默认镜像 image: $HARBOR_URL/tools/alpine stages: - build - deploy # 全局变量定义 variables: # 镜像名,tag默认使用pipeline_id IMAGE_NAME: <harbor_url>/<image_path>/<image_name> # 定义应用名称,即deployment_name、container_name、service_name等 APP_NAME: <application_name> # 应用端口,一般应用端口和service的端口一致 APP_PORT: 80 # 定义命名空间,需要根据不同的打包命令替换为真实命名空间 NAMESPACE: dev # HARBOR_URL 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: - <runner_tag> # 使用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_ID k8s_deploy_job: # 包含kubectl 工具的镜像 image: $HARBOR_URL/tools/kubectl:1.12.6 stage: deploy only: refs: - dev tags: - <runner_tag> # 该 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_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,会上传到gitlab-server artifacts: paths: - dist.tar.gz
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: - <runner_tag> script: # 重新使得JAVA_HOME、M2_HOME环境变量生效 - source /etc/profile - mvn -P$NAMESPACE clean package - cd <module_dir> - mvn -P$NAMESPACE docker:build docker:push
deployment.yaml文件中包含2部分,k8s的deployment
对象和service
对象。
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 # 前端项目,使用的是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: 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
至此,一个完整的基于gitlab的CICD流程可以跑起来了。因为是配合k8s运行的,在整个搭建的过程还是坎坷。例如使用javaj镜像但是需要运行docker命令,services
那块的定义如果不去看文档就稀里糊涂的;然后前端的yarn
和mvn install
等命令都会涉及到从公网下载依赖包,这些依赖包如何缓存才能使得下一次构建可以直接使用,这个就涉及到k8s的PV和PVC的相关概念和使用。
另外,对于.gitlab-ci.yml的变量还是有写死的内容,例如namespace,还需要另外一个脚本根据打包命令来替换对应的变量。还有待优化。
这个整套流程跑下来,感觉又学到了一些东西。
关于基于GitLab的CICD流程是怎样的问题的解答就分享到这里了,希望以上内容可以对大家有一定的帮助,如果你还有很多疑惑没有解开,可以关注亿速云行业资讯频道了解更多相关知识。
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。