侧边栏壁纸
博主头像
极客日记 博主等级

行动起来,活在当下

  • 累计撰写 93 篇文章
  • 累计创建 17 个标签
  • 累计收到 1 条评论

目 录CONTENT

文章目录
Git

GitLab CI/CD 初体验

Jack.Jia
2022-03-28 / 0 评论 / 0 点赞 / 9 阅读 / 0 字

GitLab CI/CD 简介

GitLab CI/CD 是一个内置在 GitLab 中的工具,用于通过持续方法进行软件开发:

  • Continuous Integration (CI) 持续集成
  • Continuous Delivery (CD) 持续交付
  • Continuous Deployment (CD) 持续部署

详细介绍可以看官方文档:CI/CD 概念

持续集成的工作原理是将小的代码块推送到 Git 仓库中托管的应用程序代码库中,并且每次推送时,都要运行一系列脚本来构建、测试和验证代码更改,然后再将其合并到主分支中。

持续交付和部署相当于更进一步的 CI,可以在每次推送到仓库默认分支的同时将应用程序部署到生产环境。

这些方法使得可以在开发周期的早期发现 BUG 和错误,从而确保部署到生产环境的所有代码都符合为应用程序建立的代码标准。

GitLab CI

GitLab CI 是为 GitLab 提供持续集成服务的一整套系统。在 GitLab8.0 以后的版本是默认集成了 GitLab-CI 并且默认启用的。

使用 GitLab CI 需要在仓库跟目录创建一个 gitlab-ci.yml 的文件,它用来指定持续集成需要运行的环境,以及要执行的脚本。还需要设置一个 gitlab-runner,当有代码 push 变更的时候,gitlab-runner 会自动开始 pipeline,并在 gitlab 上显示持续集成的结果。

GitLab Runner

那 GitLab-Runner 又是什么东东呢?与 GitLab-CI 有什么关系呢?

GitLab-Runner 是配合 GitLab-CI 进行使用的。一般地,GitLab 里面的项目会定义一个属于这个项目的软件集成脚本(gitlab-ci.yml),用来自动化地完成一些软件集成工作。当这个工程的仓库代码发生变动时,比如有人 push 了代码,GitLab 就会将这个变动通知 GitLab-CI。这时 GitLab-CI 会找出与这个项目相关联的 Runner,并通知这些 Runner 把代码更新到本地并执行预定义好的执行脚本。

所以,GitLab-Runner 就是一个用来执行软件集成脚本的东西。可以想象一下:Runner 就像一个个的工人,而 GitLab-CI 就是这些工人的一个管理中心,所有工人都要在 GitLab-CI 里面登记注册,并且表明自己是为哪个工程服务的。当相应的工程发生变化时,GitLab-CI 就会通知相应的工人执行软件集成脚本。如下图所示:
abfnhsyef9.png

GitLab-Runner 执行情况如下:

  1. 本地代码改动
  2. 变动代码推送到 GitLab 上
  3. GitLab 将这个变动通知 GitLab-CI
  4. GitLab-CI 找出这个工程相关联的 gitlab-runner
  5. gitlab-runner 把代码更新到本地
  6. 根据预设置的条件配置好环境
  7. 根据预定义的脚本 ( 一般是.gitlab-ci.yml) 执行
  8. 把执行结果通知给 GitLab
  9. GitLab 显示最终执行的结果

Runner 可以分布在不同的主机上,同一个主机上也可以有多个 Runner。

GitLab CI/CD 快速开始

.gitlab-ci.yml 文件告诉 GitLab Runner 要做什么。一个简单的管道通常包括三个阶段:buildtestdeploy

流水线页面在 CI/CD > Pipelines 页面

创建一个 .gitlab-ci.yml 文件

通过配置.gitlab-ci.yml 文件来告诉 CI 要对你的项目做什么。它位于仓库的根目录下。

