[Terraform] EFS 파일 시스템 생성 및 인스턴스에 마운트

HYEOB KIM·2022년 7월 4일
2

Terraform

목록 보기
11/11

AWS 콘솔을 이용해 EFS 생성하는 방법: [AWS] EFS 파일 시스템 생성

개요

  • EFS 파일 시스템, 인스턴스를 생성하고 인스턴스에 파일 시스템을 마운트하는 과정을 테라폼을 이용해 자동화 해봅시다.

아키텍처

디렉토리 구조

코드 리뷰

vpc.tf

VPC서브넷, 인터넷 게이트웨이, 라우팅 테이블을 생성하고, 라우팅 테이블과 서브넷을 연결, 네트워크 인터페이스와 서브넷을 연결합니다.

# VPC 생성
resource "aws_vpc" "test_hyeob_vpc" {
  cidr_block       = "10.0.0.0/16"
  instance_tenancy = "default"

  # 인스턴스에 public DNS가 표시되도록 하는 속성
  enable_dns_hostnames = true
  enable_dns_support   = true

  tags = local.tags
}

# 서브넷 생성
resource "aws_subnet" "test_hyeob_subnet" {
  vpc_id            = aws_vpc.test_hyeob_vpc.id
  cidr_block        = "10.0.1.0/24"
  availability_zone = "ap-northeast-2a"

  tags = local.tags
}

# 인터넷 게이트웨이 생성 후 VPC에 연결
resource "aws_internet_gateway" "gw" {
  vpc_id = aws_vpc.test_hyeob_vpc.id

  tags = local.tags
}

# 라우팅 테이블 생성 후 igw에 연결
resource "aws_route_table" "rt" {
  vpc_id = aws_vpc.test_hyeob_vpc.id

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

  tags = local.tags
}

# 서브넷과 라우팅 테이블 연결
resource "aws_route_table_association" "rta" {
  subnet_id      = aws_subnet.test_hyeob_subnet.id
  route_table_id = aws_route_table.rt.id
}

# 네트워크 인터페이스를 서브넷에 연결
resource "aws_network_interface" "ni" {
  subnet_id       = aws_subnet.test_hyeob_subnet.id
  private_ips     = ["10.0.1.10"]
  security_groups = [aws_security_group.test_hyeob_sg.id]

  tags = local.tags
}

앞서 생성한 VPC와 연결될 보안 그룹을 총 2개 생성합니다. 하나는 인스턴스에 연결될 보안 그룹이고, 다른 하나는 탑재 대상에 연결될 보안 그룹입니다. 인스턴스에 연결될 보안 그룹의 경우 SSH, HTTP 통신을 위해 22, 80번 인바운드 포트를 열어줍니다. 탑재 대상에 연결될 보안 그룹에는 NFS 통신을 위해 2049번 인바운드 포트를 열어줍니다.

# 인스턴스에 연결할 보안 그룹 생성
resource "aws_security_group" "test_hyeob_sg" {
  name        = "test_hyeob_sg"
  description = "Allow SSH inbound traffic"
  vpc_id      = aws_vpc.test_hyeob_vpc.id

  # 인바운드: ingress
  ingress {
    description = "SSH from VPC"

    # 포트 범위: from_port ~ to_port
    from_port   = 22
    to_port     = 22
    protocol    = "tcp"
    cidr_blocks = ["0.0.0.0/0"]
  }

  ingress {
    description = "HTTP"

    # 포트 범위: from_port ~ to_port
    from_port   = 80
    to_port     = 80
    protocol    = "tcp"
    cidr_blocks = ["0.0.0.0/0"]
  }

  # 아웃바운드: egress
  egress {
    from_port   = 0
    to_port     = 0
    protocol    = "-1"
    cidr_blocks = ["0.0.0.0/0"]
  }

  tags = local.tags
}

# EFS 탑재 대상에 연결할 보안 그룹을 생성
resource "aws_security_group" "efs_sg" {
  name        = "tf-test-hyeob-efs_sg"
  description = "Allow SSH inbound traffic"
  vpc_id      = aws_vpc.test_hyeob_vpc.id

  # 인바운드: ingress
  ingress {
    description = "SSH from VPC"

    # 포트 범위: from_port ~ to_port
    from_port   = 2049
    to_port     = 2049
    protocol    = "tcp"
    cidr_blocks = ["0.0.0.0/0"]
  }

  # 아웃바운드: egress
  egress {
    from_port   = 0
    to_port     = 0
    protocol    = "-1"
    cidr_blocks = ["0.0.0.0/0"]
  }

  tags = local.tags
}

efs.tf

