GitLab 백업 문제 해결

GitLab을 백업할 때 다음과 같은 문제가 발생할 수 있습니다.

Secrets 파일이 손실된 경우

비밀 파일을 백업하지 않은 경우, GitLab이 다시 제대로 작동하도록 하려면 여러 단계를 완료해야 합니다.

비밀 파일은 필요한 민감한 정보가 포함된 열의 암호화 키를 저장하는 것을 담당합니다. 이 키가 손실되면 GitLab은 해당 열을 해독할 수 없어 다음과 같은 항목에 대한 액세스를 방해합니다:

CI/CD 변수 및 실행자 인증과 같은 경우 예기치 않은 동작을 경험할 수 있습니다:

  • 작업이 멈춤.
  • 500 오류.

이 경우, CI/CD 변수 및 실행자 인증에 대한 모든 토큰을 재설정해야 하며, 이에 대한 자세한 내용은 다음 섹션에서 설명합니다. 토큰을 재설정한 후 프로젝트를 방문하면 작업이 다시 시작될 것입니다.

경고: 이 섹션의 단계는 위에 나열된 항목에서 잠재적으로 데이터 손실로 이어질 수 있습니다. 프리미엄 또는 얼티밋 고객이라면 지원 요청을 열어보는 것을 고려해보세요.

모든 값을 해독할 수 있는지 확인

현재 비밀을 사용하여 데이터베이스에 있는 값을 해독할 수 있는지 확인할 수 있습니다. 레이크 태스크를 사용하십시오.

백업 수행

손실된 비밀 파일을 우회하기 위해 GitLab 데이터를 직접 수정해야 합니다.

경고: 변경을 시도하기 전에 전체 데이터베이스 백업을 만드십시오.

사용자 이중 인증 비활성화 (2FA)

2FA가 활성화된 사용자는 GitLab에 로그인할 수 없습니다. 이 경우, 모든 사용자의 2FA를 비활성화해야 하며, 사용자는 이후에 2FA를 재활성화해야 합니다.

CI/CD 변수 재설정

  1. 데이터베이스 콘솔에 입력하십시오:

    Linux 패키지(Omnibus) GitLab 14.1 및 이전 버전:

    sudo gitlab-rails dbconsole
    

    Linux 패키지(Omnibus) GitLab 14.2 및 이후 버전:

    sudo gitlab-rails dbconsole --database main
    

    직접 컴파일한 설치의 경우, GitLab 14.1 및 이전 버전:

    sudo -u git -H bundle exec rails dbconsole -e production
    

    직접 컴파일한 설치의 경우, GitLab 14.2 및 이후 버전:

    sudo -u git -H bundle exec rails dbconsole -e production --database main
    
  2. ci_group_variablesci_variables 테이블을 검사하십시오:

    SELECT * FROM public."ci_group_variables";
    SELECT * FROM public."ci_variables";
    

    이러한 변수는 삭제해야 하는 변수입니다.

  3. 모든 변수를 삭제하십시오:

    DELETE FROM ci_group_variables;
    DELETE FROM ci_variables;
    
  4. 삭제하려는 특정 그룹 또는 프로젝트를 알고 있다면 해당 DELETE에 지정할 WHERE 문을 포함할 수 있습니다:

    DELETE FROM ci_group_variables WHERE group_id = <GROUPID>;
    DELETE FROM ci_variables WHERE project_id = <PROJECTID>;
    

변경 사항이 적용되려면 GitLab을 다시 구성하거나 재시작해야 할 수 있습니다.

