gitlab部署私有化git


.gitlab-ci.yml文件定义 CI/CD 流水线
一个python程序的管道示范:

yaml
stages:                       # 定义流水线阶段列表,按顺序执行
  - build                     # 第一个阶段:构建(build)
  - deploy                    # 第二个阶段:部署(deploy)

# 默认变量,可通过 rules 覆盖          # 说明:下面是一些默认的 CI/CD 变量,必要时可在 job 中覆盖
variables:                    # 定义整个流水线通用的环境变量
  # Telegram Bot              # 注释:这几项是 Telegram 机器人通知相关配置
  TELEGRAM_TOKEN: "test"  # Telegram Bot 的 token(建议放到 GitLab CI 变量里)
  TELEGRAM_CHAT_ID: "-4706391872"                                  # 接收通知的 Telegram 群/频道 ID
  IMAGE_NAME: "registry.gbox.one/ai-poker/video_talk_api"          # 要构建和推送的 Docker 镜像完整名称
  TEST_SERVER_HOST: "172.26.97.44"                                 # 测试服务器的 IP 地址
  TEST_SERVER_USER: "root"                                         # 测试服务器的登录用户

.common_failure_notification: &common_failure_notification  # 定义一个通用模板(锚点),用于“失败时通知”的 job 复用
  after_script:                # 在 job 主脚本执行结束后,无论成功失败都会执行这里的脚本
    - |                        # 使用多行脚本块,交给 Shell 执行
      if [[ "$CI_JOB_STATUS" != "success" ]]; then          # 如果当前 job 状态不是 success(说明失败或被取消)
        MSG="                                                # 定义要发送给 Telegram 的消息内容(多行字符串)
              ❌ *${CI_PROJECT_NAME} 打包失败*
              📁 项目:*${CI_PROJECT_NAME}*
              🔧 分支:*${CI_COMMIT_REF_NAME}*
              🎯 Job:*${CI_JOB_NAME}*
              ❌ 状态:*${CI_JOB_STATUS}*
              🪪 提交者:*${CI_COMMIT_AUTHOR}*
              🔗 [查看详情](${CI_JOB_URL})
            "
        curl -s -X POST https://api.telegram.org/bot${TELEGRAM_TOKEN}/sendPhoto \  # 调用 Telegram Bot API,发送带图片的通知
        # 上一行的“\”表示命令续行

        -d photo=https://raw.githubusercontent.com/coder-tye/media/refs/heads/main/banner.png \  # 指定要附带发送的图片 URL
        # 继续上一行命令参数

        -d chat_id=${TELEGRAM_CHAT_ID} \                     # 指定发送到哪一个 chat(群/频道)
        # 继续上一行命令参数

        -d parse_mode=Markdown \                             # 启用 Markdown 格式解析,支持加粗/链接等
        # 继续上一行命令参数

        -d caption="$MSG"                                    # 把上面拼好的 MSG 作为图片说明文字发送
      fi                                                     # 条件结束:只有失败时才会发送通知



.common_all_notification: &common_all_notification          # 定义另一个通用模板,用于“部署成功或失败都通知”
  after_script:                # job 完成后统一发送部署结果到 Telegram
    - |                        # 多行 Shell 脚本块
      if [[ "$CI_JOB_STATUS" == "success" ]]; then           # 如果 job 成功
        MSG="                                                # 定义成功时的通知内容
          🚀 *${CI_PROJECT_NAME} ${CI_ENV} 部署完成*
          📁 项目:*${CI_PROJECT_NAME}*
          🔧 分支:*${CI_COMMIT_REF_NAME}*
          🔗 [访问部署环境](${TARGET_URL})
        "
      else                                                   # 否则(失败或被取消)
        MSG="                                                # 定义失败时的通知内容
          ❌ *${CI_PROJECT_NAME} ${CI_ENV} 部署失败!*
          📁 项目:*${CI_PROJECT_NAME}*
          🛠️ 分支:*${CI_COMMIT_REF_NAME}*
          🚨 Job:*${CI_JOB_NAME}*
          🔗 [查看日志](${CI_JOB_URL})"
      fi                                                     # 结束 if 判断
      curl -s -X POST https://api.telegram.org/bot${TELEGRAM_TOKEN}/sendPhoto \  # 无论成功失败,都会发送一条带图片的通知
        -d photo=https://raw.githubusercontent.com/coder-tye/media/refs/heads/main/banner.png \ # 使用统一的 banner 图片
        -d chat_id=${TELEGRAM_CHAT_ID} \                     # 指定接收通知的 chat
        -d parse_mode=Markdown \                             # 启用 Markdown 渲染
        -d caption="$MSG"                                    # 发送上面构造的 MSG 作为说明文字