仓库一旦收到任何推送,GitLab 将立即查找.gitlab-ci.yml 文件,并根据文件的内容在 Runner 上启动作业。

官方文档:https://docs.gitlab.com/ee/ci/yaml/index.html
其他文档:https://juejin.cn/post/6971013569986953223

下面是一个 Rails 项目配置例子:

# 定义在每个job之前运行的命令
before_script:
  - echo '在每个job之前运行的命令'

# 定义在每个job之后运行的命令
after_script:
  - echo '在每个job之后运行的命令'

# 定义全局变量
variables:
  PROJECT: gitlab-rails-demo
  IMAGE_NAME: ccr.ccs.tencentyun.com/jxd-dev/gitlab-rails-demo
  IMAGE_TAG: $CI_PIPELINE_ID

# Cache 在使用时制定一系列的文件或者文件目录,使得其在不同的 job 之间被缓存下来
# https://zhuanlan.zhihu.com/p/106971627
cache:
  untracked: true
  key: $PROJECTt-$CI_COMMIT_REF_NAME
  paths:
    - public/

stages:
  - build   # 构建
  - test   # 测试
  - deploy   # 部署

build_job:
  stage: build
  tags:
    - gitlab-rails-demo
  only:
    - dev
    - master
  except: # 排除某些分支
    - new-dev
  script:
    - echo '这里是构建docker镜像阶段'
    - docker login ccr.ccs.tencentyun.com --username=$DOCKER_REGISTRY_USERNAME --password=$DOCKER_REGISTRY_PASSWORD
    - docker build -t $IMAGE_NAME:$IMAGE_TAG --network webapp .  # 构建docker镜像
    - docker push $IMAGE_NAME:$IMAGE_TAG # 推送镜像

test_job:
  stage: test
  tags:
    - gitlab-rails-demo
  only:
    - dev
    - master
  script:
    - ls -a
    - echo '这里是测试阶段'
  allow_failure: true # 设置 allow_failure 的 job 失败后不会中断 CI 的执行

deploy_job:
  stage: deploy
  tags:
    - gitlab-rails-demo
  only:
    - dev
    - master
  script:
    - echo '这里是部署阶段'
    - docker-compose up -d # docker-compose
  after_script:
    - echo y | docker image prune --filter="dangling=true"  # 清理dangling镜像
    - docker images

注册一个 Runner

在 GitLab 中,Runner 运行你定义在.gitlab-ci.yml 中的阶段(job)

一个 Runner 可以是一个虚拟机、物理机、docker 容器,或者一个容器集群

GitLab 与 Runner 之间通过 API 进行通信,因此只需要 Runner 所在的机器有网络并且可以访问 GitLab 服务器即可。

可以去 Settings ➔ CI/CD 看是否已经有 Runner 关联到你的项目,因为还未注册 runner,所以肯定是未关联状态。

1641751300122_runner.png

注册步骤如下(已安装 gitlab-runner):

  1. 执行命令
    gitlab-runner register
    
  2. 输入 gitlab-ci url
    https://gitlab.explorexd.com/
    
  3. 输入 gitlab-ci token
    Rqpt3DY3VF9c9KuY2k66
    
  4. 输入这个 runner 的一些描述,不填也可以
    gitlab-rails-demo
    
  5. 输入这个 runner 关联的标签
    gitlab-rails-demo
    
    1641751321931_shell.png

注册成功后如下图:

1641751336416_srunner.png

修改代码并提交

此时,推送修改后的 master 或者 dev 分支就可以启动流水线了:

1641751345420_ppip.png

1641751382696_Snipaste_20220110_020241.png

扩展知识

DockerFile

# 使用安装了最少的软件的镜像
FROM ruby:2.7.4-alpine3.14

