基于Gitlab-CI/CD Docker 持续集成 node 项目

·  阅读 2669

最近挥霍青春、沉沦于学习科学文化知识,摸了些旁门左道,故而在此想做一些分享,同时也是小弟我第一次编写文章。以下都是一些仅代表个人的一些观点和心得,本人尽量使用比较通俗易懂的话语来阐述,希望能给各位少侠一些启发和帮助。若有解释不当的地方,还请各位大锅指点一二。


CI/CD介绍

对与Gitlab 提供的 CI/CD, 其称之为持续集成服务、通俗点就是自动化(打包、测试、部署 ...)

CI (持续构建)  -->  代码提交后触发自动化的单元测试,代码预编译,构建镜像,上传镜像等.

CD (持续发布)  --> 将构建好的程序发布到各种环境,如预发布环境,正式环境.


为什么要使用持续集成?

我们都知道,项目开发最基本的流程不过于 "开发" -> "打包" -> "测试" -> "部署",在一个完整项目的生命周期中,避免不了多次以上这样的流程。传统的模式可能会让我们觉得厌烦,原因不外乎于下面几点:

1、开发和打包都在同一台机器上运作,可能导致打包的过程中,影响开发的进度

2、一天天的都是手动打包、测试、部署、日复一日的工作使我们厌倦

3、每个开发者都在自己的机器打包项目,不同的环境配置可能会有各种千奇百怪的问题

除以上问题,当然还有其他不尽人意的缺点,就不一 一描述了,上面的问题足以让人脑壳深疼。在这个时候,我相信强大的持续集成方案一定能解决你对开发流程不满的地方

1、提供后台集成服务,开发、打包,互不影响

2、减少人工编译部署过程中的低级错误

3、解决不同环境下构建项目产生不一致的问题

还有各种好处。。。(具体还是根据大家不同的场景需求定制自己的自动化方案吧)


特别说明

本人使用的系统环境都是 ubuntu、使用docker,项目语言是node.js

不熟悉docker基础的仁兄们需要先看看docker的一些基础知识

个人建议使用两台以上的服务器, 一台开发+测试, 一台部署发布项目 (笔者认为,如果只使用一台服务器,实际上发挥不出 CI/CD 的威力)

对与网上现有的各大分享gitlab ci/cd 的文章,使用 shell 来搭建ci/cd服务的太多了,在此我就不介绍这种方案了。但是基于docker 方案的文章,也看了不少,对与我个人而言并不是太友好,有些说的比较高深,难以理解,有些过于简单,不够详细。所以决定写下这篇文章希望能和大家互相探讨。该文章主要是基于docker 的持续集成方案。


认识Gitlab-CI/CD流程

该小节适于初步认识gitlab持续集成服务的读者阅读、对于已经理解基本流程的可以直接跳过本小节(这一节已经不能教你什么了)

GitLab8.0之后,GitLab CI/CD 就已经集成在GitLab里了。给我几分钟,你会发现,其实流程很简单。

pipeline

每次代码提交就会触发一次pipeline。如上去所示,每一行就是一个集成服务,我们称之为流水线。一次pipeline可以看成一次构建任务。

stage

stage就是上述构建任务中的各个构建阶段。一般会包含:安装依赖,测试,编译,部署服务等多个阶段。

job

job表示构建工作,是每个stage构建阶段里具体执行的工作。

我们可以点击进去看看,你会发现整个流程就像工厂车间里面的任务一样,一个任务完成后接着执行下一个(或多个)任务,不难看出来,以上的任务顺序为 build ->test -> deploy。

(并且如果有其中一个任务失败了,我们可以选择后面的任务是否能继续下去,这对我们很有用,而这些任务都是我们可以预先设定好的,并按照我们的规则来进行)

通过上面这些概念上的东西,你应该对 Gitlab-CI/CD 的工作 流程有了初步的了解,但是这些任务都是交给谁来托管呢? 没错,它就是 GitLab runner。下面就开始我们的主题吧。


启动GitLab runner服务

1、首先要安装docker、已经安装的可跳过此步骤:

(附上docker 安装的官方文档 Get Docker CE for Ubuntu | Docker Documentation)

sudo apt-get update
sudo apt-get install docker-ce
复制代码

2、创建gitlab-runner容器:

