gitlab + docker ci/cd 实践

685 阅读2分钟

1. 创建项目

vue create vue3-admin
git remote add origin "xxxxx"
git branch -M master
git push -f -u origin master

2. 起草 gitlab-ci.yml

# 定义了 3 个阶段
stages:  
  - test  
  - build  
  - deploy

# 预先定义的常量,后面要使用的字面量建议使用变量预先定义
variables:  
  SSH_SERVER: 192.168.200.101 #ssh 部署地址
  CONTAINER_DEV: ${CI_PROJECT_NAME}_${CI_PROJECT_ID}_${CI_DEV} #开发环境容器名称
  CONTAINER_PROD: ${CI_PROJECT_NAME}_${CI_PROJECT_ID}_${CI_PROD} #生产环境容器名称
  CONTAINER_DEV_IMAGE: ${CI_REGISTRY_IMAGE}:${CI_COMMIT_TAG} #开发环境镜像名称
  CONTAINER_PROD_IMAGE: ${CI_REGISTRY_IMAGE}:${CI_COMMIT_TAG} #生产环境镜像名称
  CI_PROD: production #生产环境名称
  CI_DEV: development #开发环境名称
  CI_PROD_URL: http://192.168.200.100 #生产环境部署地址
  CI_DEV_URL: http://192.168.200.100 #开发环境部署地址
  CI_PROD_PORT: 7080 #生产环境部署端口
  CI_DEV_PORT: 6080 #开发环境部署端口

#开发构建阶段
build_dev:
  stage: build #构建阶段
  tags:
    - docker #使用 docker executor
  only:
    variables:
      - $CI_COMMIT_TAG =~ /^dev.*/ # 只有 tag 名称以 dev 开头,本阶段才会加入流水线
  before_script:
    #登录 docker registry
    - echo "$CI_REGISTRY_PASSWORD" | docker login $CI_REGISTRY --username $CI_REGISTRY_USER --password-stdin
  script:
    - echo "--- build_dev ---"
    - docker build -t $CONTAINER_DEV_IMAGE -f Dockerfile.dev --force-rm . #构建开发镜像
    - docker push $CONTAINER_DEV_IMAGE #推送镜像

#生产构建阶段
build_prod:
  stage: build
  tags:
    - docker
  only:
    variables:
      - $CI_COMMIT_TAG =~ /^release.*/
  before_script:
    - echo "$CI_REGISTRY_PASSWORD" | docker login $CI_REGISTRY --username $CI_REGISTRY_USER --password-stdin
  script:
    - echo "--- build_prod ---"
    - docker build -t $CONTAINER_PROD_IMAGE -f Dockerfile.prod --force-rm .
    - docker push $CONTAINER_PROD_IMAGE

#开发部署阶段
deploy_dev:
  stage: deploy #部署阶段
  variables:
    GIT_STRATEGY: none #默认每个阶段都会拉去代码,这里禁止拉取
  tags:
    - docker #定义 docker 执行器
  only:
    variables:
      - $CI_COMMIT_TAG =~ /^dev.*/ #tag 名称以 dev 开头,本阶段才能加入流水线
  before_script:
    #登录 docker registry
    - echo "$CI_REGISTRY_PASSWORD" | docker login $CI_REGISTRY --username $CI_REGISTRY_USER --password-stdin
  script:
    - echo "--- deploy_dev ---"
    - docker container rm $CONTAINER_DEV -f #停止和删除旧容器
    - docker run -d -p $CI_DEV_PORT:80 --restart always --name $CONTAINER_DEV $CONTAINER_DEV_IMAGE #启动容器

#生产部署阶段
deploy_prod:
  stage: deploy
  variables:
    GIT_STRATEGY: none
  tags:
    - docker
  only:
    variables:
      - $CI_COMMIT_TAG =~ /^release.*/
  environment:
    name: $CI_PROD
    url: $CI_PROD_URL:$CI_PROD_PORT
  before_script:
    - echo "$CI_REGISTRY_PASSWORD" | docker login $CI_REGISTRY --username $CI_REGISTRY_USER --password-stdin
  script:
    - echo "--- deploy_prod ---"
    - docker container rm $CONTAINER_PROD -f
    - docker run -d -p $CI_PROD_PORT:80 --restart=always --name $CONTAINER_PROD $CONTAINER_PROD_IMAGE

