安装离线 GitLab 自托管实例
- Tier: 免费版、高级版、旗舰版
- Offering: GitLab 自托管
这是一份分步指南,帮助您完全离线地安装、配置和使用 GitLab 自托管实例。
安装
本指南假设服务器使用的是 Ubuntu 20.04 并采用 Linux 包安装方法,运行的是 GitLab 企业版。其他服务器的说明可能有所不同。
本指南还假设服务器主机解析为 my-host.internal,您应该将其替换为服务器的 FQDN,并且您能够访问另一台具有互联网连接的服务以下载所需的包文件。
有关此过程的视频教程,请参阅 离线 GitLab 安装:下载与安装。
下载 GitLab 包
您应该 手动下载 GitLab 包 和相关依赖项,使用一台能够访问互联网且操作系统类型相同的服务器。
如果您的离线环境没有本地网络访问权限,您必须通过物理介质(如 USB 驱动器)手动传输相关包。
在 Ubuntu 中,可以在具有互联网访问权限的服务器上使用以下命令执行此操作:
# 下载准备仓库的 bash 脚本
curl --silent "https://packages.gitlab.com/install/repositories/gitlab/gitlab-ee/script.deb.sh" | sudo bash
# 将 gitlab-ee 包和依赖项下载到 /var/cache/apt/archives
sudo apt-get install --download-only gitlab-ee
# 将 apt 下载文件夹的内容复制到挂载的媒体设备
sudo cp /var/cache/apt/archives/*.deb /path/to/mount安装 GitLab 包
先决条件:
- 在离线环境中安装 GitLab 包之前,请确保已先安装所有必需的依赖项。
如果您使用的是 Ubuntu,可以使用 dpkg 安装您复制过来的依赖项 .deb 包。暂时不要安装 GitLab 包。
# 进入物理媒体设备
sudo cd /path/to/mount
# 安装依赖包
sudo dpkg -i <package_name>.deb使用适用于您操作系统的相关命令安装包,但在 EXTERNAL_URL 安装步骤中务必指定一个 http URL。安装完成后,我们可以手动配置 SSL。
强烈建议设置域名用于 IP 解析,而不是绑定到服务器的 IP 地址。这能更好地确保证书 CN 的稳定目标,并使长期解析更简单。
以下 Ubuntu 示例使用 HTTP 指定 EXTERNAL_URL 并安装 GitLab 包:
sudo EXTERNAL_URL="http://my-host.internal" dpkg -i <gitlab_package_name>.deb启用 SSL
按照以下步骤为您的全新实例启用 SSL。这些步骤反映了 在 NGINX 配置中手动配置 SSL 的步骤:
-
对
/etc/gitlab/gitlab.rb进行以下更改:# 将 external_url 从 "http" 更新为 "https" external_url "https://my-host.internal" # 将 Let's Encrypt 设置为 false letsencrypt['enable'] = false -
创建以下目录,并设置适当的权限以生成自签名证书:
sudo mkdir -p /etc/gitlab/ssl sudo chmod 755 /etc/gitlab/ssl sudo openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout /etc/gitlab/ssl/my-host.internal.key -out /etc/gitlab/ssl/my-host.internal.crt -
重新配置您的实例以应用更改:
sudo gitlab-ctl reconfigure
启用 GitLab 容器注册表
按照以下步骤启用容器注册表。这些步骤反映了 在现有域下配置容器注册表 的步骤:
-
对
/etc/gitlab/gitlab.rb进行以下更改:# 将 external_registry_url 更改为与 external_url 匹配,但附加端口 4567 external_url "https://gitlab.example.com" registry_external_url "https://gitlab.example.com:4567" -
重新配置您的实例以应用更改:
sudo gitlab-ctl reconfigure
允许 Docker 守护进程信任注册表和 GitLab Runner
通过 遵循使用可信证书与您的注册表配合使用的步骤,为您的 Docker 守护进程提供您的证书:
sudo mkdir -p /etc/docker/certs.d/my-host.internal:5000
sudo cp /etc/gitlab/ssl/my-host.internal.crt /etc/docker/certs.d/my-host.internal:5000/ca.crt通过 遵循使用可信证书与您的 Runner 配合使用的步骤,为您的 GitLab Runner(将在下一步安装)提供您的证书:
sudo mkdir -p /etc/gitlab-runner/certs
sudo cp /etc/gitlab/ssl/my-host.internal.crt /etc/gitlab-runner/certs/ca.crt启用 GitLab Runner
遵循与我们将 GitLab Runner 安装为 Docker 服务类似的步骤,我们必须首先注册我们的 Runner:
$ sudo docker run --rm -it -v /etc/gitlab-runner:/etc/gitlab-runner gitlab/gitlab-runner register
Updating CA certificates...
Runtime platform arch=amd64 os=linux pid=7 revision=1b659122 version=12.8.0
Running in system-mode.
Enter the GitLab instance URL (for example, https://gitlab.com/):
https://my-host.internal
Enter the registration token:
XXXXXXXXXXX
Enter a description for the runner:
[eb18856e13c0]:
Enter tags for the runner (comma-separated):
Enter optional maintenance note for the runner:
Registering runner... succeeded runner=FSMwkvLZ
Please enter the executor: custom, docker, virtualbox, kubernetes, docker+machine, docker+ssh+machine, docker+ssh, parallels, shell, ssh:
docker
Please enter the default Docker image (for example, ruby:2.6):
ruby:2.6
Runner registered successfully. Feel free to start it, but if it's running already the config should be automatically reloaded!现在我们必须为我们的 Runner 添加一些额外的配置:
对 /etc/gitlab-runner/config.toml 进行以下更改:
- 将 Docker socket 添加到卷
volumes = ["/var/run/docker.sock:/var/run/docker.sock", "/cache"] - 在执行器配置中添加
pull_policy = "if-not-present"
现在我们可以启动我们的 Runner:
sudo docker run -d --restart always --name gitlab-runner -v /etc/gitlab-runner:/etc/gitlab-runner -v /var/run/docker.sock:/var/run/docker.sock gitlab/gitlab-runner:latest
90646b6587127906a4ee3f2e51454c6e1f10f26fc7a0b03d9928d8d0d5897b64对主机操作系统进行注册表身份验证
如 Docker 注册表身份验证文档 中所述,某些版本的 Docker 需要在操作系统级别信任证书链。
在 Ubuntu 的情况下,这涉及使用 update-ca-certificates:
sudo cp /etc/docker/certs.d/my-host.internal\:5000/ca.crt /usr/local/share/ca-certificates/my-host.internal.crt
sudo update-ca-certificates如果一切顺利,您应该看到以下内容:
1 added, 0 removed; done.
Running hooks in /etc/ca-certificates/update.d...
done.禁用版本检查和服务 Ping
版本检查和服务 Ping 改善了 GitLab 用户体验,并确保用户使用的是最新版本的 GitLab。这两个服务可以在离线环境中关闭,以避免它们尝试连接 GitLab 服务但失败。
有关更多信息,请参阅 启用或禁用服务 Ping。
禁用 Runner 版本管理
Runner 版本管理从 GitLab 检索最新的 Runner 版本以 确定您环境中的哪些 Runner 已过时。您必须 禁用 Runner 版本管理 以用于离线环境。
配置 NTP
Gitaly Cluster (Praefect) 假设可以访问 pool.ntp.org。如果无法访问 pool.ntp.org,请在 Gitaly 和 Praefect 服务器上 自定义时间服务器设置,以便它们可以使用可访问的 NTP 服务器。
在离线实例上,GitLab Geo 检查 Rake 任务 总是失败,因为它使用 pool.ntp.org。此错误可以忽略,但您可以 阅读有关如何解决此问题的更多信息。
启用包元数据库
启用包元数据库是启用 持续漏洞扫描 和 CycloneDX 文件的许可证扫描 所必需的。此过程需要使用在包元数据库中统称为许可证和/或建议数据,该数据根据 EE 许可证 授权。请注意关于包元数据库使用的以下事项:
- 我们可能会随时更改或停止全部或任何部分的包元数据库,恕不另行通知,完全由我们自行决定。
- 包元数据库可能包含指向第三方网站或资源的链接。我们仅提供这些链接作为便利,不对这些网站或资源上的任何第三方数据、内容、产品或服务或其上显示的链接负责。
- 包元数据库部分基于第三方提供的信息,GitLab 对所提供内容的准确性或完整性不承担责任。
包元数据存储在以下 Google Cloud Provider (GCP) 存储桶中:
- 许可证扫描 -
prod-export-license-bucket-1a6c642fc4de57d4 - 依赖项扫描 -
prod-export-advisory-bucket-1a6c642fc4de57d4
使用 gsutil 工具下载包元数据导出
-
安装
gsutil工具。 -
找到 GitLab Rails 目录的根目录。
export GITLAB_RAILS_ROOT_DIR="$(gitlab-rails runner 'puts Rails.root.to_s')" echo $GITLAB_RAILS_ROOT_DIR -
设置您希望同步的数据类型。
# 对于许可证扫描 export PKG_METADATA_BUCKET=prod-export-license-bucket-1a6c642fc4de57d4 export DATA_DIR="licenses" # 对于依赖项扫描 export PKG_METADATA_BUCKET=prod-export-advisory-bucket-1a6c642fc4de57d4 export DATA_DIR="advisories" -
下载包元数据导出。
# 要下载包元数据导出,必须允许到 Google Cloud Storage 存储桶的出站连接。 mkdir -p "$GITLAB_RAILS_ROOT_DIR/vendor/package_metadata/$DATA_DIR" gsutil -m rsync -r -d gs://$PKG_METADATA_BUCKET "$GITLAB_RAILS_ROOT_DIR/vendor/package_metadata/$DATA_DIR" # 或者,如果 GitLab 实例不允许连接到 Google Cloud Storage 存储桶,则可以使用具有允许访问权限的机器下载包元数据 # 导出,然后复制到 GitLab Rails 目录的根目录。 rsync rsync://example_username@gitlab.example.com/package_metadata/$DATA_DIR "$GITLAB_RAILS_ROOT_DIR/vendor/package_metadata/$DATA_DIR"
使用 Google Cloud Storage REST API 下载包元数据导出
也可以使用 Google Cloud Storage API 下载包元数据导出。内容可在 https://storage.googleapis.com/storage/v1/b/prod-export-license-bucket-1a6c642fc4de57d4/o 和 https://storage.googleapis.com/storage/v1/b/prod-export-advisory-bucket-1a6c642fc4de57d4/o 找到。以下是使用 cURL 和 jq 下载此内容的示例。
#!/bin/bash
set -euo pipefail
DATA_TYPE=$1
GITLAB_RAILS_ROOT_DIR="$(gitlab-rails runner 'puts Rails.root.to_s')"
if [ "$DATA_TYPE" == "license" ]; then
PKG_METADATA_DIR="$GITLAB_RAILS_ROOT_DIR/vendor/package_metadata/licenses"
elif [ "$DATA_TYPE" == "advisory" ]; then
PKG_METADATA_DIR="$GITLAB_RAILS_ROOT_DIR/vendor/package_metadata/advisories"
else
echo "Usage: import_script.sh [license|advisory]"
exit 1
fi
PKG_METADATA_BUCKET="prod-export-$DATA_TYPE-bucket-1a6c642fc4de57d4"
PKG_METADATA_DOWNLOADS_OUTPUT_FILE="/tmp/package_metadata_${DATA_TYPE}_object_links.tsv"
# 下载存储桶内容
# 该脚本下载所有对象并创建以 JSON 格式保存的文件,每个文件最多 1000 个对象。
MAX_RESULTS=1000
TEMP_FILE="out.json"
curl --silent --show-error --request GET "https://storage.googleapis.com/storage/v1/b/$PKG_METADATA_BUCKET/o?maxResults=$MAX_RESULTS" >"$TEMP_FILE"
NEXT_PAGE_TOKEN="$(jq -r '.nextPageToken' $TEMP_FILE)"
jq -r '.items[] | [.name, .mediaLink] | @tsv' "$TEMP_FILE" >"$PKG_METADATA_DOWNLOADS_OUTPUT_FILE"
while [ "$NEXT_PAGE_TOKEN" != "null" ]; do
curl --silent --show-error --request GET "https://storage.googleapis.com/storage/v1/b/$PKG_METADATA_BUCKET/o?maxResults=$MAX_RESULTS&pageToken=$NEXT_PAGE_TOKEN" >"$TEMP_FILE"
NEXT_PAGE_TOKEN="$(jq -r '.nextPageToken' $TEMP_FILE)"
jq -r '.items[] | [.name, .mediaLink] | @tsv' "$TEMP_FILE" >>"$PKG_METADATA_DOWNLOADS_OUTPUT_FILE"
#用于 API 速率限制
sleep 1
done
trap 'rm -f "$TEMP_FILE"' EXIT
echo "已获取 $DATA_TYPE 导出清单"
# 解析存储桶对象的链接和名称,并将它们输出到 tsv 文件
echo -e "将包元数据导出保存到 $PKG_METADATA_DIR\n"
# 跟踪将下载多少个对象
INDEX=1
TOTAL_OBJECT_COUNT="$(wc -l "$PKG_METADATA_DOWNLOADS_OUTPUT_FILE" | awk '{print $1}')"
# 下载对象
while IFS= read -r line; do
FILE="$(echo -n "$line" | awk '{print $1}')"
URL="$(echo -n "$line" | awk '{print $2}')"
OUTPUT_PATH="$PKG_METADATA_DIR/$FILE"
echo "正在下载 $FILE"
if [ ! -f "$OUTPUT_PATH" ]; then
curl --progress-bar --create-dirs --output "$OUTPUT_PATH" --request "GET" "$URL"
else
echo "发现现有文件"
fi
echo -e "已下载 $INDEX 个中的 $TOTAL_OBJECT_COUNT 个对象\n"
INDEX=$((INDEX + 1))
done <"$PKG_METADATA_DOWNLOADS_OUTPUT_FILE"
echo "所有对象已保存到 $PKG_METADATA_DIR"自动同步
您的 GitLab 实例定期与 package_metadata 目录的内容 同步。要自动使用上游更改更新您的本地副本,可以添加一个 cron 作业来定期下载新的导出。例如,可以添加以下 crontabs 来设置一个每 30 分钟运行一次的 cron 作业。
对于许可证扫描:
*/30 * * * * gsutil -m rsync -r -d -y "^v1\/" gs://prod-export-license-bucket-1a6c642fc4de57d4 $GITLAB_RAILS_ROOT_DIR/vendor/package_metadata/licenses对于依赖项扫描:
*/30 * * * * gsutil -m rsync -r -d gs://prod-export-advisory-bucket-1a6c642fc4de57d4 $GITLAB_RAILS_ROOT_DIR/vendor/package_metadata/advisories更改说明
包元数据的目录在 16.2 版本中从 vendor/package_metadata_db 更改为 vendor/package_metadata/licenses。如果此目录已存在于实例上并且需要添加依赖项扫描,则需要执行以下步骤。
-
重命名许可证目录:
mv vendor/package_metadata_db vendor/package_metadata/licenses。 -
更新任何保存的自动化脚本或命令,将
vendor/package_metadata_db更改为vendor/package_metadata/licenses。 -
更新任何 cron 条目,将
vendor/package_metadata_db更改为vendor/package_metadata/licenses。sed -i '.bckup' -e 's#vendor/package_metadata_db#vendor/package_metadata/licenses#g' [FILE ...]
故障排除
缺少数据库数据
如果许可证或建议数据在依赖项列表或 MR 页面中缺失,可能的原因之一是数据库尚未与导出数据同步。
package_metadata 同步是通过使用 cron 作业(建议同步 和 许可证同步)触发的,并且仅导入在 管理员设置 中启用的包注册表类型。
vendor/package_metadata 中的文件结构必须与之前启用的包注册表类型一致。例如,要同步 maven 许可证或建议数据,Rails 目录下的包元数据目录必须具有以下结构:
- 对于许可证:
$GITLAB_RAILS_ROOT_DIR/vendor/package_metadata/licenses/v2/maven/**/*.ndjson。 - 对于建议:
$GITLAB_RAILS_ROOT_DIR/vendor/package_metadata/advisories/v2/maven/**/*.ndjson。
成功运行后,数据库中 pm_ 表下的数据应该已填充(使用 Rails 控制台 检查):
- 对于许可证:
sudo gitlab-rails runner "puts \"Package model has #{PackageMetadata::Package.where(purl_type: 'maven').size} packages\"" - 对于建议:
sudo gitlab-rails runner "puts \"Advisory model has #{PackageMetadata::AffectedPackage.where(purl_type: 'maven').size} packages\""
此外,对于正在同步的特定包注册表,应该存在检查点数据。例如,对于 Maven,在成功的同步运行后应该创建一个检查点:
- 对于许可证:
sudo gitlab-rails runner "puts \"maven data has been synced up to #{PackageMetadata::Checkpoint.where(data_type: 'licenses', purl_type: 'maven')}\"" - 对于建议:
sudo gitlab-rails runner "puts \"maven data has been synced up to #{PackageMetadata::Checkpoint.where(data_type: 'advisories', purl_type: 'maven')}\""
最后,您可以通过搜索类为 PackageMetadata::SyncService 的 DEBUG 消息来检查 application_json.log 日志,以验证同步作业已运行且无错误。示例:{"severity":"DEBUG","time":"2023-06-22T16:41:00.825Z","correlation_id":"a6e80150836b4bb317313a3fe6d0bbd6","class":"PackageMetadata::SyncService","message":"Evaluating data for licenses:gcp/prod-export-license-bucket-1a6c642fc4de57d4/v2/pypi/1694703741/0.ndjson"}。