# 安装依赖
RUN sed -i 's/dl-cdn.alpinelinux.org/mirrors.aliyun.com/g' /etc/apk/repositories
RUN apk update && apk add --no-cache libpq vim imagemagick sqlite-libs tzdata
RUN apk add --no-cache --virtual .temp-build-libs \
    alpine-sdk gcc musl-dev build-base libffi-dev make sqlite-dev nodejs yarn

# 设置环境变量
# 来指代容器中的 rails 程序放的目录
ENV RAILS_ROOT /var/www/gitlab-rails-demo
ENV NODE_ENV production
ENV RAILS_ENV production
ENV HOST 0.0.0.0
ENV PORT 3000
ENV PIDFILE $RAILS_ROOT/tmp/pids/server.pid
ENV RAILS_MASTER_KEY 404aa1c143755a2541eba84121c52671

# 设置容器里的工作目录
WORKDIR $RAILS_ROOT

# 创建 rails 程序目录和程序运行所需要的 pids 的目录
RUN mkdir -p $RAILS_ROOT/tmp/pids

# 拷贝 docker-entrypoint.sh
COPY ./docker-entrypoint.sh .
RUN sed -i 's/\r$//g'  $RAILS_ROOT/docker-entrypoint.sh

# 拷贝 Gemfile 及 lock到容器的工作目录中
# 当Gemfile 没有改变时,省略下面的 bundle install
COPY Gemfile Gemfile
COPY Gemfile.lock Gemfile.lock

# 安装 Rails 环境
RUN bundle install

# 拷贝js依赖
COPY package.json yarn.lock /app/

# 将 Dockerfile 目录下所有内容复制到容器工作目录
COPY . .

# 编译静态文件
RUN bundle exec rails webpacker:verify_install
RUN SECRET_KEY_BASE=nein bundle exec rails assets:precompile

# 删除依赖
RUN apk del .temp-build-libs

# 可执行权限
RUN chmod +x  $RAILS_ROOT/docker-entrypoint.sh

# 暴露服务端口
EXPOSE 3000

# 运行 docker-entrypoint.sh
ENTRYPOINT ["./docker-entrypoint.sh"]

docker-entrypoint.sh

#!/bin/sh

# 启动服务
bundle exec puma -C config/puma.rb

exec "$@"

docekr-compose

version: '3.9'
services:
  gitlab-rails-demo:
    container_name: gitlab-rails-demo
    image: ccr.ccs.tencentyun.com/jxd-dev/gitlab-rails-demo:${IMAGE_TAG:-latest}
    networks:
      - webapp
    restart: always
    expose:
      - 3000
    volumes:
      - '/data/docker/gitlab-rails-demo/log:/var/www/gitlab-rails-demo/log'
networks:
  webapp:
    name: webapp
    driver: bridge

nginx 配置文件

upstream gitlab-rails-demo-puma {
  server gitlab-rails-demo:3000;
}

## Redirects all HTTP traffic to the HTTPS host
server {
  listen 80;
  server_name rails.explorexd.com;
  access_log  /var/log/nginx/gitlab-rails-demo.log;
  error_log   /var/log/nginx/gitlab-rails-demo.log;

    location / {
      client_max_body_size 256m;
      gzip on;

      proxy_read_timeout      300;
      proxy_connect_timeout   300;
      proxy_redirect          off;

      proxy_http_version 1.1;

      proxy_set_header    Host                $http_host;
      proxy_set_header    X-Real-IP           $remote_addr;
      proxy_set_header    X-Forwarded-Ssl     on;
      proxy_set_header    X-Forwarded-For     $proxy_add_x_forwarded_for;
      proxy_set_header    X-Forwarded-Proto   $scheme;
      proxy_pass http://gitlab-rails-demo-puma;
    }
}

参考文档

https://zhuanlan.zhihu.com/p/59538397
https://www.cnblogs.com/cjsblog/p/12256843.html
https://docs.docker.com/samples/rails/
https://docs.gitlab.com/ee/ci/introduction/index.html
https://docs.gitlab.com/ee/ci/yaml/index.html

0

评论区