시스템 관리자를 위한 작업 아티팩트 문제 해결

작업 아티팩트를 관리할 때 다음과 같은 문제가 발생할 수 있습니다.

디스크 공간을 너무 많이 사용하는 작업 아티팩트

작업 아티팩트가 예상보다 더 빨리 디스크 공간을 채울 수 있습니다. 일부 가능한 이유는 다음과 같습니다.

이와 같은 경우에는 디스크 공간 사용량이 가장 많은 프로젝트를 확인하고, 가장 공간을 많이 차지하는 아티팩트 유형을 파악하며 경우에 따라 수동으로 작업 아티팩트를 삭제하여 디스크 공간을 회수해야 합니다.

아티팩트 housekeeping

아티팩트 housekeeping은 만료된 아티팩트를 식별하여 삭제하는 프로세스입니다.

GitLab 14.6에서 15.2까지는 housekeeping 비활성화

GitLab 14.6에서는 아티팩트 housekeeping이 비활성화되었습니다. GitLab 14.10에서 크게 개선되었으며 변경 사항은 GitLab 14.6 이후의 패치 버전으로 백포팅되었으며, 기본 설정에서 비활성화된 기능 플래그를 통해 도입되었습니다. 해당 플래그는 기본적으로 GitLab 15.3에서 활성화되었습니다.

GitLab 14.6에서 15.2에서 아티팩트 housekeeping이 작동하지 않는 것으로 보인다면, 기능 플래그가 활성화되어 있는지 확인해야 합니다.

기능 플래그가 활성화되어 있는지 확인하려면:

  1. 레일즈 콘솔를 시작합니다.

  2. 기능 플래그가 활성화되어 있는지 확인합니다.

    • GitLab 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_job_artifacts_backlog_work, default_enabled: :yaml)
      
    • GitLab 15.0 및 이후:

      Feature.enabled?(:ci_detect_wrongly_expired_artifacts)
      Feature.enabled?(:ci_update_unlocked_job_artifacts)
      Feature.enabled?(:ci_job_artifacts_backlog_work)
      
  3. 기능 플래그 중 비활성화된 것이 있다면, 활성화합니다.

    Feature.enable(:ci_detect_wrongly_expired_artifacts)
    Feature.enable(:ci_update_unlocked_job_artifacts)
    Feature.enable(:ci_destroy_unlocked_job_artifacts)
    

이러한 변경 사항은 아티팩트를 잠금으로 전환하여 유지되어야 하는 경우를 포함합니다.

unknown 상태의 아티팩트

housekeeping이 업데이트되기 전에 생성된 아티팩트는 unknown 상태를 가집니다. 만료된 후 새로운 housekeeping에 의해 이러한 아티팩트는 처리되지 않습니다.

데이터베이스를 확인하여 인스턴스에 unknown 상태의 아티팩트가 있는지 확인할 수 있습니다:

  1. 데이터베이스 콘솔을 시작합니다:

    리눅스 패키지 (Omnibus)
    sudo gitlab-psql
    
    헬름 차트 (쿠버네티스)
    # 도구상자 팟을 찾습니다
    kubectl --namespace <namespace> get pods -lapp=toolbox
    # PostgreSQL 콘솔에 연결합니다
    kubectl exec -it <toolbox-pod-name> -- /srv/gitlab/bin/rails dbconsole --include-password --database main
    
    도커
    sudo docker exec -it <container_name> /bin/bash
    gitlab-psql
    
    직접 컴파일한 경우 (소스)
    sudo -u git -H psql -d gitlabhq_production
    
  2. 다음 쿼리를 실행합니다:

    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;
    

레코드가 반환되면, housekeeping 작업이 처리하지 못하는 아티팩트가 있습니다. 예를 들어:

           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인 아티팩트는 알 수 없음입니다. 자세한 내용은 이슈 #346261을 확인하세요.

unknown 아티팩트 정리

unknown 아티팩트를 처리하는 Sidekiq 워커는 기본적으로 GitLab 15.3 이상에서 활성화됩니다. 이는 위의 데이터베이스 쿼리에서 반환된 아티팩트를 분석하고 잠금 또는 잠금 해제해야 하는지를 결정합니다. 그런 다음 해당 워커가 필요한 경우 아티팩트를 삭제합니다.

이 워커는 GitLab 14.10 이상을 실행하는 셀프 매니지드 인스턴스에서 활성화할 수 있습니다.

  1. Rails 콘솔을 시작합니다.

  2. 기능이 활성화되어 있는지 확인하세요.

    • GitLab 14.10:

      Feature.enabled?(:ci_job_artifacts_backlog_work, default_enabled: :yaml)
      
    • GitLab 15.0 및 이후:

      Feature.enabled?(:ci_job_artifacts_backlog_work)
      
  3. 필요한 경우 기능을 활성화합니다:

    Feature.enable(:ci_job_artifacts_backlog_work)
    

