lostvita / blog

60 stars 47 forks source link

基于GitLab-Runner打造锋利的CI/CD #2

Open lostvita opened 5 years ago

lostvita commented 5 years ago

前言

本文介绍的内容包含:

阅读本文需要你:

持续交互(Continuous Delivery)是在持续集成的基础上,将构建的代码部署到「类生产环境」,完成QA测试之后手动部署到生成环境的过程。强调代码部署,这个过程产出测试报告。 image 说明:这里的 test 是真的test

持续部署(Continuous Deployment)是持续交互的下一步,强调部署生产环境代码的过程自动化,同时可以处理上线通知等操作。 image 说明:与持续交互主要就是手动跟自动的区别。

2. CI/CD的必要性

以一言概之的话我想应该是:机械的事情让机器做。一个开发团队,没有CI/CD,我想可能是这样子的:无法管理代码多人多地协作(git repository也是CI的一部分),系列的shell需要人工处理,代码的发布需要登录服务器等等;相反,拥有CI/CD,这些事情都交给机器去完成,腾出的碎片时间去做更有意义的事情(比如摸鱼放松下)。

3. 理想的CI/CD开发流应该是怎样的?

我认为理想的CI/CD开发流应该包含三个阶段:build、deploy和notify build阶段专注做代码构建与单元测试,deploy阶段专注做test/gray/prod环境的代码部署,notify阶段专注做上线通知,如下图; image

以下内容围绕build和deploy两个阶段完成从0到1的部署。笔者的系统环境:Ubuntu 18.04.1 LTS

Gitlab-Runner安装并注册

注册成功后,我们就能在:Settings >> CI/CD >> Runners下看到我们注册的runner image

Gitlab-Runner配置

在项目根目录下新建 .gitlab.yml文件,加入如下内容:

image: node:8.11.2-stretch

cache:
  paths:
    - node_modules/

stages:
  - build
  - deploy

unit_test:
  stage: build
  only: 
    - feature/test
  script: 
    - echo 'Unit testing.....'
  after_script:
    - echo 'Unit test done.'

compile:
  stage: build
  before_script:
    - npm install
  script:
    - npm run build
  artifacts:
    paths:
      - dist/
  only:
    - feature/test
    - tags

deploy_test:
  stage: deploy
  only:
    - feature/test
  dependencies:
    - compile
  environment:
    name: test_env
    url: https://test.example.com
  before_script:
    - mkdir -p ~/.ssh
    - chmod 700 ~/.ssh
    - eval $(ssh-agent -s)
    - echo "$TEST_KNOWN_HOST" > ~/.ssh/known_hosts
    - chmod 644 ~/.ssh/known_hosts
    - echo "$TEST_CONFIG" > ~/.ssh/config
    - chmod 600 ~/.ssh/config
    - echo "$SSH_PRIVATE_KEY" > ~/.ssh/id_rsa
    - chmod 600 ~/.ssh/id_rsa
    - ssh-add ~/.ssh/id_rsa
    - command -v rsync || (apt-get -qq update && apt-get -qq install -y rsync)
  script:
    - rsync -rve ssh dist/ user@server_host:project_path/dist
  after_script:
    - echo 'deploy test env done.'
  when:
    on_success

unit_test、compile和deploy_test是自定义的job名字,另外几点配置说明:

先在本机(注册runner所在的机器)配一遍免密登录服务器的流程: 1. 生成一对公私钥:使用rsa作为非对称加密方式

ssh-keygen -t rsa -C "$(whoami)@$(hostname)-$(date -I)"

说明:一路enter就好了,切记 Enter passphrase 时直接enter,这样就是 no passphrase。如果你非要加个password,对不起,没救了!

2. 定义ssh config内容:在~/.ssh/config文件写入以下内容(文件不存在直接创建)

Host any_name
  Port your_port
  HostName server_ip
  User user
  IdentityFile ~/.ssh/id_rsa

说明:定义ssh的config文件是为了快捷访问,就像你配置host一样,没有hostname,你只能访问ip。配置后你就可以通过 ssh any_name 登录服务器了。当然,不出意外,会要求你输入服务器的登录密码。

3. 免密登录: 免密登录的精髓就是:把本机的公钥存储到目标服务器的authorized_keys文件内(该文件服务器上不存在可以直接创建。)

ssh-copy-id -i ~/.ssh/id_rsa.pub username@ip

特别地:如果你的端口不是默认的22端口,则加上端口号 -p PORT

4. 验证登录

ssh any_name

不出意外,你应该可以直接登录服务器了。那么,我们回到gitlab的配置上~

gitlab上定义ssh配置信息

我们进入gitlab页面位置:Settings >> CI/CD >> Environment variables下定义 .gitlab.yml 上出现的几个变量: image

踩坑小记

在整个搭建过程,很多都是关于ssh登录服务器的问题,择几个高频出现的问题说明下: 1. Host key verification failed 当我们初次使用ssh登录服务器的时候,ssh会要求验证远程服务器的身份,通过身份验证之后才允许连接。解决该问题有两种方式:

2. Permission denied, please try again 出现这个问题是没有配置「ssh免密登录」,配置操作见@为什么需要免密登录部分

3. rsync: Failed to exec a: No such file or directory 这个问题一般情况下并不会出现,但却是个实实在在的坑。我在deploy的job里面通过rsync将构建生成的dist目录上传至服务器,抛出不存在该目录的错误。我在compile这个job执行后,list下根目录下的文件/夹: image 可以看见,实实在在是生成了dist目录,但进入下一个job的时候却提示不存在!问题出在: dist目录并不是由构建直接生成的文件夹,而是release-[timestamp]目录的软链接(笔者用的是Ubuntu,在webpack配置里面设置了个骚操作:每次构建产出一个release-[timestamp]目录,同时建立一个软链。软链不是一个目录,它的内容就是目标文件夹的地址)。 在我的.gitlab.yml配置里面,artifacts缓存的是dist,没有把实际的文件夹release-[timestamp]缓存,那么进入下一个job的时候,自然就提示不存在该目录了。解决办法是:

cp dist public

在compile这个job里面,构建之后复制一份dist目录,再将public目录交由artifacts缓存。

参考文章