본문 바로가기

♻ Terraform(테라폼)/Architecture 구성

목표 아키텍처 구성 및 terraform 을 활용한 생성

# 목표아키텍처를 기반으로 테라폼 코드를 활용한 인프라 구성

1. 목표 아키텍처

- 목표 아키텍처 리소스

VPC, 인터넷 게이트웨이, NAT 게이트웨어, EC2 인스턴스, 퍼블릭 서브넷 2개, 프라이빗 서브넷 2개, ap-northeast-2 A-C

EC2_Basic.drawio
0.00MB

- 위와 같이 목표 아키텍처를 정의 하였고, 실행한 아파치 웹서버로 접근을 하게 되면 아래와 같은 페이지를 출력하게 된다.

2. 테라폼 코드 살펴보기

- 일단 모듈로 구성을 했기때문에 폴더 구조는 아래와 같다.

- Root 경로의 파일을 정의하여 해당 모듈인 vpc 및 ec2를 실행하여 리소스를 생성하는 구조이다.

- ec2 폴더

main.tf

더보기
# RSA 알고리즘을 이용해 private 키 생성
resource "tls_private_key" "pk" {
  algorithm = "RSA"
  rsa_bits  = 4096
}

# private 키를 가지고 keypair 파일 생성
resource "aws_key_pair" "kp" {
  key_name   = var.key_name
  public_key = tls_private_key.pk.public_key_openssh
}

# 키 파일을 생성하고 로컬에 다운로드
resource "local_file" "ssh_key" {
  filename = "${aws_key_pair.kp.key_name}.pem"
  content  = tls_private_key.pk.private_key_pem
}

# EC2 인스턴스 생성 (Public)
resource "aws_instance" "webserver" {
  ami                    = var.ami_number
  instance_type          = var.instance_type
  key_name               = var.key_name
  subnet_id              = var.public_subnet
  vpc_security_group_ids = ["${aws_security_group.webserversg.id}"] # 내부에 생성된 리소스를 참조
  user_data              = <<-EOF
                           #!/bin/bash
                           sudo yum install -y httpd
                           echo "zzanggu의 웹서버 테스트 중..." > /var/www/html/index.html
                           sudo systemctl start httpd
                           sudo systemctl enable httpd
                           EOF

  # shellscript 사용을 위한 설정 
  provisioner "local-exec" {
    command = "echo \"Hello, World from $(uname -smp)\""
  }

  # 태그값 설정
  tags = {
    Name = "webserver"
  }

  #   depends_on = ["aws_internet_gateway.igw"]
}

resource "aws_eip" "webserver" {
  vpc = true

  instance = aws_instance.webserver.id
  #   depends_on = [aws_internet_gateway.igw]
}

resource "aws_security_group" "webserversg" {
  name        = "webserversg"
  description = "allow 22, 80"
  vpc_id      = var.vpc_id
}

resource "aws_security_group_rule" "websg_ssh" {
  type              = "ingress"
  from_port         = 22
  to_port           = 22
  protocol          = "tcp"
  cidr_blocks       = ["0.0.0.0/0"]
  security_group_id = aws_security_group.webserversg.id
  description       = "ssh"
}

resource "aws_security_group_rule" "websg_http" {
  type              = "ingress"
  from_port         = 80
  to_port           = 80
  protocol          = "tcp"
  cidr_blocks       = ["0.0.0.0/0"]
  security_group_id = aws_security_group.webserversg.id
  description       = "http"
}

resource "aws_security_group_rule" "websg_outbound" {
  type              = "egress"
  from_port         = 0
  to_port           = 0
  protocol          = "-1"
  cidr_blocks       = ["0.0.0.0/0"]
  security_group_id = aws_security_group.webserversg.id
  description       = "outbound"
}

output.tf

더보기
output "public_ip" {
  value       = aws_instance.webserver.public_ip
  description = "The public IP of the Instance"
}

variables.tf

더보기
variable "ami_number" {
  type = string
}

variable "instance_type" {
  type = string
}

variable "key_name" {
  type = string
}

variable "public_subnet" {
  type = string
}

variable "vpc_id" {
  type = string
}

- vpc 폴더

main.tf

더보기
# VPC 생성
resource "aws_vpc" "main" {
  cidr_block = var.vpc_cidr_block

  tags = {
    Name = "terraform_vpc_seungkim"
  }
}

# Public 서브넷 생성
resource "aws_subnet" "public" {
  vpc_id     = aws_vpc.main.id
  cidr_block = var.public_subnet_cidr_block
}

# Public-A 서브넷 생성
resource "aws_subnet" "public-a" {
  vpc_id     = aws_vpc.main.id
  cidr_block = var.public_subnet_cidr_block-a
}


# Private 서브넷 생성
resource "aws_subnet" "private" {
  vpc_id     = aws_vpc.main.id
  cidr_block = var.private_subnet_cidr_block
}

# Private-A 서브넷 생성
resource "aws_subnet" "private-a" {
  vpc_id     = aws_vpc.main.id
  cidr_block = var.private_subnet_cidr_block-a
}

# 인터넷 게이트웨이 생성
resource "aws_internet_gateway" "main" {
  vpc_id = aws_vpc.main.id
}

# EIP 생성
resource "aws_eip" "nat" {
  vpc = true
}

# NAT 게이트웨이 생성
resource "aws_nat_gateway" "main" {
  allocation_id = aws_eip.nat.id
  subnet_id     = aws_subnet.public.id
}

# 퍼블릭 라우팅 테이블 생성
resource "aws_route_table" "public" {
  vpc_id = aws_vpc.main.id

  route {
    cidr_block = "0.0.0.0/0"
    gateway_id = aws_internet_gateway.main.id
  }
}