EFS 파일 시스템을 생성합니다. 원존 클래스를 이용할 경우 별도로 availability_zone_name 속성을 이용해 특정 가용 영역 한 개를 지정합니다. encrypted 속성은 유휴 시 데이터 암호화와 관련된 속성입니다. 암호화를 활성화하고 싶다면 true를 입력하시면 됩니다. 성능 모드(performance_mode)와 처리량 모드(throughput_mode)를 지정해주고, IA 스토리지를 사용하고 싶다면 수명 주기 관리(lifecycle_policy)를 지정합니다.

# EFS 파일 시스템 생성
resource "aws_efs_file_system" "efs" {
  # 원존 클래스를 이용할 경우
  # availability_zone_name = "ap-northeast-2a"

  # 유휴 시 데이터 암호화
  encrypted = true
  # KMS에서 관리형 키를 이용하려면 kms_key_id 속성을 붙여줍니다.

  # 성능 모드: generalPurpose(범용 모드), maxIO(최대 IO 모드)
  performance_mode = "generalPurpose"
  
  # 버스팅 처리량 모드
  throughput_mode = "bursting"

  # 프로비저닝 처리량 모드
  # throughput_mode = "provisioned"
  # provisioned_throughput_in_mibps = 100

  # 수명 주기 관리
  lifecycle_policy {
    transition_to_ia = "AFTER_30_DAYS"
  }
}

탑재 대상을 수동으로 생성해줍니다. AWS 콘솔에서 작업하면 이러한 탑재 대상을 표준 클래스의 경우 모든 가용 영역에 자동으로 생성해주지만, 테라폼을 이용하게 되면 모두 수동으로 생성해주어야 합니다. 탑재 대상에 2049번 포트를 허용하는 보안 그룹을 연결합니다.

# 표준 클래스로 EFS를 생성하더라도 탑재 대상은 모든 가용영역에 수동으로 지정해주어야 합니다. 
resource "aws_efs_mount_target" "mount" {
  file_system_id  = aws_efs_file_system.efs.id
  subnet_id       = aws_subnet.test_hyeob_subnet.id
  security_groups = [aws_security_group.efs_sg.id]
}

ec2.tf

인스턴스를 생성합니다. 인스턴스는 의도적으로 의존성을 주어 탑재 대상(aws_efs_mount_target) 리소스가 모두 생성 완료되면 인스턴스가 생성되도록 설정합니다(depends_on). 앞서 생성한 네트워크 인터페이스를 붙여줍니다. 보안 그룹은 이전에 VPC 생성 단계에서 네트워크 인터페이스를 생성할 때 붙여주었으므로 인스턴스 생성 과정에서 중복으로 속성을 주어 연결할 필요가 없습니다. 네트워크 인터페이스를 연결하면 자동으로 보안 그룹과도 연결됩니다. user_data를 이용해서 인스턴스 생성 후 마운트 폴더를 생성하고, EFS 파일 시스템을 마운트하는 작업까지 프로비저닝하도록 스크립트 내용을 작성하였습니다.

resource "aws_instance" "test_hyeob_instance" {
  ami           = data.aws_ami.amazon-linux-2.id
  instance_type = "t2.micro"

  network_interface {
    network_interface_id = aws_network_interface.ni.id
    device_index         = 0
  }

  # network_interface를 인스턴스에 붙이지 않는다면 아래 속성으로 보안 그룹을 붙여줍니다.
  #   vpc_security_group_ids = [aws_security_group.test_hyeob_sg.id]

  # 키 파일을 이용해 생성
  key_name = aws_key_pair.kp.key_name

  root_block_device {
    volume_size = 30
    volume_type = "gp3"
  }

  tags = local.tags

  user_data = <<EOF
#!/bin/bash
sudo mkdir -p efs
sudo mount -t nfs4 -o nfsvers=4.1,rsize=1048576,wsize=1048576,hard,timeo=600,retrans=2,noresvport ${aws_efs_file_system.efs.dns_name}:/ efs
  EOF

  depends_on = [
    aws_efs_mount_target.mount
  ]
}

# amazon linux 2 이미지 불러오기
data "aws_ami" "amazon-linux-2" {
  most_recent = true

  owners = ["amazon"]

  filter {
    name   = "name"
    values = ["amzn2-ami-hvm-*-x86_64-ebs"]
  }
}

# 탄력적 IP 붙여주기
resource "aws_eip" "lb" {
  instance = aws_instance.test_hyeob_instance.id
  vpc      = true
}

keypair.tf

프라이빗 키를 생성(tls_private_key)하고, 키 페어 파일을 생성(aws_key_pair)해서 로컬에 다운로드까지 수행(local_file)하는 코드입니다.

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

# private 키를 가지고 keypair 파일 생성.
resource "aws_key_pair" "kp" {
  key_name   = "test_hyeob_keypair"
  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
}
profile
Devops Engineer

0개의 댓글