Cloud/IaC

[Terraform] 간단한 3-tier 아키텍쳐 - Application

Omoknooni 2024. 4. 16. 21:43

지난 3-tier VPC 구축에 이어서, 이번에는 Application단(EC2, ALB 등)을 설계해보도록 한다.

 

아키텍쳐 구성도

 

 

Terraform 코드 작성

Application 단에서 생성할 리소스는 크게 다음과 같다.

  • 인스턴스 4개
  • 보안그룹
  • 키 페어
  • ALB 2개 (외부, 내부)
  • 대상그룹 2개 (외부, 내부)

먼저 Application 모듈의 변수들을 구성한다.

Application 단에서 사용될 외부 변수들에는 주로 vpc 관련의 것이 있다. 인스턴스를 생성할 때 사용될 vpc_id나 배치될 서브넷의 id 값이 여기에 해당된다.

이외에도 ami의 id값이나 미리 생성해둔 security group의 id 같은 리소스도 변수로 불러와서 사용할 수도 있을 것이다.

variable "vpc_id" {}
variable "public_subnet_id" {
    type = list(string)
}
variable "application_subnet_id" {
    type = list(string)
}

 

 

이어서 인스턴스를 생성해본다. 생성해야할 인스턴스는 총 4개로 웹 서버용 2개, WAS 서버용 2개가 있다.

이들은 앞서 생성했던 6개의 Private 서브넷 중 4개에 각각 배치되어야한다. 

여기에서도 앞서 VPC 부분에서 사용했던 count를 통해 resource block을 2개로 처리해보았다.

# Instance
resource "aws_instance" "simple-3tier-web" {
    count = 2
    ami = var.instance_ami
    instance_type = "t2.micro"
    subnet_id = element(var.application_subnet_id, count.index)

    user_data = filebase64("${path.module}/script/install_nginx.sh")

    key_name = aws_key_pair.simple-3tier-key.key_name
    vpc_security_group_ids = [ aws_security_group.simple-3tier-application-sg.id ]

    tags = {
        Name = "simple-3tier-web-${count.index+1}"
    }
}


resource "aws_instance" "simple-3tier-was" {
    count = 2
    ami = var.instance_ami
    instance_type = "t2.micro"
    subnet_id = element(var.application_subnet_id, 2+count.index)
    
    user_data = filebase64("${path.module}/script/install_tomcat.sh")

    key_name = aws_key_pair.simple-3tier-key.key_name
    vpc_security_group_ids = [ aws_security_group.simple-3tier-application-sg.id ]

    tags = {
        Name = "simple-3tier-was-${count.index+1}"
    }
}

 

 

 

인스턴스 resource block을 보면 키 페어를 설정해주는 attribute를 확인할 수 있다.

Terraform에서는 키 페어를 직접 생성하고 등록할 수 있다. 

# Key pair
resource "tls_private_key" "simple-3tier-key" {
    algorithm = "RSA"
    rsa_bits = 4096
}

resource "aws_key_pair" "simple-3tier-key" {
    key_name = "simple-3tier-key"
    public_key = tls_private_key.simple-3tier-key.public_key_openssh
}

resource "local_file" "simple-3tier-key" {
    content = tls_private_key.simple-3tier-key.private_key_pem
    filename = "simple-3tier-key.pem"
}

 

tls_private_key 리소스로 private key를 생성할 수 있고, 여기에서는 Key의 알고리즘과 bit 수를 지정할 수 있다.

그리고 aws_key_pair 리소스에서 tls_private_key 리소스의 public_key 정보를 담아 AWS상에서 사용할 수 있는 키 페어로 등록할 수 있다.

 

더 나아가 local_file 리소스를 이용해 이 Private key를 로컬파일 형태로 저장할 수도 있다.

이 경우 private_key 리소스의 private_key_pem 값을 content로 가져와서 저장해준다.

 

