Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion config/secrets
6 changes: 6 additions & 0 deletions environment/prod/main.tf
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,12 @@ module "prod_stack" {
instance_type = var.server_instance_type
db_instance_class = var.db_instance_class

# DB EC2 설정
enable_db_ec2 = true
db_instance_type = var.db_ec2_instance_type
db_ami_id = var.db_ec2_ami_id
db_subnet_id = var.db_ec2_subnet_id

# 보안 그룹 규칙
api_ingress_rules = var.api_ingress_rules
db_ingress_rules = var.db_ingress_rules
Expand Down
15 changes: 15 additions & 0 deletions environment/prod/variables.tf
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,21 @@ variable "db_instance_class" {
type = string
}

variable "db_ec2_instance_type" {
description = "DB EC2 인스턴스 타입"
type = string
}

variable "db_ec2_ami_id" {
description = "DB EC2에 사용할 커스텀 AMI ID"
type = string
}

variable "db_ec2_subnet_id" {
description = "DB EC2를 배치할 Private Subnet ID"
type = string
}

variable "api_ingress_rules" {
description = "List of ingress rules for API Server"
type = list(object({
Expand Down
58 changes: 58 additions & 0 deletions modules/app_stack/db_ec2.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
data "cloudinit_config" "db_init" {
count = var.enable_db_ec2 ? 1 : 0
gzip = true
base64_encode = true

part {
content_type = "text/x-shellscript"
content = templatefile("${path.module}/scripts/mysql_setup.sh.tftpl", {
db_root_username_b64 = base64encode(var.db_username)
db_root_password_b64 = base64encode(var.db_password)
mysql_config_content = file("${path.module}/templates/mysql_tuning.cnf")
})
filename = "mysql_setup.sh"
}
}

resource "aws_instance" "db_server" {
count = var.enable_db_ec2 ? 1 : 0

ami = var.db_ami_id
instance_type = var.db_instance_type
subnet_id = var.db_subnet_id

vpc_security_group_ids = [aws_security_group.db_ec2_sg[count.index].id]
associate_public_ip_address = false
iam_instance_profile = var.ec2_iam_instance_profile
key_name = var.key_name

user_data_base64 = data.cloudinit_config.db_init[count.index].rendered

metadata_options {
http_endpoint = "enabled"
http_tokens = "required"
http_put_response_hop_limit = 1
}

root_block_device {
volume_size = 8
volume_type = "gp3"
encrypted = true
delete_on_termination = true
}

tags = {
Name = "solid-connection-db-mysql-${var.env_name}"
}

user_data_replace_on_change = false

lifecycle {
ignore_changes = [
user_data,
user_data_base64,
user_data_replace_on_change,
key_name,
]
}
Comment thread
coderabbitai[bot] marked this conversation as resolved.
}
9 changes: 9 additions & 0 deletions modules/app_stack/output.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
output "db_server_private_ip" {
description = "DB EC2 서버 private IP"
value = try(aws_instance.db_server[0].private_ip, null)
}

output "db_server_instance_id" {
description = "DB EC2 서버 인스턴스 ID"
value = try(aws_instance.db_server[0].id, null)
}
61 changes: 61 additions & 0 deletions modules/app_stack/scripts/mysql_setup.sh.tftpl
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
#!/bin/bash
set -euo pipefail

DB_ROOT_USER="$(printf '%s' '${db_root_username_b64}' | base64 -d)"
DB_ROOT_PASS="$(printf '%s' '${db_root_password_b64}' | base64 -d)"

mysql_escape() {
local value="$1"
value="$${value//\\/\\\\}"
value="$${value//\'/\\\'}"
printf '%s' "$value"
}

DB_ROOT_USER_SQL="$(mysql_escape "$DB_ROOT_USER")"
DB_ROOT_PASS_SQL="$(mysql_escape "$DB_ROOT_PASS")"

command -v docker >/dev/null
systemctl enable --now docker
docker image inspect mysql:8.4 >/dev/null

mkdir -p /var/lib/mysql
chown -R 999:999 /var/lib/mysql
chmod 750 /var/lib/mysql

mkdir -p /etc/mysql/conf.d
cat > /etc/mysql/conf.d/tuning.cnf <<'CNFEOF'
${mysql_config_content}
CNFEOF
chmod 644 /etc/mysql/conf.d/tuning.cnf

docker rm -f mysql-server 2>/dev/null || true

docker run -d \
--name mysql-server \
--restart always \
-p 3306:3306 \
-v /var/lib/mysql:/var/lib/mysql \
-v /etc/mysql/conf.d:/etc/mysql/conf.d \
-e MYSQL_ROOT_PASSWORD="$DB_ROOT_PASS" \
mysql:8.4

MYSQL_READY=false
for i in $(seq 1 30); do
if docker exec mysql-server mysqladmin ping -uroot -p"$DB_ROOT_PASS" 2>/dev/null; then
MYSQL_READY=true
break
fi
sleep 2
done

if [ "$MYSQL_READY" != "true" ]; then
echo "MySQL container did not become ready within 60 seconds." >&2
docker logs --tail 100 mysql-server >&2 || true
exit 1
fi

docker exec -i mysql-server mysql -uroot -p"$DB_ROOT_PASS" <<SQLEOF
CREATE USER IF NOT EXISTS '$DB_ROOT_USER_SQL'@'%' IDENTIFIED BY '$DB_ROOT_PASS_SQL';
GRANT ALL PRIVILEGES ON *.* TO '$DB_ROOT_USER_SQL'@'%' WITH GRANT OPTION;
FLUSH PRIVILEGES;
SQLEOF
29 changes: 28 additions & 1 deletion modules/app_stack/security_groups.tf
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,34 @@ resource "aws_security_group" "api_sg" {
}
}

# 2. RDS용 보안 그룹 (API Server만 믿음)
# 2. DB EC2용 보안 그룹 (API Server만 믿음)
resource "aws_security_group" "db_ec2_sg" {
count = var.enable_db_ec2 ? 1 : 0
name = "sc-${var.env_name}-db-ec2-sg"
description = "Security Group for DB EC2"
vpc_id = var.vpc_id

ingress {
description = "MySQL from API server"
from_port = 3306
to_port = 3306
protocol = "tcp"
security_groups = [aws_security_group.api_sg.id]
}

egress {
from_port = 0
to_port = 0
protocol = "-1"
cidr_blocks = ["0.0.0.0/0"]
}

tags = {
Name = "solid-connection-${var.env_name}-db-ec2-sg"
}
Comment thread
coderabbitai[bot] marked this conversation as resolved.
}

# 3. RDS용 보안 그룹 (API Server만 믿음)
resource "aws_security_group" "db_sg" {
count = var.enable_rds ? 1 : 0
name = "sc-${var.env_name}-db-sg"
Expand Down
6 changes: 6 additions & 0 deletions modules/app_stack/templates/mysql_tuning.cnf
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
[mysqld]
max_connections = 64
innodb_buffer_pool_size = 128M
innodb_redo_log_capacity = 128M
bind-address = 0.0.0.0
skip-name-resolve
24 changes: 24 additions & 0 deletions modules/app_stack/variables.tf
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,30 @@ variable "enable_rds" {
default = true
}

variable "enable_db_ec2" {
description = "DB EC2 사용 여부"
type = bool
default = false
}

variable "db_instance_type" {
description = "DB EC2 인스턴스 타입"
type = string
default = null
}

variable "db_ami_id" {
description = "DB EC2에 사용할 커스텀 AMI ID"
type = string
default = null
}

variable "db_subnet_id" {
description = "DB EC2를 배치할 Private Subnet ID"
type = string
default = null
}

variable "ec2_iam_instance_profile" {
description = "EC2에 연결할 IAM Instance Profile 이름"
type = string
Expand Down
Loading