#远程生产部署
deploy_ssh_prod:
  stage: deploy #部署阶段
  variables:
    GIT_STRATEGY: none #禁止拉取仓库代码
  tags:
    - ssh #ssh executor
  only:
    variables:
      - $CI_COMMIT_TAG =~ /^release.*/ # 标签名称以 release 开头,本阶段方可加入流水线
  when: manual # 手动触发本阶段执行
  environment:
    name: $CI_PROD #环境名称
    url: $SSH_SERVER:$CI_PROD_PORT #部署地址
  before_script: # 配置 ssh 远程登录
    - eval $(ssh-agent -s)
    - echo "$SSH_PRIVATE_KEY" | tr -d '\r' | ssh-add -
    - mkdir -p ~/.ssh
    - chmod 700 ~/.ssh
  script: # ssh远程登录,执行部署脚本
    - >
      ssh -o StrictHostKeyChecking=no root@${SSH_SERVER}
      "
      echo $CI_REGISTRY_PASSWORD | docker login $CI_REGISTRY --username $CI_REGISTRY_USER --password-stdin;
      docker container rm $CONTAINER_PROD -f;
      docker run -d -p $CI_PROD_PORT:80 --restart=always --name $CONTAINER_PROD $CONTAINER_PROD_IMAGE
      "

#远程开发部署
deploy_ssh_dev:
  stage: deploy
  variables:
    GIT_STRATEGY: none
  tags:
    - ssh  
  only:
    variables:
      - $CI_COMMIT_TAG =~ /^dev.*/
  when: manual
  environment:
    name: $CI_DEV
    url: $SSH_SERVER:$CI_DEV_PORT
  before_script:
    - eval $(ssh-agent -s)
    - echo "$SSH_PRIVATE_KEY" | tr -d '\r' | ssh-add -
    - mkdir -p ~/.ssh    - chmod 700 ~/.ssh
  script:
    - >
      ssh -o StrictHostKeyChecking=no root@${SSH_SERVER}
      "
      echo $CI_REGISTRY_PASSWORD | docker login $CI_REGISTRY --username $CI_REGISTRY_USER --password-stdin;
      docker container rm $CONTAINER_DEV -f;
      docker run -d -p $CI_DEV_PORT:80 --restart=always --name $CONTAINER_DEV $CONTAINER_DEV_IMAGE
      "

3. 起草 Dockerfile

Dockerfile.dev

FROM node:14.15.1 AS builder
WORKDIR /app
COPY package* .eslintrc.js .dockerignore ./
RUN npm install
COPY public ./public
COPY src ./src
RUN npm run build:dev

FROM nginx:alpine
COPY --from=builder /app/dist /usr/share/nginx/html

Dockerfile.prod

FROM node:14.15.1 AS builder
WORKDIR /app
COPY package* .eslintrc.js .dockerignore ./RUN npm install
COPY public ./public
COPY src ./src
RUN npm run build:prod

FROM nginx:alpine
COPY --from=builder /app/dist /usr/share/nginx/html

.dockerignore

node_modules

4. 配置 gitlab

  1. 配置 gitlab-runner

    a. 安装 gitlab-runner

    juejin.cn/post/691060…

    b. 注册 runner

    #敲入下面命令,根据提示填写相关信息
    gitlab-runner register
    

    c. 配置 docker runner

    # 使用 docker 命令,有三种方式 1. docker in docker service 2. bind sock 3. shell executor
    # 这里使用 bind sock,编辑 /etc/gitlab-runner/config.toml
    # 主要:关闭 tls;关闭特权模式;绑定 sock 文件;绑定 daemon.json 文件
    [runners.docker]
      tls_verify=false
      image="docker:latest"
      privileged = false
      volumes = ["/cache","/etc/docker/daemon.json:/etc/docker/daemon.json:ro","/var/run/docker.sock:/var/run/docker.sock"]
    
    # daemon.json 文件
    {
      "registry-mirrors":["https://0d08o2ps.mirror.aliyuncs.com"],
      "insecure-registries":["192.168.200.100:5050"]
    }
    

       d. 配置 shell runner(可选,主要是 ssh 部署用的到它)

2. gitlab-registry

# 编辑 /etc/gitlab/gitlab.rb
registry_external_url 'http://192.168.200.100:5050'

# gitlab-ctl reconfigure

# gitlab-ctl restart

4. 发布

配置邮件通知:

Settings > Integration > Email Pipelien status 
填写邮件地址、流水线分支触发

# 提交代码,打 tag,push tag 完成

5. 参考

docs.gitlab.com/ee/ci/