build-docker-image:            # 定义一个名为 build-docker-image 的 job(构建 Docker 镜像)
  stage: build                 # 这个 job 属于 build 阶段
  script:                      # 该 job 的主要执行脚本
    - echo "🐳 构建 Docker 镜像..."                         # 打印提示,说明正在构建 Docker 镜像
    - |                        # 多行 Shell 命令块
      docker buildx build -f Dockerfile.test \               # 使用 buildx 和 Dockerfile.test 构建镜像
        -t "$IMAGE_NAME:latest" \                            # 给镜像打一个 latest 标签
        -t "$IMAGE_NAME:$CI_COMMIT_SHORT_SHA" \              # 再打一个短提交 SHA 作为版本标签
        .                                                    # 构建上下文为当前目录
    - docker push "$IMAGE_NAME:latest"                       # 推送 latest 标签的镜像到镜像仓库
    - docker push "$IMAGE_NAME:$CI_COMMIT_SHORT_SHA"         # 推送带提交哈希标签的镜像,便于回滚和追踪
  extends: .common_failure_notification                      # 继承上面定义的“失败时 Telegram 通知”模板



deploy-to-test:                # 定义部署到测试环境的 job
  stage: deploy                # 这个 job 属于 deploy 阶段
  dependencies: []             # ❌ 不自动下载 artifacts  # 显式禁止从其他 job 下载构建产物(此处只依赖镜像,不靠 artifacts)
  when: on_success             # 仅在之前阶段的 job 全部成功时才执行该 job
  needs: ["build-docker-image"] # 声明依赖 build-docker-image,确保构建 job 成功后再执行部署
  #only:                       # 注释掉的 only 规则
  #  - release                 # 如果启用,则表示只在 release 分支/tag 上执行这个部署 job
  script:                      # 部署脚本
    - |                        # 多行 Shell 命令块
      echo "🚀 正在部署到测试服务器..."                      # 提示开始部署
      ssh "$TEST_SERVER_USER@$TEST_SERVER_HOST" << EOF       # 通过 SSH 连到测试服务器,并执行下面的 bash 脚本(heredoc)
        docker pull $IMAGE_NAME:latest                       # 在测试服务器上拉取最新镜像
        docker stop video-talk || true                       # 停掉旧的容器(如果不存在则忽略错误)
        docker rm video-talk || true                         # 删除旧容器(如果不存在则忽略错误)
        docker run -d \                                      # 以后台方式启动新容器
          --restart unless-stopped \                         # 设置容器自动重启策略
          -v /data/video_talk/.env:/app/.env \               # 挂载服务器上的 .env 文件到容器内,提供配置
          -v /data/video_talk/logs:/app/logs \               # 挂载日志目录,方便持久化日志
          -p 8199:8000 \                                     # 映射宿主机 8199 端口到容器 8000 端口
          --name video-talk \                                # 指定容器名称为 video-talk
          $IMAGE_NAME:latest                                 # 使用刚刚构建并推送的 latest 镜像启动容器
      EOF                                                    # 结束 heredoc,SSH 远程命令执行完毕
  variables:                    # 仅在这个 job 中生效的变量
    TARGET_URL: "https://tailk.masterpoker.pro"              # 部署好的测试环境访问地址,用于通知消息中展示
    CI_ENV: "测试环境"                                        # 当前部署环境名称,用于通知(比如“测试环境”)
  extends: .common_all_notification                          # 继承“成功/失败都通知”的通用模板

