feat: Prod DB EC2 리소스 추가#53
Conversation
📝 WalkthroughWalkthrough
ChangesDB EC2 리소스 추가 및 Prod 환경 적용
Sequence Diagram(s)sequenceDiagram
participant Terraform as Terraform
participant Prod as environment/prod
participant AppStack as modules/app_stack
participant CloudInit as cloudinit_config.db_init
participant EC2 as aws_instance.db_server
participant Docker as Docker
participant MySQL as mysql:8.4
Prod->>AppStack: enable_db_ec2=true, db_instance_type, db_ami_id, db_subnet_id 전달
AppStack->>CloudInit: mysql_setup.sh.tftpl 기반 user_data_base64 생성
AppStack->>EC2: db_ec2_sg, private subnet, IMDS 제한, gp3 EBS 적용
EC2->>CloudInit: 부팅 시 초기화 스크립트 실행
CloudInit->>Docker: docker systemd 활성화 및 mysql:8.4 컨테이너 실행
CloudInit->>MySQL: mysqladmin ping 대기 후 SQL 실행
AppStack-->>Terraform: db_server_private_ip, db_server_instance_id 출력
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes Suggested labels
Suggested reviewers
Poem
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ 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 |
Terraform Plan:
|
Terraform Plan:
|
Terraform Plan:
|
Terraform Plan:
|
There was a problem hiding this comment.
Actionable comments posted: 2
🧹 Nitpick comments (4)
modules/app_stack/db_ec2.tf (1)
43-45: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win공통 태그(
Project,Env) 누락
db_server도Name태그만 지정되어 있습니다. 프로바이더default_tags로 주입되지 않는다면 가이드라인대로Project = "solid-connection",Env = var.env_name태그를 추가해 주세요. (확인 스크립트는security_groups.tf코멘트 참조)As per coding guidelines: "Apply common tags to all AWS resources:
Project = \"solid-connection\"andEnv = \"<environment-name>\"".🤖 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 `@modules/app_stack/db_ec2.tf` around lines 43 - 45, The tags block in the database server resource (RDS instance) currently only includes the Name tag. Add the missing required tags Project = "solid-connection" and Env = var.env_name to the tags object alongside the existing Name tag to comply with the common tagging guidelines.Source: Coding guidelines
modules/app_stack/scripts/mysql_setup.sh.tftpl (2)
43-49: 🔒 Security & Privacy | 🔵 Trivial | 💤 Low value비밀번호가 명령줄 인자로 노출됨 (선택)
-p"$DB_ROOT_PASS"는 컨테이너 내부 프로세스 목록(ps)에 노출됩니다.MYSQL_PWD환경변수나 임시 옵션 파일(--defaults-extra-file) 사용을 고려해 노출 표면을 줄일 수 있습니다. private 전용 + SG 제한 환경이라 위험도는 낮습니다.🤖 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 `@modules/app_stack/scripts/mysql_setup.sh.tftpl` around lines 43 - 49, The MySQL root password in DB_ROOT_PASS is exposed as a command-line argument in both the mysqladmin ping command and the docker exec mysql command, which can be visible in process listings. Remove the inline -p"$DB_ROOT_PASS" parameters from these commands and instead pass the MYSQL_PWD environment variable through the docker exec invocation using the -e flag, which keeps the password from appearing in process listings.
42-47: 🩺 Stability & Availability | 🔵 Trivial | 💤 Low value헬스체크 실패 시 명시적 처리 권장 (선택)
30회(약 60초) 동안
mysqladmin ping이 모두 실패해도 루프는 정상 종료되고, 이후 49행의docker exec에서야set -e로 스크립트가 종료됩니다. 컨테이너가 끝내 안 떴는지 진단하기 어려우므로, 루프 후 ready 여부를 명시적으로 검사하고 실패 시 컨테이너 로그를 출력하면 부트스트랩 디버깅이 쉬워집니다.🤖 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 `@modules/app_stack/scripts/mysql_setup.sh.tftpl` around lines 42 - 47, The health check loop for the MySQL container (lines 42-47 with the for loop checking seq 1 30) exits normally even if all 30 iterations fail, causing the actual failure to only manifest later with set -e, making debugging difficult. After the loop completes, add an explicit check to verify that the mysql-server container successfully responded to the mysqladmin ping, and if the health check failed (the loop completed without breaking), output the container logs or exit with a clear error message before proceeding to the next operations.modules/app_stack/security_groups.tf (1)
46-51: 🔒 Security & Privacy | 🔵 Trivial | 💤 Low value아웃바운드 전체 허용(0.0.0.0/0) 검토 (선택)
Trivy(AWS-0104)가 무제한 egress를 지적합니다. 기존
api_sg와 동일한 패턴이라 일관성은 있으나, private 전용 DB 서버는 외부로 향하는 트래픽이 거의 없으므로 필요한 목적지(예: 패키지/이미지 미러, VPC 엔드포인트)로 제한하면 보안 태세가 개선됩니다.🤖 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 `@modules/app_stack/security_groups.tf` around lines 46 - 51, The egress rule in the security group configuration allows unrestricted outbound traffic to 0.0.0.0/0, which Trivy flags as AWS-0104 (overly permissive egress). Since this is a private database-only server with minimal outbound requirements, replace the broad 0.0.0.0/0 CIDR block in the cidr_blocks parameter with specific, necessary destinations such as the VPC CIDR range, package manager mirrors, or VPC endpoint IP ranges. This restricts outbound traffic to only the destinations actually required by the database server, improving the overall security posture while maintaining necessary functionality.Source: Linters/SAST tools
🤖 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 `@modules/app_stack/db_ec2.tf`:
- Around line 36-56: The EC2 instance in the database resource lacks protection
against AMI changes in its lifecycle configuration. When the db_ami_id variable
is updated, the instance will be recreated, and since MySQL data is stored on
the root EBS volume with delete_on_termination set to true, this will result in
data loss. Add ami to the ignore_changes list in the lifecycle block (which
already contains user_data, user_data_base64, user_data_replace_on_change, and
key_name) to prevent instance replacement when the AMI ID changes.
In `@modules/app_stack/security_groups.tf`:
- Around line 53-55: The db_ec2_sg security group resource is missing the
required standard tags according to the coding guidelines. The tags block
currently only includes the Name tag and is missing Project and Env tags. Add
the Project tag with value "solid-connection" and the Env tag with value
referencing var.env_name to the tags block in the db_ec2_sg resource to comply
with the coding guidelines. Ensure both tags are added alongside the existing
Name tag so all three tags are present in the resource definition.
---
Nitpick comments:
In `@modules/app_stack/db_ec2.tf`:
- Around line 43-45: The tags block in the database server resource (RDS
instance) currently only includes the Name tag. Add the missing required tags
Project = "solid-connection" and Env = var.env_name to the tags object alongside
the existing Name tag to comply with the common tagging guidelines.
In `@modules/app_stack/scripts/mysql_setup.sh.tftpl`:
- Around line 43-49: The MySQL root password in DB_ROOT_PASS is exposed as a
command-line argument in both the mysqladmin ping command and the docker exec
mysql command, which can be visible in process listings. Remove the inline
-p"$DB_ROOT_PASS" parameters from these commands and instead pass the MYSQL_PWD
environment variable through the docker exec invocation using the -e flag, which
keeps the password from appearing in process listings.
- Around line 42-47: The health check loop for the MySQL container (lines 42-47
with the for loop checking seq 1 30) exits normally even if all 30 iterations
fail, causing the actual failure to only manifest later with set -e, making
debugging difficult. After the loop completes, add an explicit check to verify
that the mysql-server container successfully responded to the mysqladmin ping,
and if the health check failed (the loop completed without breaking), output the
container logs or exit with a clear error message before proceeding to the next
operations.
In `@modules/app_stack/security_groups.tf`:
- Around line 46-51: The egress rule in the security group configuration allows
unrestricted outbound traffic to 0.0.0.0/0, which Trivy flags as AWS-0104
(overly permissive egress). Since this is a private database-only server with
minimal outbound requirements, replace the broad 0.0.0.0/0 CIDR block in the
cidr_blocks parameter with specific, necessary destinations such as the VPC CIDR
range, package manager mirrors, or VPC endpoint IP ranges. This restricts
outbound traffic to only the destinations actually required by the database
server, improving the overall security posture while maintaining necessary
functionality.
🪄 Autofix (Beta)
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.yaml
Review profile: CHILL
Plan: Pro
Run ID: 3aa6c31d-52db-42ff-beae-f50c37ced810
📒 Files selected for processing (9)
config/secretsenvironment/prod/main.tfenvironment/prod/variables.tfmodules/app_stack/db_ec2.tfmodules/app_stack/output.tfmodules/app_stack/scripts/mysql_setup.sh.tftplmodules/app_stack/security_groups.tfmodules/app_stack/templates/mysql_tuning.cnfmodules/app_stack/variables.tf
관련 이슈
작업 내용
Prod 환경에 DB EC2 리소스를 추가했습니다.
db_ec2_subnet_id로 지정한 private subnet에 배치됩니다.DB EC2의 MySQL 8.4 실행 방식을 추가했습니다.
db_ec2_ami_id를 연결했습니다.mysql:8.4이미지가 사전 준비되어 있어야 합니다.MySQL 초기 튜닝 설정을 분리했습니다.
modules/app_stack/templates/mysql_tuning.cnf파일로 튜닝 설정을 분리했습니다.innodb_log_file_size대신innodb_redo_log_capacity를 사용합니다.DB EC2를 Private Subnet에 명시적으로 배치하도록 변경했습니다.
db_ec2_subnet_id를 Prod 환경 변수로 추가했습니다.db_subnet_id를 app_stack 모듈에 전달하고, DB EC2의subnet_id로 사용합니다.DB EC2 관련 output과 tfvars 연결을 추가했습니다.
db_server_private_ipdb_server_instance_iddb_ec2_instance_typedb_ec2_ami_id특이 사항
DB EC2는 public subnet의 public IP 미할당 방식이 아니라, 명시적으로 private subnet에 배치됩니다.
db_ec2_subnet_id값은prod.tfvars에서 관리합니다.t4g-docker-mysql8.4-ami)의 root snapshot이 8GB라, DB EC2 root volume도 8GB로 맞췄습니다.이번 PR은 RDS를 제거하지 않습니다.
이번 PR은 MySQL data volume 분리를 포함하지 않습니다.
/var/lib/mysql을 사용합니다.이번 PR은 데이터 마이그레이션을 수행하지 않습니다.
이번 PR은
additional_db_users생성/권한 부여를 DB EC2에 적용하지 않습니다.이번 PR은 운영 중 MySQL 튜닝값 변경 반영 자동화를 포함하지 않습니다.
후속 작업 흐름은 다음과 같습니다.
리뷰 요구사항 (선택)
DB EC2의 private subnet 배치가 현재 Prod API 서버 접근 경로와 맞는지 확인해주세요.
DB EC2 root volume을 8GB로 둔 것과, MySQL data volume 분리를 ops: Prod DB 데이터 마이그레이션 (RDS → DB EC2) #51/feat: Prod DB EC2 전환에 따른 자동 백업 전략 수립 #48 후속 논의로 넘긴 것이 적절한지 확인해주세요.
DB EC2가 private-only로 생성되는 구성과 보안 그룹 범위를 확인해주세요.
커스텀 AMI 전제 조건이 적절한지 확인해주세요.
mysql:8.4이미지 pull 완료/var/lib/mysql초기 데이터 미포함MySQL 튜닝값을 bootstrap 시에만 적용하고, 운영 중 변경 반영은 후속 작업으로 분리하는 방향이 적절한지 의견 부탁드립니다.
#51에서 기존 RDS 접근 방식처럼 API 서버 EC2를 경유한 SSM 포트포워딩으로 DB EC2 계정/권한 및 마이그레이션 작업을 처리하는 방향에 대해 의견 부탁드립니다.
Summary by CodeRabbit
릴리스 노트