이 워커는 7분마다 10,000개의 unknown 아티팩트를 처리하며, 24시간 동안 약 200만 개의 아티팩트를 처리합니다.

이에 관련된 ci_job_artifacts_backlog_large_loop_limit 피처 플래그가 있으며, 이 플래그는 워커가 5배 더 큰 일괄 처리로 unknown 아티팩트를 처리하도록합니다. 이 플래그는 셀프 매니지드 인스턴스에서 사용하지 않는 것이 좋습니다.

특정 만료일(또는 만료일이 없는)이 있는 프로젝트 및 빌드 목록

Rails 콘솔을 사용하여 다음과 같은 작업에 대한 프로젝트를 찾을 수 있습니다:

  • 만료일이 없는 작업 아티팩트가 있는 프로젝트
  • 미래 7일 이상인 만료일이 있는 프로젝트

아티팩트 삭제와 유사하게, 다음 예제 시간 범위를 사용하고 필요에 따라 변경하세요:

  • 7.days.from_now
  • 10.days.from_now
  • 2.weeks.from_now
  • 3.months.from_now

다음 각 스크립트는 또한 .limit(50)으로 검색을 50개로 제한하지만, 필요에 따라 숫자를 변경할 수도 있습니다:

# 만료되지 않는 아티팩트가 있는 빌드 및 프로젝트 찾기
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 "ID가 #{build.id}인 빌드에는 만료되지 않는 아티팩트가 있으며, 프로젝트는 #{build.project.full_path}입니다."
end

# 오늘부터 7일 후에 만료되는 아티팩트가 있는 빌드 및 프로젝트 찾기
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 "ID가 #{build.id}인 빌드에는 만료일이 #{build.artifacts_expire_at}이며, 프로젝트는 #{build.project.full_path}입니다."
end

저장된 작업 아티팩트의 총 크기에 따른 상위 20개 프로젝트 목록

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 콘솔에서 다음 코드를 실행하여 특정 프로젝트의 가장 큰 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 "작업 ID: #{art.job_id} - 크기: #{art.size}바이트 - 유형: #{art.file_type} - 작성일: #{art.created_at} - 파일 위치: #{art.file}"
end

limit(50)의 숫자를 변경하여 표시할 작업 아티팩트 수를 변경할 수 있습니다.

특정 날짜 이전에 완료된 작업의 작업 아티팩트 삭제

경고: 이 명령은 데이터를 데이터베이스와 저장소에서 영구적으로 삭제합니다. 실행하기 전에 Support Engineer로부터 지침을 얻거나 백업된 인스턴스가 복원될 준비가 된 테스트 환경에서 실행하는 것을 강력히 권장합니다.

작업 로그를 유지한 채 여러 완료된 작업과 관련된 작업 아티팩트를 수동으로 삭제할 수 있습니다 Rails 콘솔에서.

완료된 작업은 성공, 실패, 취소 또는 건너뛴 상태의 작업입니다.

특정 날짜 이전에 완료된 작업의 작업 아티팩트를 삭제하려면:

  1. 삭제할 아티팩트가 있는 작업을 선택합니다:

    단일 프로젝트의 모든 아티팩트가 있는 작업을 선택하려면:

    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
    
  2. 특정 날짜 이전의 작업 아티팩트를 삭제합니다:

    참고: 이 단계는 사용자가 “보관”을 선택한 아티팩트도 삭제합니다.

    builds_to_clear = builds_with_artifacts.where("finished_at < ?", 1.year.ago)
    builds_to_clear.find_each do |build|
      Ci::JobArtifacts::DeleteService.new(build).execute
      build.update!(artifacts_expire_at: Time.now)
    end
    

    GitLab 15.3 및 이전 버전에서는 대신 다음을 사용합니다:

    builds_to_clear = builds_with_artifacts.where("finished_at < ?", 1.year.ago)
    builds_to_clear.find_each do |build|
      build.artifacts_expire_at = Time.now
      build.erase_erasable_artifacts!
    end
    

    1.year.ago은 Rails ActiveSupport::Duration 메소드입니다. 여전히 사용 중인 아티팩트를 실수로 삭제할 위험을 줄이기 위해 오랜 기간으로 시작합니다. 필요에 따라 더 짧은 기간으로 삭제를 다시 실행하십시오. 예: 3.months.ago, 2.weeks.ago, 또는 7.days.ago.

    erase_erasable_artifacts!은 동기 메소드이며 실행 시 즉시 아티팩트가 제거됩니다. 백그라운드 대기열에서 예약되지 않습니다.

특정 날짜 이전에 완료된 작업의 작업 아티팩트 및 로그 삭제

