我写 CI/CD 遇到的几个问题和项目结构

概述

项目即将交付测试,最近将项目发布分为了测试环境和开发环境。主要逻辑是把代码打包成镜像(image),然后使用 docker-compose 部署。

整个 CI/CD 的过程基于 gitlab 完成。使用到的 executor 是 docker 和 shell 两种形式。

前端项目中,使用 docker executor 构建整个项目,然后使用 shell executor 的形式将构建产物放到 nginx 对应路径下。

后端项目一(基于 NodeJS,服务端渲染,gulp 构建前端),使用 docker executor 构建,然后使用 docker 部署到服务端。

后端项目二(基于 ts-node),没有构建,直接使用 docker executor 部署到服务器。

不同 executor 有什么不同

gitlab runner 的工作流程大致如下

tag 匹配 runner --> runner 启动 --> 启动 executor --> 初始化环境变量 -> 拉取代码 --> 执行 脚本 --> 打包并上传 artifacts --> 清理工作环境

不同之处就在于 启动 executor。如果使用的是 docker,则 runner 会按照 image 指令指定的镜像初始化一个 container,然后在这个 container 中执行后续步骤。

如果使用的是 ssh,则 runner 会根据配置参数连接到指定设备,然后执行后续步骤。

如果使用的是 shell,则相当于打开了一个终端。在这个终端环境执行后续步骤。

需要注意的点

不同的 executor 中,除了 ssh 外,其他形式的 executor 都是使用 gitlab-runner 用户(组)执行代码。

所以在使用 shell executor 时要格外注意权限问题。如果在 shell 中使用到了 docker,建议安装高版本的 dockers(支持 rootless 模式)。把 gitlab-runner 添加到 docker 用户组。在脚本的 before_script 中使用 newgrp docker 将当前用户默认组切换为 docker 组,这样就可以直接在当前用户使用 dockers,无需 root 权限。

关于环境变量

环境变量的管理分为三个层级:gitlab、.gitlab-ci.yml、docker-compose.yml。

公共的全局性参数可以在 gitlab 中设置和管理,如:harbor 的用户名、密码、地址等。

在 .gitlab-ci.yml 中可以根据需要在不同层级设置环境变量。范围从大到小依次为:全局(default、variables)、workflow、job。具体使用可以参照最后的样例。

docker-compose.yml 本身可以使用外部的环境变量。例如外部环境有一个环境变量记录了镜像名称(IMAGE_TAG),则在 docker-compose.yml 中可以使用这种方式指定镜像名称:image: $IMAGE_TAG。具体使用可以参照最后的样例

清理缓存

这是比较容易忽略的一点。如果不清理缓存磁盘会逐渐被占满,可以使用如下命令清理缓存

# 以下命令分别会清除容器(已停止容器)、镜像(没有被容器引用的镜像)、构建缓存(build 镜像产生的缓存)
docker container prune -f
docker image prune -af
docker builder prune -af
docker buildx prune -af

# 慎用,因为这个命令会清除不被使用的 volume、image 等;使用不当会造成数据丢失
# 只有上面的命令仍然无法释放空间时才能尝试此命令
docker system prune -af

问题描述及解决方案

dind 问题

报错信息如下:

error during connect: Get "http://docker:2375/v1.24/images/json": dial tcp: lookup docker on 10.0.6.102:53: server misbehaving

当使用 docker executor 时,需要把宿主机中的 docker、sock 挂载到 executor 中,否则 docker executor 中 docker 相关功能不能正常使用。

fatal: git fetch-pack: expected shallow list

目前没有定位到具体原因。出现这个问题是在这样一个场景:构建使用 docker,部署使用 shell。在部署时发生该错误。

