🧱 [Terraform] Terraform 으로 AWS 인프라 구축해보기

서론

Windows 환경 + vscode로 진행했다.

 IaC(Infrastructure as Code)인 테라폼을 공부하는 겸 AWS 인프라를 구축해보고자 한다.

 

 

 

🎈 기본 개념

1. 프로바이더 (Provider)

테라폼과 외부서비스를 연결하는 기능하는 모듈
즉, AWS 서비스의 자원을 생성하기 위해선 AWS 프로바이더를 먼저 준비해야한다.

 

2. 리소스 (Resource)

특정 프로바이더가 제공해 주는 조작 가능한 대상의 최소 단위
즉, AWS 프로바이더는 aws_instance 리소스 타입을 제공
이 리소스 타입 사용해서 EC2의 가상 머신 리소스 선언 및 조작이 가능

3. 계획 (Plan)

테라폼 프로젝트 디렉터리 아래 모든 .tf일의 내용을 실제로 적용가능한지 확인하는 작업을 계획
테라폼에서는 이를 terraform plan 명령어로 제공

명령어 실행 시 어떤 리소스 생성, 수정, 실행, 삭제될지 계획 보여준다

 

4. 적용 (Apply)

테라폼 프로젝트 디렉터리 아래 모든 .tf 일의 내용대로 리소스 생성, 수정, 삭제하는 일을 적용
테라폼에서는 이를 terraform apply 명령어로 제공

변경 예정사항 plan을 통해 확인 가능

 

 

✅ AWS 인프라 구축해 보기

1. AWS 프로바이더 정의

프로젝트 디렉터리와 테라폼 파일 2개를 생성해 준다.

원칙은 없으니 자신이 원하는 디렉토리명을 만들어주자.

테라폼은 디렉터리에 있는 모든 .tf 파일 읽고 리소스 생성, 수정, 삭제 작업을 한다.

mkdir aws_infra
touch provider.tf web_infra.tf

 

이후 provider.tf 파일을 작성해 주자.

사용자 정보와 리전을 의미하는 내용이다.

참고로 보안을 위해 root 계정이 아닌 IAM 사용자를 만들어서 하는 것을 추천한다.
#provider.tf 파일 내용

provider "aws" {
  access_key = "<AWS_ACCESS_KEY>"
  secret_key = "<AWS_SECRET_KEY>"
  region = "ap-northeast-2"
}
✅ 추가적으로 이러한 민감한 정보를 저장소에 기록하지 않도록 주의해야 한다.
✅ 이러한 인증 정보를 프로바이더 속성 값 설정이 아닌 테라폼 실행하는 환경에 직접 환경변수로 정의하면 노출 피할 수 있다.
# 환경변수 설정 방법

$ export AWS_ACCESS_KEY_ID="<AWS_ACCESS_KEY_ID>"         # access_key
$ export AWS_SECRET_ACCESS_KEY="<AWS_SECRET_ACCESS_KEY>" # secret_key
$ export AWS_DEFAULT_REGION="ap-northeast-2"             # region

만약 환경변수를 설정했다면, 다음과 같이 프로바이더를 정의하면 된다.

#provider.tf 파일 내용

provider "aws" {}

 

2. init 하기

프로바이더 설정이 마무리 됐으니, 프로젝트 디렉터리에서 다음 명령어를 수행

terrafrom init

terraform init 명령어 수행한 모습

 

 

3. EC2용 SSH 키 페어 생성하기 

EC2 생성하기 전 키페어를 생성하여 EC2 인스턴스에 접근할 준비를 하자

 

3-1. HCL 언어로 리소스 정의하기

web_infra.tf 파일에 다음 내용을 추가하자

resource "aws_key_pair" "web_admin" {
  key_name = "web_admin"
  public_key = "<PUBLIC_KEY>"
}

"aws_key_pair" : 리소스 타입의 이름을 의미, 프로바이더에서 제공하는 리소스 타입이름은 한정적

