prod DB 를 RDS 에서 자체 관리 EC2 MySQL 로 이관 - #899
Conversation
- 신규 AWS Free Plan 이 RDS 의 backup_retention_period > 0 을 거부해 자동 백업·PITR 을 못 쓰는 상태였다. 관리형 비용을 내면서 관리형의 핵심 이점을 못 받고 있어, 백업을 직접 통제하는 쪽으로 전환한다 - 앱 박스 동거를 먼저 검토했으나 prod 앱이 메모리 캡에 100% 붙어 스왑 454MB 를 쓰고 있어 불가능했다. 별도 박스로 분리한다 - 사이즈는 t4g.micro. dev 의 같은 구성이 111MB / CPU 0.97% 를 쓰고 데이터가 2.1MB 라 버퍼풀에 전량이 올라간다. small 로 올리면 월 $20.65 로 RDS($20.87)와 같아져 이관 명분이 사라지고, nano 는 실가용 400MB 라 상시 스왑이다 - 기본 설정으로 띄웠더니 RAM 234MB + swap 185MB 로 캡(384m)을 넘겨 상시 스왑이었다. performance_schema=OFF · 버퍼풀 64M · max_connections 60 으로 191MB(swap 0)까지 낮췄다 - 백업 검증 중 박스가 자기 백업을 못 읽어 복구가 막히는 걸 발견해 IAM 에 GetObject·ListBucket 을 더했다. Delete 는 계속 주지 않는다 - 이 버킷이 유일한 복구 경로라 침해 시에도 지워지지 않아야 한다 - 데이터 소멸 경로를 막기 위해 루트 볼륨 delete_on_termination=false 와 lifecycle ignore_changes=[ami, user_data] 를 걸었다. 둘 다 terraform 이 인스턴스를 파괴·재생성하는 사유이고, 이 박스에서 그것은 곧 DB 소멸이다 - MySQL 기동·백업 cron 설치를 user_data 가 아니라 별도 멱등 스크립트(provision-db.sh)에 둔 이유도 같다. user_data 는 첫 부팅에만 돌아 수정 반영에 인스턴스 교체가 필요하다
|
Discord 스레드 연동용 메타데이터입니다. discord-pr-bot 워크플로가 자동 생성하며, 수정·삭제하면 PR 과 Discord 알림 연동이 끊깁니다. |
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Path: .coderabbit.yml Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (5)
💤 Files with no reviewable changes (2)
🚧 Files skipped from review as they are similar to previous changes (1)
Walkthrough자체 관리 MySQL용 DB EC2와 Docker 런타임을 추가했다. SSM에서 자격증명을 조회하고, 매일 Changes자체 관리 MySQL 전환 기반
Estimated code review effort: 4 (Complex) | ~45 minutes Sequence Diagram(s)sequenceDiagram
participant Cron
participant BackupScript
participant SSM
participant MySQL
participant S3
Cron->>BackupScript: 19:00 UTC 백업 실행
BackupScript->>SSM: DB 이름·비밀번호·버킷 조회
BackupScript->>MySQL: mysqldump 실행
BackupScript->>S3: gzip 백업 업로드
S3-->>BackupScript: 업로드 결과 반환
Assessment against linked issues
🚥 Pre-merge checks | ✅ 2✅ Passed checks (2 passed)
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 5
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@infra/scripts/provision-db.sh`:
- Around line 37-40: Separate the MySQL root credential from the application
credential: update the provisioning flow around DB_NAME/DB_PASSWORD to load a
distinct SecureString parameter named db-root-password and use it only for
MYSQL_ROOT_PASSWORD, while retaining DB_PASSWORD for the application account.
Update db-backup.sh to retrieve db-root-password instead of db-password for root
authentication, and ensure the new parameter is referenced consistently.
- Around line 102-109: Update the cron setup around CRON_LINE so it invokes a
Bash wrapper with pipefail instead of directly piping piki-db-backup.sh to
logger. Ensure the wrapper sends backup output to journald while preserving and
returning piki-db-backup.sh’s exit status, allowing cron monitoring to detect
failures.
In `@terraform/db_ec2.tf`:
- Around line 106-110: Enable S3 versioning for the bucket resource
aws_s3_bucket.db_backup and add a lifecycle rule that expires noncurrent object
versions after the configured retention period. Keep the existing backup access
policy, and ensure the lifecycle configuration applies to the backup objects.
- Around line 60-62: Remove the lifecycle ignore_changes setting for ingress so
Terraform detects and removes unauthorized MySQL access rules. Keep ingress
managed by the security group resource, and manage any required SSH exceptions
through Terraform variables and rules rather than ignoring ingress changes.
- Around line 265-270: Update the lifecycle block for the DB EC2 instance to add
prevent_destroy = true alongside the existing ignore_changes settings. Preserve
the current AMI and user_data ignore behavior while preventing Terraform destroy
or replacement operations outside the documented migration procedure.
🪄 Autofix
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yml
Review profile: CHILL
Plan: Pro Plus
Run ID: 769812ed-4125-4b0b-8b7d-8e8a705df465
📒 Files selected for processing (6)
infra/scripts/db-backup.shinfra/scripts/provision-db.shterraform/db_ec2.tfterraform/outputs.tfterraform/terraform.tfvars.exampleterraform/variables.tf
- cron 이 백업 스크립트를 logger 로 파이프해, 파이프라인 종료 코드가 항상 마지막 명령(logger)의 0 이 되고 있었다. 백업이 실패해도 성공으로 보여 실패 감지를 붙일 수 없는 구조라, bash -o pipefail 로 감싸 실패 코드가 올라오게 했다. 박스에서 대조 확인했다 - 기존 구조는 종료코드 0, 수정 후 1 - DB 보안그룹의 ingress ignore_changes 를 걷어냈다. 앱 SG 를 따라 넣었지만 사정이 다르다. 앱 SG 는 콘솔로 추가된 접속 IP 가 쌓여 있어 terraform 이 덮으면 배포·SSH 가 끊기지만, 이 SG 는 방금 만들어 그런 이력이 없고 terraform 이 유일한 관리자다. 그대로 두면 누가 콘솔에서 3306 을 열어도 apply 가 잡아내지 못한다 (#223 이 기존 SG 의 ignore_changes 를 걷어내는 방향이라 새 리소스가 역행할 이유도 없다) - 인스턴스에 prevent_destroy 를 더했다. ignore_changes 가 막는 것은 속성 변경으로 인한 재생성뿐이라, destroy 를 직접 부르거나 다른 사유로 replace 가 잡히면 그대로 지워진다. RDS 의 deletion_protection 과 같은 결의 마지막 층이다 - plan 으로 확인한 결과 세 변경 모두 실제 AWS 리소스에는 영향이 없다(No changes). SG 는 drift 가 없었고 lifecycle 은 terraform 메타 설정이다
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@terraform/db_ec2.tf`:
- Around line 268-275: Update the EC2 instance resource containing this
lifecycle block to enable AWS-level termination protection with
disable_api_termination, preserving the existing prevent_destroy behavior.
Ensure the root EBS data survives replacement and is reattached to the
replacement instance before provisioning MySQL, using an explicit preserved
volume and attachment if necessary. Keep termination protection enabled by
default and require an approved workflow to disable it for migration or
retirement.
🪄 Autofix
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yml
Review profile: CHILL
Plan: Pro Plus
Run ID: 4a26ad71-2be2-46e2-9882-ad9a227d9046
📒 Files selected for processing (2)
infra/scripts/provision-db.shterraform/db_ec2.tf
🚧 Files skipped from review as they are similar to previous changes (1)
- infra/scripts/provision-db.sh
- root 와 앱 계정이 같은 비밀번호(db-password)를 쓰고 있었다. 앱 자격증명이 새는 순간 DB 전체 권한까지 함께 넘어가는 구조라, SSM 에 db-root-password 를 신설해 root 전용으로 분리했다. 앱은 admin 계정으로 붙으므로 서비스 영향이 없고, root 사용처는 백업 스크립트 하나뿐이다 - 분리하면서 root@% 가 있다는 것도 드러났다. 이미지의 MYSQL_ROOT_HOST 기본값이 % 라 네트워크 너머에서도 root 로 붙을 수 있었다. 보안그룹이 앱 박스만 통과시키지만 그 박스가 뚫리면 그대로 DB 전체 권한이 넘어가므로, 계정을 제거하고 MYSQL_ROOT_HOST=localhost 를 명시해 재생성 때도 안 생기게 했다. root 는 컨테이너 안에서만 쓰이니 잃는 게 없다 - 검증: 새 비번으로 root 접속 성공, 앱 비번으로는 거부(Access denied), 계정 목록에 root@% 없음, 백업 수동 실행 성공(262KB), 앱 헬스 UP + DB 오류 0건 - 기존 컨테이너에는 ALTER USER 와 DROP USER 로 적용했다. MYSQL_ROOT_PASSWORD 는 컨테이너 최초 생성 때만 쓰여, 스크립트 수정만으로는 이미 뜬 인스턴스에 반영되지 않는다
- prevent_destroy 는 terraform 이 파괴 계획을 거부하게 할 뿐이라, 콘솔·CLI·API 로 직접 종료하는 경로는 그대로 열려 있었다. disable_api_termination 을 더해 두 층에서 막는다 - 함께 root 볼륨 보존의 한계를 주석에 박았다. delete_on_termination=false 는 볼륨을 남길 뿐, 남은 볼륨이 새 인스턴스에 자동으로 붙지는 않는다. 박스를 다시 만들면 새 루트 볼륨으로 떠서 provision-db.sh 가 빈 MySQL 을 기동하므로, 데이터가 있는데도 빈 상태로 운영될 수 있다. 주 복구 경로는 S3 백업이고 볼륨 보존은 백업까지 실패했을 때의 마지막 수동 회수 수단이라는 것을 코드가 말하게 했다 - 적용 직후 describe-instance-attribute 가 한동안 false 를 반환해 미적용으로 오인했다. CloudTrail 상 요청은 에러 없이 성공해 있었고, 시간이 지나자 True 로 반영됐다(AWS 반영 지연). 실측 True + plan No changes 로 정합을 확인했다 - EBS 볼륨을 aws_ebs_volume + aws_volume_attachment 로 분리하는 안은 채택하지 않았다. 운영 중인 DB 의 저장 구조를 바꾸는 작업이라 범위가 크고, 주 복구 경로인 S3 백업이 이미 검증돼 있다
- RDS 를 걷어내면서 관측이 후퇴했다는 것을 뒤늦게 확인했다. 관리형일 때는 CloudWatch 가 메모리(FreeableMemory)·연결 수·디스크 여유·쿼리 지연을 자동으로 줬는데, EC2 기본 메트릭에는 메모리조차 없다. 박스가 죽어가는 걸 알아챌 수단이 아예 없어, 다른 박스(core·extractor·renderer)와 같은 alloy 블록을 붙인다 - 실측으로 부담을 확인했다. 519 series, alloy 메모리 54MB, 호스트 여유 482MB. Grafana 무료 한도(10k)에 대해 여유가 있고, 전송도 정상이다(39KB 송신, 재시도·실패 0) - MySQL 컨테이너 로그는 보내지 않는다. 블록의 수집 대상이 docker label opt-in 인데, mysql·redis 로그를 제외하는 기존 정책과 결이 같아 여기서도 유지한다. 내부 지표(연결 수·쿼리 지연)는 mysqld_exporter 가 필요한 별도 작업이다 - cron 갱신부가 두 번째 실행부터 조용히 죽고 있었다. crontab 에 우리 줄만 있으면 grep -v 의 출력이 0건이라 종료 코드가 1 이고, set -euo pipefail 이 그것을 실패로 보고 스크립트를 끊는다. 첫 실행은 crontab 이 비어 이 경로를 안 타므로 드러나지 않았다. 등록/갱신 분기를 없애고 || true 로 받아 멱등을 단순화했다 - 2회 연속 실행으로 exit=0 확인 - alloy 블록은 core 에 복사하지 않고 실행 때마다 infra 에서 올린다. 그 블록의 SSOT 는 TeamPiKi/infra 이고, 사본을 두면 조용히 갈라진다
There was a problem hiding this comment.
Actionable comments posted: 2
🧹 Nitpick comments (1)
infra/scripts/db-backup.sh (1)
50-57: 🩺 Stability & Availability | 🔵 Trivial백업 성공 조건에 복구 검증을 추가하세요.
파일 크기가 1024바이트 이상이고 S3 업로드가 성공해도 실제 복구 가능성은 확인되지 않습니다. MySQL 권한, 이벤트, 루틴 또는 향후 스키마 변경 때문에 복원이 실패해도 현재 경로는 정상 백업으로 기록합니다.
격리된 MySQL 8.4 컨테이너에 주기적으로 백업을 복원하세요. 복원 후 테이블 목록과 핵심 행 수를 검증하고 실패를 알림으로 연결하세요.
As per path instructions, "데이터 정합성"과 "운영 리스크"를 우선 검토했습니다.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@infra/scripts/db-backup.sh` around lines 50 - 57, 백업 성공 조건에 파일 크기와 S3 업로드뿐 아니라 실제 복구 검증을 포함하세요. db-backup.sh의 WORK_DIR/FILE 처리 흐름에 격리된 MySQL 8.4 컨테이너로 백업을 복원하는 단계를 추가하고, 복원 후 테이블 목록과 핵심 행 수를 검증하세요. 복원 또는 검증이 실패하면 업로드 성공 여부와 관계없이 기존 log 알림을 통해 실패를 전달하고 비정상 종료하도록 하세요.Source: Path instructions
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@infra/scripts/provision-db.sh`:
- Around line 138-140: Update the Alloy provisioning check around ALLOY_DIR and
provision-alloy.sh so a missing required script fails the provisioning flow with
exit 1 instead of continuing. Only allow the installation to be skipped when an
explicit --skip-alloy option is provided, while preserving the existing Alloy
setup path otherwise.
- Around line 44-46: Update the existing-container handling in the MySQL
provisioning flow to validate the rotated SSM credentials with mysqladmin ping
or database connections using both the root and app accounts before treating
provisioning as successful. If either check fails, do not exit successfully; run
the credential-rotation procedure using ALTER USER ... IDENTIFIED BY ... and
FLUSH PRIVILEGES, then verify both accounts with the new passwords.
---
Nitpick comments:
In `@infra/scripts/db-backup.sh`:
- Around line 50-57: 백업 성공 조건에 파일 크기와 S3 업로드뿐 아니라 실제 복구 검증을 포함하세요. db-backup.sh의
WORK_DIR/FILE 처리 흐름에 격리된 MySQL 8.4 컨테이너로 백업을 복원하는 단계를 추가하고, 복원 후 테이블 목록과 핵심 행 수를
검증하세요. 복원 또는 검증이 실패하면 업로드 성공 여부와 관계없이 기존 log 알림을 통해 실패를 전달하고 비정상 종료하도록 하세요.
🪄 Autofix
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yml
Review profile: CHILL
Plan: Pro Plus
Run ID: 1fdef8ca-6f60-4790-9fb8-3bce1fb21b70
📒 Files selected for processing (3)
infra/scripts/db-backup.shinfra/scripts/provision-db.shterraform/db_ec2.tf
🚧 Files skipped from review as they are similar to previous changes (1)
- terraform/db_ec2.tf
- 자체 관리 MySQL 로 옮긴 뒤 관찰 기간을 뒀고, 종료 조건이 모두 충족돼 폐기한다. 첫 자동 백업이 사람 손 없이 성공했고(19:00 UTC, 2초), 이관 창에서 RDS 에 들어간 행은 0건이었다(마지막 쓰기가 덤프보다 3시간 43분 앞섬) - 삭제는 두 단계로 나눴다. deletion_protection 이 true 인 동안은 terraform 이 삭제를 시도조차 못 하므로 먼저 false 로 apply 한 뒤 리소스를 제거했다. 이 마찰은 의도된 것이라 한 번에 지우지 않았다 - 최종 스냅샷 team3-dev-mysql-final 이 남았다(20GB, available). 폐기 후의 마지막 되돌림 지점이다 - 함께 사라진 것: RDS 보안그룹(db_ec2.tf 의 것이 대신한다), DB 서브넷 그룹, rds_endpoint·rds_address output. private subnet 자체는 vpc.tf 에 남긴다 - 비용이 없고 향후 다른 용도가 생길 수 있다 - 앱 무영향을 확인했다(헬스 UP, DB 오류 0건). 앱은 이미 새 DB 만 보고 있어 이 삭제가 트래픽 경로에 닿지 않는다
- MYSQL_* 환경변수는 컨테이너 최초 생성 때만 쓰인다. 그 뒤 SSM 값을 바꾸면 DB 안 계정은 옛 비밀번호로 남아 둘이 조용히 갈라지고, 그 상태로 스크립트가 성공하면 나중에 그 자격증명을 쓰는 쪽(앱 배포·백업 cron)이 대신 터진다. readiness 뒤에 root·app 두 계정으로 실제 로그인을 시도해 어긋나면 회전 절차를 안내하고 중단한다 - 자동 회전(ALTER USER)까지는 하지 않는다. 앱 계정 비밀번호를 스크립트가 임의로 바꾸면 붙어 있던 커넥션이 끊기므로, 회전은 사람이 배포 창에서 할 일이다 - alloy 블록이 없을 때 경고만 하고 넘어가던 것을 실패로 바꿨다. 관측이 빠진 채 "프로비저닝 완료"가 찍히면 그 공백을 아무도 모른다 - 실제로 이 박스는 관측 없이 며칠 돌 뻔했다. 의도적 생략은 --skip-alloy 로 명시한다 - 박스에서 네 경로를 확인했다: 정상 exit=0(자격증명 검증 통과 + alloy 기동), alloy 누락 exit=1, --skip-alloy exit=0, 알 수 없는 인자 exit=2. 검증 로직 자체도 틀린 비밀번호로 대조해 exit=1 이 나오는 것을 확인했다
Situation
db.t4g.micro)인데 자동 백업이 꺼져 있었다. 신규 AWS Free Plan 이backup_retention_period > 0을 거부해서이고, 그 결과 복구 지점이 수동 스냅샷 1개뿐이었다.Task
Action
배치 결정: 전용 박스
실측이 선택지를 좁혔다. prod 앱 박스는 여유 메모리가 563MB 뿐이고, 앱 컨테이너가 이미 캡(768MB)에 100% 붙어 swap 454MB 를 쓰고 있었다.
사이즈도 micro 여야 의미가 있었다.
인프라 (
terraform/db_ec2.tf)rds.tf와 대칭이라 무엇이 그 자리를 대신하는지 한눈에 드러난다.ignore_changes를 두지 않는다. 처음엔 앱 SG 패턴을 따라 넣었으나 사정이 다르다. 앱 SG 는 콘솔로 추가된 접속 IP 가 쌓여 있어 terraform 이 덮으면 배포가 끊기지만, 이 SG 는 새로 만들어 그런 이력이 없고 terraform 이 유일한 관리자다. 그대로 두면 누가 콘솔에서 3306 을 열어도 apply 가 잡아내지 못한다.MySQL 메모리 튜닝
기본 설정으로 띄웠더니 RAM 234MB + swap 185MB = 419MB 로 컨테이너 캡(384m)을 넘겨 상시 스왑 상태였다. 데이터가 2.1MB 인데 과했다.
performance_schema=OFF가 가장 큰 몫이었다. 앱 지표는 Micrometer·Grafana 로 따로 받고 있어 DB 내부 계측을 켜 둘 실익이 없다.max_connections=60(기본 151). HikariCP 기본 풀이 10 이고 blue-green 전환 때만 잠시 2배가 된다.performance_schema=OFF면information_schema.PROCESSLIST가 비어 나온다. 연결 확인은SHOW PROCESSLIST를 쓴다.자격증명 분리
db-root-password를 신설해 root 전용으로 분리했다. 앱은admin계정으로 붙으므로 서비스 영향이 없었고, root 사용처는 백업 스크립트 하나뿐이다.root@%가 있다는 것도 드러났다. 이미지의MYSQL_ROOT_HOST기본값이%라 네트워크 너머에서도 root 접속이 가능했다. 보안그룹이 앱 박스만 통과시키지만 그 박스가 뚫리면 그대로 DB 전체 권한이 넘어가므로, 계정을 제거하고MYSQL_ROOT_HOST=localhost를 명시해 재생성 때도 생기지 않게 했다.GRANT ALL ON team3.*)을 가진 계정을 쓰는 것은 남아 있다.백업
mysqldump --single-transaction-> gzip -> S3, cron 04:00 KST.--single-transaction이라 백업 중에도 서비스가 그대로 돈다.logger로 파이프하면 파이프라인의 종료 코드가logger의 것(항상 0)이 되어, 백업이 실패해도 성공으로 보인다.bash -o pipefail로 감쌌다.grep -v가 0건 매칭으로 종료 코드 1 을 반환하는데set -euo pipefail이 그걸 실패로 처리했다. 첫 실행은 crontab 이 비어 이 경로를 안 타므로 드러나지 않았다. 등록/갱신 분기를 없애고|| true로 받아 멱등을 단순화했다.GetObject·ListBucket을 더했다.DeleteObject는 끝까지 주지 않는다. 이 버킷이 유일한 복구 경로라 침해 시에도 지워지지 않아야 한다.데이터 이관 (무중단)
RELOAD권한이 없어FLUSH TABLES WITH READ LOCK에서 막혔다. GTID 수집이 원인이라--set-gtid-purged=OFF --no-tablespaces로 우회했다.관측 회복
RDS 를 걷어내며 관측이 후퇴한다는 것을 뒤늦게 알아챘다. 관리형일 때 CloudWatch 가 자동으로 주던 것이 EC2 에는 없다.
데이터 소멸 경로 차단
인스턴스가 사라지는 경로를 층별로 막았다.
ignore_changes = [ami, user_data]prevent_destroy = truedisable_api_termination = trueprevent_destroy는 terraform 안에서만 유효해 콘솔에서 종료 버튼을 누르는 경로가 열려 있었다.delete_on_termination = false는 자동 복구 장치가 아니다. 볼륨은 남지만 새 인스턴스에 자동으로 붙지 않는다. 박스를 다시 만들면 새 루트 볼륨으로 떠서provision-db.sh가 빈 MySQL 을 기동하므로, 데이터가 남아 있는데도 빈 상태로 운영될 수 있다. 그 한계를 코드 주석에 명시했다. 주 복구 경로는 S3 백업이고, 볼륨 보존은 백업까지 실패했을 때의 마지막 수동 회수 수단이다.user_data가 아니라 별도 멱등 스크립트(provision-db.sh)에 뒀다.user_data는 첫 부팅에만 돌아 수정 반영에 인스턴스 교체가 필요하다.RDS 폐기
deletion_protection이 true 인 동안은 terraform 이 삭제를 시도조차 못 하므로, 먼저 그것만 false 로 apply 한 뒤 리소스를 제거했다. 그 마찰은 의도된 것이라 한 번에 지우지 않았다.db_ec2.tf의 것이 대신한다), DB 서브넷 그룹,rds_endpoint·rds_addressoutput. private subnet 자체는vpc.tf에 남긴다 (비용이 없고 향후 용도가 생길 수 있다).Result
이관부터 폐기까지 완료했고, 각 단계를 실측으로 검증했다.
root@%제거DisableApiTermination = Trueteam3-dev-mysql-final확보검토 후 채택하지 않은 것
DeleteObject도 주지 않아 versioning 이 막을 사고가 없다. 켜면 만료를 current/noncurrent 두 축으로 관리해야 해 복잡도만 는다aws_ebs_volume로 분리후속
journalctl -t piki-db-backup으로 사람이 확인하는 구조다. 이것이 유일한 복구 경로이므로 알림이 필요하지만, Grafana 무료 한도가 빠듯해 이번 범위에서 뺐다. 위 cron 수정으로 실패 코드가 올라오게 되어, 알림을 붙이면 실제로 동작한다.mysqld_exporter가 별도로 필요하다. 이번엔 호스트 메트릭까지만 붙였다.github_ecr_pushrole 의 신뢰 정책이 실제 AWS 는 와일드카드(repo:TeamPiKi/core:*), 코드는 환경 2개 제한으로 어긋나 있다. 코드 쪽이 더 엄격하지만 적용 시 배포가 끊길 수 있어-target으로 제외했다. 별도로 다뤄야 한다.연관 이슈
Summary by CodeRabbit
새 기능
운영 개선