1.安装配置gitlab Runner
1. 注册Runner
注册一个新的Runner。具体步骤如下:
- 在服务器上安装GitLab Runner,通常使用以下命令:
# 更新apt包列表
sudo apt update
# 安装GitLab Runner
sudo apt install gitlab-runner
- 注册Runner:
sudo gitlab-runner register
在此过程中,系统将提示你输入GitLab实例的URL、注册令牌、Runner描述、标签、执行器(比如docker执行器)等信息,这些在gitlab>>设置>>概览>>runner标签页获取。
- 启动Runner:
如果gitlab项目 clone地址跟gitlab 服务器内网地址不一样,可以extra_hosts添加docker hosts映射
防止docker无法clone,拉取
vim /etc/gitlab-runner/config.toml
concurrent = 1
check_interval = 0
connection_max_age = "15m0s"
shutdown_timeout = 0
[session_server]
session_timeout = 1800
[[runners]]
name = nux002"
url = "http://192.168.162.19"
id = 2
token = "izB6xxxxxxfTu5_Hd"
token_obtained_at = 2024-11-05T02:05:58Z
token_expires_at = 0001-01-01T00:00:00Z
executor = "docker"
[runners.custom_build_dir]
[runners.cache]
MaxUploadedArchiveSize = 0
[runners.cache.s3]
[runners.cache.gcs]
[runners.cache.azure]
[runners.docker]
extra_hosts = ["nux002.xxx.com:192.168.162.19"]
tls_verify = false
image = "sonarsource/sonar-scanner-cli:latest"
privileged = false
disable_entrypoint_overwrite = false
oom_kill_disable = false
disable_cache = false
volumes = ["/cache"]
shm_size = 0
network_mtu = 0
sudo gitlab-runner start
安装报错解决
apt update
Hit:1 http://mirrors.tuna.tsinghua.edu.cn/ubuntu focal InRelease
Hit:2 http://mirrors.tuna.tsinghua.edu.cn/ubuntu focal-updates InRelease
Hit:3 http://mirrors.tuna.tsinghua.edu.cn/ubuntu focal-backports InRelease
Hit:4 http://mirrors.tuna.tsinghua.edu.cn/ubuntu focal-security InRelease
Hit:6 https://jfrog.bintray.com/artifactory-debs focal InRelease
Hit:7 https://packages.gitlab.com/runner/gitlab-runner/ubuntu focal InRelease
Get:5 https://packages.gitlab.com/gitlab/gitlab-ce/ubuntu focal InRelease [23.3 kB]
Err:5 https://packages.gitlab.com/gitlab/gitlab-ce/ubuntu focal InRelease
The following signatures were invalid: EXPKEYSIG 3F01618A51312F3F GitLab B.V. (package repository signing key) <packages@gitlab.com>
Fetched 23.3 kB in 5s (5,152 B/s)
Reading package lists... Done
Building dependency tree
Reading state information... Done
10 packages can be upgraded. Run 'apt list --upgradable' to see them.
W: An error occurred during the signature verification. The repository is not updated and the previous index files will be used. GPG error: https://packages.gitlab.com/gitlab/gitlab-ce/ubuntu focal InRelease: The following signatures were invalid: EXPKEYSIG 3F01618A51312F3F GitLab B.V. (package repository signing key) <packages@gitlab.com>
W: Failed to fetch https://packages.gitlab.com/gitlab/gitlab-ce/ubuntu/dists/focal/InRelease The following signatures were invalid: EXPKEYSIG 3F01618A51312F3F GitLab B.V. (package repository signing key) <packages@gitlab.com>
W: Some index files failed to download. They have been ignored, or old ones used instead.
你遇到的错误信息表明GitLab的APT仓库的签名密钥已经过期,因此无法验证包的完整性。解决这个问题需要更新GitLab的签名密钥。请按照以下步骤进行操作:
1. 更新GitLab的签名密钥
可以通过运行以下命令来更新GitLab的APT密钥:
curl -s https://packages.gitlab.com/gpg.key | sudo gpg --dearmor -o /etc/apt/trusted.gpg.d/gitlab.gpg
这个命令会从GitLab的官方网站获取最新的GPG密钥,并将其保存到系统的信任密钥文件中。
2. 清理旧密钥
如果你在更新密钥时想要清理旧的密钥,可以使用以下命令来查看并删除过期的密钥:
sudo apt-key list
查看到GitLab相关的密钥后,可以通过以下命令删除:
sudo apt-key del <密钥ID>
请将<密钥ID>
替换为你想要删除的密钥的实际ID。
3. 再次更新APT源
更新密钥后,运行以下命令以更新APT源:
sudo apt update
4. 安装GitLab Runner
如果更新成功,则可以继续安装GitLab Runner:
sudo apt install gitlab-runner
5. 检查安装状态
安装完成后,确认GitLab Runner是否安装成功:
gitlab-runner --version
2.runner执行器选择
注册时提示
Enter an executor: docker+machine, kubernetes, instance, shell, ssh, virtualbox, docker, docker-windows, docker-autoscaler, custom, parallels:
在注册GitLab Runner时,系统会要求选择一个执行器(executor),用于指定Runner将如何执行作业。每种执行器代表一种运行方式。以下是常用执行器的介绍和适用情况:
常用执行器选项
-
shell:
直接在注册Runner的主机上运行任务。适用于简单的任务,不需要容器化,且主机已配置好运行所需的环境。Enter an executor: shell
-
docker:
使用Docker容器来运行每个作业。适合需要隔离环境的任务,每个任务会在独立的容器中执行。需要主机上已安装Docker。Enter an executor: docker
-
docker+machine:
使用Docker Machine自动创建并管理虚拟机来运行容器,适合需要动态扩展的CI/CD环境。Enter an executor: docker+machine
-
kubernetes:
在Kubernetes集群中运行任务,适合大规模、容器化的应用部署。需要Kubernetes集群的支持。Enter an executor: kubernetes
-
ssh:
通过SSH连接到远程服务器执行任务。适用于已配置的远程服务器上运行作业。Enter an executor: ssh
如何选择
- 如果在Docker环境中运行作业,推荐使用
docker
。 - 如果是在本地服务器上直接运行,可以选择
shell
。 - 如果有Kubernetes集群,选择
kubernetes
。
例如,我选选择 docker
执行器(容器执行服务器环境干扰小),输入:
docker
然后按 Enter。
3.runner注册完成后配置
共享runner
如果需要全部项目使用这个runner
gitlab runner界面点击进入runner
去掉
此Runner仅在受保护分支上触发的流水线上运行
当Runner被锁定时,不能将其分配给其他项目
增加runner使用项目
Restrict projects for this runner
下搜索gitlab项目点击启用
2. gitlab-ci.yml编写
gitlab项目下增加.gitlab-ci.yml文件,这样每次提交触发自动扫描
sonarqube扫描不通过这边使用sendgrid发送邮件通知
所以模板为
stages:
- build # 添加 build 阶段
- sonar
- notification
variables:
SONAR_HOST_URL: "http://192.168.162.20:9000" # 替换为SonarQube服务器地址
SONAR_PROJECT_KEY: "$CI_PROJECT_NAME" # 替换为SonarQube项目Key
SONAR_PROJECT_NAME: "$CI_PROJECT_NAME" # 替换为SonarQube项目名称
SONAR_TOKEN: "$SONAR_TOKEN" # 在GitLab CI/CD中设置的SonarQube Token
GIT_COMMITTER_EMAIL: "$CI_COMMITTER_EMAIL" # GitLab自动提供的提交者邮箱
SENDGRID_API_KEY: "$SENDGRID_API_KEY" # 在GitLab CI/CD中设置的SendGrid API Key
# SonarQube 扫描阶段
sonarqube-scan:
stage: sonar
image: sonarsource/sonar-scanner-cli:latest
script:
- mkdir -p build # 创建空的 build 目录
- |
sonar-scanner \
-Dsonar.projectKey=$SONAR_PROJECT_KEY \
-Dsonar.host.url=$SONAR_HOST_URL \
-Dsonar.login=$SONAR_TOKEN \
-Dsonar.sources=. \ #扫描路径
-Dsonar.inclusions=**/* \
-Dsonar.java.binaries=build # 指定为刚创建的空目录,如果不是java项目可以注释此行
#-Dsonar.language=vue \
#-Dsonar.sourceEncoding=UTF-8
#-Dsonar.exclusions=**/*.java # 排除所有Java文件
only:
- branches # 仅在 dev 分支触发扫描
# 发送邮件阶段
send-email:
stage: notification
image: bitnami/minideb:latest
script:
- |
set -x
install_packages jq curl ca-certificates
# 获取SonarQube质量门禁状态和详细信息
export RECIPIENT_EMAIL=$(echo "$CI_COMMIT_AUTHOR" | sed -n 's/.*<\(.*\)>.*/\1/p')
RECIPIENT_EMAILS="$RECIPIENT_EMAIL"
CC_EMAILS="$GLOBAL_CC_EMAILS"
# 获取 SonarQube 质量门禁状态和详细信息
quality_gate_info=$(curl -s -u "$SONAR_TOKEN:" "$SONAR_HOST_URL/api/qualitygates/project_status?projectKey=$SONAR_PROJECT_KEY&branch=$CI_COMMIT_BRANCH")
status=$(echo "$quality_gate_info" | jq -r '.projectStatus.status')
period_date=$(echo "$quality_gate_info" | jq -r '.projectStatus.period.date')
# 准备邮件内容
email_content="项目 '$SONAR_PROJECT_NAME' 分支 '$CI_COMMIT_BRANCH' 的 SonarQube 扫描质量门禁状态: $status\n评估日期: $period_date\n\n详细信息:\n"
# 从子进程中读取循环内容,并追加到 email_content
conditions=$(echo "$quality_gate_info" | jq -c '.projectStatus.conditions[]')
while read -r condition; do
rule=$(echo "$condition" | jq -r '.metricKey')
condition_status=$(echo "$condition" | jq -r '.status')
comparator=$(echo "$condition" | jq -r '.comparator')
error_threshold=$(echo "$condition" | jq -r '.errorThreshold')
actual_value=$(echo "$condition" | jq -r '.actualValue')
email_content+="指标: $rule, 比较符: $comparator, 错误阈值: $error_threshold, 实际值: $actual_value, 状态: $condition_status\n"
done <<< "$conditions"
# 准备邮件内容并追加 SonarQube 项目链接
sonar_project_url="http://sonarqube_url:9000/dashboard?branch=$CI_COMMIT_BRANCH&id=$SONAR_PROJECT_KEY"
email_content+="\n SonarQube 项目地址: $sonar_project_url\n\n"
# 打印 email_content 以便检查内容是否正确追加
echo -e "$email_content"
# 判断质量门禁状态,未通过时发送邮件
if [ "$status" != "OK" ]; then
echo "SonarQube质量门禁未通过,发送邮件通知..."
# 生成收件人和抄送人的 JSON 数组
# 使用 jq 处理邮件地址并去除换行符
recipients=$(echo "$RECIPIENT_EMAILS" | jq -R -s 'split(",") | map({"email": (. | gsub("\n";""))})')
# 如果收件人在 CC 中,则移除
if [[ -n "$CC_EMAILS" ]]; then
CC_EMAILS=$(echo "$CC_EMAILS" | sed "s/$RECIPIENT_EMAIL//g" | sed 's/,,/,/g' | sed 's/^,//;s/,$//')
fi
# 检查 CC_EMAILS 是否为空,为空则不包括 cc 字段
if [ -n "$CC_EMAILS" ]; then
cc_list=$(echo "$CC_EMAILS" | jq -R -s 'split(",") | map({"email": (. | gsub("\n";""))})')
cc_field='"cc": '"$cc_list"','
else
cc_field=''
fi
# 调用 SendGrid API 发送邮件
curl -s --request POST --url https://api.sendgrid.com/v3/mail/send \
--header "Authorization: Bearer $SENDGRID_API_KEY" \
--header 'Content-Type: application/json' \
--data '{
"personalizations": [
{
"to": '"$recipients"',
'"$cc_field"'
"subject": "SonarQube 扫描未通过通知"
}
],
"from": {"email": "gitlab@noreply.xxxx.com"},
"content": [
{
"type": "text/plain",
"value": "'"$email_content"'"
}
]
}'
fi
dependencies:
- sonarqube-scan
only:
- branches # 仅在指定分支触发
模版中使用了变量,在girlab>>设置>> CICD >>变量 中增加
GLOBAL_CC_EMAILS : 全局抄送邮件列表,英文逗号分隔
SENDGRID_API_KEY : sendgrid密钥
SONAR_TOKEN : sonarqube api 密钥
其他通知方式,可以让ai帮忙修改
多项目共用配置合并扫描主分支不扫描修改版.gitlab.yml
适用于多项目共用.gitlab-ci.yml,不然实际使用中几十个项目挨个改真的吐血
1.变量 env
GLOBAL_CC_EMAILS : 全局抄送邮件列表,英文逗号分隔
SENDGRID_API_KEY : sendgrid密钥
SONAR_TOKEN : sonarqube api 密钥
除了以上新增gitlab全局变量
GITLAB_INTERNAL_URL gitlab内网地址,适用于内外网隔离地址不一样的企业网络状况
GITLAB_TOKEN gitlab API token 用于获取提交合并的请求人 审核人 指派人的邮箱
SONAR_PUBLIC_URL sonarqube公网地址,适用于内外网隔离地址不一样的企业网络状况
2.gitlab创建共享项目
Visibility Level: 选择 Internal。
ps: gitlabURL/fynn/devops
创建共用CI脚本
gitlabURL/fynn/devops 创建文件夹CI
CI文件夹下创建ci_path_all.yml 共享文件
stages:
- build
- sonar
- notification
variables:
SONAR_HOST_URL: "http://192.168.162.20:9000"
SONAR_PROJECT_KEY: "$CI_PROJECT_NAME"
SONAR_PROJECT_NAME: "$CI_PROJECT_NAME"
SONAR_TOKEN: "$SONAR_TOKEN"
GIT_COMMITTER_EMAIL: "$CI_COMMITTER_EMAIL"
SENDGRID_API_KEY: "$SENDGRID_API_KEY"
# SonarQube 扫描阶段
sonarqube-scan:
stage: sonar
image: sonarsource/sonar-scanner-cli:latest
script:
- mkdir -p build
- |
sonar-scanner \
-Dsonar.projectKey=$SONAR_PROJECT_KEY \
-Dsonar.host.url=$SONAR_HOST_URL \
-Dsonar.login=$SONAR_TOKEN \
$SONAR_OPTIONS
#-Dsonar.sources=.
#-Dsonar.inclusions=**/*.java,**/*.yml \
#-Dsonar.java.binaries=build # 指定为刚创建的空目录
#-Dsonar.language=vue \
#-Dsonar.sourceEncoding=UTF-8
#-Dsonar.exclusions=**/*.java # 排除所有Java文件
rules:
- if: '$CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH'
when: never # 主分支跳过
- if: $CI_PIPELINE_SOURCE == "push"
- if: $CI_PIPELINE_SOURCE == "merge_request_event"
# 通知阶段
send-email:
stage: notification
image: bitnami/minideb:latest
script:
- |
set -x
install_packages jq curl ca-certificates
# 判断是否是合并请求
if [[ -n "$CI_MERGE_REQUEST_IID" ]]; then
# 获取合并请求详细信息
merge_request_info=$(curl -s --header "PRIVATE-TOKEN: $GITLAB_TOKEN" \
"$GITLAB_INTERNAL_URL/api/v4/projects/$CI_PROJECT_ID/merge_requests/$CI_MERGE_REQUEST_IID")
# 获取 author 的用户名并查询邮箱
author_username=$(echo "$merge_request_info" | jq -r '.author.username')
RECIPIENT_EMAIL=$(curl -s --header "PRIVATE-TOKEN: $GITLAB_TOKEN" \
"$GITLAB_INTERNAL_URL/api/v4/users?username=$author_username" | jq -r '.[0].email')
# 获取 assignees 和 reviewers 的用户名列表
assignees_usernames=$(echo "$merge_request_info" | jq -r '.assignees[].username')
reviewers_usernames=$(echo "$merge_request_info" | jq -r '.reviewers[].username')
# 初始化抄送人邮箱
CC_EMAILS=""
# 获取 assignees 的邮箱
for username in $assignees_usernames; do
email=$(curl -s --header "PRIVATE-TOKEN: $GITLAB_TOKEN" \
"$GITLAB_INTERNAL_URL/api/v4/users?username=$username" | jq -r '.[0].email')
CC_EMAILS+="$email,"
done
# 获取 reviewers 的邮箱
for username in $reviewers_usernames; do
email=$(curl -s --header "PRIVATE-TOKEN: $GITLAB_TOKEN" \
"$GITLAB_INTERNAL_URL/api/v4/users?username=$username" | jq -r '.[0].email')
CC_EMAILS+="$email,"
done
# 去重并移除收件人邮箱
if [[ -n "$RECIPIENT_EMAIL" && -n "$CC_EMAILS" ]]; then
CC_EMAILS=$(echo "$CC_EMAILS" | sed "s/$RECIPIENT_EMAIL//g" | sed 's/,,/,/g' | sed 's/^,//;s/,$//')
fi
SOURCE_BRANCH=$(echo "$merge_request_info" | jq -r '.source_branch')
else
RECIPIENT_EMAIL=$(echo "$CI_COMMIT_AUTHOR" | sed -n 's/.*<\(.*\)>.*/\1/p')
CC_EMAILS="$GLOBAL_CC_EMAILS"
SOURCE_BRANCH="$CI_COMMIT_BRANCH"
if [[ -n "$CC_EMAILS" ]]; then
CC_EMAILS=$(echo "$CC_EMAILS" | sed "s/$RECIPIENT_EMAIL//g" | sed 's/,,/,/g' | sed 's/^,//;s/,$//')
fi
fi
# 获取 SonarQube 质量门禁状态
quality_gate_info=$(curl -s -u "$SONAR_TOKEN:" "$SONAR_HOST_URL/api/qualitygates/project_status?projectKey=$SONAR_PROJECT_KEY&branch=$SOURCE_BRANCH")
status=$(echo "$quality_gate_info" | jq -r '.projectStatus.status')
period_date=$(echo "$quality_gate_info" | jq -r '.projectStatus.period.date')
# 准备邮件内容
email_content="项目 '$SONAR_PROJECT_NAME' 分支 '$SOURCE_BRANCH' 的 SonarQube 扫描质量门禁状态: $status\n评估日期: $period_date\n\n详细信息:\n"
conditions=$(echo "$quality_gate_info" | jq -c '.projectStatus.conditions[]')
while read -r condition; do
rule=$(echo "$condition" | jq -r '.metricKey')
comparator=$(echo "$condition" | jq -r '.comparator')
error_threshold=$(echo "$condition" | jq -r '.errorThreshold')
actual_value=$(echo "$condition" | jq -r '.actualValue')
condition_status=$(echo "$condition" | jq -r '.status')
email_content+="指标: $rule, 比较符: $comparator, 错误阈值: $error_threshold, 实际值: $actual_value, 状态: $condition_status\n"
done <<< "$conditions"
sonar_project_url="$SONAR_PUBLIC_URL/dashboard?branch=$SOURCE_BRANCH&id=$SONAR_PROJECT_KEY"
email_content+="\n SonarQube 项目地址: $sonar_project_url\n\n"
# 如果质量门禁未通过,发送邮件
if [ "$status" != "OK" ]; then
echo "SonarQube质量门禁未通过,发送邮件通知..."
# 生成收件人和抄送人 JSON 数组
recipients=$(echo "$RECIPIENT_EMAIL" | jq -R -s 'split(",") | map({"email": (. | gsub("\n";""))})')
if [ -n "$CC_EMAILS" ]; then
cc_list=$(echo "$CC_EMAILS" | jq -R -s 'split(",") | map({"email": (. | gsub("\n";""))})')
cc_field='"cc": '"$cc_list"','
else
cc_field=''
fi
# 调用 SendGrid API 发送邮件
curl -s --request POST --url https://api.sendgrid.com/v3/mail/send \
--header "Authorization: Bearer $SENDGRID_API_KEY" \
--header 'Content-Type: application/json' \
--data '{
"personalizations": [
{
"to": '"$recipients"',
'"$cc_field"'
"subject": "SonarQube 扫描未通过通知"
}
],
"from": {"email": "gitlab@noreply.tomra.com"},
"content": [
{
"type": "text/plain",
"value": "'"$email_content"'"
}
]
}'
fi
dependencies:
- sonarqube-scan
rules:
- if: '$CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH'
when: never # 主分支跳过
- if: $CI_PIPELINE_SOURCE == "push"
- if: $CI_PIPELINE_SOURCE == "merge_request_event"
4.项目.gitlab-ci.yml引用共享脚本
variables配置每个项目不同的扫描路径,或者其他不一样的sonarqube扫描参数
include:
- project: 'fynn/devops'
file: 'CI/ci_path_all.yml'
variables:
SONAR_OPTIONS: >
-Dsonar.sources=./app
-Dsonar.inclusions=**/*
-Dsonar.java.binaries=build
这样一次扫描脚本修改生效到所有项目,项目扫描变更更新自己的相关扫描配置就行
近期评论