作业产物管理
本文是管理员文档。要了解如何在 GitLab CI/CD 流水线中使用作业产物,请参阅作业产物配置文档。
产物是作业完成后附加到作业的文件和目录列表。在所有极狐GitLab 安装中默认启用此功能。
禁用作业产物
要在站点范围内禁用产物:
Omnibus
-
编辑
/etc/gitlab/gitlab.rb
:gitlab_rails['artifacts_enabled'] = false
-
保存文件并重新配置极狐GitLab,使更改生效。
sudo gitlab-ctl reconfigure
Kubernetes
-
导出 Helm 值:
helm get values gitlab > gitlab_values.yaml
-
编辑
gitlab_values.yaml
:global: appConfig: artifacts: enabled: false
-
保存文件并应用新值:
helm upgrade -f gitlab_values.yaml gitlab gitlab/gitlab
Docker
-
编辑
docker-compose.yml
:version: "3.6" services: gitlab: environment: GITLAB_OMNIBUS_CONFIG: | gitlab_rails['artifacts_enabled'] = false
-
保存文件并重启极狐GitLab:
docker compose up -d
源安装
-
编辑
/home/git/gitlab/config/gitlab.yml
:production: &base artifacts: enabled: false
-
保存文件并重启极狐GitLab:
# For systems running systemd sudo systemctl restart gitlab.target # For systems running SysV init sudo service gitlab restart
存储作业产物
GitLab Runner 可以将包含作业产物的存档上传到极狐GitLab。默认情况下,这是在作业成功时完成的,但也可以在失败时完成,或者总是使用 artifacts:when
参数完成。
大多数产物在发送到 coordinator 之前由 GitLab Runner 压缩。报告产物例外,它们在上传后被压缩。
使用本地存储
如果您使用的是 Linux 包或自编译安装,则可以更改产物在本地存储的位置。
Omnibus
产物默认存储在 /var/opt/gitlab/gitlab-rails/shared/artifacts
中。
-
例如,要将存储路径更改为
/mnt/storage/artifacts
,请编辑/etc/gitlab/gitlab.rb
并添加以下行:gitlab_rails['artifacts_path'] = "/mnt/storage/artifacts"
-
保存文件并重新配置极狐GitLab:
shell sudo gitlab-ctl reconfigure
源安装
产物默认存储在 /home/git/gitlab/shared/artifacts
中。
-
要更改存储路径,例如更改为
/mnt/storage/artifacts
,请编辑/home/git/gitlab/config/gitlab.yml
并添加或修改以下行:production: &base artifacts: enabled: true path: /mnt/storage/artifacts
-
保存文件并重启极狐GitLab:
# For systems running systemd sudo systemctl restart gitlab.target # For systems running SysV init sudo service gitlab restart
使用对象存储
如果您不想使用安装极狐GitLab 的本地磁盘来存储产物,则可以改用像 AWS S3 这样的对象存储。 此配置依赖于已配置的有效 AWS 凭证。 使用像 AWS S3 这样的对象存储选项来存储作业产物。
如果您将极狐GitLab 配置为在对象存储上存储产物,您可能还想禁用作业日志使用本地磁盘。 在这两种情况下,作业日志都会在作业完成时存档并移动到对象存储中。
迁移到对象存储
您可以将作业产物从本地存储迁移到对象存储。使用以下任务将现有作业产物从本地存储迁移到远程存储。 处理在后台 worker 中完成,要求无停机时间。
- 配置对象存储。
-
迁移产物:
Omnibus
sudo gitlab-rake gitlab:artifacts:migrate
Docker
sudo docker exec -t <container name> gitlab-rake gitlab:artifacts:migrate
源安装
sudo -u git -H bundle exec rake gitlab:artifacts:migrate RAILS_ENV=production
- 可选。使用 PostgreSQL 控制台跟踪进度并验证所有作业产物是否已成功迁移。
-
打开 PostgreSQL 控制台:
Omnibus
sudo gitlab-psql
Docker
sudo docker exec -it <container_name> /bin/bash gitlab-psql
源安装
sudo -u git -H psql -d gitlabhq_production
-
使用以下 SQL 查询验证是否所有包都已迁移到对象存储。
objectstg
的数量应与total
相同:gitlabhq_production=# SELECT count(*) AS total, sum(case when file_store = '1' then 1 else 0 end) AS filesystem, sum(case when file_store = '2' then 1 else 0 end) AS objectstg FROM ci_job_artifacts; total | filesystem | objectstg ------+------------+----------- 19 | 0 | 19
-
-
验证
artifacts
目录中的磁盘上没有文件:Omnibus
sudo find /var/opt/gitlab/gitlab-rails/shared/artifacts -type f | grep -v tmp | wc -l
Docker
假设您将
/var/opt/gitlab
挂载到/srv/gitlab
:sudo find /srv/gitlab/gitlab-rails/shared/artifacts -type f | grep -v tmp | wc -l
源安装
sudo find /home/git/gitlab/shared/artifacts -type f | grep -v tmp | wc -l
在某些情况下,您需要运行孤立产物文件清理 Rake 任务来清理孤立产物。
从对象存储迁移到本地存储
要迁移回本地存储,您必须有选择地禁用产物存储。
过期产物
如果 artifacts:expire_in
用于设置产物的到期时间,则在该日期过后将立即将其标记为删除。
否则,它们会根据默认产物过期设置过期。
产物由 Sidekiq 每 7 分钟运行一次的 expire_build_artifacts_worker
cron 作业清理(*/7 * * * *
)。
要更改产物过期的默认计划:
::Tabs
Omnibus
-
编辑
/etc/gitlab/gitlab.rb
并添加以下行(如果它已经存在并被注释掉,则取消注释),用 cron 语法替换您的计划:gitlab_rails['expire_build_artifacts_worker_cron'] = "*/7 * * * *"
-
保存文件并重新配置极狐GitLab:
sudo gitlab-ctl reconfigure
Kubernetes
-
导出 Helm 值:
helm get values gitlab > gitlab_values.yaml
-
编辑
gitlab_values.yaml
:global: appConfig: cron_jobs: expire_build_artifacts_worker: cron: "*/7 * * * *"
-
保存文件并应用新值:
helm upgrade -f gitlab_values.yaml gitlab gitlab/gitlab
Docker
-
编辑
docker-compose.yml
:version: "3.6" services: gitlab: environment: GITLAB_OMNIBUS_CONFIG: | gitlab_rails['expire_build_artifacts_worker_cron'] = "*/7 * * * *"
-
保存文件并重启极狐GitLab:
docker compose up -d
源安装
-
编辑
/home/git/gitlab/config/gitlab.yml
:production: &base cron_jobs: expire_build_artifacts_worker: cron: "*/7 * * * *"
-
保存文件并重启极狐GitLab:
# For systems running systemd sudo systemctl restart gitlab.target # For systems running SysV init sudo service gitlab restart
设置产物的最大文件大小
如果启用了产物,您可以通过管理中心设置,更改 产物的最大文件大小。
存储统计
您可以在管理中心,以及通过群组和项目 API 查看用于群组和项目上的作业产物的总存储空间。
实施细则
当极狐GitLab 收到产物存档时,GitLab Workhorse 也会生成存档元数据文件。此元数据文件描述了位于产物存档本身中的所有条目。 元数据文件采用二进制格式,带有额外的 Gzip 压缩。
极狐GitLab 不提取产物存档,节省空间、内存和磁盘 I/O。相反,它会检查包含所有相关信息的元数据文件。当存在大量产物或存档文件非常大时,这一点尤其重要。
单击特定文件时,GitLab Workhorse 从存档中提取它并开始下载。此实现可节省空间、内存和磁盘 I/O。
故障排查
作业产物使用过多磁盘空间
作业工件可以比预期更快地填满您的磁盘空间。一些可能的原因是:
- 用户已将作业产物的到期时间配置为比需要的时间长。
- 运行的作业数量以及由此产生的产物数量高于预期。
- 作业日志比预期的要大,并且随着时间的推移而累积。
- 文件系统可能会用完 inodes,因为产物理性维护处理留下了空目录。 Orphan 产物文件的 Rake 任务可以删除这些文件。
- 产物文件可能会留在磁盘上,不会被例行维护删除。运行 Orphan 产物文件的 Rake 任务删除它们。这个脚本也会删除空目录(见上文)。
- 产物例行维护功能发生了重大变化,您可能需要启用功能标志才能使用更新后的系统。
在以上和其他情况下,确定对磁盘空间使用负有最大责任的项目,找出使用最多空间的产物类型,并且在某些情况下,手动删除作业产物来回收磁盘空间。
产物例行维护功能在 14.6 到 15.2 版本禁用
产物例行维护功能在 14.10 版本发生了重大变化,这些变化被移植回 14.6 及更高版本。在 15.3 版本之前,必须使用功能标志启用更新的例行维护功能。
要检查功能标志是否已启用:
-
启动 Rails 控制台。
-
检查是否启用了功能标志。
-
14.10 及更早版本:
Feature.enabled?(:ci_detect_wrongly_expired_artifacts, default_enabled: :yaml) Feature.enabled?(:ci_update_unlocked_job_artifacts, default_enabled: :yaml) Feature.enabled?(:ci_destroy_unlocked_job_artifacts, default_enabled: :yaml)
-
15.0 及更高版本:
Feature.enabled?(:ci_detect_wrongly_expired_artifacts) Feature.enabled?(:ci_update_unlocked_job_artifacts) Feature.enabled?(:ci_destroy_unlocked_job_artifacts)
-
-
如果禁用了任何功能标志,请启用它们:
Feature.enable(:ci_detect_wrongly_expired_artifacts) Feature.enable(:ci_update_unlocked_job_artifacts) Feature.enable(:ci_destroy_unlocked_job_artifacts)
这些更改包括将产物从 unlocked
切换到 ulocked
,如果它们应该保留。
在引入此功能之前创建的产物的状态为 unknown
。在它们过期后,这些产物不会由新的理性维护作业处理。
您可以检查数据库,确认您的实例是否具有状态为 unknown
的产物:
-
启动数据库控制台:
Omnibus
sudo gitlab-psql
Kubernetes
# Find the toolbox pod kubectl --namespace <namespace> get pods -lapp=toolbox # Connect to the PostgreSQL console kubectl exec -it <toolbox-pod-name> -- /srv/gitlab/bin/rails dbconsole --include-password --database main
Docker
sudo docker exec -it <container_name> /bin/bash gitlab-psql
源安装
sudo -u git -H psql -d gitlabhq_production
-
运行以下查询:
select expire_at, file_type, locked, count(*) from ci_job_artifacts where expire_at is not null and file_type != 3 group by expire_at, file_type, locked having count(*) > 1;
如果返回记录,则存在例行维护作业无法处理的产物。例如:
expire_at | file_type | locked | count
-------------------------------+-----------+--------+--------
2021-06-21 22:00:00+00 | 1 | 2 | 73614
2021-06-21 22:00:00+00 | 2 | 2 | 73614
2021-06-21 22:00:00+00 | 4 | 2 | 3522
2021-06-21 22:00:00+00 | 9 | 2 | 32
2021-06-21 22:00:00+00 | 12 | 2 | 163
锁定状态为 2
的产物为 unknown
。
15.3 及更高版本默认启用处理所有 unknown
产物的 Sidekiq worker。它分析上述数据库查询返回的产物,并确定哪些应该 locked
或 unlocked
。如果需要,该 worker 随后会删除产物。
可以在运行 14.10 及更高版本的私有化部署实例上启用 worker:
-
启动 Rails 控制台。
-
检查该功能是否已启用。
-
14.10 版本:
Feature.enabled?(:ci_job_artifacts_backlog_work, default_enabled: :yaml)
-
15.0 及更高版本:
Feature.enabled?(:ci_job_artifacts_backlog_work)
-
-
如果需要,启用该功能:
Feature.enable(:ci_job_artifacts_backlog_work)
Worker 每 7 分钟处理 10,000 个 unknown
产物,或者 24 小时内处理大约 200 万个。
有一个相关的 ci_job_artifacts_backlog_large_loop_limit
功能标志,它会使得 worker 以五倍大的批次处理 unknown
产物。不建议在私有化部署实例上使用此标志。
列出具有特定到期时间(或无到期时间)的产物的项目和构建
使用 Rails 控制台,您可以找到具有以下作业产物的项目:
- 没有到期日期。
- 未来 7 天以上的到期日期。
类似于删除产物,使用以下示例时间范围并根据需要更改它们:
7.days.from_now
10.days.from_now
2.weeks.from_now
3.months.from_now
以下每个脚本还使用 .limit(50)
将搜索限制为 50 个结果,但也可以根据需要更改此数字:
# Find builds & projects with artifacts that never expire
builds_with_artifacts_that_never_expire = Ci::Build.with_downloadable_artifacts.where(artifacts_expire_at: nil).limit(50)
builds_with_artifacts_that_never_expire.find_each do |build|
puts "Build with id #{build.id} has artifacts that don't expire and belongs to project #{build.project.full_path}"
end
# Find builds & projects with artifacts that expire after 7 days from today
builds_with_artifacts_that_expire_in_a_week = Ci::Build.with_downloadable_artifacts.where('artifacts_expire_at > ?', 7.days.from_now).limit(50)
builds_with_artifacts_that_expire_in_a_week.find_each do |build|
puts "Build with id #{build.id} has artifacts that expire at #{build.artifacts_expire_at} and belongs to project #{build.project.full_path}"
end
按存储的作业产物的总大小列出项目
通过在 Rails 控制台(sudo gitlab-rails 控制台
)中运行以下代码,列出前 20 个项目,按存储的作业产物的总大小排序:
include ActionView::Helpers::NumberHelper
ProjectStatistics.order(build_artifacts_size: :desc).limit(20).each do |s|
puts "#{number_to_human_size(s.build_artifacts_size)} \t #{s.project.full_path}"
end
您可以通过将 .limit(20)
修改为您想要的数量来更改列出的项目数量。
列出单个项目中最大的产物
通过在 Rails 控制台(sudo gitlab-rails 控制台
)中运行以下代码,列出单个项目中 50 个最大的作业产物:
include ActionView::Helpers::NumberHelper
project = Project.find_by_full_path('path/to/project')
Ci::JobArtifact.where(project: project).order(size: :desc).limit(50).map { |a| puts "ID: #{a.id} - #{a.file_type}: #{number_to_human_size(a.size)}" }
您可以通过将 .limit(50)
修改为您想要的数量来更改列出的作业产物的数量。
列出单个项目中的产物
列出单个项目的产物,按产物大小排序。输出包括:
- 创建产物的作业 ID
- 产物大小
- 产物文件类型
- 产物创建日期
- 产物的磁盘位置
p = Project.find_by_id(<project_id>)
arts = Ci::JobArtifact.where(project: p)
list = arts.order(size: :desc).limit(50).each do |art|
puts "Job ID: #{art.job_id} - Size: #{art.size}b - Type: #{art.file_type} - Created: #{art.created_at} - File loc: #{art.file}"
end
要更改列出的作业产物数量,请更改 limit(50)
中的数量。
从特定日期之前完成的作业中删除作业产物
如果您需要在保留作业日志的同时手动删除与多个作业关联的作业产物,可以从 Rails 控制台(sudo gitlab-rails 控制台
)完成:
-
选择要删除的作业:
要为单个项目选择所有带有产物的作业:
project = Project.find_by_full_path('path/to/project') builds_with_artifacts = project.builds.with_downloadable_artifacts
要在整个 GitLab 实例中选择所有带有产物的作业:
builds_with_artifacts = Ci::Build.with_downloadable_artifacts
-
删除早于特定日期的作业产物:
此步骤还会删除用户选择 “keep” 的产物。builds_to_clear = builds_with_artifacts.where("finished_at < ?", 1.week.ago) builds_to_clear.find_each do |build| Ci::JobArtifacts::DeleteService.new(build).execute build.update!(artifacts_expire_at: Time.now) end
在 15.3 及更早版本,使用以下命令:
builds_to_clear = builds_with_artifacts.where("finished_at < ?", 1.week.ago) builds_to_clear.find_each do |build| build.artifacts_expire_at = Time.now build.erase_erasable_artifacts! end
1.week.ago
是 Rails 的ActiveSupport::Duration
方法,用于计算过去的新日期或时间。其他有效的例子包括:7.days.ago
3.months.ago
1.year.ago
erase_erasable_artifacts!
是一种同步方法,执行后会立即删除工件;它们不是由后台队列调度的。
从特定日期之前完成的作业中删除作业产物和日志
如果您需要手动删除与多个作业关联的所有作业产物,包括作业日志,可以从 Rails 控制台(sudo gitlab-rails 控制台
)完成:
-
选择要删除的作业:
要为单个项目选择具有产物的作业:
project = Project.find_by_full_path('path/to/project') builds_with_artifacts = project.builds.with_existing_job_artifacts(Ci::JobArtifact.trace)
要在整个极狐GitLab 实例中选择具有产物的作业:
builds_with_artifacts = Ci::Build.with_existing_job_artifacts(Ci::JobArtifact.trace)
-
选择 Web UI 中提到的用户擦除作业:
admin_user = User.find_by(username: 'username')
-
清除早于特定日期的作业产物和日志:
builds_to_clear = builds_with_artifacts.where("finished_at < ?", 1.week.ago) builds_to_clear.find_each do |build| print "Ci::Build ID #{build.id}... " if build.erasable? Ci::BuildEraseService.new(build, admin_user).execute puts "Erased" else puts "Skipped (Nothing to erase or not erasable)" end end
在 15.3 及更早版本,使用
build.erase(erased_by: admin_user)
代替Ci::BuildEraseService.new(build, admin_user).execute
。1.week.ago
是 Rails 的ActiveSupport::Duration
方法,用于计算过去的新日期或时间。其他有效的例子包括:7.days.ago
3.months.ago
1.year.ago
作业产物上传失败,错误 500
如果您将对象存储用于产物并且作业产物无法上传,请查看:
-
错误消息的作业日志类似于:
WARNING: Uploading artifacts as "archive" to coordinator... failed id=12345 responseStatus=500 Internal Server Error status=500 token=abcd1234
-
workhorse 日志的错误消息类似于:
{"error":"MissingRegion: could not find region configuration","level":"error","msg":"error uploading S3 session","time":"2021-03-16T22:10:55-04:00"}
在这两种情况下,您可能需要将 region
添加到作业产物对象存储配置。
作业产物上传失败 500 Internal Server Error (Missing file)
合并对象存储不支持包含文件夹路径的存储桶名称。
例如,bucket/path
。如果存储桶名称中包含路径,您可能会收到类似于以下内容的错误:
WARNING: Uploading artifacts as "archive" to coordinator... POST https://gitlab.example.com/api/v4/jobs/job_id/artifacts?artifact_format=zip&artifact_type=archive&expire_in=1+day: 500 Internal Server Error (Missing file)
FATAL: invalid argument
如果在使用整合对象存储时作业产物上传失败并出现上述错误,请确保您为每种数据类型使用单独的存储桶。