GitLab-CI 使用方法

GitLab 自带 GitLab-CI,可用于自动构建、测试、部署

基本概念

  • Job: 任务,执行命令的单元

    • 可配置执行环境、依赖、执行的条件、要执行的 shell 命令等
    • shell 命令执行成功(返回值为 0)则任务成功,否则失败
    • 不同任务完全独立,因此可配置不同的环境、依赖,可并行执行,但需注意每个任务中都要执行安装依赖等命令(为避免重复,可放在 before_script 中)
  • Stage: 任务的类别

    • 任务的 stage 默认为 test
    • 一个 stage 可以包含多个任务
    • 不同 stage 的任务按 stages 指令指定的顺序(默认为build, test, deploy)执行
    • 同一 stage 的多个任务可并行执行
  • Executor: 执行任务的容器类别,如 ssh, docker, virtualbox 等。我们使用 docker

  • Runner: 执行任务的容器

    • 分共享和专用两种,共享的可供所有项目使用,专用的只能用于特定项目(一个或多个)
    • 项目必须有可用的 runner 才能执行 GitLab-CI 任务
    • 创建 runner 只能在安装了 gitlab-runner 的服务器上执行 shell 命令
    • 查看/管理项目的 runner 在项目的 Settings -> CI/CD -> Runners
  • Deploy key: 对 git 仓库有只读权限的密钥对的公钥,可用于在部署服务器上拉取代码。在项目的 Settings -> Repository -> Deploy keys 中配置

  • Variables: GitLab-CI 中执行任务时的环境变量,只有对仓库有 master 及以上权限的用户才能查看和管理。可用于保存配置信息(避免写死在 .gitlab-ci.yml 中),或敏感信息(如部署使用的 SSH 私钥,直接在 .gitlab-ci.yml 中配置有安全风险)。在项目的 Settings -> CI/CD -> Variables 中配置

配置

  1. 在项目的 Settings -> General -> Visibility, project features, permissions 中启用 Pipelines

  2. 确保有可用 runner。创建 runner 只能由 GitLab 服务器管理员操作。尽量使用共享型 runner 以便管理

    如使用共享 runner,在项目的 Settings -> CI/CD -> Runners 中启用共享 runner

  3. 在项目代码的根目录下添加 .gitlab-ci.yml,配置自动构建的环境(Docker镜像名称)、依赖的服务(MySQL、Redis等,也需是 Docker 镜像名称)、需要执行的任务(stage)等。将文件提交到版本库

    配置文件语法参考官方文档

  4. 如需自动部署,生成一对 SSH 密钥(在任意机器上均可)

    1. ssh-kengen -t rsa -C 'project_name@gitlab-ci'
    • 为使 GitLab-CI 有权限操作部署服务器:

      • 将公钥添加到要部署服务器的 ~/.ssh/authorized_keys
      • 将私钥添加到项目的 Secret Variables 中,名称随意,如 “SSH_PRIVATE_KEY”
      • .gitlab-ci.yml 配置文件中,执行部署命令前从环境变量中读取 SSH 私钥
    • 为使部署服务器有权限拉取代码(若不需要在部署服务器上拉取代码,略过):

      • 若自动部署工具(如 mina)启用了 SSH agent forwarding, 将公钥添加到项目的 Deploy Keys 中
      • 若未启用,将部署服务器上的 ~/.ssh/id_rsa.pub 添加到项目的 Deploy Keys 中

构建邮件提醒

GitLab 支持在构建失败时邮件提示,但默认未开启

可在 Project -> Integrations -> Pipelines emails 中开启

管理员用户可在 Admin Area -> Service Templates -> Pipelines emails 中为新项目默认启用

技巧/注意事项

以下部分命令通过修改环境变量 PATH 生效,若放在外部文件中,须通过 source 命令引入方有效

处理 SSH 私钥

私钥属敏感信息,不应保存在人人可见的 .gitlab-ci.yml 或其它项目文件中,应保存在项目配置的 Variables 中

