美文网首页
基于Gitlab-CI/CD Docker 持续集成 node

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

作者: 举杯丶独醉 | 来源:发表于2018-12-09 15:01 被阅读0次

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


    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

    相关文章

      网友评论

          本文标题:基于Gitlab-CI/CD Docker 持续集成 node

          本文链接:https://www.haomeiwen.com/subject/rpnchqtx.html