실행자 등록 토큰 재설정

  1. 데이터베이스 콘솔에 입력하십시오:

    Linux 패키지(Omnibus) GitLab 14.1 및 이전 버전:

    sudo gitlab-rails dbconsole
    

    Linux 패키지(Omnibus) GitLab 14.2 및 이후 버전:

    sudo gitlab-rails dbconsole --database main
    

    직접 컴파일한 설치의 경우, GitLab 14.1 및 이전 버전:

    sudo -u git -H bundle exec rails dbconsole -e production
    

    직접 컴파일한 설치의 경우, GitLab 14.2 및 이후 버전:

    sudo -u git -H bundle exec rails dbconsole -e production --database main
    
  2. 프로젝트, 그룹 및 전체 인스턴스에 대한 모든 토큰을 지웁니다:

    경고: 최종 UPDATE 작업은 실행자가 새 작업을 가져올 수 없게 만듭니다. 새 실행자를 등록해야 합니다.

    -- 프로젝트 토큰 삭제
    UPDATE projects SET runners_token = null, runners_token_encrypted = null;
    -- 그룹 토큰 삭제
    UPDATE namespaces SET runners_token = null, runners_token_encrypted = null;
    -- 인스턴스 토큰 삭제
    UPDATE application_settings SET runners_registration_token_encrypted = null;
    -- JWT 인증에 사용되는 키 삭제
    -- 이는 $CI_JWT_TOKEN 작업 변수를 망가뜨릴 수 있습니다:
    -- https://gitlab.com/gitlab-org/gitlab/-/issues/325965
    UPDATE application_settings SET encrypted_ci_jwt_signing_key = null;
    -- 실행자 토큰 삭제
    UPDATE ci_runners SET token = null, token_encrypted = null;
    

보류 중인 파이프라인 작업 재설정

  1. 데이터베이스 콘솔에 입력하세요:

    리눅스 패키지(Omnibus) GitLab 14.1 및 이전 버전:

    sudo gitlab-rails dbconsole
    

    리눅스 패키지(Omnibus) GitLab 14.2 및 이후 버전:

    sudo gitlab-rails dbconsole --database main
    

    직접 컴파일한 설치, GitLab 14.1 및 이전 버전:

    sudo -u git -H bundle exec rails dbconsole -e production
    

    직접 컴파일한 설치, GitLab 14.2 및 이후 버전:

    sudo -u git -H bundle exec rails dbconsole -e production --database main
    
  2. 보류 중인 작업에 대한 모든 토큰을 지웁니다:

    GitLab 15.3 및 이전 버전:

    -- 빌드 토큰 지우기
    UPDATE ci_builds SET token = null, token_encrypted = null;
    

    GitLab 15.4 및 이후 버전:

    -- 빌드 토큰 지우기
    UPDATE ci_builds SET token_encrypted = null;
    

나머지 기능에 대해서도 비슷한 전략을 사용할 수 있습니다. 복호화할 수 없는 데이터를 제거함으로써 GitLab을 다시 작동시킬 수 있고, 손실된 데이터를 수동으로 대체할 수 있습니다.

통합 및 웹훅 수정

시크릿 키를 잃어버린 경우, 통합 설정웹훅 설정 페이지에서 500 오류 메시지가 표시될 수 있습니다. 잃어버린 시크릿 키는 이전에 구성된 통합 또는 웹훅이 있는 프로젝트의 저장소에 액세스하려고 시도할 때도 500 오류를 발생시킬 수 있습니다.

해결 방법은 영향을 받는 테이블(암호화된 열을 포함하는 테이블)을 잘라내는 것입니다. 이렇게 하면 구성된 통합, 웹훅 및 관련 메타데이터가 모두 삭제됩니다. 데이터를 삭제하기 전에 시크릿 키가 문제의 원인인지 확인해야 합니다.

  1. 데이터베이스 콘솔에 입력하세요:

    리눅스 패키지(Omnibus) GitLab 14.1 및 이전 버전:

    sudo gitlab-rails dbconsole
    

    리눅스 패키지(Omnibus) GitLab 14.2 및 이후 버전:

    sudo gitlab-rails dbconsole --database main
    

    직접 컴파일한 설치, GitLab 14.1 및 이전 버전:

    sudo -u git -H bundle exec rails dbconsole -e production
    

    직접 컴파일한 설치, GitLab 14.2 및 이후 버전:

    sudo -u git -H bundle exec rails dbconsole -e production --database main
    
  2. 다음 테이블을 잘라냅니다:

    -- web_hooks 테이블 잘라내기
    TRUNCATE integrations, chat_names, issue_tracker_data, jira_tracker_data, slack_integrations, web_hooks, zentao_tracker_data, web_hook_logs CASCADE;
    

백업에서 복원한 후 컨테이너 레지스트리 푸시 실패

컨테이너 레지스트리를 사용하는 경우, 리눅스 패키지(Omnibus) 인스턴스에서 백업을 복원한 후 레지스트리 데이터에 대한 푸시가 실패할 수 있습니다.

이러한 실패는 레지스트리 로그에서 권한 문제를 언급합니다. 다음과 유사합니다:

level=error
msg="response completed with error"
err.code=unknown
err.detail="filesystem: mkdir /var/opt/gitlab/gitlab-rails/shared/registry/docker/registry/v2/repositories/...: permission denied"
err.message="unknown error"

이 문제는 복원이 권한이없는 사용자 ‘git’으로 실행되어 레지스트리 파일에 올바른 소유권을 할당하지 못하는 것에서 발생합니다(issue #62759).

레지스트리를 다시 작동시키려면 다음을 실행하세요:

sudo chown -R registry:registry /var/opt/gitlab/gitlab-rails/shared/registry/docker

레지스트리의 기본 파일 시스템 위치를 변경한 경우, /var/opt/gitlab/gitlab-rails/shared/registry/docker 대신 사용자 정의 위치에 대해 chown을 실행하세요.

Gzip 오류로 백업이 완료되지 않음

백업을 실행하는 동안 Gzip 오류 메시지를 받을 수 있습니다:

sudo /opt/gitlab/bin/gitlab-backup create
...
Dumping ...
...
gzip: stdout: Input/output error

Backup failed

이런 경우 다음을 확인하세요:

  • Gzip 작업에 충분한 디스크 공간이 있는지 확인하세요. 백업 생성 중에는 기본 전략을 사용하는 백업의 경우 인스턴스 크기의 절반 정도의 무료 디스크 공간이 필요할 수 있습니다.
  • NFS를 사용하는 경우, 마운트 옵션 timeout이 설정되어 있는지 확인하세요. 기본값은 600이며, 이를 더 작은 값으로 변경하면 이 오류가 발생할 수 있습니다.

‘파일 이름이 너무 깁니다’ 오류로 백업 실패

백업 중에 파일 이름이 너무 깁니다 오류가 발생할 수 있습니다 (이슈 #354984). 예를 들어:

문제: <class 'OSError: [Errno 36] File name too long:

이 문제로 백업 스크립트가 완료되지 못합니다. 이 문제를 해결하려면 문제를 일으키는 파일 이름을 잘라내야 합니다. 파일 확장자를 포함하여 최대 246자까지 허용됩니다.

경고: 이 섹션의 단계는 잠재적으로 데이터 손실로 이어질 수 있습니다. 모든 단계를 엄격히 순서대로 따라야 합니다. 프리미엄 또는 얼티밋 고객이라면 지원 요청을 열어보는 것을 고려해보세요.

오류 해결을 위해 파일 이름을 잘라내는 단계는 다음과 같습니다:

  • 데이터베이스에서 추적되지 않는 원격 업로드 파일 정리
  • 데이터베이스에 있는 파일 이름 잘라내기
  • 백업 작업 다시 실행

원격 업로드 파일 정리

부모 리소스가 삭제된 후에도 객체 저장소 업로드가 남아있는 알려진 문제가 있었습니다. 이 문제가 해결되었습니다.

이러한 파일을 수정하려면 데이터베이스 테이블에 기록되지 않은 저장소에 있는 모든 원격 업로드 파일을 정리해야 합니다.

  1. 데이터베이스에 없는 파일들을 ‘잃어버린 물품 보관함’으로 이동할 수 있는 모든 객체 저장소 업로드 파일을 나열합니다:

    bundle exec rake gitlab:cleanup:remote_upload_files RAILS_ENV=production
    
  2. 이러한 파일을 삭제하고 참조되지 않는 모든 업로드 파일을 제거하려면 다음 명령을 실행합니다:

    경고: 다음 동작은 되돌릴 수 없습니다.

    bundle exec rake gitlab:cleanup:remote_upload_files RAILS_ENV=production DRY_RUN=false
    

데이터베이스에서 참조된 파일 이름 잘라내기

문제를 일으키는 데이터베이스에 있는 파일 이름을 잘라내야 합니다. 데이터베이스에 기록된 파일 이름은 다음과 같이 저장됩니다:

  • uploads 테이블
  • 참조된 항목. 다른 데이터베이스 테이블 및 열에서 찾은 참조

uploads 테이블에서 파일 이름을 잘라냅니다:

  1. 데이터베이스 콘솔에 입력합니다:

    리눅스 패키지 (Omnibus) GitLab 14.2 이상:

    sudo gitlab-rails dbconsole --database main
    

    리눅스 패키지 (Omnibus) GitLab 14.1 이하:

    sudo gitlab-rails dbconsole
    

    자체 컴파일한 설치에서 GitLab 14.2 이상:

    sudo -u git -H bundle exec rails dbconsole -e production --database main
    

    자체 컴파일한 설치에서 GitLab 14.1 이하:

    sudo -u git -H bundle exec rails dbconsole -e production
    
  2. 246자보다 긴 파일 이름을 검색하려면 uploads 테이블을 다음과 같이 쿼리합니다:

    다음 쿼리는 0에서 10000까지 일괄로 246자보다 긴 파일 이름을 가진 uploads 레코드를 선택합니다. 이렇게 하면 레코드가 수천 개인 대형 GitLab 인스턴스에서 성능이 향상됩니다.

    CREATE TEMP TABLE uploads_with_long_filenames AS
    SELECT ROW_NUMBER() OVER(ORDER BY id) row_id, id, path
    FROM uploads AS u
    WHERE LENGTH((regexp_match(u.path, '[^\\/:*?"<>|\r\n]+$'))[1]) > 246;
    
    CREATE INDEX ON uploads_with_long_filenames(row_id);
    
    SELECT
       u.id,
       u.path,
       -- 현재 파일 이름
       (regexp_match(u.path, '[^\\/:*?"<>|\r\n]+$'))[1] AS current_filename,
       -- 새 파일 이름
       CONCAT(
          LEFT(SPLIT_PART((regexp_match(u.path, '[^\\/:*?"<>|\r\n]+$'))[1], '.', 1), 242),
          COALESCE(SUBSTRING((regexp_match(u.path, '[^\\/:*?"<>|\r\n]+$'))[1] FROM '\.(?:.(?!\.))+$'))
       ) AS new_filename,
       -- 새 경로
       CONCAT(
          COALESCE((regexp_match(u.path, '(.*\/).*'))[1], ''),
          CONCAT(
             LEFT(SPLIT_PART((regexp_match(u.path, '[^\\/:*?"<>|\r\n]+$'))[1], '.', 1), 242),
             COALESCE(SUBSTRING((regexp_match(u.path, '[^\\/:*?"<>|\r\n]+$'))[1] FROM '\.(?:.(?!\.))+$'))
          )
       ) AS new_path
    FROM uploads_with_long_filenames AS u
    WHERE u.row_id > 0 AND u.row_id <= 10000;
    

    출력 예시:

    -[ RECORD 1 ]----+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
    id               | 34
    path             | public/@hashed/loremipsumdolorsitametconsecteturadipiscingelitseddoeiusmodtemporincididuntutlaboreetdoloremagnaaliquaauctorelitsedvulputatemisitloremipsumdolorsitametconsecteturadipiscingelitseddoeiusmodtemporincididuntutlaboreetdoloremagnaaliquaauctorelitsedvulputatemisit.txt
    current_filename | loremipsumdolorsitametconsecteturadipiscingelitseddoeiusmodtemporincididuntutlaboreetdoloremagnaaliquaauctorelitsedvulputatemisitloremipsumdolorsitametconsecteturadipiscingelitseddoeiusmodtemporincididuntutlaboreetdoloremagnaaliquaauctorelitsedvulputatemisit.txt
    new_filename     | loremipsumdolorsitametconsecteturadipiscingelitseddoeiusmodtemporincididuntutlaboreetdoloremagnaaliquaauctorelitsedvulputatemisitloremipsumdolorsitametconsecteturadipiscingelitseddoeiusmodtemporincididuntutlaboreetdoloremagnaaliquaauctorelits.txt
    new_path         | public/@hashed/loremipsumdolorsitametconsecteturadipiscingelitseddoeiusmodtemporincididuntutlaboreetdoloremagnaaliquaauctorelitsedvulputatemisitloremipsumdolorsitametconsecteturadipiscingelitseddoeiusmodtemporincididuntutlaboreetdoloremagnaaliquaauctorelits.txt

    여기서:

    • current_filename: 현재 246자보다 더 긴 파일 이름
    • new_filename: 246자까지 잘라낸 새 파일 이름
    • new_path: new_filename (잘라낸 파일 이름)을 고려한 새 경로

    일괄처리 결과를 확인한 후, uploads 테이블의 마지막 레코드에 도달할 때까지 다음 숫자 시퀀스(10000부터 20000)로 일괄 크기(row_id)를 변경해야 합니다.

  3. uploads 테이블에서 찾은 파일의 이름을 잘라낸 새로운 파일 이름으로 변경합니다. 다음 쿼리는 업데이트를 되돌림으로서 안전하게 결과를 확인할 수 있도록합니다:

    CREATE TEMP TABLE uploads_with_long_filenames AS
    SELECT ROW_NUMBER() OVER(ORDER BY id) row_id, path, id
    FROM uploads AS u
    WHERE LENGTH((regexp_match(u.path, '[^\\/:*?"<>|\r\n]+$'))[1]) > 246;
    
    CREATE INDEX ON uploads_with_long_filenames(row_id);
    
    BEGIN;
    WITH updated_uploads AS (
       UPDATE uploads
       SET
          path =
          CONCAT(
             COALESCE((regexp_match(updatable_uploads.path, '(.*\/).*'))[1], ''),
             CONCAT(
                LEFT(SPLIT_PART((regexp_match(updatable_uploads.path, '[^\\/:*?"<>|\r\n]+$'))[1], '.', 1), 242),
                COALESCE(SUBSTRING((regexp_match(updatable_uploads.path, '[^\\/:*?"<>|\r\n]+$'))[1] FROM '\.(?:.(?!\.))+$'))
             )
          )
       FROM
          uploads_with_long_filenames AS updatable_uploads
       WHERE
          uploads.id = updatable_uploads.id
       AND updatable_uploads.row_id > 0 AND updatable_uploads.row_id  <= 10000
       RETURNING uploads.*
    )
    SELECT id, path FROM updated_uploads;
    ROLLBACK;
    

    일괄 업데이트 결과를 확인한 후, uploads 테이블의 마지막 레코드에 도달할 때까지 다음 숫자 시퀀스(10000부터 20000)로 일괄 크기(row_id)를 변경해야 합니다.

  4. 이전 쿼리에서 얻은 새 파일 이름이 예상대로인지 확인합니다. 이전 단계에서 찾은 레코드를 246자로 잘라내려면 다음 단계를 실행합니다:

    경고: 다음 동작은 되돌릴 수 없습니다.

    CREATE TEMP TABLE uploads_with_long_filenames AS
    SELECT ROW_NUMBER() OVER(ORDER BY id) row_id, path, id
    FROM uploads AS u
    WHERE LENGTH((regexp_match(u.path, '[^\\/:*?"<>|\r\n]+$'))[1]) > 246;
    
    CREATE INDEX ON uploads_with_long_filenames(row_id);
    
    UPDATE uploads
    SET
    path =
       CONCAT(
          COALESCE((regexp_match(updatable_uploads.path, '(.*\/).*'))[1], ''),
          CONCAT(
             LEFT(SPLIT_PART((regexp_match(updatable_uploads.path, '[^\\/:*?"<>|\r\n]+$'))[1], '.', 1), 242),
             COALESCE(SUBSTRING((regexp_match(updatable_uploads.path, '[^\\/:*?"<>|\r\n]+$'))[1] FROM '\.(?:.(?!\.))+$'))
          )
       )
    FROM
    uploads_with_long_filenames AS updatable_uploads
    WHERE
    uploads.id = updatable_uploads.id
    AND updatable_uploads.row_id > 0 AND updatable_uploads.row_id  <= 10000;
    

    일괄 업데이트를 완료한 후, uploads 테이블의 마지막 레코드에 도달할 때까지 다음 숫자 시퀀스(updatable_uploads.row_id)로 일괄 크기를 변경해야 합니다.

파일 시스템에서 파일 이름을 잘라냅니다. uploads 테이블을 쿼리하여 얻은 새 파일 이름으로 파일 시스템에서 파일 이름을 수동으로 변경해야 합니다.

백업 작업 다시 실행하기

이전 단계를 모두 따른 후, 백업 작업을 다시 실행하세요.

pg_stat_statements가 이전에 활성화되었을 때 데이터베이스 백업 복원이 실패하는 경우

PostgreSQL 데이터베이스의 GitLab 백업에는 이전에 데이터베이스에서 활성화되었던 확장 기능을 활성화하는 데 필요한 모든 SQL 문이 포함됩니다.

pg_stat_statements 확장 기능은 슈퍼유저 역할을 가진 PostgreSQL 사용자만이 활성화 또는 비활성화할 수 있습니다. 복원 프로세스는 제한된 권한을 가진 데이터베이스 사용자를 사용하므로 다음 SQL 문을 실행할 수 없습니다:

DROP EXTENSION IF EXISTS pg_stat_statements;
CREATE EXTENSION IF NOT EXISTS pg_stat_statements WITH SCHEMA public;

pg_stats_statements 확장 기능이 없는 PostgreSQL 인스턴스에서 백업을 복원하려고 할 때 다음 오류 메시지가 표시됩니다:

ERROR: permission denied to create extension "pg_stat_statements"
HINT: Must be superuser to create this extension.
ERROR: extension "pg_stat_statements" does not exist

pg_stats_statements 확장 기능이 활성화된 인스턴스에서 복원을 시도하면 정리 단계에서 다음과 유사한 오류 메시지로 실패합니다:

rake aborted!
ActiveRecord::StatementInvalid: PG::InsufficientPrivilege: ERROR: must be owner of view pg_stat_statements
/opt/gitlab/embedded/service/gitlab-rails/lib/tasks/gitlab/db.rake:42:in `block (4 levels) in <top (required)>'
/opt/gitlab/embedded/service/gitlab-rails/lib/tasks/gitlab/db.rake:41:in `each'
/opt/gitlab/embedded/service/gitlab-rails/lib/tasks/gitlab/db.rake:41:in `block (3 levels) in <top (required)>'
/opt/gitlab/embedded/service/gitlab-rails/lib/tasks/gitlab/backup.rake:71:in `block (3 levels) in <top (required)>'
/opt/gitlab/embedded/bin/bundle:23:in `load'
/opt/gitlab/embedded/bin/bundle:23:in `<main>'
Caused by:
PG::InsufficientPrivilege: ERROR: must be owner of view pg_stat_statements
/opt/gitlab/embedded/service/gitlab-rails/lib/tasks/gitlab/db.rake:42:in `block (4 levels) in <top (required)>'
/opt/gitlab/embedded/service/gitlab-rails/lib/tasks/gitlab/db.rake:41:in `each'
/opt/gitlab/embedded/service/gitlab-rails/lib/tasks/gitlab/db.rake:41:in `block (3 levels) in <top (required)>'
/opt/gitlab/embedded/service/gitlab-rails/lib/tasks/gitlab/backup.rake:71:in `block (3 levels) in <top (required)>'
/opt/gitlab/embedded/bin/bundle:23:in `load'
/opt/gitlab/embedded/bin/bundle:23:in `<main>'
Tasks: TOP => gitlab:db:drop_tables
(See full trace by running task with --trace)

덤프 파일에 pg_stat_statements 포함 방지

백업 번들의 일부인 PostgreSQL 덤프 파일에 확장 기능을 포함하지 않으려면 public 스키마 이외의 스키마에서 확장 기능을 활성화하세요:

CREATE SCHEMA adm;
CREATE EXTENSION pg_stat_statements SCHEMA adm;

확장 기능이 이전에 public 스키마에서 활성화된 경우 새로운 스키마로 이동하세요:

CREATE SCHEMA adm;
ALTER EXTENSION pg_stat_statements SET SCHEMA adm;

스키마를 변경한 후에 pg_stat_statements 데이터를 쿼리하려면 새로운 스키마 이름으로 뷰 이름을 접두어로 사용하세요:

SELECT * FROM adm.pg_stat_statements limit 0;

public 스키마에서 활성화되어 있어야 하는 타사 모니터링 솔루션과 호환성을 유지하려면 search_path에 포함해야 합니다:

set search_path to public,adm;

pg_stat_statements에 대한 참조를 제거하기 위해 기존 덤프 파일 수정

기존 백업 파일을 수정하려면 다음 변경을 수행하세요:

  1. 백업에서 다음 파일을 추출하세요: db/database.sql.gz.
  2. 파일을 압축 해제하거나 압축 처리할 수 있는 편집기를 사용하세요.
  3. 다음 라인 또는 유사한 라인을 제거하세요:

    CREATE EXTENSION IF NOT EXISTS pg_stat_statements WITH SCHEMA public;
    
    COMMENT ON EXTENSION pg_stat_statements IS 'track planning and execution statistics of all SQL statements executed';
    
  4. 변경 사항을 저장하고 파일을 다시 압축하세요.
  5. 수정된 db/database.sql.gz로 백업 파일을 업데이트하세요.