+) Terraform Resource로 생성되는 private key는 State file에 Unencrypted되어 저장된다고 한다. Private Key는 Terraform 외부에서 생성한 뒤 Private Key를 사용하는 리소스를 생성할 때에 가져오는 것이 권장된다.

 

Terraform Registry

 

registry.terraform.io

 

 

다음으로 인스턴스들을 연결할 ALB 리소스를 생성한다.

ALB 리소스를 만들기 위한 하위 리소스로는 Target Group과 Listener가 존재한다.

### External ALB
resource "aws_alb" "simple-3tier-ex-alb" {
    name = "simple-3tier-ex-alb"
    internal = false
    load_balancer_type = "application"
    security_groups = [ aws_security_group.simple-3tier-alb-sg.id ]
    subnets = var.public_subnet_id
}

resource "aws_alb_target_group" "simple-3tier-ex-tg" {
    name = "simple-3tier-ex-tg"
    port = 80
    protocol = "HTTP"
    vpc_id = var.vpc_id
}

resource "aws_alb_listener" "simple-3tier-ex-listener" {
    load_balancer_arn = aws_alb.simple-3tier-ex-alb.arn
    port = "80"
    protocol = "HTTP"

    default_action {
      type = "forward"
      target_group_arn = aws_alb_target_group.simple-3tier-ex-tg.arn
    }
}

 

간단하게 구성하기 위해 Target group의 포트와 Listener의 포트를 모두 80으로 설정해주었다.

 

 

 

그리고 각 ALB에 연결할 Target group과 Listener외에도 Target group을 ALB에 연결하는 리소스(alb_target_group_attachment)도 선언을 해준다. 

resource "aws_alb_target_group_attachment" "simple-3tier-ex-attach" {
    count = 2
    target_group_arn = aws_alb_target_group.simple-3tier-ex-tg.arn
    target_id = element(aws_instance.simple-3tier-web.*.id, count.index)
    port = 80
}

 

앞서 생성해주었던 웹 서버 인스턴스 2개를 Target group에 할당해주는 것을 볼 수 있다. 

 

 

웹서버 방향의 외부 ALB를 구축한 것과 마찬가지로 WAS 서버 방향의 내부 ALB도 구축해준다.

### Internal ALB
resource "aws_alb" "simple-3tier-inner-alb" {
    name = "simple-3tier-inner-alb"
    internal = true
    load_balancer_type = "application"
    security_groups = [ aws_security_group.simple-3tier-alb-sg.id ]
    
    # subnet is last 2 item of var.application_subnet_id
    subnets = slice(var.application_subnet_id, 2,4)
}

resource "aws_alb_target_group" "simple-3tier-inner-tg" { 
    name = "simple-3tier-inner-tg"
    port = 8080
    protocol = "HTTP"
    vpc_id = var.vpc_id
}

resource "aws_alb_target_group_attachment" "simple-3tier-inner-attach" {
    count = 2
    target_group_arn = aws_alb_target_group.simple-3tier-inner-tg.arn
    target_id = element(aws_instance.simple-3tier-was.*.id, count.index)
    port = 8080
}

resource "aws_alb_listener" "simple-3tier-inner-listener" {
    load_balancer_arn = aws_alb.simple-3tier-inner-alb.arn
    port = "8080"
    protocol = "HTTP"

    default_action {
      type = "forward"
      target_group_arn = aws_alb_target_group.simple-3tier-inner-tg.arn
    }
}

 

내부 ALB에서는 8080포트로 Target group 포트와 Listener 포트를 설정해주었다.

 

마지막으로 Application 모듈의 output을 작성한다. 생성된 ALB의 DNS 주소 같은 값들이 사용될 수 있다.

output "alb_dns" {
    value = aws_alb.simple-3tier-ex-alb.dns_name
}

 

이렇게 3tier 아키텍쳐의 Application 모듈을 구성해보았다.

해당 프로젝트는 깃헙 레포에서 확인할 수 있다.