一个node.js管道示范:

yaml
stages:                      # 定义流水线的阶段列表,按顺序执行
  - build                    # 第一阶段:build(打包构建)
  - deploy                   # 第二阶段:deploy(部署)

variables:                   # 定义全局变量,所有 job 默认都能用
  TELEGRAM_TOKEN: key        # Telegram 机器人 token(示例,实际建议用 CI 变量存)
  TELEGRAM_CHAT_ID: -4706391872  # Telegram 聊天/频道 ID,用于发送通知

# ================= 通用 build 脚本 =================

.default_build_script: &build_script  # 定义一个锚点 build_script,后面 job 的 script 可以复用这段命令
  - source ~/.nvm/nvm.sh              # 加载 nvm 环境脚本,让当前 shell 支持 nvm 命令
  - nvm use 20                        # 切换到 Node.js 20 版本
  - node --version                    # 打印当前 Node.js 版本,方便在 CI 日志中确认
  - yarn install --frozen-lockfile    # 安装依赖,严格按照 yarn.lock,不允许变更锁文件
  - yarn run build                    # 执行前端项目的打包构建命令,生成 dist 等产物

# ================= 通用 deploy 脚本 =================
.default_deploy_script: &deploy_script |  # 定义一个部署脚本锚点 deploy_script,作为整段 shell 脚本复用
  set -e                                  # 遇到任意命令出错则立即退出,保证部署过程出错不会悄悄继续
  echo "🚀 部署开始..."                   # 输出部署开始提示

  DEPLOY_TIMESTAMP=$(date +%Y%m%d-%H%M%S) # 生成当前时间戳,用于备份目录命名(如 20251203-153000)
  DEPLOY_BACKUP="${DEPLOY_BACKUP_PATH}${CI_PROJECT_NAME}-$DEPLOY_TIMESTAMP"  # 拼接备份目录完整路径
  ssh "$HOSTNAME" << EOF                  # 通过 SSH 登录到远程服务器,执行下面的多行命令
    if [[ -d "$DEPLOY_PATH" ]]; then      # 判断目标部署目录是否存在
      echo "🗃️ 备份旧版本到 $DEPLOY_BACKUP" # 提示要备份旧版本
      mv "$DEPLOY_PATH" "$DEPLOY_BACKUP"  # 把当前部署目录移动到备份目录
    fi
    mkdir -p "$DEPLOY_PATH"               # 创建新的部署目录(如果不存在就创建)
  EOF                                     # 结束 SSH heredoc,多行远程命令结束
  rsync -avz dist/ "$HOSTNAME:$DEPLOY_PATH/"  # 使用 rsync 把本地 dist/ 目录同步到远程部署目录
  echo "✅ 部署完成"                      # 输出部署完成提示

.common_failure_notification: &common_failure_notification  # 定义一个“失败通知”模板锚点,供 job 继承
  after_script:                      # 在 job 主脚本结束后执行,无论成功失败都会执行这里
    - |                              # 多行 shell 脚本块
      if [[ "$CI_JOB_STATUS" != "success" ]]; then   # 如果当前 job 状态不是 success(说明失败或被取消)
        MSG="                                      # 定义要发送到 Telegram 的消息内容(多行字符串)
              ❌ *${CI_PROJECT_NAME} 打包失败*
              📁 项目:*${CI_PROJECT_NAME}*
              🔧 分支:*${CI_COMMIT_REF_NAME}*
              🎯 Job:*${CI_JOB_NAME}*
              ❌ 状态:*${CI_JOB_STATUS}*
              🪪 提交者:*${CI_COMMIT_AUTHOR}*
              🔗 [查看详情](${CI_JOB_URL})
            "
        curl -s -X POST https://api.telegram.org/bot${TELEGRAM_TOKEN}/sendPhoto \  # 调用 Telegram Bot API 发送图片消息
        -d photo=https://raw.githubusercontent.com/coder-tye/media/refs/heads/main/banner.png \  # 指定要附带的 banner 图片
        -d chat_id=${TELEGRAM_CHAT_ID} \                   # 指定推送到哪个聊天/频道
        -d parse_mode=Markdown \                           # 启用 Markdown 渲染,让加粗/链接生效
        -d caption="$MSG"                                  # 把上面构造的 MSG 作为图片说明文字发送
      fi                                                   # 结束 if 条件判断