"web_admin" : 리소스에 붙이는 임의 이름  *참고로 AWS에 정의되는 이름은 아니다!!

key_name : AWS에 정의하는 이름

public_key : 접속에 사용할 공개키 값 필요

키가 없다면 다음 명령어로 SSH 키 생성 가능 

#SSH 키 생성

#참고로 Powershell 에서 본인은 진행 with VSC

ssh-keygen -t rsa -b 4096 -C "{본인이메일주소}" -f "$HOME/.ssh/web_admin"

키 생성했다면 다시 web_infra.tf를 다음과 같이 정의할 수 있다.

resource "aws_key_pair" "web_admin" {
  key_name = "web_admin"
  public_key = file("~/.ssh/web_admin.pub")
}

file() 함수는 경로를 문자열로 읽음

 

 

4. Plan 해보기

앞에서 만든 aws키페어 리소스 생성이 aws에 실제로 가능한지 확인해볼 것이다.

프로젝트 디렉터리에서 다음 명령어 수행해 보자

terraform plan

그렇다면 테라폼이 어떤 작업 수행할지 계획을 보여준다

+ 생성하겠다는 의미이다.

 

5. Apply 해보기

계획(Plan)을 이제 적용해보고자 한다.

다음 명령어를 수행하자

terraform apply

 Plan을 보여주고 yes를 입력하여서 Apply 하면 된다.

 

web_admin 이 성공적으로 생성된 모습

✅ 기억해야 할 것은 plan을 습관화하고 Apply를 함으로써 변경사항을 수시로 확인하는 것이다!

 

6. 보안그룹 열기

이번에 적용할 리소스는 aws_security_group, 즉 보안그룹이다.

EC2 인스턴스에 접근하기 위해선 SSH port를 열어줘야 하기 때문이다. 따라서 보안그룹을 만들어줘야 한다.

webinfra.tf 에서 다음 코드를 작성하자

resource "aws_security_group" "ssh" {
    name = "allow_ssh"
    description = "ssh port open"
    ingress {
        from_port = 22
        to_port = 22
        protocol = "tcp"
        cidr_blocks = ["0.0.0.0/0"]
    }
}

 

name : 보안그룹 이름

description : 보안그룹 설명

ingress : 인바운드 속성 

from_port, to_port : 열어줄 포트를 의미 

protocol : 통신 프로토콜

cidr_blocks : 보안그룹 적용할 사이더 범위

 

이후 plan을 적용해 보자

terraform plan

보안그룹 plan

apply 적용해 보기

terraform apply

성공적으로 생성된 것을 확인

 

7. VPC default 보안그룹 불러오기

테라폼은 클라우드에 이미 정의되어 있는 리소스를 데이터 소스로 불러오는 기능을 제공

따라서 기본 default 보안그룹을 불러와보자

data "aws_security_group" "default" {
  name = "default"
}

 

8. EC2 인스턴스 정의하기

EC2 인스턴스를 정의하는 리소스는 다음과 같다.

resource "aws_instance" "web" {
  ami = "ami-0e6f2b2fa0ca704d0" #2024.06.20 기준 ubuntu AMI ID
  instance_type = "t2.micro"
  key_name = aws_key_pair.web_admin.key_name
  vpc_security_group_ids = [
    aws_security_group.ssh.id,
    data.aws_security_group.default.id
  ]
}

ami : 에는 본인이 희망하는 EC2 인스턴스 AMI ID를 설정하면 된다. 본인은 ubuntu로 설정

key_name : 키페어 리소스 aws_key_pair.web_admin 에서  설정했었던 key_name이라는 속성을 참조한다.

vpc_security_group_ids : 배열 형식이고, 위에서 추가한 보안 그룹 ssh의 id 속성과 default 보안 그룹의 id 속성을 참조한다.

 

이후 terraform plan을 실행시켜 주자

 

이후 terraform apply 실행

..?

