3 Tier란?
3-tier 아키텍처는 소프트웨어 애플리케이션을 세 가지 계층으로 나누어 구성하는 방식이다. 시스템을 이렇게 계층별로 분리하면, 구조가 명확해지고 유지보수나 확장도 훨씬 수월해진다. 각 계층은 고유한 역할을 맡아 서로 독립적으로 동작하며, 주로 프레젠테이션 계층, 애플리케이션 계층, 데이터 계층으로 나뉜다.

프레젠테이션 계층(Presentation Tier)은 사용자와 상호작용하는 부분이다. 사용자에게 화면을 보여주고 입력을 받는 역할을 하며, 흔히 말하는 프론트엔드에 해당한다. 주로 HTML, CSS, JavaScript, React 같은 기술이 사용된다. 이 계층은 사용자와 시스템 간의 인터페이스 역할을 맡고 있다.
애플리케이션 계층(Application Tier)은 비즈니스 로직을 처리하는 중간 계층이다. 프레젠테이션 계층에서 받은 요청을 처리하고, 필요한 데이터를 가져와 다시 사용자에게 전달한다. 여기서는 Java, Node.js, Python 같은 백엔드 기술이 사용되며, 흔히 웹 애플리케이션 서버(WAS)가 동작하는 영역이다.
데이터 계층(Data Tier)은 데이터를 저장하고 관리하는 계층이다. 애플리케이션 계층에서 요청한 데이터를 검색하거나 저장하는 역할을 한다. MySQL, PostgreSQL, MongoDB 같은 데이터베이스가 이 계층에 포함되며, 데이터의 영속성과 무결성을 책임진다.
Iac 도구란?
Infrastructure as Code (IaC)는 인프라를 코드로 정의하고 관리하는 방식이다. 기존처럼 수동으로 설정하는 게 아니라, 코드로 인프라 구성을 작성해서 버전 관리하고 반복적으로 사용할 수 있게 만든다. 클라우드 환경과 DevOps 문화에서 자연스럽게 발전한 개념이며, 자동화와 일관성 있는 인프라 구성을 가능하게 해준다.

IaC(Infrastructure as Code)의 가장 큰 장점은 자동화, 가시성, 효율성, 그리고 확장성이다. 코드를 통해 인프라를 정의하고 관리하다 보니, 배포 속도도 빨라지고 사람 손으로 하던 실수나 보안 이슈도 줄어든다. 환경 간 일관성도 자연스럽게 유지되고, 클라우드나 데이터 센터 간에 인프라를 옮길 때도 훨씬 수월하다.

아키텍처 구성
먼저 자신이 선택한 코드 에디터에 맞게 버전과 같은 Terrform을 설치해준다. 작성된 테라폼 소스 코드는 다음 링크에서 참고해주시면 된다.
https://github.com/rlaehdwn0105/AWS-NCP-3Tier-Terraform