.common_all_notification: &common_all_notification          # 定义“成功/失败都通知”的模板锚点
  after_script:                      # job 结束后统一执行,用于部署相关结果通知
    - |                              # 多行 shell 脚本块
      if [[ "$CI_JOB_STATUS" == "success" ]]; then         # 如果 job 成功
        MSG="                                              # 定义成功时的通知内容
          🚀 *${CI_PROJECT_NAME} ${CI_ENV} 部署完成*
          📁 项目:*${CI_PROJECT_NAME}*
          🔧 分支:*${CI_COMMIT_REF_NAME}*
          🔗 [访问部署环境](${TARGET_URL})
        "
      else                                                 # 否则视为部署失败
        MSG="                                              # 定义失败时的通知内容
          ❌ *${CI_PROJECT_NAME} ${CI_ENV} 部署失败!*
          📁 项目:*${CI_PROJECT_NAME}*
          🛠️ 分支:*${CI_COMMIT_REF_NAME}*
          🚨 Job:*${CI_JOB_NAME}*
          🔗 [查看日志](${CI_JOB_URL})"
      fi                                                   # 结束成功/失败判断
      curl -s -X POST https://api.telegram.org/bot${TELEGRAM_TOKEN}/sendPhoto \  # 不论成功失败都会发送一条带图片的通知
        -d photo=https://raw.githubusercontent.com/coder-tye/media/refs/heads/main/banner.png \  # 使用统一 banner 图片
        -d chat_id=${TELEGRAM_CHAT_ID} \                   # 发送到指定 Telegram 聊天/频道
        -d parse_mode=Markdown \                           # 使用 Markdown 解析
        -d caption="$MSG"                                  # 发送上面构建好的 MSG 内容

# ================= 打包 =================
# 专业版测试环境
build_pro_test:                 # 定义一个名为 build_pro_test 的 job,用于构建“专业版测试环境”的前端
  stage: build                  # 这个 job 属于 build 阶段
  script: *build_script         # 使用前面定义的通用构建脚本锚点 build_script
  artifacts:                    # 指定本 job 产生的构建产物,以便后续 job(如部署)使用
    paths:                      # 要打包保存的文件/目录路径列表
      - $DIST_FILE              # 使用 DIST_FILE 变量指定的构建产物路径(例如 dist/ 或 zip 文件)
    expire_in: 1 week           # 构建产物在 GitLab 中保存 1 周后自动过期删除
  extends: .common_failure_notification  # 继承“失败时发送 Telegram 通知”的模板

# ================= 部署流程 =================

deploy_pro_test:                # 定义一个名为 deploy_pro_test 的 job,用于部署到测试环境
  stage: deploy                 # 这个 job 属于 deploy 阶段
  when: on_success              # 仅当前面依赖的 job 全部成功时才会执行本 job
  needs: ["build_pro_test"]     # 声明依赖 build_pro_test job,以确保构建完成后再部署(并可并行优化流水线)
  variables:                    # 仅在这个部署 job 中生效的变量
    HOSTNAME: "root@172.26.97.44"            # SSH 目标地址(用户名 + 服务器 IP)
    DEPLOY_PATH: "/data/video_talk/html/"    # 部署的目标目录(新版本会同步到这里)
    DEPLOY_BACKUP_PATH: "/data/video_talk/html_bak/"  # 旧版本备份目录前缀
    TARGET_URL: "https://talk.masterpoker.pro"        # 部署完成后对外访问的 URL,用于通知里给链接
    CI_ENV: "测试环境"                                  # 当前部署环境名称,通知中显示“测试环境”
  script: *deploy_script        # 使用通用部署脚本锚点 deploy_script(上面那一大段 SSH+rsync)
  extends: .common_all_notification  # 继承“成功/失败都发送 Telegram 通知”的模板