# 프라이빗 라우팅 테이블 생성
resource "aws_route_table" "private" {
  vpc_id = aws_vpc.main.id

  route {
    cidr_block     = "0.0.0.0/0"
    nat_gateway_id = aws_nat_gateway.main.id
  }
}

# 라우팅 테이블 연결 (퍼블릭 서브넷)
resource "aws_route_table_association" "public" {
  subnet_id      = aws_subnet.public.id
  route_table_id = aws_route_table.public.id
}

# 라우팅 테이블 연결 (퍼블릭 서브넷-a)
resource "aws_route_table_association" "public-a" {
  subnet_id      = aws_subnet.public-a.id
  route_table_id = aws_route_table.public.id
}

# 라우팅 테이블 연결 (프라이빗 서브넷)
resource "aws_route_table_association" "private" {
  subnet_id      = aws_subnet.private.id
  route_table_id = aws_route_table.private.id
}

# 라우팅 테이블 연결 (프라이빗 서브넷-a)
resource "aws_route_table_association" "private-a" {
  subnet_id      = aws_subnet.private-a.id
  route_table_id = aws_route_table.private.id
}

output.tf

더보기
output "vpc_id" {
  value = aws_vpc.main.id
  description = ""
}

output "public_subnet_id" {
  value = aws_subnet.public.id
  description = ""
}

output "private_subnet_id" {
  value = aws_subnet.private.id
  description = ""
}

variables.tf

더보기
variable "vpc_cidr_block" {
  type = string
}

variable "public_subnet_cidr_block" {
  type = string
}

variable "public_subnet_cidr_block-a" {
  type = string
}

variable "private_subnet_cidr_block" {
  type = string
}

variable "private_subnet_cidr_block-a" {
  type = string
}

- Root 폴더

provider.tf

더보기
terraform {
  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = "3.27.0"
    }
  }
}

provider "aws" {
  region = "ap-northeast-2"
}

ec2.tf

더보기
module "ec2" {
  source        = "../ec2"
  ami_number    = "ami-00000000000000"
  instance_type = "t2.micro"
  key_name      = "webserver"
  public_subnet = "subnet-00000000000000"
  vpc_id        = "vpc-0000000000000"
}

vpc.tf

더보기
module "vpc" {
  source                      = "../vpc"
  vpc_cidr_block              = "10.0.0.0/16"
  public_subnet_cidr_block    = "10.0.0.0/24"
  public_subnet_cidr_block-a  = "10.0.0.0/24"
  private_subnet_cidr_block   = "10.0.0.0/24"
  private_subnet_cidr_block-a = "10.0.0.0/24"
}

output.tf

더보기
output "vpc_id" {
  value = module.vpc.vpc_id
  description = ""
}

output "public_subnet_id" {
  value = module.vpc.public_subnet_id
  description = ""
}

output "private_subnet_id" {
  value = module.vpc.private_subnet_id
  description = ""
}

3. Terraform Code 수정하기 :: Subnet에 tag 값 입력하여 업데이트하기

- 테라폼 코드를 활용하여 인프라를 생성하면 Subnet의 이름이 아래와 같이 빈칸으로 입력되어 나온다.

해당 값을 부여하기 위해서는 tag값을 따로 지정해 줘야 한다. tag 값을 부여하여 업데이트를 진행해보자.

- tag 값은 terraform_vpc_seungkim_public_subnet 을 기본으로 이와같은 방법으로 태그값을 설정해보자.

① 일단 서브넷 리소스를 찾는다. vpc → main.tf 파일에 정의된 서브넷 리소스를 찾고 tag 값을 부여한다.

② 코드 수정 :: subnet 리소스를 찾아 아래와 같이 tag 값을 부여한다.

- vpc 폴더 → main.tf 파일을 아래와 같이 수정

더보기
# Public 서브넷 생성
resource "aws_subnet" "public" {
  vpc_id     = aws_vpc.main.id
  cidr_block = var.public_subnet_cidr_block

  tags = {
    Name = "terraform_vpc_seungkim_public_subnet"
  }
}

# Public-A 서브넷 생성
resource "aws_subnet" "public-a" {
  vpc_id     = aws_vpc.main.id
  cidr_block = var.public_subnet_cidr_block-a

  tags = {
    Name = "terraform_vpc_seungkim_public_subnet-a"
  }
}


# Private 서브넷 생성
resource "aws_subnet" "private" {
  vpc_id     = aws_vpc.main.id
  cidr_block = var.private_subnet_cidr_block

  tags = {
    Name = "terraform_vpc_seungkim_private_subnet"
  }
}

# Private-A 서브넷 생성
resource "aws_subnet" "private-a" {
  vpc_id     = aws_vpc.main.id
  cidr_block = var.private_subnet_cidr_block-a

  tags = {
    Name = "terraform_vpc_seungkim_private_subnet-a"
  }
}

③ terraform plan, terraoform apply 를 통해 변경된 내용을 적용한다.

- terraform plan을 적용하면 추가되는 태그값을 확인할 수 있다.

- terraform apply를 적용 후 subnet 리스트를 보면 아래와 같이 name 값이 업데이트 된 것을 확인할 수 있다.

④ tag 값을 변수로 설정하는 방법

- 예시로 public subnet 리소스를 확인해보자.

vpc → main.tf

# Public-A 서브넷 생성
resource "aws_subnet" "public-a" {
  vpc_id     = aws_vpc.main.id
  cidr_block = var.public_subnet_cidr_block-a

  tags = {
    Name = "${var.public_subnet_name-a}"
  }
}

vpc → variables.tf

variable "public_subnet_name-a" {
  type = string
}

Root → vpc.tf

public_subnet_name-a        = "terraform_vpc_seungkim_public_subnet-a"

이상 오늘은 여기까지...