- VPC x 1
- Public Subnet x 1(Bastion Server), Private Subnet x 3(Web, Was, DB Server), Public Subnet x1(Load Balancer), Public Subnet x 1(NAT)
- NAT x 1
- Bastion server(ubuntu 20.04 , 2cpu 4GB RAM) + 1 Public IP,
Web, Was server(ubuntu 20.04 , 2cpu 4GB RAM) - Network interface x 3
- ACG(+Rule) x 2
- Application Load Balancer x 1 , Target Group x 1
프로젝트 디렉터리 구조
ncp_3tier_terraform_code % tree
.
├── acg.tf
├── db.tf
├── load_balancer.tf
├── main.tf
├── nat.tf
├── output.tf
├── providers.tf
├── server.tf
├── subnets.tf
├── variables.tf
└── vpc.tf
main.tf
provider "ncloud" {
support_vpc = true
region = var.region
access_key = var.access_key
secret_key = var.secret_key
}
main.tf 폴더에서는 NCP의 인증키의 access_key, secret_key값을 입력해준다. 저변수를 통해 따로 작성하여주었다.
providers.tf
terraform {
required_providers {
ncloud = {
source = "navercloudplatform/ncloud"
}
}
required_version = ">= 0.13"
}
vpc.tf
#### VPC 생성 ####
resource "ncloud_vpc" "vpc" {
name = "${var.name_customer}-vpc"
ipv4_cidr_block = var.vpc_cidr
}
subnet.tf
### Subnet 생성 ###
### Public Subnet - Bastion Subnet 생성 ###
resource "ncloud_subnet" "public-bastion-subnet" {
vpc_no = ncloud_vpc.vpc.id
subnet = cidrsubnet(ncloud_vpc.vpc.ipv4_cidr_block, 8, 0)
zone = var.zone_1
network_acl_no = ncloud_vpc.vpc.default_network_acl_no
subnet_type = "PUBLIC"
name = "${var.name_customer}-bastion-kr1"
usage_type = "GEN"
}
### Private Subnet - Web Subnet 생성 ###
resource "ncloud_subnet" "private-web-subnet" {
vpc_no = ncloud_vpc.vpc.id
subnet = cidrsubnet(ncloud_vpc.vpc.ipv4_cidr_block, 8, 1)
zone = var.zone_1
network_acl_no = ncloud_vpc.vpc.default_network_acl_no
subnet_type = "PRIVATE"
name = "${var.name_customer}-web-kr1"
usage_type = "GEN"
}
### Private Subnet - Was Subnet 생성 ###
resource "ncloud_subnet" "private-was-subnet" {
vpc_no = ncloud_vpc.vpc.id
subnet = cidrsubnet(ncloud_vpc.vpc.ipv4_cidr_block, 8, 7)
zone = var.zone_1
network_acl_no = ncloud_vpc.vpc.default_network_acl_no
subnet_type = "PRIVATE"
name = "${var.name_customer}-was-kr1"
usage_type = "GEN"
}
### Private Subnet - DB Subnet 생성 ###
resource "ncloud_subnet" "private-db-subnet" {
vpc_no = ncloud_vpc.vpc.id
subnet = cidrsubnet(ncloud_vpc.vpc.ipv4_cidr_block, 8, 5)
zone = var.zone_1
network_acl_no = ncloud_vpc.vpc.default_network_acl_no
subnet_type = "PRIVATE"
name = "${var.name_customer}-db-kr1"
usage_type = "GEN"
}
### Nat Subnet - Nat Subnet 생성 ###
resource "ncloud_subnet" "public-nat-subnet" {
vpc_no = ncloud_vpc.vpc.id
subnet = cidrsubnet(ncloud_vpc.vpc.ipv4_cidr_block, 8, 3)
zone = var.zone_1
network_acl_no = ncloud_vpc.vpc.default_network_acl_no
subnet_type = "PUBLIC"
name = "${var.name_customer}-nat-kr1"
usage_type = "NATGW"
}
### Load Balancer Subnet - ALB Subnet 생성 ###
resource "ncloud_subnet" "alb-subnet" {
vpc_no = ncloud_vpc.vpc.id
subnet = cidrsubnet(ncloud_vpc.vpc.ipv4_cidr_block, 8, 4)
zone = var.zone_1
network_acl_no = ncloud_vpc.vpc.default_network_acl_no
subnet_type = "PUBLIC"
name = "${var.name_customer}-was-alb"
usage_type = "LOADB"
}
server.tf
### Key Pair ###
resource "ncloud_login_key" "loginkey" {
key_name = "${var.name_customer}-key"
}
### Server Information ###
data "ncloud_server_image" "server_image" {
filter {
name = "product_name"
values = ["ubuntu-20.04"]
}
}
data "ncloud_server_product" "product" {
server_image_product_code = data.ncloud_server_image.server_image.id
filter {
name = "product_code"
values = ["SSD"]
regex = true
}
filter {
name = "cpu_count"
values = ["2"]
}
filter {
name = "memory_size"
values = ["4GB"]
}
filter {
name = "product_type"
values = ["HICPU"]
}
}
### NIC ###
### NIC Bastion ###
resource "ncloud_network_interface" "nic_bastion" {
name = "${var.name_customer}-bastion-nic"
subnet_no = ncloud_subnet.public-bastion-subnet.id
access_control_groups = [ncloud_access_control_group.public-acg.id]
}
### NIC Web ###
resource "ncloud_network_interface" "nic_web" {
name = "${var.name_customer}-web-nic"
subnet_no = ncloud_subnet.public-bastion-subnet.id
access_control_groups = [ncloud_access_control_group.private-acg.id]
}
### NIC Was ###
resource "ncloud_network_interface" "nic_was" {
name = "${var.name_customer}-was-nic"
subnet_no = ncloud_subnet.public-bastion-subnet.id
access_control_groups = [ncloud_access_control_group.private-acg.id]
}
### Public IP ###
resource "ncloud_public_ip" "public_ip" {
server_instance_no = ncloud_server.bastion-server.id
description = "for ${ncloud_server.bastion-server.name} public ip"
}
### Bastion Server ###
resource "ncloud_server" "bastion-server" {
subnet_no = ncloud_subnet.public-bastion-subnet.id
name = "${var.name_customer}-bastion-kr1"
server_image_product_code = data.ncloud_server_image.server_image.id
server_product_code = data.ncloud_server_product.product.id
login_key_name = ncloud_login_key.loginkey.key_name
}
### Web Server ###
resource "ncloud_server" "Web-server" {
subnet_no = ncloud_subnet.private-web-subnet.id
name = "${var.name_customer}-web-kr1"
server_image_product_code = data.ncloud_server_image.server_image.id
server_product_code = data.ncloud_server_product.product.id
login_key_name = ncloud_login_key.loginkey.key_name
}
### Was Server ###
resource "ncloud_server" "Was-server" {
subnet_no = ncloud_subnet.private-was-subnet.id
name = "${var.name_customer}-was-kr1"
server_image_product_code = data.ncloud_server_image.server_image.id
server_product_code = data.ncloud_server_product.product.id
login_key_name = ncloud_login_key.loginkey.key_name
}
/*
### Export Root Password ###
data "ncloud_root_password" "default" {
server_instance_no = ncloud_server.bastion-server.instance_no
private_key = ncloud_login_key.loginkey.private_key
}
resource "local_file" "bastion_svr_root_pw" {
filename = "${ncloud_server.bastion_server.name}-root_password.txt"
content = "${ncloud_server.bastion_server.name} => ${data.ncloud_root_password.default.root_password}"
}
*/
nat.tf
### NAT Gateway ###
resource "ncloud_nat_gateway" "nat_gateway" {
name = "${var.name_customer}-nat-kr1"
subnet_no = ncloud_subnet.public-nat-subnet.id
vpc_no = ncloud_vpc.vpc.id
zone = var.zone_1
}
resource "ncloud_route" "nat" {
route_table_no = ncloud_vpc.vpc.default_private_route_table_no
destination_cidr_block = "0.0.0.0/0"
target_type = "NATGW"
target_name = ncloud_nat_gateway.nat_gateway.name
target_no = ncloud_nat_gateway.nat_gateway.id
}
load_balancer.tf
### ALB ###
resource "ncloud_lb" "alb" {
name = "${var.name_customer}-was-alb"
network_type = "PUBLIC"
type = "APPLICATION"
subnet_no_list = [ncloud_subnet.alb-subnet.id]
}
### ALB Listener ###
resource "ncloud_lb_listener" "alb_listener" {
load_balancer_no = ncloud_lb.alb.load_balancer_no
protocol = "HTTP"
port = 80
target_group_no = ncloud_lb_target_group.alb-target.target_group_no
}
### ALB Target_group & attachment ###
resource "ncloud_lb_target_group" "alb-target" {
name = "${var.name_customer}-was-alb-tg"
vpc_no = ncloud_vpc.vpc.id
protocol = "HTTP"
target_type = "VSVR"
port = 80
description = "ALB-Was-target-group"
health_check {
protocol = "HTTP"
http_method = "GET"
port = 80
url_path = "/"
cycle = 60
up_threshold = 2
down_threshold = 2
}
algorithm_type = "RR"
}
resource "ncloud_lb_target_group_attachment" "attachment" {
target_group_no = ncloud_lb_target_group.alb-target.target_group_no
target_no_list = [ncloud_server.Was-server.instance_no]
}
db.tf
### Cloud DB for MySQL ###
resource "ncloud_mysql" "mysql" {
subnet_no = ncloud_subnet.private-db-subnet.id
service_name = "${var.name_customer}-mysql"
server_name_prefix = "${var.name_customer}-mysql"
user_name = var.db_username
user_password = var.db_password
host_ip = "%"
database_name = "${var.name_customer}-mysql"
is_ha = false
#image_product_code = data.ncloud_mysql_image_products.image.id
# product_code = data.ncloud_mysql_products.product.id
}
/*
data "ncloud_mysql_image_products" "image" {
filter {
name = "product_code"
values = ["SW.VDBAS.DBAAS.LNX64.CNTOS.0708.MYSQL.8021.B050"]
}
}
data "ncloud_mysql_products" "product" {
image_product_code = data.ncloud_mysql_image_products.image.id
filter {
name = "cpu_count"
values = ["2"]
}
filter {
name = "memory_size"
values = ["4GB"]
}
filter {
name = "product_type"
values = ["HICPU"]
}
}
*/
acg.tf
### Public ACG ###
resource "ncloud_access_control_group" "public-acg" {
name = "${var.name_customer}-public-acg"
description = "public-acg"
vpc_no = ncloud_vpc.vpc.id
}
resource "ncloud_access_control_group_rule" "public-acg-rule" {
access_control_group_no = ncloud_access_control_group.public-acg.id
inbound {
protocol = "TCP"
ip_block = "0.0.0.0/0"
port_range = "22"
description = "accept 22 port"
}
inbound {
protocol = "TCP"
ip_block = "0.0.0.0/0"
port_range = "80"
description = "accept 80 port"
}
outbound {
protocol = "TCP"
ip_block = "0.0.0.0/0"
port_range = "1-65535"
description = "accept 1-65535 port"
}
}
### Private ACG ###
resource "ncloud_access_control_group" "private-acg" {
name = "${var.name_customer}-private-acg"
description = "private-acg"
vpc_no = ncloud_vpc.vpc.id
}
resource "ncloud_access_control_group_rule" "private-acg-rule" {
access_control_group_no = ncloud_access_control_group.private-acg.id
inbound {
protocol = "TCP"
ip_block = var.vpc_cidr
port_range = "1-65535"
description = "accept 1-65535 port"
}
inbound {
protocol = "TCP"
ip_block = "0.0.0.0/0"
port_range = "80"
description = "accept 80 port"
}
outbound {
protocol = "TCP"
ip_block = "0.0.0.0/0"
port_range = "1-65535"
description = "accept 1-65535 port"
}
}
variable.tf
### VPC ###
variable "name_customer" {
description = "customer-Name"
type = string
default = "kdj"
}
variable "vpc_cidr" {
description = "VPC-cidr"
type = string
default = "10.16.0.0/16"
}
### Subnet ###
### availability_zone ###
### zone ###
variable "zone_1" {
description = "availability_zone-1"
type = string
default = "KR-1"
}
variable "zone_2" {
description = "availability_zone-2"
type = string
default = "KR-2"
}
### DB for MySQL
variable "db_password" {
description = "db_password"
type = string
default = "본인의 설정하고 싶은 DB_password"
}
variable "db_username" {
description = "db_username"
type = string
default = "본인의 설정하고 싶은 DB_username"
}
### module id ###
variable "region" {
default = "KR"
}
variable "access_key" {
default = "본인 인증키 access_key 값"
}
variable "secret_key" {
default = "본인 인증키 secret_key 값"
}
이후 terraform init(초기 설정) -> terraform fmt(코드 정리)-> terraform validate(코드 검사) -> tarraform plan(변경 계획 보기) -> tarraform apply(변경 적용)를 통해 작성한 tf 파일로 ncp인프라 소스를 생성할 수 있다.

1. terraform init

2. terraform fmt, terraform validate

3. terraform plan

4. terrform apply
이제 콘솔에 들어가서 확인해보면 다음과 같이 자동으로 서버가 구축된 모습을 확인할 수 있다.

콘솔 화면
이제 실습이 끝났으니 terraform destroy명령어를 통해 리소스들을 전부 삭제해주겠다.

'NCP' 카테고리의 다른 글
| [NCP] STS를 통한 임시자격 증명 (0) | 2024.12.31 |
|---|---|
| [NCP] 블록 스토리지 확장법(KVM, XEN) (0) | 2024.12.31 |
| [NCP] Image Optimizer를 이용한 이미지 리사이징 (0) | 2024.12.31 |
| [NCP] LoadBalancer Path Pattern (0) | 2024.12.31 |
| [NCP] AutoScaling 구현 (0) | 2024.12.31 |