GitLab CICD 跑通实践

412 阅读3分钟

概念

Gitlab内置了CI/CD的工具,在项目中添加.gitlab-ci.yml文件,并且配置gitlab-runner(运行器)后,代码更新时会自动构建、部署。

.gitlab-ci.yml一般放在项目根目录,该文件是用来指定构建、测试和部署流程、以及CI触发条件的脚本。当Gitlab检测到代码提交符合.gitlab-ci.yml文件指定的触发条件时,则会使用配置的gitlab-runner执行.gitlab-ci.yml脚本。

gitlab-runner相当于Gitlab中任务的执行器,Gitlab会在需要执行任务时调用它。

配置gitlab CICD流程

配置gitlab CICD流程需要两步:

  • 第一步:在服务器安装 gitlab-runner 并关联仓库。
  • 第二步:编写gitlab-ci.yml。

在服务器安装 gitlab-runner,编写gitlab-ci.yml:juejin.cn/post/740058…

最终YML文件: sonar检测 - build - 上传sentry源码映射 - 删除MAP文件 - 丢到nginx

今天专门解决丢到nginx,而且是丢到宿主机的Nginx.

知识点:

  1. gitLab为了安全,不支持在.gitlab-ci.yml中直接使用volumes(卷挂载),但可以在gitLabrunner配置文件中配置加载卷,与宿主机进行文件交互。位置在/etc/gitlab-runner/config.toml,修改完了要记得重启。
[[runners]]
  ...
  [runners.custom_build_dir]
  [runners.docker]
    tls_verify = false
    # 在这里进行目录挂载
    volumes = ["/cache", "宿主机目录:容器内目录"]
    privileged = truePS: 这个设置允许容器以特权模式运行。特权模式给予容器几乎与主机相同的权限,包括访问所有设备。这对于运行需要更高权限的任务(如 Docker-in-Docker)是必要的。警告:特权模式可能带来安全风险,应谨慎使用。)
     pull_policy = ["if-not-present", "always"](PS: 现在普通环境不允许访问docker了,所以要加上缓存,如果有镜像就不拉取了)
  1. GitLab artifacts: 整个构建脚本分N个阶段,artifacts是当前阶段可以传递到其他阶段的产物。每个阶段执行前先下载之前所有阶段传递的产物(所以产物尽量不要过大)
  artifacts:
    name: "dist-${CI_COMMIT_REF_NAME}"
    paths:
      - dist/
    expire_in: 1 hour

3.DinD: DIND(Docker-in-Docker)是让你可以在 Docker 容器里面运行 Docker 的一种方式.

工作原理:

-   在主机上运行一个 Docker 容器(父容器)
-   这个父容器内部运行另一个 Docker 守护进程
-   允许在父容器内创建和管理子容器
  services:
    - docker:dind

环境说明

nginx是部署在服务器本地的(宿主机),没有使用docker。所以需要将构建产物丢到/usr/local/nginx/html。目录,但是整个stage都是docker运行的,卡在了不知如何同宿主机进行交互,apk-get和yum等等常用工具都没办法使用,容器内也不能下载一些常用包。GPT了一下,方案大概有四种:

  1. 使用 SSH 部署:

在这种方法中,我们使用 SSH 将构建好的文件复制到目标服务器。

