linux上gitlab runner部署文档

2025年11月16日

背景

平常使用的CI/CD主要是用Jenkins,git的本地hook,但是对于代码上传后执行差异代码优化这个技术场景流程场景来说:

  1. Jenkins流程只会做到全量排查,如果中途遇到问题代码导致失败,得不偿失,且一个仓库可能会有不再维护代码与无关代码,造成资源浪费
  2. git本地hook问题在于,更新时每个组员都需要做,并且git commit的时候可以通过--no-verify 规避本地check,同时如果直接在gitlab上面IDE直接修改,则本地git hook脚本不会执行

因此为了优化这一块的流水线,避免上述2个问题,我打算通过git合入时通过git 的CI/CD,执行脚本分析差异化文件

(本文因为离职后所有消息记录会被删除,因此图片是没有的,请见谅)

部署与验证

gitlab自带部署runner文档 docs.gitlab.cn/docs/jh/ins... ,同时csdn也有对应的文档可以借鉴 blog.csdn.net/qq_39826207... 不过实际上我在开发时也遇到了一点问题,所以也可以通过以下方式部署:

  1. 准备Linux环境(Centos为例)

  2. 通过wget或者离线等方式获取gitlab runner的安装包

sh 复制代码
 # 创建专用用户(不创建 home 目录)
 sudo useradd --comment 'GitLab Runner' --create-home gitlab-runner
 ​
 # 创建 runner 工作目录
 sudo mkdir /home/gitlab-runner/runner
 ​
 sudo chown gitlab-runner:gitlab-runner /home/gitlab-runner/runner
  1. 初始化并启动 GitLab Runner(作为服务)

    虽然使用二进制,但建议以系统服务方式运行。

    1. 创建 systemd 服务文件

      sh 复制代码
       sudo tee /etc/systemd/system/gitlab-runner.service <<EOF
       [Unit]
       Description=GitLab Runner
       After=syslog.target network.target
       ConditionFileIsExecutable=/usr/local/bin/gitlab-runner
       ​
       [Service]
       StartLimitInterval=5
       StartLimitBurst=10
       ExecStart=/usr/local/bin/gitlab-runner run --working-directory /home/gitlab-runner/runner
       SuccessExitStatus=0 143
       Restart=always
       RestartSec=5
       KillMode=mixed
       WorkingDirectory=/home/gitlab-runner/runner
       User=gitlab-runner
       Group=gitlab-runner
       Environment=PATH=/bin:/usr/local/bin:/usr/bin
       CacheDirectory=gitlab-runner
       CacheDirectoryMode=0750
       ​
       [Install]
       WantedBy=multi-user.target
       EOF
    2. 重载 systemd 并启动服务

      bash 复制代码
       sudo systemctl daemon-reexec
       sudo systemctl daemon-reload
       sudo systemctl enable gitlab-runner
       sudo systemctl start gitlab-runner
    3. 检查服务状态

      sh 复制代码
       sudo systemctl status gitlab-runner
  2. 注册GitLab Runner 到 GitLab 实例

    (如果是多次注册,则需要优先按照第一步切换成对应的gitlab用户进行命令操作,整个的安装流程,我按照官方流程没成功,和当前流程唯一的差别就是官方没有切换到gitlab用户)

    1. 获取注册令牌 登录 GitLab Web 界面。 进入你的项目 → Settings → CI / CD → Runners。 复制 Registration token(项目级 Runner)。 或者在 Admin Area → Overview → Runners 获取实例级令牌。

    2. 运行注册命令: 切换到 gitlab-runner 用户并注册:

      sh 复制代码
       sudo -u gitlab-runner -H /usr/local/bin/gitlab-runner register

      按提示输入:

      • GitLab instance URL: gitlab.com(或你的自建 GitLab 地址)
      • Registration token: 你复制的令牌
      • Description: my-runner(自定义描述)
      • Tags: linux,docker(可选,用于任务匹配)
      • Executor: shell(或 docker, docker+machine 等)
      • Default Docker image: alpine:latest(如果使用 docker executor)
    3. 按提示输入:

      • GitLab instance URL: gitlab.com(或你的自建 GitLab 地址)
      • Registration token: 你复制的令牌
      • Description: my-runner(自定义描述)
      • Tags: linux,docker(可选,用于任务匹配)、
      • Executor: shell(或 docker, docker+machine 等)
      • Default Docker image: alpine:latest(如果使用 docker executor)
      • 注册成功后,配置会保存在 /home/gitlab-runner/runner/config.toml。