使用以下命令在任务中使用私钥:

  1. if [ -n "$SSH_PRIVATE_KEY" ]; then
  2. eval $(ssh-agent -s)
  3. ssh-add <(echo "$SSH_PRIVATE_KEY")
  4. mkdir -p ~/.ssh && chmod 700 ~/.ssh
  5. # disable host key checking
  6. echo -e "Host *\n\tStrictHostKeyChecking no\n\n" > ~/.ssh/config
  7. fi

RVM

由于 GitLab-CI 使用 docker 容器时使用的是 non-login shell,导致默认无法使用 RVM

使用以下命令解决:

  1. if [ -x '/etc/profile.d/rvm.sh' ]; then
  2. source /etc/profile.d/rvm.sh
  3. rvm use default
  4. fi

使用服务

可以使用任何 docker 镜像作为服务,如 MySQL, Redis

这些提供服务的 docker 容器会被链接到执行 GitLab-CI 任务的容器,主机名称通过以下规则从 docker 镜像名称转换:

  • 忽略 “:” 及其后面的版本号
  • “/“ 替换为 “__“

如 “bianjp/mariadb-alpine:latest” 的主机名为 “bianjp__mariadb-alpine”,”redis:alpine” 的主机名为 “redis”

在应用代码中可通过这些主机名使用这些服务

为了便于维护,建议在 .gitlab-ci.yml 中把主机名定义为变量,在应用代码中动态获取环境变量而非硬编码

为减少带宽、内存占用,尽量使用轻量级的 docker 镜像

示例

项目根目录下添加 .gitlab-ci-before-script.sh:

  1. #!/bin/bash
  2. # SSH private key
  3. if [ -n "$SSH_PRIVATE_KEY" ]; then
  4. eval $(ssh-agent -s)
  5. ssh-add <(echo "$SSH_PRIVATE_KEY")
  6. mkdir -p ~/.ssh && chmod 700 ~/.ssh
  7. # disable host key checking
  8. echo -e "Host *\n\tStrictHostKeyChecking no\n\n" > ~/.ssh/config
  9. fi
  10. # RVM
  11. if [ -x '/etc/profile.d/rvm.sh' ]; then
  12. source /etc/profile.d/rvm.sh
  13. rvm use default
  14. fi
  15. # locale
  16. export LANG=en_US.UTF-8
  17. export LC_ALL=en_US.UTF-8

.gitlab-ci.yml 示例:

  1. image: bianjp/rails-env-centos7:latest
  2. # 服务、任务运行时的环境变量
  3. variables:
  4. # 用于 bianjp/mariadb-alpine 镜像初始化
  5. MYSQL_ROOT_PASSWORD: 'root'
  6. MYSQL_INITDB_SKIP_TZINFO: 'true'
  7. # 用于 Rails 配置,在配置文件中动态获取这些环境变量
  8. DB_HOST: 'bianjp__mariadb-alpine'
  9. DB_USERNAME: 'root'
  10. DB_PASSWORD: 'root'
  11. REDIS_HOST: 'redis'
  12. REDIS_PORT: '6379'
  13. # 在不同构建之间缓存部分内容
  14. cache:
  15. key: 'global'
  16. paths:
  17. - vendor/bundle
  18. services:
  19. - bianjp/mariadb-alpine:latest
  20. - redis:alpine
  21. stages:
  22. - test
  23. - deploy
  24. before_script:
  25. # 必须使用 source 命令
  26. - source .gitlab-ci-before-script.sh
  27. # 处理配置文件
  28. - cp config/database.gitlab-ci.yml config/database.yml
  29. - cp config/secrets.gitlab-ci.yml config/secrets.yml
  30. # 安装依赖
  31. - bundle install --path vendor/bundle
  32. # 测试
  33. test:
  34. stage: test
  35. script:
  36. - RAILS_ENV=test bundle exec rake db:setup
  37. - bundle exec rake spec
  38. # 部署到生产服务器
  39. production:
  40. stage: deploy
  41. enrironment: production
  42. script:
  43. - bundle exec mina production deploy
  44. only:
  45. - master
  46. # 部署到开发服务器
  47. development:
  48. stage: deploy
  49. environment: development
  50. script:
  51. - bundle exec mina dev deploy
  52. only:
  53. - dev

参考资料