最后的解决方法是,在 after_script 中每次删除源代码(rm -rf ../../*)。

也可以通过升级 git 版本解决(最好升级到 2.x.x 或以上版本)。因为 gitlab 随着升级会使用一些高版本 git 才有的 api。这个问题在使用 CentOS 7 时容易遇到。

样例

项目 1

default:
  interruptible: false

variables:
  LATEST_TAG: "itools-harbor.example.com/simulation/nplatform-core:${CI_COMMIT_BRANCH}_latest"
  TAG: "itools-harbor.example.com/simulation/nplatform-core:${CI_COMMIT_BRANCH}_${CI_COMMIT_SHORT_SHA}"

workflow:
  rules:
    - if: $CI_COMMIT_BRANCH == "dev"
      when: always
    - if: $CI_COMMIT_BRANCH == "master"
      when: always
    - when: never

stages:
  - build
  - deploy

build-job:
  stage: build
  allow_failure: false
  tags:
    - "docker"
  before_script:
    - docker login -u "${HARBOR_USERNAME}" --password "${HARBOR_PASSWORD}" "${HARBOR_URL}"
  script:
    - docker build -t "${TAG}" -t "${LATEST_TAG}" .
    - docker push "${TAG}"
    - docker push "${LATEST_TAG}"
    - docker image rm "${TAG}"
    - docker image rm "${LATEST_TAG}"

deploy-job:
  stage: deploy
  tags:
    - "107-shell"
  allow_failure: false
  dependencies:
    - build-job
  only:
    refs:
      - master
  before_script:
    - newgrp docker
    - docker login -u "${HARBOR_USERNAME}" --password "${HARBOR_PASSWORD}" "${HARBOR_URL}"
    - docker compose down
    - if [ `docker image ls "${LATEST_TAG}" --format "{{.ID}}" | wc -l` -gt 0 ]; then docker image rm "${LATEST_TAG}"; fi
    - export DEPLOY_ENV="prod"
  script:
    - docker compose up -d

deploy-job-dev:
  stage: deploy
  tags:
    - "12-shell"
  allow_failure: false
  dependencies:
    - build-job
  only:
    refs:
      - dev
  before_script:
    - newgrp docker
    - docker login -u "${HARBOR_USERNAME}" --password "${HARBOR_PASSWORD}" "${HARBOR_URL}"
    - docker compose down
    - if [ `docker image ls "${LATEST_TAG}" --format "{{.ID}}" | wc -l` -gt 0 ]; then docker image rm "${LATEST_TAG}"; fi
    - export DEPLOY_ENV="dev"
  script:
    - docker compose up -d
version: "3"

services:
  editor:
    image: ${LATEST_TAG}
    container_name: nplatform_core
    ports:
      - 5000:1880
    restart: always
    environment:
      DEPLOY_ENV: ${DEPLOY_ENV}
FROM itools-harbor.example.com/common/node-nplatform:0.0.1

RUN mkdir /app
COPY . /app
WORKDIR /app
RUN npm install && npm run build
ENTRYPOINT npm run start

项目 2

default:
  interruptible: false

variables:
  LATEST_TAG: "itools-harbor.example.com/simulation/nplatform-filesystem:${CI_COMMIT_BRANCH}_latest"
  TAG: "itools-harbor.example.com/simulation/nplatform-filesystem:${CI_COMMIT_BRANCH}_${CI_COMMIT_SHORT_SHA}"

workflow:
  rules:
    - if: $CI_COMMIT_BRANCH == "master"
      when: always
    - if: $CI_COMMIT_BRANCH == "dev"
      when: always
    - when: never

stages:
  - check
  - build
  - deploy

sonarqube-check:
  stage: check
  tags:
    - "docker"
  image: 
    name: sonarsource/sonar-scanner-cli:latest
    entrypoint: [""]
  variables:
    SONAR_USER_HOME: "${CI_PROJECT_DIR}/.sonar"  # Defines the location of the analysis task cache
    GIT_DEPTH: "0"  # Tells git to fetch all the branches of the project, required by the analysis task
  cache:
    key: "${CI_JOB_NAME}"
    paths:
      - .sonar/cache
  script: 
    - sonar-scanner
  allow_failure: false
  only:
    - merge_requests
    - master

build-job:
  stage: build
  allow_failure: false
  tags:
    - "docker"
  before_script:
    - docker login -u "$HARBOR_USERNAME" --password "${HARBOR_PASSWORD}" "${HARBOR_URL}"
  script:
    - docker build -t "${TAG}" -t "${LATEST_TAG}"  .
    - docker push "${TAG}"
    - docker push "${LATEST_TAG}"
    - docker image rm "${TAG}"
    - docker image rm "${LATEST_TAG}"

deploy-job:
  stage: deploy
  tags:
    - "docker"
  allow_failure: false
  dependencies:
    - build-job
  only:
    refs:
      - master
  before_script:
    - docker compose down
    - if [ `docker image ls "${LATEST_TAG}" --format "{{.ID}}" | wc -l` -gt 0 ]; then docker image rm "${LATEST_TAG}"; fi
    - docker login -u "$HARBOR_USERNAME" --password "${HARBOR_PASSWORD}" "${HARBOR_URL}"
    - export DEPLOY_ENV="prod"
  script:
    - docker compose up -d

deploy-job-dev:
  stage: deploy
  tags:
    - "12-docker"
  allow_failure: false
  dependencies:
    - build-job
  only:
    refs:
      - dev
  before_script:
    - docker compose down
    - if [ `docker image ls "${LATEST_TAG}" --format "{{.ID}}" | wc -l` -gt 0 ]; then docker image rm "${LATEST_TAG}"; fi
    - docker login -u "$HARBOR_USERNAME" --password "${HARBOR_PASSWORD}" "${HARBOR_URL}"
    - export DEPLOY_ENV="dev"
  script:
    - docker compose up -d
version: "3"

services:
  storage:
    container_name: nplatform_storage
    image: $LATEST_TAG
    ports:
      - 5002:80
    restart: always
    healthcheck:
      test: "wget --no-verbose --tries=1 --spider http://localhost/ops/healthy || kill 1"
      interval: 2m
      timeout: 10s
      retries: 2
      start_period: 1m
    environment:
      DEPLOY_ENV: ${DEPLOY_ENV}
FROM itools-harbor.example.com/common/node-nplatform:0.0.1
RUN mkdir /app
COPY ./ /app
WORKDIR /app
RUN npm install
ENTRYPOINT npm run start

项目 3

default:
  interruptible: false

workflow:
  rules:
    - if: $CI_COMMIT_BRANCH == "master"
      when: always
    - if: $CI_COMMIT_BRANCH == "dev"
      when: always
    - when: never

stages:
  - check
  - build
  - deploy

sonarqube-check:
  stage: check
  image: 
    name: sonarsource/sonar-scanner-cli:latest
    entrypoint: [""]
  tags:
    - "docker"
  variables:
    SONAR_USER_HOME: "${CI_PROJECT_DIR}/.sonar"  # Defines the location of the analysis task cache
    GIT_DEPTH: "0"  # Tells git to fetch all the branches of the project, required by the analysis task
  cache:
    key: "${CI_JOB_NAME}"
    paths:
      - .sonar/cache
  script: 
    - sonar-scanner
  allow_failure: false
  only:
    - merge_requests
    - dev


build-job:
  stage: build
  allow_failure: false
  image: "itools-harbor.example.com/common/node-nplatform:0.0.1"
  tags:
    - "docker"
  only:
    - master
  before_script:
    - npm config set registry http://mirrors.example.com/repository/npm/
    - npm install
  script:
    - npm run build:prod
  artifacts:
    untracked: false
    expire_in: 20 mins
    paths:
      - ./dist

build-job-dev:
  stage: build
  allow_failure: false
  image: "itools-harbor.example.com/common/node-nplatform:0.0.1"
  tags:
    - "docker"
  only:
    - dev
  before_script:
    - npm config set registry http://mirrors.example.com/repository/npm/
    - npm install
  script:
    - npm run build
  artifacts:
    untracked: false
    expire_in: 20 mins
    paths:
      - ./dist

deploy-job:
  stage: deploy
  tags:
    - "107-shell"
  allow_failure: false
  dependencies:
    - build-job
  script:
    - for c in `ls $NGINX_ROOT`; do rm -rf "${NGINX_ROOT}/${c}";done;
    - cp -r ./dist/* "${NGINX_ROOT}/"
  only:
    refs:
      - master

deploy-job-dev:
  stage: deploy
  tags:
    - "12-shell"
  allow_failure: false
  dependencies:
    - build-job-dev
  script:
    - for c in `ls $NGINX_ROOT_DEV`; do rm -rf "${NGINX_ROOT_DEV}/${c}"; done;
    - cp -r ./dist/* "${NGINX_ROOT_DEV}/"
  after_script:
    - rm -rf ../../*
  only:
      - dev
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值