验证注册: 在 GitLab Web 界面的 Runners 页面,应看到新注册的 Runner 处于"在线"状态。

卸载

有时候可能是安装错误,可能是需要迁移业务,需要现在原有的环境的服务,可以按照以下步骤

  1. 停止并禁用服务

    sh 复制代码
     sudo systemctl stop gitlab-runner
     sudo systemctl disable gitlab-runner
  2. 删除服务文件

    sh 复制代码
     sudo rm /etc/systemd/system/gitlab-runner.service
     sudo systemctl daemon-reload
  3. 删除二进制文件和用户

    sh 复制代码
     sudo rm /usr/local/bin/gitlab-runner
     # -r 删除用户主目录
     sudo userdel -r gitlab-runner  
  4. 清理残留文件(可选)

    sh 复制代码
    sudo rm -rf /home/gitlab-runner

脚本分享

.gitlab-ci.yml

这个是仓库全局的git CI/CD的配置文件,根据触发阶段可以执行对应的script相关的脚本,在该脚本可以执行更多shell脚本,方便管理

该例子是合入时执行2个脚本,可供参考

yml 复制代码
stages:
  - check

# 全局变量
variables:
  GIT_DEPTH: ""  # 完整克隆

# 只在 Merge Request 时触发流水线(即"合入前检查")
workflow:
  rules:
    - if: $CI_PIPELINE_SOURCE == "merge_request_event"
    - when: never

check:
  stage: check
  interruptible: true  # 可中断:当 MR 更新时取消旧流水线
  script:
    # 脚本1:权限/配置检查
    - chmod +x ./cloud/env/install/script/config_checkstyle.sh
    - ./cloud/env/install/script/config_checkstyle.sh ucs-server $GITLAB_USER_EMAIL $CI_MERGE_REQUEST_TARGET_BRANCH_NAME

    # 脚本2:另一个检查脚本(示例)
    - chmod +x ./cloud/env/install/script/another_check.sh
    - ./cloud/env/install/script/another_check.sh

  # 只在 MR 中运行
  only:
    - merge_requests

  tags:
    - ucs_server

  # 可选:指定 MR 的目标分支(比如只对 main/develop 的合入做检查)
  # rules:
  #   - if: $CI_MERGE_REQUEST_TARGET_BRANCH_NAME =~ /^(main|develop)$/

sh脚本文件

Java验证差异文件

用于验证合入时两个分支之间的差异文件,对差异文件进行checkstyle(通过执行jar包)有问题就返回0,无问题会返回1,gitlab合并检测会根据返回值判定流水线成功/失败

原有脚本已经遗失,判断逻辑应当是jar包产生的输出,应当只看[WARN][ERROR]开头的的行是否>0,有则有问题(需要jar包启动checkstyle,需要xml配置文件进行规则配置)

Java程序的checkstyle需要以不同版本为大前提创建各自环境,其他的如本地执行hook,Jenkins执行,git CI/CD执行流程,需要的各种静态资源需要一致

sh 复制代码
#!/bin/bash

