1. 소개
이 Codelab에서는 RPM 조정자를 사용하여 AlloyDB Omni용 S3 호환 객체 스토리지에 고가용성 (HA) 클러스터를 백업합니다.
이 Codelab에서는 RPM Orchestrator를 사용하여 GCE VM에 AlloyDB Omni 고가용성 클러스터 배포 Codelab의 클러스터를 사용하여 Compute Engine 가상 머신 (VM)에 HA 클러스터를 만듭니다. 이 Codelab에서는 VM 중 하나에 S3 호환 객체 스토리지 서버를 추가합니다. HA 클러스터의 객체 스토리지 서버를 사용하여 데이터를 백업하고 서버에서 클러스터를 복원합니다.

기본 요건
- 결제가 사용 설정된 Google Cloud 프로젝트.
- HA Codelab에 나열된 IAM 역할입니다.
- Linux 명령어 및 SQL에 관한 기본 지식
학습할 내용
- 백업을 위해 S3 호환 객체 스토리지 서버를 설치하고 실행하는 방법
- S3 호환 스토리지에 백업을 쓰는 백업 계획을 만드는 방법
- 주문형 백업을 만드는 방법
- 백업에서 특정 시점으로 클러스터를 복원하는 방법
필요한 항목
- AlloyDB Omni 소프트웨어 저장소 및 조정자 Ansible 컬렉션의 URL입니다. URL을 받으려면 AlloyDB Omni 가입 양식을 작성하세요. 자세한 내용은 RPM을 사용한 AlloyDB Omni 개요를 참고하세요. HA Codelab에서 URL을 사용합니다.
- RPM 조정자를 사용하여 GCE VM에 AlloyDB Omni 고가용성 클러스터 배포 Codelab의 AlloyDB Omni HA 클러스터
- Google Cloud 및 Cloud Shell에 액세스할 수 있는 터미널
2. 설정 및 요구사항
- 이 단계에서는 Codelab RPM 조정자를 사용하여 GCE VM에 AlloyDB Omni 고가용성 클러스터 배포를 사용하여 HA 클러스터를 만듭니다. 다음 단계를 완료합니다. Codelab에서 클러스터를 이미 만든 경우 다음 단계로 계속 진행합니다.
- 참고: 이 단계에서는 '리소스 정리' 단계를 실행하지 마세요. 이 단계는 이 Codelab의 끝부분에서 실행합니다.
- 이 Codelab으로 돌아가기
3. 클러스터에 연결하고 샘플 데이터 추가
이 단계에서는 컨트롤 VM에 클러스터 설정을 로드합니다. 그런 다음 클러스터에 연결하고 샘플 데이터가 포함된 테이블을 추가합니다.
- 제어 VM에 연결되어 있지 않으면 Cloud Shell에서 연결합니다.
gcloud compute ssh "$CLUSTER-control" --zone="$ZONE" --project="$PROJECT"CLUSTER,ZONE,PROJECT변수는 RPM 조정자를 사용하여 GCE VM에 AlloyDB Omni 고가용성 클러스터 배포 Codelab의 배포를 위해 VM 준비 단계에서 가져옵니다. Cloud Shell에 이러한 변수가 없으면 다시 설정합니다. - 제어 VM에서 홈 디렉터리로 변경하고 환경 변수를 로드합니다. 그런 다음 환경 파일에 클러스터 이름과 SSH 사용자를 추가합니다.
출력에cd ~ source /tmp/cluster.conf cat >> ~/.codelab.env <<EOF export CLUSTER="$cluster" export SSH_USER="$service_account" EOF source ~/.codelab.env env | grep -E '^(CLUSTER|SSH_USER|VIRTUAL_IP)='CLUSTER,SSH_USER,VIRTUAL_IP이 표시되는지 확인합니다. 참고: 나중에 제어 VM에 다시 연결하는 경우 계속하기 전에cd ~및source ~/.codelab.env을 실행하세요. - 환경 파일에 연결 설정을 추가합니다.
read명령에서 비밀번호를 묻는 메시지가 표시되면postgres사용자의 비밀번호를 입력합니다. 이 비밀번호는 RPM 조정자를 사용하여 GCE VM에 AlloyDB Omni 고가용성 클러스터 배포 Codelab의 AlloyDB Omni 클러스터 부트스트랩 단계에서 설정합니다.cat >> ~/.codelab.env <<'EOF' export PATH="/usr/pgsql-18/bin:$PATH" export PGHOST="$VIRTUAL_IP" export PGUSER="postgres" EOF read -rsp "Password of the postgres user: " PGPASSWORD; echo printf 'export PGPASSWORD=%q\n' "$PGPASSWORD" >> ~/.codelab.env source ~/.codelab.env env | grep -E '^(PGHOST|PGUSER|PGPASSWORD)=' - 표를 만들고 1,000개의 행을 추가합니다.
psql <<'SQL' CREATE TABLE public.orders ( id integer PRIMARY KEY, item text NOT NULL, created_at timestamptz NOT NULL DEFAULT pg_catalog.now() ); INSERT INTO public.orders (id, item) SELECT g, 'item-' || g FROM pg_catalog.generate_series(1, 1000) AS g; SQL - 행 수를 계산합니다.
출력이psql -c "SELECT pg_catalog.count(*) FROM public.orders;"1000을 반환하는지 확인합니다.
4. S3 호환 객체 스토리지 설치 및 실행
이 단계에서는 제어 VM에 MinIO 서버를 설치하는 Ansible 플레이북을 작성합니다. 플레이북은 백업용 버킷과 사용자를 만들고 데이터베이스 VM이 MinIO에 연결할 수 있는지 확인합니다. 이 단계의 모든 명령어는 제어 VM에서 실행합니다.
- 제어 VM에서 환경 파일에 스토리지 설정을 추가합니다.
openssl명령어는 무작위 비밀번호를 만듭니다. 출력에 제어 VM의 이름과 내부 IP 주소가 표시되는지 확인합니다(예:MD=http://metadata.google.internal/computeMetadata/v1/instance S3_IP=$(curl -s -H "Metadata-Flavor: Google" "$MD/network-interfaces/0/ip") cat >> ~/.codelab.env <<EOF export S3_IP="$S3_IP" export S3_HOST="$CLUSTER-control" export S3_BUCKET="alloydb-backups" export S3_REGION="us-east-1" export MINIO_ROOT_USER="s3admin" export MINIO_ROOT_PASSWORD="$(openssl rand -hex 16)" export S3_ACCESS_KEY_ID="alloydb-backup" export S3_SECRET_ACCESS_KEY="$(openssl rand -hex 16)" export MINIO_URL="https://github.com/minio/minio/releases/download/RELEASE.2024-05-10T01-41-38Z/minio.linux-amd64.RELEASE.2024-05-10T01-41-38Z" export MC_URL="https://github.com/minio/mc/releases/download/RELEASE.2024-05-09T17-04-24Z/mc.linux-amd64.RELEASE.2024-05-09T17-04-24Z" EOF source ~/.codelab.env echo "$S3_HOST $S3_IP"my-cluster-control 10.1.0.2). 데이터베이스 VM은 이 호스트 이름과 IP 주소를 사용하여 MinIO에 연결합니다. VM의 메타데이터 서버가 IP 주소를 제공합니다. 자세한 내용은 VM 메타데이터 문서를 참고하세요.MINIO_URL및MC_URL값은 MinIO 서버와 MinIO 클라이언트 (mc)의 다운로드 URL입니다. - 제어 VM에 필요한
community.cryptoAnsible 컬렉션을 설치합니다.ansible-galaxy collection install community.crypto s3_server.yaml플레이북을 만듭니다.cat > s3_server.yaml <<EOF - name: Install and run MinIO on the control VM hosts: localhost connection: local become: true gather_facts: false tasks: - name: Create MinIO directories ansible.builtin.file: path: "{{ item }}" state: directory mode: "0755" loop: - /var/lib/minio/data - /var/lib/minio/certs - name: Download MinIO server and client ansible.builtin.get_url: url: "{{ item.url }}" dest: "{{ item.dest }}" mode: "0755" loop: - url: "$MINIO_URL" dest: /usr/local/bin/minio - url: "$MC_URL" dest: /usr/local/bin/mc - name: Generate MinIO TLS private key community.crypto.openssl_privatekey: path: /var/lib/minio/certs/private.key size: 2048 mode: "0600" - name: Generate MinIO certificate signing request community.crypto.openssl_csr_pipe: privatekey_path: /var/lib/minio/certs/private.key common_name: "$S3_HOST" subject_alt_name: - "DNS:$S3_HOST" - "DNS:$S3_BUCKET.$S3_HOST" - "DNS:localhost" - "IP:127.0.0.1" - "IP:$S3_IP" register: minio_csr - name: Generate self-signed MinIO TLS certificate community.crypto.x509_certificate: path: /var/lib/minio/certs/public.crt csr_content: "{{ minio_csr.csr }}" privatekey_path: /var/lib/minio/certs/private.key provider: selfsigned selfsigned_not_after: "+365d" mode: "0644" - name: Create MinIO systemd service unit ansible.builtin.copy: dest: /etc/systemd/system/minio.service mode: "0600" content: | [Unit] Description=MinIO Object Storage After=network.target [Service] Environment="MINIO_ROOT_USER=$MINIO_ROOT_USER" Environment="MINIO_ROOT_PASSWORD=$MINIO_ROOT_PASSWORD" Environment="MINIO_DOMAIN=$S3_HOST" ExecStart=/usr/local/bin/minio server /var/lib/minio/data --certs-dir /var/lib/minio/certs Restart=on-failure [Install] WantedBy=multi-user.target - name: Start and enable MinIO service ansible.builtin.systemd_service: name: minio daemon_reload: true state: started enabled: true - name: Add storage host names to /etc/hosts on the control VM ansible.builtin.lineinfile: path: /etc/hosts line: "$S3_IP $S3_HOST $S3_BUCKET.$S3_HOST" state: present - name: Wait for MinIO health endpoint ansible.builtin.uri: url: "https://$S3_HOST:9000/minio/health/live" ca_path: /var/lib/minio/certs/public.crt status_code: 200 register: minio_health until: minio_health.status == 200 retries: 6 delay: 5 - name: Create backup bucket and user in MinIO ansible.builtin.command: argv: "{{ item }}" loop: - - /usr/local/bin/mc - --insecure - alias - set - s3repo - "https://$S3_HOST:9000" - "$MINIO_ROOT_USER" - "$MINIO_ROOT_PASSWORD" - - /usr/local/bin/mc - --insecure - mb - --ignore-existing - "s3repo/$S3_BUCKET" - - /usr/local/bin/mc - --insecure - admin - user - add - s3repo - "$S3_ACCESS_KEY_ID" - "$S3_SECRET_ACCESS_KEY" - - /usr/local/bin/mc - --insecure - admin - policy - attach - s3repo - readwrite - --user - "$S3_ACCESS_KEY_ID" become: false no_log: true - name: Configure database VMs for MinIO hosts: primary_instance_nodes become: true gather_facts: false vars: ansible_user: $SSH_USER ansible_ssh_private_key_file: $HOME/ssh-key-cluster-sa tasks: - name: Set SELinux to permissive mode ansible.builtin.command: cmd: setenforce 0 - name: Add storage host names to /etc/hosts ansible.builtin.lineinfile: path: /etc/hosts line: "$S3_IP $S3_HOST $S3_BUCKET.$S3_HOST" state: present - name: Verify storage host resolution ansible.builtin.getent: database: hosts key: "$S3_BUCKET.$S3_HOST" - name: Verify connection to MinIO ansible.builtin.uri: url: "https://$S3_HOST:9000/minio/health/live" validate_certs: false status_code: 200 EOFMINIO_DOMAIN변수를 사용하면 MinIO가 가상 호스트 스타일 요청을 수락할 수 있습니다. RPM 조정자는alloydb-backup사용자를 사용하여 백업을 작성합니다.readwrite정책은 MinIO 기본 제공 정책입니다.- 플레이북을 실행합니다.
ansible-playbook s3_server.yaml -i deployment_spec.yamlPLAY RECAP출력에localhost및 각 데이터베이스 VM에 대해failed=0이 표시되는지 확인합니다. - 버킷이 있는지 확인합니다.
출력에mc --insecure ls s3repoalloydb-backups/버킷이 표시되는지 확인합니다.
5. 백업 계획 만들기
백업 계획에는 클러스터 백업의 저장 위치, 일정, 보관 기간이 포함됩니다. 이 단계에서는 MinIO 버킷의 백업 계획을 만듭니다.
- 제어 VM에서 백업 플레이북과 상태 플레이북을 만듭니다.
Secret,BackupPlan,Backup리소스에 백업 플레이북을 사용합니다. 상태 플레이북을 사용하여 리소스의 상태를 표시합니다.cat > backup.yaml <<EOF - name: Manage AlloyDB Omni backups hosts: localhost roles: - role: google.alloydbomni_orchestrator.backup EOF cat > status.yaml <<EOF - name: Get resource status hosts: localhost roles: - role: google.alloydbomni_orchestrator.status EOF - S3 사용자 인증 정보의
Secret리소스를 만듭니다. 그런 다음 리소스를 적용합니다.S3_KEY_ID_B64=$(printf '%s' "$S3_ACCESS_KEY_ID" | base64 -w 0) S3_KEY_B64=$(printf '%s' "$S3_SECRET_ACCESS_KEY" | base64 -w 0) cat > s3_secret.yaml <<EOF Secret: metadata: name: s3-backup-secret spec: type: Opaque data: access-key-id: "$S3_KEY_ID_B64" access-key: "$S3_KEY_B64" EOF ansible-playbook backup.yaml -i deployment_spec.yaml \ -e resource_spec=s3_secret.yamldata섹션의 키 이름은access-key-id및access-key이어야 합니다.BackupPlan리소스를 적용하기 전에Secret리소스를 적용해야 합니다. BackupPlan리소스를 만든 다음 리소스를 적용합니다.cat > backup_plan.yaml <<EOF BackupPlan: metadata: name: s3-backup-plan spec: dbclusterRef: $CLUSTER backupLocation: type: S3 s3Options: bucket: $S3_BUCKET key: /backups endpoint: https://$S3_HOST:9000 region: $S3_REGION secretRef: name: s3-backup-secret caBundle: - | $(sed 's/^/ /' /var/lib/minio/certs/public.crt) EOF ansible-playbook backup.yaml -i deployment_spec.yaml \ -e resource_spec=backup_plan.yamlkey값은 버킷의 백업 경로입니다. 이 경로는 슬래시 (/)로 시작해야 합니다.caBundle필드에는 S3 스토리지 서버의 인증서를 검증하는 PEM 인코딩 CA 인증서가 포함되어 있습니다.- 백업 계획이 준비되었는지 확인합니다.
ansible-playbook status.yaml -i deployment_spec.yaml \ -e resource_type=BackupPlan -e resource_name=s3-backup-planphase필드에Ready이 표시되는지 확인합니다. 단계가Ready이 아니면 1분 정도 기다린 후 명령어를 다시 실행합니다. - 백업 계획이 생성되면 RPM 오케스트레이터가 초기 전체 백업을 자동으로 시작합니다. 주문형 백업을 만들기 전에 초기 백업이 완료되었는지 확인합니다.
초기 백업 단계가 성공하는지 확인합니다.ansible-playbook status.yaml -i deployment_spec.yaml \ -e resource_type=Backup
6. 주문형 백업 만들기
이 단계에서는 클러스터의 주문형 백업을 만듭니다.
- 제어 VM에서
Backup리소스를 만듭니다. 그런 다음 리소스를 적용합니다.cat > create_backup.yaml <<EOF Backup: metadata: name: s3-backup-1 spec: backupPlanRef: s3-backup-plan dbclusterRef: $CLUSTER EOF ansible-playbook backup.yaml -i deployment_spec.yaml \ -e resource_spec=create_backup.yamlbackupPlanRef필드는 백업 계획의 이름입니다.dbclusterRef필드는 클러스터의 이름입니다. - 백업이 완료되었는지 확인합니다.
ansible-playbook status.yaml -i deployment_spec.yaml \ -e resource_type=Backup -e resource_name=s3-backup-1phase필드에Succeeded이 표시되는지 확인합니다. 단계가Succeeded이 아니면 1분 정도 기다린 후 명령어를 다시 실행합니다. - 백업 파일이 버킷에 있는지 확인합니다.
출력에mc --insecure tree "s3repo/$S3_BUCKET"db폴더가 포함된backup폴더가 표시되는지 확인합니다.
7. 백업에서 클러스터 복원
RPM 오케스트레이터는 클러스터를 제자리에서 복원합니다. 이 단계에서는 테이블을 삭제하고 백업에서 복원합니다. 그런 다음 선택적으로 클러스터를 특정 시점으로 복원할 수 있습니다.
주의: 복원 작업은 데이터베이스 클러스터의 모든 데이터를 덮어씁니다.
백업에서 복원
- 제어 VM에서
orders테이블을 삭제합니다. 그런 다음 행을 계산합니다. 두 번째 명령어가 오류와 함께 실패하는지 확인합니다. 오류 메시지는 관계가 존재하지 않음을 보여줍니다. 예: 'ERROR: table "orders" does not exist'psql -c "DROP TABLE public.orders;" psql -c "SELECT pg_catalog.count(*) FROM public.orders;" - 복원 플레이북을 만듭니다.
cat > restore.yaml <<EOF - name: Restore AlloyDB Omni cluster hosts: localhost roles: - role: google.alloydbomni_orchestrator.restore EOF s3-backup-1백업의Restore리소스를 만듭니다. 그런 다음 리소스를 적용합니다.cat > restore_backup.yaml <<EOF Restore: metadata: name: s3-restore-1 spec: sourceDBCluster: $CLUSTER backup: s3-backup-1 EOF ansible-playbook restore.yaml -i deployment_spec.yaml \ -e resource_spec=restore_backup.yaml- 복원 작업이 완료되었는지 확인합니다.
ansible-playbook status.yaml -i deployment_spec.yaml \ -e resource_type=Restore -e resource_name=s3-restore-1phase필드에ProvisionSucceeded이 표시되는지 확인합니다. 단계가ProvisionSucceeded이 아니면 1분 정도 기다린 후 명령어를 다시 실행합니다. - 복원된 테이블의 행 수를 계산합니다.
출력에psql -c "SELECT pg_catalog.count(*) FROM public.orders;"1000이 표시되는지 확인합니다.
(선택사항) 특정 시점으로 복원
특정 시점 복원에서는 백업과 보관처리된 미리 쓰기 로그 (WAL)를 사용합니다. 백업 계획의 복구 기간 내에 있는 시점으로 클러스터를 복원할 수 있습니다.
목표 시간 규칙
타겟 시간의 값과 형식을 선택하려면 다음 규칙을 모두 따라야 합니다.
- UTC의 RFC 3339 형식을 사용합니다(
YYYY-MM-DDThh:mm:ssZ). 예를 들어2026-06-19T14:30:00Z은 2026년 6월 19일 14시 30분(UTC)입니다. 날짜와 시간은 문자T로 구분됩니다. 문자Z는 UTC를 나타냅니다. - 과거의 시간을 사용합니다.
BackupPlanCRD의recoveryWindow필드의begin값 이후의 시간을 사용합니다.
현재 시간을 RFC 3339 형식으로 표시하려면 다음 명령어를 실행합니다.
date -u +%Y-%m-%dT%H:%M:%SZ
현지 시간을 이 형식으로 변경하려면 현지 시간의 UTC 오프셋을 date 명령어에 추가합니다. 예를 들어 다음 명령어는 UTC+02:00에서 19 June 2026의 16:30:00를 변경합니다.
date -u -d "2026-06-19 16:30:00 +0200" +%Y-%m-%dT%H:%M:%SZ
이 명령어는 2026-06-19T14:30:00Z를 반환합니다.
녹화된 시간으로 복원
이 절차에서는 테이블에 행을 추가하고 시간을 기록합니다. 시간을 기록할 때 데이터베이스가 완전히 손상되지 않은 (정확히 1,500개의 행이 있는) 정확한 순간을 북마크합니다. 그런 다음 행을 삭제하고 기록된 시간으로 클러스터를 복원합니다.
- 표에 500개의 행을 추가합니다.
psql <<'SQL' INSERT INTO public.orders (id, item) SELECT g, 'item-' || g FROM pg_catalog.generate_series(1001, 1500) AS g; SQL - 시간을 기록합니다. 현재 표에는 1,500개의 행이 있습니다.
출력에sleep 5 PITR_TIME=$(date -u +%Y-%m-%dT%H:%M:%SZ) echo "export PITR_TIME=$PITR_TIME" >> ~/.codelab.env echo "$PITR_TIME" sleep 5YYYY-MM-DDThh:mm:ssZ형식(예:2026-10-05T11:16:02Z)으로 시간이 표시되는지 확인합니다. - 테이블에서 행을 삭제하여 실수로 데이터가 삭제된 상황을 시뮬레이션합니다. 그런 다음 새 WAL 파일을 시작합니다.
psql -c "DELETE FROM public.orders WHERE id > 1000;" psql -c "SELECT pg_catalog.count(*) FROM public.orders;" psql -c "SELECT pg_catalog.pg_switch_wal();"count쿼리에1000가 표시되는지 확인합니다.pg_switch_wal함수는 서버가 새 WAL 파일을 시작하도록 합니다. 그러면 서버가 변경사항이 포함된 WAL 파일을 보관처리할 수 있습니다. - 백업 계획의 복구 기간에 기록된 시간이 포함되어 있는지 확인합니다.
test -n "$PITR_TIME" || { echo "PITR_TIME is not set. Run step 2 again."; exit 1; } echo "$PITR_TIME" ansible-playbook status.yaml -i deployment_spec.yaml \ -e resource_type=BackupPlan -e resource_name=s3-backup-planPITR_TIME값이recoveryWindow필드의begin값 뒤에 있는지 확인합니다. - 녹화된 시간에 대한
Restore리소스를 만듭니다. 그런 다음 리소스를 적용합니다.cat > restore_pitr.yaml <<EOF Restore: metadata: name: s3-restore-pitr spec: sourceDBCluster: $CLUSTER pointInTime: "$PITR_TIME" EOF ansible-playbook restore.yaml -i deployment_spec.yaml \ -e resource_spec=restore_pitr.yaml - 복원 작업이 완료되었는지 확인합니다.
ansible-playbook status.yaml -i deployment_spec.yaml \ -e resource_type=Restore -e resource_name=s3-restore-pitrphase필드에ProvisionSucceeded이 표시되는지 확인합니다. 단계가ProvisionSucceeded이 아니면 1분 정도 기다린 후 명령어를 다시 실행합니다. - 행 수를 계산합니다.
출력에psql -c "SELECT pg_catalog.count(*) FROM public.orders;"1500이 표시되는지 확인합니다.
8. 삭제
Google Cloud 계정에 요금이 청구되지 않도록 하려면 이 Codelab과 RPM 조정자를 사용하여 GCE VM에 AlloyDB Omni 고가용성 클러스터 배포 Codelab의 리소스를 삭제하세요. 먼저 백업 리소스를 삭제한 다음 클러스터와 컴퓨팅 환경을 삭제합니다.
- 제어 VM에서 삭제 플레이북을 만듭니다.
cat > delete.yaml <<EOF - name: Delete AlloyDB Omni resources hosts: localhost roles: - role: google.alloydbomni_orchestrator.delete EOF - 백업을 나열합니다.
출력에ansible-playbook status.yaml -i deployment_spec.yaml -e resource_type=Backups3-backup-1백업이 표시되는지 확인합니다. s3-backup-1백업을 삭제합니다.ansible-playbook delete.yaml -i deployment_spec.yaml \ -e resource_type=Backup -e resource_name=s3-backup-1- 백업 계획을 삭제합니다.
ansible-playbook delete.yaml -i deployment_spec.yaml \ -e resource_type=BackupPlan -e resource_name=s3-backup-plan - RPM 조정자를 사용하여 GCE VM에 AlloyDB Omni 고가용성 클러스터 배포 Codelab의 리소스 정리 단계에 따라 클러스터와 컴퓨팅 환경을 삭제합니다. MinIO 서버와 그 안의 백업은 제어 VM에 있습니다. 컴퓨팅 환경을 삭제하면 서버와 백업이 모두 삭제됩니다.
9. 축하합니다
축하합니다 RPM 조정자를 사용하여 AlloyDB Omni용 S3 호환 객체 스토리지에 고가용성 (HA) 클러스터를 백업했습니다. 그런 다음 백업에서 클러스터를 복원했습니다.
학습한 내용
- MinIO를 S3 호환 객체 스토리지로 설치하고 실행하는 방법
- 백업 계획 및 주문형 백업을 만드는 방법
- 백업에서 특정 시점으로 클러스터를 복원하는 방법
자세한 내용은 다음 페이지를 참조하세요.