Skip to content

Commit 36b375e

Browse files
committed
chore[infra]: 테라폼 생성
1 parent 2bfd987 commit 36b375e

File tree

5 files changed

+381
-7
lines changed

5 files changed

+381
-7
lines changed

backend/Dockerfile

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
# 첫 번째 스테이지: 빌드 스테이지
2+
FROM gradle:jdk-21-and-23-graal-jammy AS builder
3+
4+
# 작업 디렉토리 설정
5+
WORKDIR /app
6+
7+
# 소스 코드와 Gradle 래퍼 복사
8+
COPY build.gradle .
9+
COPY settings.gradle .
10+
11+
# 종속성 설치
12+
RUN gradle dependencies --no-daemon
13+
14+
# 소스 코드 복사
15+
COPY .env .
16+
COPY src src
17+
18+
# 애플리케이션 빌드
19+
RUN gradle build --no-daemon
20+
21+
# 두 번째 스테이지: 실행 스테이지
22+
FROM container-registry.oracle.com/graalvm/jdk:21
23+
24+
# 작업 디렉토리 설정
25+
WORKDIR /app
26+
27+
# 첫 번째 스테이지에서 빌드된 JAR 파일 복사
28+
COPY --from=builder /app/build/libs/*.jar app.jar
29+
COPY --from=builder /app/.env .env
30+
31+
# 실행할 JAR 파일 지정
32+
ENTRYPOINT ["java", "-Dspring.profiles.active=prod", "-jar", "app.jar"]

infra/.gitignore

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,7 @@
11
.idea
2-
.terraform
2+
.terraform
3+
.terraform.lock.hcl
4+
terraform.tfstate
5+
terraform.tfstate.backup
6+
.terraform.tfstate.lock.info
7+
secrets.tf

infra/main.tf

Lines changed: 310 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,326 @@
11
terraform {
2-
// 자바의 import 와 비슷함
32
// aws 라이브러리 불러옴
43
required_providers {
54
aws = {
6-
source = "hashicorp/aws"
5+
source = "hashicorp/aws"
76
}
87
}
98
}
109

11-
# Configure the AWS Provider
10+
# AWS 설정 시작
1211
provider "aws" {
13-
region = "ap-northeast-2"
12+
region = var.region
1413
}
14+
# AWS 설정 끝
1515

16-
resource "aws_vpc" "example" {
16+
# VPC 설정 시작
17+
resource "aws_vpc" "vpc_1" {
1718
cidr_block = "10.0.0.0/16"
1819

20+
enable_dns_support = true
21+
enable_dns_hostnames = true
22+
23+
tags = {
24+
Name = "${var.prefix}-vpc-1"
25+
}
26+
}
27+
28+
resource "aws_subnet" "subnet_1" {
29+
vpc_id = aws_vpc.vpc_1.id
30+
cidr_block = "10.0.0.0/24"
31+
availability_zone = "${var.region}a"
32+
map_public_ip_on_launch = true
33+
34+
tags = {
35+
Name = "${var.prefix}-subnet-1"
36+
}
37+
}
38+
39+
resource "aws_subnet" "subnet_2" {
40+
vpc_id = aws_vpc.vpc_1.id
41+
cidr_block = "10.0.1.0/24"
42+
availability_zone = "${var.region}b"
43+
map_public_ip_on_launch = true
44+
45+
tags = {
46+
Name = "${var.prefix}-subnet-2"
47+
}
48+
}
49+
50+
resource "aws_subnet" "subnet_3" {
51+
vpc_id = aws_vpc.vpc_1.id
52+
cidr_block = "10.0.2.0/24"
53+
availability_zone = "${var.region}c"
54+
map_public_ip_on_launch = true
55+
56+
tags = {
57+
Name = "${var.prefix}-subnet-3"
58+
}
59+
}
60+
61+
resource "aws_subnet" "subnet_4" {
62+
vpc_id = aws_vpc.vpc_1.id
63+
cidr_block = "10.0.3.0/24"
64+
availability_zone = "${var.region}d"
65+
map_public_ip_on_launch = true
66+
67+
tags = {
68+
Name = "${var.prefix}-subnet-4"
69+
}
70+
}
71+
72+
resource "aws_internet_gateway" "igw_1" {
73+
vpc_id = aws_vpc.vpc_1.id
74+
75+
tags = {
76+
Name = "${var.prefix}-igw-1"
77+
}
78+
}
79+
80+
resource "aws_route_table" "rt_1" {
81+
vpc_id = aws_vpc.vpc_1.id
82+
83+
route {
84+
cidr_block = "0.0.0.0/0"
85+
gateway_id = aws_internet_gateway.igw_1.id
86+
}
87+
88+
tags = {
89+
Name = "${var.prefix}-rt-1"
90+
}
91+
}
92+
93+
resource "aws_route_table_association" "association_1" {
94+
subnet_id = aws_subnet.subnet_1.id
95+
route_table_id = aws_route_table.rt_1.id
96+
}
97+
98+
resource "aws_route_table_association" "association_2" {
99+
subnet_id = aws_subnet.subnet_2.id
100+
route_table_id = aws_route_table.rt_1.id
101+
}
102+
103+
resource "aws_route_table_association" "association_3" {
104+
subnet_id = aws_subnet.subnet_3.id
105+
route_table_id = aws_route_table.rt_1.id
106+
}
107+
108+
resource "aws_route_table_association" "association_4" {
109+
subnet_id = aws_subnet.subnet_4.id
110+
route_table_id = aws_route_table.rt_1.id
111+
}
112+
113+
resource "aws_security_group" "sg_1" {
114+
name = "${var.prefix}-sg-1"
115+
116+
ingress {
117+
from_port = 0
118+
to_port = 0
119+
protocol = "all"
120+
cidr_blocks = ["0.0.0.0/0"]
121+
}
122+
123+
egress {
124+
from_port = 0
125+
to_port = 0
126+
protocol = "all"
127+
cidr_blocks = ["0.0.0.0/0"]
128+
}
129+
130+
vpc_id = aws_vpc.vpc_1.id
131+
19132
tags = {
20-
Name = "example"
133+
Name = "${var.prefix}-sg-1"
21134
}
135+
}
136+
137+
# EC2 설정 시작
138+
139+
# EC2 역할 생성
140+
resource "aws_iam_role" "ec2_role_1" {
141+
name = "${var.prefix}-ec2-role-1"
142+
143+
# 이 역할에 대한 신뢰 정책 설정. EC2 서비스가 이 역할을 가정할 수 있도록 설정
144+
assume_role_policy = <<EOF
145+
{
146+
"Version": "2012-10-17",
147+
"Statement": [
148+
{
149+
"Sid": "",
150+
"Action": "sts:AssumeRole",
151+
"Principal": {
152+
"Service": "ec2.amazonaws.com"
153+
},
154+
"Effect": "Allow"
155+
}
156+
]
157+
}
158+
EOF
159+
160+
tags = {
161+
Name = "${var.prefix}-ec2-role-1"
162+
}
163+
}
164+
165+
# EC2 역할에 AmazonS3FullAccess 정책을 부착
166+
resource "aws_iam_role_policy_attachment" "s3_full_access" {
167+
role = aws_iam_role.ec2_role_1.name
168+
policy_arn = "arn:aws:iam::aws:policy/AmazonS3FullAccess"
169+
}
170+
171+
# EC2 역할에 AmazonEC2RoleforSSM 정책을 부착
172+
resource "aws_iam_role_policy_attachment" "ec2_ssm" {
173+
role = aws_iam_role.ec2_role_1.name
174+
policy_arn = "arn:aws:iam::aws:policy/service-role/AmazonEC2RoleforSSM"
175+
}
176+
177+
# IAM 인스턴스 프로파일 생성
178+
resource "aws_iam_instance_profile" "instance_profile_1" {
179+
name = "${var.prefix}-instance-profile-1"
180+
role = aws_iam_role.ec2_role_1.name
181+
182+
tags = {
183+
Name = "${var.prefix}-instance-profile-1"
184+
}
185+
}
186+
187+
locals {
188+
ec2_user_data_base = <<-END_OF_FILE
189+
#!/bin/bash
190+
# 가상 메모리 4GB 설정
191+
dd if=/dev/zero of=/swapfile bs=128M count=32
192+
chmod 600 /swapfile
193+
mkswap /swapfile
194+
swapon /swapfile
195+
sh -c 'echo "/swapfile swap swap defaults 0 0" >> /etc/fstab'
196+
197+
# 타임존 설정
198+
timedatectl set-timezone Asia/Seoul
199+
200+
# 환경변수 세팅(/etc/environment)
201+
echo "PASSWORD_1=${var.password_1}" >> /etc/environment
202+
echo "APP_1_DOMAIN=${var.app_1_domain}" >> /etc/environment
203+
echo "APP_1_DB_NAME=${var.app_1_db_name}" >> /etc/environment
204+
echo "GITHUB_ACCESS_TOKEN_1_OWNER=${var.github_access_token_1_owner}" >> /etc/environment
205+
echo "GITHUB_ACCESS_TOKEN_1=${var.github_access_token_1}" >> /etc/environment
206+
source /etc/environment
207+
208+
# 도커 설치 및 실행/활성화
209+
yum install docker -y
210+
systemctl enable docker
211+
systemctl start docker
212+
213+
# 도커 네트워크 생성
214+
docker network create common
215+
216+
# nginx 설치
217+
docker run -d \
218+
--name npm_1 \
219+
--restart unless-stopped \
220+
--network common \
221+
-p 80:80 \
222+
-p 443:443 \
223+
-p 81:81 \
224+
-e TZ=Asia/Seoul \
225+
226+
-e INITIAL_ADMIN_PASSWORD=${var.password_1} \
227+
-v /dockerProjects/npm_1/volumes/data:/data \
228+
-v /dockerProjects/npm_1/volumes/etc/letsencrypt:/etc/letsencrypt \
229+
jc21/nginx-proxy-manager:latest
230+
231+
# mysql 설치
232+
docker run -d \
233+
--name mysql_1 \
234+
--restart unless-stopped \
235+
-v /dockerProjects/mysql_1/volumes/var/lib/mysql:/var/lib/mysql \
236+
-v /dockerProjects/mysql_1/volumes/etc/mysql/conf.d:/etc/mysql/conf.d \
237+
--network common \
238+
-p 3306:3306 \
239+
-e MYSQL_ROOT_PASSWORD=${var.password_1} \
240+
-e TZ=Asia/Seoul \
241+
mysql:latest
242+
243+
# MySQL 컨테이너가 준비될 때까지 대기
244+
echo "MySQL이 기동될 때까지 대기 중..."
245+
until docker exec mysql_1 mysql -uroot -p${var.password_1} -e "SELECT 1" &> /dev/null; do
246+
echo "MySQL이 아직 준비되지 않음. 5초 후 재시도..."
247+
sleep 5
248+
done
249+
echo "MySQL이 준비됨. 초기화 스크립트 실행 중..."
250+
251+
docker exec mysql_1 mysql -uroot -p${var.password_1} -e "
252+
CREATE USER 'lldjlocal'@'127.0.0.1' IDENTIFIED WITH caching_sha2_password BY '1234';
253+
CREATE USER 'lldjlocal'@'172.18.%.%' IDENTIFIED WITH caching_sha2_password BY '1234';
254+
CREATE USER 'lldj'@'%' IDENTIFIED WITH caching_sha2_password BY '${var.password_1}';
255+
256+
GRANT ALL PRIVILEGES ON *.* TO 'lldjlocal'@'127.0.0.1';
257+
GRANT ALL PRIVILEGES ON *.* TO 'lldjlocal'@'172.18.%.%';
258+
GRANT ALL PRIVILEGES ON *.* TO 'lldj'@'%';
259+
260+
CREATE DATABASE \`${var.app_1_db_name}\`;
261+
262+
FLUSH PRIVILEGES;
263+
"
264+
265+
echo "${var.github_access_token_1}" | docker login ghcr.io -u ${var.github_access_token_1_owner} --password-stdin
266+
267+
END_OF_FILE
268+
}
269+
270+
# 최신 Amazon Linux 2023 AMI 조회 (프리 티어 호환)
271+
data "aws_ami" "latest_amazon_linux" {
272+
most_recent = true
273+
owners = ["amazon"]
274+
275+
filter {
276+
name = "name"
277+
values = ["al2023-ami-2023.*-x86_64"]
278+
}
279+
280+
filter {
281+
name = "architecture"
282+
values = ["x86_64"]
283+
}
284+
285+
filter {
286+
name = "virtualization-type"
287+
values = ["hvm"]
288+
}
289+
290+
filter {
291+
name = "root-device-type"
292+
values = ["ebs"]
293+
}
294+
}
295+
296+
# EC2 인스턴스 생성
297+
resource "aws_instance" "ec2_1" {
298+
# 사용할 AMI ID
299+
ami = data.aws_ami.latest_amazon_linux.id
300+
# EC2 인스턴스 유형
301+
instance_type = "t3.micro"
302+
# 사용할 서브넷 ID
303+
subnet_id = aws_subnet.subnet_2.id
304+
# 적용할 보안 그룹 ID
305+
vpc_security_group_ids = [aws_security_group.sg_1.id]
306+
# 퍼블릭 IP 연결 설정
307+
associate_public_ip_address = true
308+
309+
# 인스턴스에 IAM 역할 연결
310+
iam_instance_profile = aws_iam_instance_profile.instance_profile_1.name
311+
312+
# 인스턴스에 태그 설정
313+
tags = {
314+
Name = "${var.prefix}-ec2-1"
315+
}
316+
317+
# 루트 볼륨 설정
318+
root_block_device {
319+
volume_type = "gp3"
320+
volume_size = 30 # 볼륨 크기를 12GB로 설정
321+
}
322+
323+
user_data = <<-EOF
324+
${local.ec2_user_data_base}
325+
EOF
22326
}

infra/secrets.tf.default

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
variable "app_1_db_name" {
2+
description = "app_1 db_name"
3+
default = "" // mysql 데이터베이스 이름
4+
}
5+
6+
variable "password_1" {
7+
description = "password_1"
8+
default = "" // nginx, mysql, redis 비밀번호, 공개되면 안됨, 팀원하고만 공유
9+
}
10+
11+
variable "github_access_token_1_owner" {
12+
description = "github_access_token_1_owner"
13+
default = "" // GITHUB 계정 소문자(이메일 아님)
14+
}
15+
16+
variable "github_access_token_1" {
17+
description = "github_access_token_1, read:packages only"
18+
default = "" // GITHUB API KEY(class token, read:packages only, expiration: 300일 이하 키)
19+
}

0 commit comments

Comments
 (0)