경고: 이 명령은 데이터를 데이터베이스와 디스크에서 영구적으로 삭제합니다. 실행하기 전에 Support Engineer로부터 지침을 얻거나 백업된 인스턴스가 복원될 준비가 된 테스트 환경에서 실행하는 것을 강력히 권장합니다.

작업 로그를 유지한 채 완료된 작업과 관련된 작업 아티팩트를 수동으로 삭제할 수 있습니다 Rails 콘솔에서.

완료된 작업은 성공, 실패, 취소 또는 건너뛴 상태의 작업입니다.

특정 날짜 이전에 완료된 작업의 작업 아티팩트 및 로그를 삭제하려면:

  1. 아티팩트와 로그가 있는 작업을 선택합니다:

    단일 프로젝트에서 아티팩트가 있는 작업을 선택하려면:

    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
    

    때로는 아티팩트가 있는 작업을 선택할 때 프로세스가 많은 행을 선택하여 종료될 위험이 있습니다. 이로 인해 높은 메모리 사용량 및 최종적으로 메모리 부족(OOM) 오류로 인해 프로세스가 종료될 수 있습니다. 이를 해결하기 위해 작은 배치에서 실행할 수 있습니다. 아래 예제는 각 배치를 최대 1000으로 제한합니다.

    단일 프로젝트에서 아티팩트가 있는 작업을 선택하려면:

    project = Project.find_by_full_path('path/to/project')
    builds_with_artifacts = project.builds.with_downloadable_artifacts.find_each(batch_size: 1000)
    

    전체 GitLab 인스턴스에서 아티팩트가 있는 작업을 선택하려면:

    builds_with_artifacts = Ci::Build.with_downloadable_artifacts.find_each(batch_size: 1000)
    
  2. 웹 UI에서 작업을 삭제하는 사용자를 선택합니다:

    admin_user = User.find_by(username: 'username')
    
  3. 특정 날짜 이전의 작업 아티팩트 및 로그를 삭제합니다:

    builds_to_clear = builds_with_artifacts.where("finished_at < ?", 1.year.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
    

    GitLab 15.3 및 이전 버전에서는 Ci::BuildEraseService.new(build, admin_user).execute 대신 build.erase(erased_by: admin_user)를 사용합니다.

    1.year.ago은 Rails ActiveSupport::Duration 메소드입니다. 여전히 사용 중인 아티팩트를 실수로 삭제할 위험을 줄이기 위해 오랜 기간으로 시작합니다. 필요에 따라 더 짧은 기간으로 삭제를 다시 실행하십시오. 예: 3.months.ago, 2.weeks.ago, 또는 7.days.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

통합된 객체 저장소를 사용할 때 위의 오류로 작업 아티팩트 업로드가 실패하는 경우, 각 데이터 유형에 대해 별도의 버킷을 사용하는지 확인해야 합니다.

Windows 마운트를 사용하는 경우 작업 아티팩트가 FATAL: invalid argument로 업로드되지 않는 경우

작업 아티팩트에 Windows 마운트 및 CIFS를 사용하는 경우, 실행자가 아티팩트를 업로드하려고 시도할 때 invalid argument 오류가 발생할 수 있습니다:

WARNING: Uploading artifacts as "dotenv" to coordinator... POST https://<your-gitlab-instance>/api/v4/jobs/<JOB_ID>/artifacts: 500 Internal Server Error  id=1296 responseStatus=500 Internal Server Error status=500 token=*****
FATAL: invalid argument

이 문제를 해결하기 위해 다음을 시도해볼 수 있습니다:

  • CIFS 대신 ext4 마운트로 전환
  • CIFS 파일 임대에 관한 중요한 버그 수정을 포함하는 최소 Linux 커널 5.15로 업그레이드
  • 이전 커널의 경우 파일 임대를 비활성화하기 위해 nolease 마운트 옵션 사용

더 많은 정보는 조사 세부 정보를 참조하세요.

사용량 할당량이 아티팩트 저장소 사용량을 잘못 표시함

때때로 아티팩트 저장소 사용량이 아티팩트에 의해 사용된 총 저장 공간에 대한 잘못된 값이 표시됩니다. 인스턴스의 모든 프로젝트에 대해 아티팩트 사용량 통계를 다시 계산하려면 다음 백그라운드 스크립트를 실행할 수 있습니다:

gitlab-rake gitlab:refresh_project_statistics_build_artifacts_size[https://example.com/path/file.csv]

https://example.com/path/file.csv 파일에는 다시 계산하려는 모든 프로젝트의 프로젝트 ID를 나열해야 합니다. 파일 형식은 다음과 같이 사용하세요:

PROJECT_ID
1
2

스크립트가 실행되는 동안 아티팩트 사용량 값이 0으로 변동할 수 있습니다. 다시 계산된 후에는 사용량이 다시 예상대로 표시되어야 합니다.