# ================== 参数校验 ==================
if [ $# -ne 4 ]; then
    echo "Usage: $0 <namespace> <email> <source_branch> <target_branch>"
    echo "Example: $0 ucs-server dev@example.com feature/add-config main"
    exit 1
fi

NAMESPACE=$1
EMAIL=$2
SOURCE_BRANCH=$3
TARGET_BRANCH=$4

# ================== 配置区 ==================
# Checkstyle jar 包路径(请根据实际路径修改)
CHECKSTYLE_JAR="./cloud/env/install/script/checkstyle.jar"

# Checkstyle 配置文件路径(checkstyle.xml)
CHECKSTYLE_CONFIG="./cloud/env/install/script/checkstyle.xml"

# 临时文件用于保存 Checkstyle 输出
CHECKSTYLE_LOG="/tmp/checkstyle_output_$$_$(date +%s).txt"
# ===========================================

echo "Analyzing Java files changed between '$SOURCE_BRANCH' and '$TARGET_BRANCH'..."

# 1. 确保远程分支存在
if ! git rev-parse --verify "origin/$SOURCE_BRANCH" > /dev/null 2>&1; then
    echo "Error: Remote branch 'origin/$SOURCE_BRANCH' not found."
    echo "Available branches:"; git branch -r
    exit 1
fi

if ! git rev-parse --verify "origin/$TARGET_BRANCH" > /dev/null 2>&1; then
    echo "Error: Remote branch 'origin/$TARGET_BRANCH' not found."
    echo "Available branches:"; git branch -r
    exit 1
fi

# 2. 获取两个分支之间变更的 Java 文件
CHANGED_JAVA_FILES=()

while IFS= read -r file; do
    if [[ "$file" == *.java ]] && [ -f "$file" ]; then
        CHANGED_JAVA_FILES+=("$file")
    fi
done < <(git diff --name-only "origin/$TARGET_BRANCH"...origin/$SOURCE_BRANCH)

# 3. 检查是否有变更的 Java 文件
if [ ${#CHANGED_JAVA_FILES[@]} -eq 0 ]; then
    echo "No Java files changed between 'origin/$TARGET_BRANCH' and 'origin/$SOURCE_BRANCH'."
    echo "No Java changes detected." | mail -s "$NAMESPACE: No Java changes" "$EMAIL"
    exit 0  # 无变更视为通过
fi

echo "Found ${#CHANGED_JAVA_FILES[@]} Java file(s) to check:"
printf '  %s\n' "${CHANGED_JAVA_FILES[@]}"

# 4. 执行 Checkstyle 检查(一次性传入所有文件)
echo "Running Checkstyle..."
# 使用 -c 指定配置,-f xml 或 summary 可选,这里使用简洁格式
# 如果你希望详细输出,可以使用 -f xml 并用 xmllint 格式化
if java -jar "$CHECKSTYLE_JAR" -c "$CHECKSTYLE_CONFIG" "${CHANGED_JAVA_FILES[@]}" > "$CHECKSTYLE_LOG" 2>&1; then
    # Checkstyle 命令执行成功(语法正确),但不代表无警告/错误
    OUTPUT=$(cat "$CHECKSTYLE_LOG")
    echo "$OUTPUT"

    # 检查输出中是否包含违规信息(Checkstyle 通常会在有违规时输出内容)
    if [[ -s "$CHECKSTYLE_LOG" && "$(echo "$OUTPUT" | grep -v '^$' | wc -l)" -gt 0 ]]; then
        echo "Checkstyle found issues in changed Java files."
        echo "Checkstyle Report:" | mail -s "[FAIL] $NAMESPACE: Checkstyle failed" "$EMAIL" -A "$CHECKSTYLE_LOG"
        rm -f "$CHECKSTYLE_LOG"
        exit 1  # 有违规 → 失败
    else
        echo "All changed Java files passed Checkstyle."
        echo "No checkstyle violations found." | mail -s "[OK] $NAMESPACE: Checkstyle passed" "$EMAIL"
        rm -f "$CHECKSTYLE_LOG"
        exit 0  # 无违规 → 成功
    fi
else
    # Checkstyle 命令执行失败(如 jar 报错、配置错误等)
    echo "Checkstyle execution failed!"
    cat "$CHECKSTYLE_LOG"
    echo "Checkstyle execution failed. See details." | mail -s "[ERROR] $NAMESPACE: Checkstyle execution error" "$EMAIL" -A "$CHECKSTYLE_LOG"
    rm -f "$CHECKSTYLE_LOG"
    exit 1
fi

yml验证差异文件

与上面的Java验证类似,就是查询差异文件yml与yaml,checkstyle有问题就返回0,无问题会返回1,gitlab合并检测会根据返回值判定流水线成功/失败

(如果是spring可以跳过所有的application.yml文件,因为yml 验证主要是为了交付给运维同事配置文件才会有的流水线步骤)

原有脚本已经遗失,判断逻辑应当通过yamllint进行验证,根据输出产生行数>0则有问题(需要ymlconf文件作为配置规则)

sh 复制代码
#!/bin/bash

if [ $# -ne 2 ]; then
    echo "Usage: $0 <namespace> <email>"
    exit 1
fi

NAMESPACE=$1
EMAIL=$2

# ================== 配置区 ==================
TARGET_BRANCH="main"  # 目标合并分支,可根据需要改为 dev、release 等
CONFIG_FILE="./cloud/env/install/script/ymlconf"
# ===========================================

echo "🔍 Checking YAML files changed between current branch and '$TARGET_BRANCH'..."

# 1. 获取当前分支相对于目标分支的差异文件(仅新增或修改)
# 注意:GitLab CI 会自动 fetch 所有分支,可以直接使用
CHANGED_YAML_FILES=()
while IFS= read -r file; do
    if [[ "$file" == *.yml || "$file" == *.yaml ]]; then
        if [ -f "$file" ]; then  # 确保文件存在(避免删除的文件)
            CHANGED_YAML_FILES+=("$file")
        fi
    fi
done < <(git diff --name-only "origin/$TARGET_BRANCH"...HEAD)

# 2. 检查是否有变更的 YAML 文件
if [ ${#CHANGED_YAML_FILES[@]} -eq 0 ]; then
    echo "✅ No YAML files changed. Skipping yamllint."
    echo "No YAML changes detected." | mail -s "$NAMESPACE: No YAML changes" "$EMAIL"
    exit 0
fi

echo "📄 Found ${#CHANGED_YAML_FILES[@]} YAML file(s) to check:"
printf '  %s\n' "${CHANGED_YAML_FILES[@]}"

# 3. 对差异文件逐个运行 yamllint
ERRORS_FOUND=""
for file in "${CHANGED_YAML_FILES[@]}"; do
    echo " linting $file"
    if ! yamllint -c "$CONFIG_FILE" "$file" > /tmp/yamllint.log 2>&1; then
        echo "❌ yamllint failed on $file"
        ERRORS_FOUND+="$file:\n"
        ERRORS_FOUND+=$(cat /tmp/yamllint.log)
        ERRORS_FOUND+="\n\n"
    fi
done

# 4. 处理结果
if [ -n "$ERRORS_FOUND" ]; then
    echo "YAML file has syntax errors!"
    echo -e "$ERRORS_FOUND"
    echo -e "$ERRORS_FOUND" | mail -s "$NAMESPACE YAML file has syntax errors!" "$EMAIL"
    rm -f /tmp/yamllint.log
    exit 1
else
    echo "✅ All changed YAML files are valid."
    echo "All changed YAML files passed lint." | mail -s "$NAMESPACE: YAML lint passed" "$EMAIL"
    rm -f /tmp/yamllint.log
    exit 0
fi

其他问题

gitlab runner实例在shell模式下怎么占用Centos资源的

在 shell executor 模式下,GitLab Runner 的工作方式如下:

  • 直接在宿主机(Centos)上执行命令:Runner 会以运行它的用户身份(如 gitlab-runner 用户),在系统 shell 中直接执行 .gitlab-ci.yml 中定义的 script 命令。

  • 资源占用特点:

    • CPU/内存:由实际执行的脚本决定(如编译、测试、打包等),直接消耗宿主机资源。
    • 磁盘:会在临时目录(默认 /home/gitlab-runner/builds//...)克隆代码并执行任务,任务结束后默认清理(可通过 builds_dir 配置)。
    • 环境依赖:所有依赖(如 Python、Node.js、Docker CLI 等)必须预先安装在 Centos 系统中。
    • 无隔离性:多个 job 共享同一系统环境,可能互相干扰(比如修改全局 PATH、写文件到 /tmp)。
    • 并发控制:通过 concurrent(全局)和 limit(每个 runner)控制同时运行的 job 数,避免资源耗尽。

建议:

  • 生产环境慎用 shell 模式,推荐用 docker 或 kubernetes 提供隔离。
  • 如果必须用 shell,确保 runner 用户权限最小化,并监控系统负载。

gitlab CI/CD如果失败,可不可以阻止合并任务

实现方式:

  • 启用"合并前必须通过流水线":

    • 进入项目 → Settings > General > Merge requests
    • 勾选 Pipelines must succeed
    • (可选)勾选 Require approval from code owners
  • 保护目标分支(如 main / develop):(这个对于有规模的开发团队,已经有CMO进行配置过了)

    • Settings > Repository > Protected Branches

    • 对目标分支设置:

      • Allowed to merge: Maintainers(或指定角色)
      • Require status checks to pass before merging(如果启用了外部状态检查)
  • 结果:

    • 如果 CI pipeline 失败(任何 job 失败且未被 allow_failure: true 忽略),Merge 按钮变灰,无法合并。
    • 即使有 Approver 同意,只要 pipeline 失败,也无法合并。 工作流程:
  • 注册:Runner 向 GitLab Server 注册,获得唯一 token,并绑定到项目或 group。

  • 轮询/长连接:Runner 定期向 GitLab Server 的 /jobs/request API 发起请求(默认每几秒一次),询问是否有待处理的 job。

  • 领取任务:当有匹配标签(tags)的 job 到来,Runner 领取任务(包含 .gitlab-ci.yml 中的 script、variables、artifacts 等信息)。

  • 执行任务 :

    • 根据配置的 executor(shell/docker/ssh/k8s 等)启动执行环境;
    • 克隆代码;
    • 执行 before_script → script → after_script;
    • 上传 artifacts/logs;
    • 上报状态(success/failure)。
  • 释放资源:任务结束,清理临时文件(除非配置保留)。

gitlab CI/CD,如果要执行脚本,有哪些参数是gitlab这边可以提供

GitLab 自动注入大量 预定义 CI/CD 变量(Predefined Variables),你可以在脚本中直接使用,例如:

常用内置变量示例:

变量 说明
CI_COMMIT_REF_NAME 当前分支或 tag 名(如 main, v1.0)
CI_PROJECT_DIR CI 任务的工作目录(代码被 clone 到这里)
GITLAB_USER_EMAIL 触发 pipeline 的用户邮箱

其他的像是两个分支的分支hash也可以通过git提供的参数获取到,用于差异文件的排查。更多的可以看官网 docs.gitlab.com/ci/variable...

合并任务下,两个分支都有脚本,改用哪一个,如果任意一方缺少脚本,该用哪一个

GitLab 的规则非常明确: 始终使用 source branch(源分支)中的 .gitlab-ci.yml 文件

详细说明:

  • 当你创建一个从 feature → main 的 MR,
  • GitLab 会 checkout feature 分支的代码,
  • 并读取 feature 分支根目录下的 .gitlab-ci.yml 来执行 pipeline。
  • 不会去读 main 分支的 .gitlab-ci.yml。
情况 使用哪个 .gitlab-ci.yml?
feature 有,main 有 ✅ 用 feature 的
feature 有,main 没有 ✅ 用 feature 的
feature 没有,main 有 ❌ pipeline 不会触发(因为 source branch 没有 .gitlab-ci.yml)
两者都没有 ❌ 无 CI pipeline

gitlab-ci.yml会执行更多脚本,这些脚本/静态资源怎么存放

推荐将大资源(如git CI/CD可以接入通过checkstyle.jar执行checkstyle,对应的jar文件)放在服务器上,其他的则可以放在各自的代码仓库内

为什么 GitLab Runner 安装时没有 gitlab-runner 用户就无法注册?这个用户代表什么?

当你通过官方方式安装 GitLab Runner(如 yum install gitlab-runner 或 dpkg -i gitlab-runner_xxx.deb),安装脚本会自动:

  1. 创建系统用户 gitlab-runner
  2. 以该用户身份运行 runner 服务
  3. Runner 在执行 job 时,所有命令都以 gitlab-runner 身份运行

所以如果手动的安装,可能会错过这一步,最终导致无法注册runner到gitlab上面

.gitlab-ci.yml的完整克隆是什么意思

答案:GitLab 会完整克隆(checkout)源分支(source branch)的代码,并使用该分支中的 .gitlab-ci.yml 文件

  • 这个过程包括:

    • 在 Runner 上执行 git clone
    • git checkout (例如 feature/add-login 的最新 commit)
    • 读取这个 commit 中的 .gitlab-ci.yml
    • 按照它的定义执行 job

所以,"完整克隆"在这里的意思是:

不是只复制 .gitlab-ci.yml 文件,而是把整个源分支的代码仓库完整拉下来,确保 CI 配置和代码版本严格一致。

为什么重要?

  • 如果你修改了 .gitlab-ci.yml(比如加了一个测试 job),只有推送到 源分支 才会在 MR 中生效。
  • 目标分支(如 main)的 .gitlab-ci.yml完全不会被使用。

gitlab runner拉代码的时候有什么级别嘛,比如一个级别只拉代码,一个级别把全部的信息都拉取下来?如果有不同级别,gitlabcicd提供的参数还会生效吗?如何配置?如何选择?

gitlab runner拉代码的时候有什么级别嘛,比如一个级别只拉代码,一个级别把全部的信息都拉取下来?

GitLab Runner 在拉取代码时,确实支持"不同深度"的克隆(clone depth),但没有"只拉代码 / 拉全部信息"这种二元级别。

你可以通过以下方式控制 拉取多少 Git 历史(commit history):

  • 浅克隆(shallow clone):只拉最近 N 个 commit(默认行为)
  • 深克隆(full clone):拉取完整历史(所有分支、tags、完整 commit graph)

注意:无论哪种方式,都会拉取完整的当前 commit 的文件内容(即"代码")。

所谓"只拉代码"其实是误解 ------ 代码文件总是完整的,区别只在 历史记录是否完整。 浅拷贝,深拷贝的在各个方面的不同

配置 行为 适用场景
GIT_DEPTH: 1(默认) 浅克隆:只拉当前 commit + 最近 1 层历史 快速构建、节省带宽
GIT_DEPTH: 0 或未设置 深克隆:拉取完整仓库历史(等价于 git clone --mirror) 需要 git log、git describe、计算版本号等
GIT_DEPTH: 10 拉最近 10 个 commit 的历史 折中方案

不同的配置推荐场景如下:

场景 推荐配置
普通构建、测试、部署 GIT_DEPTH: 1(默认,最快)
需要生成版本号(如 v1.2.3-5-gabc123) GIT_DEPTH: 0 + git fetch --tags
需要分析 commit 差异(如 changelog) GIT_DEPTH: 0
使用 Lerna / Nx 等工具依赖 Git 历史 GIT_DEPTH: 0
节省 CI 时间和带宽 保持默认(GIT_DEPTH: 1)

GitLab CI 提供的参数还会生效吗?

会!完全不受影响。

无论你用浅克隆还是深克隆,以下内容都 正常可用

如何配置?

GitLab CI 通过一个内置变量 GIT_DEPTH 控制克隆深度:

如:

yaml 复制代码
variables:
  GIT_DEPTH: 0  # 拉取完整历史

build:
  script:
    - git log --oneline -n 5   # 只有 GIT_DEPTH > 1 或 =0 时才有多个 commit
    - git describe --tags      # 需要完整 tag 历史

默认行为是什么?

GIT_DEPTH: 1(浅克隆,高效)

相关推荐
凌波粒2 小时前
SpringMVC基础教程(3)--SSM框架整合
java·sql·spring·intellij-idea·mybatis
2021_fc2 小时前
分布式应用可观测全链路追踪技术
java
数据的世界012 小时前
JAVA和C#的语法对比
java·windows·c#
渡我白衣2 小时前
深入理解 OverlayFS:用分层的方式重新组织 Linux 文件系统
android·java·linux·运维·服务器·开发语言·人工智能
百***92652 小时前
java进阶1——JVM
java·开发语言·jvm
虫师c2 小时前
字节码(Bytecode)深度解析:跨平台运行的魔法基石
java·jvm·java虚拟机·跨平台·字节码
q***72193 小时前
Spring Boot环境配置
java·spring boot·后端
洛_尘3 小时前
数据结构--7:排序(Sort)
java·数据结构
JIngJaneIL3 小时前
就业|高校就业|基于ssm+vue的高校就业信息系统的设计与实现(源码+数据库+文档)
java·前端·数据库·vue.js·spring boot·毕设·高校就业