deploy_to_server:
  stage: deploy
  image: alpine:latest
  before_script:
    - apk add --no-cache openssh-client
    - eval $(ssh-agent -s)
    - echo "$SSH_PRIVATE_KEY" | tr -d '\r' | ssh-add -
    - mkdir -p ~/.ssh
    - chmod 700 ~/.ssh
    - echo "$SSH_KNOWN_HOSTS" > ~/.ssh/known_hosts
    - chmod 644 ~/.ssh/known_hosts
  script:
    - scp -r hcsp-frontend/dist/* $SERVER_USER@$SERVER_IP:/usr/local/nginx/html/hcsp-frontend/
  only:
    - sunshu_cicd_build

您需要在 GitLab CI/CD 变量中设置 SSH_PRIVATE_KEY、SSH_KNOWN_HOSTS、SERVER_USER 和 SERVER_IP。

卡在了没有apk包。

  1. 使用 rsync:

如果您的服务器支持 rsync,这可能是一个更好的选择:

deploy_to_server:
  stage: deploy
  image: alpine:latest
  before_script:
    - apk add --no-cache openssh-client rsync
    - eval $(ssh-agent -s)
    - echo "$SSH_PRIVATE_KEY" | tr -d '\r' | ssh-add -
    - mkdir -p ~/.ssh
    - chmod 700 ~/.ssh
    - echo "$SSH_KNOWN_HOSTS" > ~/.ssh/known_hosts
    - chmod 644 ~/.ssh/known_hosts
  script:
    - rsync -avz --delete hcsp-frontend/dist/ $SERVER_USER@$SERVER_IP:/usr/local/nginx/html/hcsp-frontend/
  only:
    - sunshu_cicd_build

卡在了不支持rsync。

  1. 使用 GitLab Runner 的 shell 执行器:

如果可能的话,您可以在目标服务器上设置一个 GitLab Runner,并使用 shell 执行器。这样,Runner 就可以直接访问服务器的文件系统。

deploy_to_server:
  stage: deploy
  tags:
    - shell  # 确保这个 tag 匹配您在服务器上设置的 Runner
  script:
    - cp -R hcsp-frontend/dist/* /usr/local/nginx/html/hcsp-frontend/
  only:
    - sunshu_cicd_build

这个也失败了。

  1. 使用 Docker 卷挂载:

如果您的 GitLab Runner 在目标服务器上运行,并且使用 Docker 执行器,您可以尝试挂载目标目录:

deploy_to_server:
  stage: deploy
  image: alpine:latest
  volumes:
    - /usr/local/nginx/html/hcsp-frontend:/deploy
  script:
    - cp -R hcsp-frontend/dist/* /deploy/
  only:
    - sunshu_cicd_build

如知识点1,这个参数根本就不支持。

这些在文档中都有讲。所以要仔细看文档啊喂!

最终YML文件: sonar检测 - build - 上传sentry源码映射 - 删除MAP文件 - 丢到nginx

stages:
  - build
  - release
  - deploy 

sonarqube-check:
  stage: .pre
  image:
    name: sonarsource/sonar-scanner-cli:latest
    entrypoint: [ "" ]
  variables:
    SONAR_USER_HOME: "${CI_PROJECT_DIR}/.sonar"  # 缓存SonarQube插件
  cache:
    key: "${CI_JOB_NAME}"
    paths:
      - .sonar/cache
  script:
    - sonar-scanner
      -Dsonar.projectKey=projectKey
      -Dsonar.sources=.
      -Dsonar.host.url=host.url
      -Dsonar.login=${SONAR_TOKEN}
      -Dsonar.scanner.timeoutSeconds=300
  allow_failure: true
  only:
    - merge_requests
    - sunshu_cicd_build

cache:
  key:
    files:
      - hcsp-frontend/package.json
      - hcsp-frontend/package-lock.json
  paths:
    - hcsp-frontend/node_modules/


build:
  stage: build
  image: node:16.19.1  # 使用适合您项目的 Node.js 版本
  script:
    - cd hcsp-frontend || echo "Failed to change directory"
    - pwd  # 再次显示当前工作目录
    - ls -la  # 再次列出当前目录下的所有文件和文件夹
    - npm install  # 或者 yarn install,取决于您使用的包管理器
    - npm run build  # 假设这是您的构建命令
    - mkdir -p $CI_PROJECT_DIR/dist
    - rm -rf $CI_PROJECT_DIR/dist/*
    - cp -r dist/* $CI_PROJECT_DIR/dist/  # 将 dist 目
  artifacts:
    name: "dist-${CI_COMMIT_REF_NAME}"
    paths:
      - dist/
    expire_in: 1 hour

sentry_release:
  stage: release
  image: getsentry/sentry-cli:latest
  script:
    - pwd  # 显示当前工作目录
    - ls -la  # 列出当前目录下的所有文件和文件夹
    - pwd  # 再次显示当前工作目录
    - ls -la  # 再次列出当前目录下的所有文件和文件夹
    - export SENTRY_AUTH_TOKEN="$SENTRY_AUTH_TOKEN"
    - export SENTRY_ORG="$SENTRY_ORG"
    - export SENTRY_PROJECT="$SENTRY_PROJECT"
    # 如果您使用的是自托管的Sentry,请取消下面这行的注释并设置正确的URL
    - export SENTRY_URL="https://tisi.sentry.io/"

    # 创建新的Sentry版本
    - sentry-cli releases new -p $SENTRY_PROJECT $CI_COMMIT_SHA

    # 设置提交数据
    - sentry-cli releases set-commits --auto $CI_COMMIT_SHA


    # 上传 /hcsp/ 目录下的文件
    - sentry-cli releases files $CI_COMMIT_SHA upload-sourcemaps dist/js --url-prefix ~/js/

    # 完成发布
    - sentry-cli releases finalize $CI_COMMIT_SHA


    # 部署到生产环境(如果适用)
    - sentry-cli releases deploys $CI_COMMIT_SHA new -e production
    
    - pwd  # 显示当前工作目录
    - ls -la  # 列出当前目录下的所有文件和文件夹
  only:
    - sunshu_cicd_build  # 或者您希望触发此作业的分支名称

    
variables:
  SENTRY_AUTH_TOKEN: - SENTRY_AUTH_TOKEN -
  SENTRY_ORG: tisi
  SENTRY_PROJECT: admin-vue


deploy:
  stage: deploy
  script:
    - rm -rf dist/js/*.map
    - mkdir -p /cache/hcsp-frontend
    - ls -al
    - cp -r dist/* /cache/hcsp-frontend
  only:
    - sunshu_cicd_build  # 只在特定分支上运行

飞书通知

找到了一个库 github.com/goodideal/g…

由于7001端口暂时没开,平替:

notify_feishu:
  stage: deploy
  image:
    name: curlimages/curl:latest
    pull_policy: if-not-present
  script:
    - |
      curl -k -X POST -H "Content-Type:application/json" \
      -d '{
        "msg_type": "post",
        "content": {
          "post": {
            "zh_cn": {
              "title": "XXX项目/分支:'"${CI_COMMIT_BRANCH/tool/}"'已发布",
              "content": [
                [
                {
                    "tag": "text",
                    "text": "提交人: '"${CI_COMMIT_AUTHOR}"'\n"
                  },
                  {
                    "tag": "text",
                    "text": "本次更新内容:'"${CI_COMMIT_MESSAGE}"'\n"
                  },
          
                  {
                    "tag": "a",
                    "text": "查看流水线",
                    "href": "'"${CI_PROJECT_URL}/-/pipelines/${CI_PIPELINE_ID}"'"
                  }
                ]
              ]
            }
          }
        }
      }' \
      https://open.feishu.cn/open-apis/bot/BOT地址
  only:
    - cicd_build  # 或者您想触发通知的分支
  when: on_success