sudo docker pull gitlab/gitlab-runner:latest
sudo docker stop gitlab-runner && docker rm gitlab-runner
复制代码
sudo docker run -d --name gitlab-runner --restart always \
  -v /srv/gitlab-runner/config:/etc/gitlab-runner \
  -v /var/run/docker.sock:/var/run/docker.sock \
  gitlab/gitlab-runner:latest
复制代码

3、注册runner(绑定gitlab项目):

首先我们需要打开自己gitlab的项目,打开一下红色指示的地方

注册runner:

sudo docker exec -it gitlab-runner gitlab-ci-multi-runner register -n \
  --url 这里填写上图中的url \
  --registration-token 这里填写上图中的token \
  --executor docker \
  --description "gitlab-runner in docker" \
  --tag-list "ci-cd" \
  --docker-privileged=false \
  --docker-pull-policy="if-not-present" \
  --docker-image "docker:latest" \
  --docker-volumes /var/run/docker.sock:/var/run/docker.sock
复制代码

成功后如下图所示(该步骤有可能会出现网络异常的情况,可以尝试多次重试)

上面的命令将注册一个新的 Runner 来使用 Docker 所提供的特殊docker:latest镜像。这里使用的是官方提供的 Use Docker socket binding 模式,是将/var/run/docker.sock绑定装载到容器中,以便 docker 在该镜像的上下文中可用。(请注意,它正在使用 宿主机 本身的 Docker 守护进程,docker 命令产生的任何容器都将是 一开始我们创建gitlab-runner容器的兄弟,而不是所运行程序的子进程)有兴趣可自行阅读官方文档,看看具体参数的用法。

这里需要说明的是 docker-pull-policy,设置gitlab是否从远程拉去image, 如果iamge是本地的,需要配置该属性的值为 if-not-present,这样可以避免docker 镜像每次都pull

4、提升gitlab-runner用户权限:

由于runner执行过程中,是通过一个叫做 gitlab-runner 的用户来进行操作的,因为不是root用户,所以免不了会有权限问题,这里我们将其添加到docker组中,并验证gitlab-runner是否可以访问Docker

sudo usermod -aG docker gitlab-runner
sudo -u gitlab-runner -H docker info
复制代码

配置.gitlab-ci.yml

好了,通过上一节,我们已经成功注册runner了,是时候定制我们的持续集成服务了,在项目根目录中创建.gitlab-ci.yml文件。(附上官方的文档说明 配置gitlab-ci.yml规则)

先附上完整版的yml,里面均有注释,后面再针对特殊的地方做些解释

# 使用docker镜像
image: docker:latest
# 设置变量
variables:
  # 镜像仓库地址
  REGISTRY: registry.cn-shenzhen.aliyuncs.com
  # 镜像版本
  REGISTRY_IMAGE_TAG: registry.cn-shenzhen.aliyuncs.com/jieyufeng/gitlab-ci-cd:master
  # 镜像启动后的容器名
  CONTAINER_NAME: gitlab-ci-cd

stages:
  - build
  - test
  - deploy

# ----------------构建-----------------
build:
  stage: build
  script:
    # 停止并删除正在使用当前镜像的容器
    - if [ "$(docker ps -a | grep $CONTAINER_NAME)" ]; then
    -  docker stop $CONTAINER_NAME && docker rm $CONTAINER_NAME
    - fi
    # 删除当前已存在的镜像
    - if [ "$(docker images | grep $REGISTRY_IMAGE_TAG)" ]; then
    -  docker rmi $REGISTRY_IMAGE_TAG
    - fi
    # 登录镜像仓库
    - docker login -u $REGISTRY_USER -p $REGISTRY_PASSWORD $REGISTRY
    # 构建新的镜像
    - docker build -t $REGISTRY_IMAGE_TAG .
    # 上传镜像
    - docker push $REGISTRY_IMAGE_TAG
  only:
    - master
  tags:
    - ci-cd

# ----------------测试-----------------
test:
  stage: test
  script:
    # 本地启动容器进行测试
    - docker run -d --name $CONTAINER_NAME -p 3000:3000 $REGISTRY_IMAGE_TAG
  when: on_success
  only:
    - master
  tags:
    - ci-cd