에러가 발생해서 보아하니 subnet 이 없었다.. 흠 하여튼 그래서 본인은 서브넷을 resource에 추가를 해줬다.
resource "aws_instance" "web" {
  ami = "ami-0e6f2b2fa0ca704d0" #2024.06.20 기준 ubuntu AMI ID
  instance_type = "t2.micro"
  subnet_id     = "subnet-01df07e67164e0468" #서브넷 추가 
  key_name = aws_key_pair.web_admin.key_name
  vpc_security_group_ids = [
    aws_security_group.ssh.id,
    data.aws_security_group.default.id
  ]
  associate_public_ip_address = true
}

 

EC2가 생성되었다..!!
보안그룹도 잘 적용된 모습

 

9. EC2 인스턴스 접속해 보기

성공적으로 생성했으니 한번 접속해 보겠다.

SSH 접속을 위해 인스턴스의 ip를 조회해 보겠다

terraform console
> aws_instance.web.public_ip

 

 

SSH로 출력된 ip에 접속해 보자

ssh -i ~\.ssh\web_admin ubuntu@13.125.216.105

성공적으로 접속!!

 

 

10. RDS 정의하기

이제 AWS 데이터베이스 서비스인 RDS의 MySQL 리소스를 만들어보겠다.

#2024.06.20 기준

resource "aws_db_instance" "web_db" {
  allocated_storage = 20 #최소용량 20GB
  engine = "mysql"
  engine_version = "8.0.35" #엔진버전
  instance_class = "db.t3.micro"
  username = "admin"
  password = "{원하는 비밀번호입력 8자리 이상}" #DB 비밀번호
  skip_final_snapshot = true #인스턴스 제거시 스냅샷 만들지 않고 제거할지 결정 
}

 

정확한 엔진버전 등 정보들은 AWS RDS에 접속하여 확인하는 수밖에 없다.

이후 Plan, Apply를 적용시켜서 생성시켜 주자

성공적으로 생성!

 

 

11. EC2 인스턴스로 RDS 접속해 보기

이제 생성한 EC2에 MySQL을 설치하고 RDS에 접속해보고자 한다

그러기 위해선 RDS 엔드포인트 정보가 필요하다

terraform console
> aws_db_instance.web_db.endpoint

이후 EC2에 MySQL을 설치하자

본인은 Ubuntu 인스턴스이다

sudo apt install mysql-server

 

설치 후 RDS endpoint를 활용하여 mysql에 접속해 보자

참고로. com까지이다.

mysql -h {RDS ENDPOINT} -u admin -p

성공적으로 RDS까지 접속이 완료!!

 

 

✅ AWS 인프라 정리하기

이제 모든 인프라 구축을 끝냈으니 정리를 해볼 시간이다.

생성된 인프라를 한 번에 종료할 수 있는 것도 테라폼의 장점이다.

 

다음 명령어를 통해서 모든 리소스를 정리할 plan을 확인할 수 있다

terraform plan -destroy

 

이 계획 즉 plan을 실행시키려면 apply를 하면 된다.

terraform apply -destroy

yes를 입력하면 리소스를 모두 제거할 수 있다

모두 제거됐음을 알린다.

실제 모든 리소스가 제거됐음을 확인할 수 있었다.

 

 

 

 

마무리

처음으로 테라폼을 이용해 보니 오히려 번거로운 부분도 있었던 거 같다.
하지만 코드를 활용함으로써 인프라 상태를 확인하기가 더 쉬울 수가 있고, 기록이 남기 때문에 관리가 더 수월할 거 같다는 생각이 들었다. 
또한 코드를 저장소에 관리함으로써 인프라를 공유할 수도 있고,,
여러모로 재밌는 테라폼 첫 경험이었던 거 같다.

 

참고 자료https://www.44bits.io/ko/post/terraform_introduction_infrastrucute_as_code#%ED%85%8C%EB%9D%BC%ED%8F%BC-%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-%EC%B4%88%EA%B8%B0%ED%99%94