# ----------------部署-----------------
deploy:
  # 切换ubuntu作为deploy任务的镜像
  image: ubuntu:latest
  stage: deploy
  script:
    # 给runner配置私钥
    - 'which ssh-agent || ( apt-get update -y && apt-get install openssh-client -y )'
    - eval $(ssh-agent -s)
    - echo "$SSH_PRIVATE_KEY" | tr -d '\r' | ssh-add - > /dev/null
    - mkdir -p ~/.ssh
    - chmod 700 ~/.ssh
    # 给runner配置ssh登录不验证HostKey
    - '[[ -f /.dockerenv ]] && echo -e "Host *\\n\\tStrictHostKeyChecking no\\n\\n" > ~/.ssh/config'
    # 使用ssh远程登录正式服务器,并拉取之前build上传好的镜像进行部署
    - ssh root@$DEPLOY_HOST "
      docker images;
      docker login -u $REGISTRY_USER -p $REGISTRY_PASSWORD $REGISTRY;
      docker pull $REGISTRY_IMAGE_TAG;
      docker run -d --name $CONTAINER_NAME -p 3000:3000 $REGISTRY_IMAGE_TAG;"
  when: manual
  allow_failure: false
  only:
    - master
  tags:
    - ci-cd
复制代码

部分说明:

1、这里会涉及一个概念,叫做docker in docker的概念,针对这个我个人也没能很好的解释是个什么东西,以免误导大家,因此提供官方的文档 docker socket binding 给大家参考

2、既然要使用自动化部署,那就免不了要使用ssh免密登录策略,此处就关于免密的就不做详细介绍了,可以参考该文档 ssh免密登录

3、试想一下,有些敏感的参数我们是不希望明文暴露在.gitlab-ci.yml 中的,比如密码、私钥等,那怎么办才好呢?对此,官方提供了很好的方案 GitLab CI/CD Variables,设置后,我们可以直接使用参数来代替铭感信息

如上图所示,我们需要在我们gitlab项目中设置对应的参数:

REGISTRY_USER:   登录你个人的docker镜像仓库用户名

REGISTRY_PASSWORD:  登录你个人的docker镜像仓库密码

DEPLOY_HOST:  你正式服务器的地址

SSH_PRIVATE_KEY:  gitlab-runner所在的服务器的ssh私钥

如下图所示,我们在.gitlab-ci.yml只需要使用对应的参数即可,很高大上的有木有

对与不敏感的信息,我们也可以.gitlab-ci.yml设置参数 (其实就跟我们平常写代码,声明一个全局的参数是一个道理的)

4、各流程简单描述

build:  因为我们runner所在的服务器就是测试服务器,所以我们在构建镜像之前,需要先将使用了该镜像的容器给删除,并删除旧的镜像。删除后我们构建新的镜像,并登陆个人镜像仓库进行上传。(由于网络没办法翻墙,这里推荐使用 阿里云容器镜像服务,也可以使用你们自己搭载的个人镜像仓库。 如果你们可以翻墙,也可以使用gitlab配套的容器镜像仓库,如下图,没有翻墙请慎用,可能会导致上传镜像失败的情况)

test:  正如刚才我们说的 runner所在的服务器就是测试服务器,所以test的任务比较简单,就是使用docker启动我们刚才编译的镜像即可

deploy:   因为docker:latest 镜像中没有ssh服务,我们可以换一种思路,切换ubuntu:latest 镜像,大家都知道,使用ssh远程登录肯定免不了登录验证, 这里一定要先打通服务器之间的ssh免密登录,也就是上面的第2点说明,否则登录不成功,接着就是给runner配置私钥了。针对这个,官方也有方案文档 ssh-keys-when-using-the-docker-executor。需要注意的地方是,一般我们不希望每一次构建一次流水线就部署一次,因此我们可以在deploy中设置when: manual,它让我们可以通过手动来控制是否需要执行部署的操作

如图所示,我们可以根据前面的任务状态来确定是否需要进行部署任务,只需点一下红色标注的地方即可


总结

鸡汤:可能对于像我这样的新手一开始接触这个,会有很多很多困惑,也会遇到各种各样的问题。但是勇于尝试,总能成功的,毕竟罗马也不是一天建成的不是吗?

最后,由于这个Gitlab-CI/CD太过强大,还有很多高大上的方案本人也还在学习中,文章中出现的文档链接都很有用,都是官方文档的,每个人可能都会遇到各种不同的问题,本文只是做一个总结分享,并不一定能解决大家所遇到的问题,大家可以多阅读资料,互相探讨一下

附上本人简单的demo: gitlab-ci-cd

分类:
后端
标签:
分类:
后端
标签: