Terraform - 이때다 싶다.
Terraform으로 인스턴스 생성까지
by HOON
1
Last updated on Feb. 7, 2025, 9:33 a.m.
안녕하세요.
오늘은 IaC(Infrastructure as Code)의 종류인 terraform을 사용해서 ec2 인스턴스까지 생성하는 과정을 적어보려고 합니다.
1. terraform 설치
우선, 저는 terraform이 설치되어있지않아서 brew로 설치부터 하겠습니다.
$ brew install terraform 127 ✘
==> Auto-updating Homebrew...
Adjust how often this is run with HOMEBREW_AUTO_UPDATE_SECS or disable with
HOMEBREW_NO_AUTO_UPDATE. Hide these hints with HOMEBREW_NO_ENV_HINTS (see `man brew`).
==> Downloading https://ghcr.io/v2/homebrew/portable-ruby/portable-ruby/blobs/sha256:4ffc8607e08e9bd536f1df71643b2ecb4cea1a15be9226f297008bc34d0bc8e2
설치가 다 되었다면, 꼭 제대로 설치되었나 확인해요!
$ terraform version
Terraform v1.5.7
on darwin_amd64
Your version of Terraform is out of date! The latest version
is 1.10.5. You can update by downloading from https://www.terraform.io/downloads.html
버전이 나오는걸 보니 제대로 설치가 된 것 같아요.
2.Provider 정의하기
terraform은 여러가지 서비스와 연계 할 수 있어요. 저희는 AWS와 연계 할 예정입니다.
따라서 테스트 프로젝트 폴더를 작성하고, 경로 아래에 provider.tf를 생성 및 작성 해볼게요.
#provider.tf
$ touch provider.tf
provider "aws" {
access_key = "<AWS_ACCESS_KEY>"
secret_key = "<AWS_SECRET_KEY>"
region = "ap-northeast-2"
}
provider는 aws로 지정했습니다. 그럼 접근하려면 key값이 있어야겠죠?? 각각의 키 값의 위치는
AWS 콘솔 - IAM - 사용자 - 액세스 키 생성시 보이는 ACCESS_KEY와 생성시에만 보이는 SECRET_KEY를 넣어주면 됩니다!!
그리고, region은 aws기준 서울 리전을 선택했습니다.
Provider는 완성됐으니 이제 init 해볼까요?? init을 하는 이유는 provider로 aws를 선택했으니 aws관련된 플러그인을 생성하기 위함입니다.
$ terraform init ✔ took 15s
Initializing the backend...
Initializing provider plugins...
- Finding latest version of hashicorp/aws...
- Installing hashicorp/aws v5.85.0...
- Installed hashicorp/aws v5.85.0 (signed by HashiCorp)
Terraform has created a lock file .terraform.lock.hcl to record the provider
selections it made above. Include this file in your version control repository
so that Terraform can guarantee to make the same selections by default when
you run "terraform init" in the future.
Terraform has been successfully initialized!
You may now begin working with Terraform. Try running "terraform plan" to see
any changes that are required for your infrastructure. All Terraform commands
should now work.
If you ever set or change modules or backend configuration for Terraform,
rerun this command to reinitialize your working directory. If you forget, other
commands will detect it and remind you to do so if necessary.
그리고 다시한번 version을 출력해보면 아까와 다르게 aws가 추가 된 것을 볼 수 있어요!
$ terraform version ✔ took 11s
Terraform v1.5.7
on darwin_amd64
+ provider registry.terraform.io/hashicorp/aws v5.85.0
Your version of Terraform is out of date! The latest version
is 1.10.5. You can update by downloading from https://www.terraform.io/downloads.html
그럼 이제 본격적으로 tf 코드를 작성해보겠습니다.
먼저, 이름은 aws_server.tf
로 정의 하겠습니다.
다음, EC2를 접속하기 위해 필요한게 뭐가 있을까요?? 아마 대부분이 ssh 연결로 접속해서 작업 하실 것으로 예상됩니다. 저도 리소스 사용을위해 항상 키를 사용하거든요.
그럼 키를 생성해서 연결해볼까요??
#aws_server.tf
$ touch aws_server.tf
resource "aws_key_pair" "server_admin" { #이름이 server_admin인 aws_key_pair 리소스
key_name = "server_admin" # 실제 aws에 저장될 키값 이름입니다.
public_key = file("~/.ssh/server_admin.pub")
}
- resource : “aws_key_pair” “server_admin”은 aws_key_pair 라는 리소스를 생성하는데 이름을 server_admin 으로 하겠다. 라는 뜻입니다.
- key_nam : 실제 aws에 해당 이름으로 키값이 생성 됩니다.
- public_key : 2048길이의 키값으로 생성된 파일을 불러옵니다.
저는 기존에 생성되어있는 키를 그대로 사용하려다 2048자가 넘어서 이후 작업에서 에러가 발생했습니다.
3. 적용 전 검증하기(plan)
그럼 저희가 작성한 tf 파일 내용이 실제로 적용이 가능한건지 검증 해야겠죠?? terraform에서는 plan 명령어를 통해 검증 할 수 있습니다. 그 이후 apply 명령어를 통해 실제 리소스를 생성하는 작업을 할 수 있습니다.
$ terraform plan ✔ took 9s
Terraform used the selected providers to generate the following execution plan. Resource
actions are indicated with the following symbols:
+ create
Terraform will perform the following actions:
# aws_key_pair.web_admin will be created
+ resource "aws_key_pair" "web_admin" {
+ arn = (known after apply)
+ fingerprint = (known after apply)
+ id = (known after apply)
+ key_name = "web_admin"
+ key_name_prefix = (known after apply)
+ key_pair_id = (known after apply)
+ key_type = (known after apply)
+ public_key = "ssh-rsa *****"
+ tags_all = (known after apply)
}
Plan: 1 to add, 0 to change, 0 to destroy.
정상적으로 적용 할 수 있을 것 같네요! + 모양은 실제 작성된 내용중 추가된 내용을 뜻합니다.
만약 작성된 내용이 사라졌다면 - 로 표시되겠죠??
그럼 추가되고 삭제된 내용을 어떻게 추적 할 수 있을까요??
그건 바로 전에 terraform init
작업을 했을 때 생성된 파일 terraform.tfstate
에 숨어있습니다.
해당 파일은 Terraform이 관리하는 클라우드 리소스(예: AWS, Azure, GCP 등)의 현재 상태를 JSON 형식으로 저장합니다.
cat terraform.tfstate ✔
{
"version": 4,
"terraform_version": "1.5.7",
"serial": 15,
"lineage": "********-****-****-****-************",
"outputs": {},
"resources": [
{
"mode": "data",
"type": "aws_security_group",
"name": "default",
"provider": "provider[\"registry.terraform.io/hashicorp/aws\"]",
"instances": [
{
"schema_version": 0,
"attributes": {
"arn": "arn:aws:ec2:ap-northeast-2:************:security-group/sg-********",
"description": "default VPC security group",
"filter": null,
"id": "sg-********",
"name": "default",
"tags": {},
"timeouts": null,
"vpc_id": "vpc-********"
},
"sensitive_attributes": []
}
]
}
],
"check_results": null
}
자, 다시 본론으로 돌아가서 이번에는 적용 가능한걸 알았으니, 실제로 적용 해볼까요??
4. 리소스 실제 생성하기 (apply)
생성을 위해 이번엔 terraform apply
명령어를 사용해볼게요.
$ terraform apply ✔ took 9s
Terraform used the selected providers to generate the following execution plan. Resource
actions are indicated with the following symbols:
+ create
Terraform will perform the following actions:
# aws_key_pair.web_admin will be created
+ resource "aws_key_pair" "web_admin" {
+ arn = (known after apply)
+ fingerprint = (known after apply)
+ id = (known after apply)
+ key_name = "web_admin"
+ key_name_prefix = (known after apply)
+ key_pair_id = (known after apply)
+ key_type = (known after apply)
+ public_key = "ssh-rsa *****"
+ tags_all = (known after apply)
}
Plan: 1 to add, 0 to change, 0 to destroy.
Do you want to perform these actions?
Terraform will perform the actions described above.
Only 'yes' will be accepted to approve.
Enter a value: yes
aws_key_pair.web_admin: Creating...
aws_key_pair.web_admin: Creation complete after 0s [id=web_admin]
Apply complete! Resources: 1 added, 0 changed, 0 destroyed.
어라? 저희 plan 명령어 출력 포맷이 한번 더 출력 됐네요.
다른점은 실제 Enter a value: yes
를 입력 받아야지만 생성을 하는 구조에요.
plan은 그래도 검증때문에라도 사용하는 습관을 들이는게 좋겠죠??
그럼 이제 실제로 생성 됐는지 확인하러 가보겠습니다!!
정상적으로 생성 된 걸 확인 할 수 있습니다.
5. SSH 접속
그럼 이제 EC2에 접속하기위해 SSH를 설정 해볼까요?
이전에 작성한 aws_key_pair 아래에 작성합니다.
#aws_server.tf
resource "aws_security_group" "ssh" {
name = "allow_ssh"
description = ""
ingress { # ingress 규칙 정의
from_port = 22 # 22번 포트 부터
to_port = 22 # 22번 포트 까지
protocol = "tcp"
cidr_blocks = ["43.*.*.*/0"] #특정 IP정의
}
}
다시한번 terraform plan
을 해볼까요??
$ terraform apply
aws_key_pair.web_admin: Refreshing state... [id=web_admin]
Terraform used the selected providers to generate the following execution plan. Resource actions
are indicated with the following symbols:
+ create
Terraform will perform the following actions:
# aws_security_group.ssh will be created
+ resource "aws_security_group" "ssh" {
+ arn = (known after apply)
+ description = ""
+ egress = (known after apply)
+ id = (known after apply)
+ ingress = [
+ {
+ cidr_blocks = [
+ "43.*.*.*/0",
]
+ description = ""
+ from_port = 22
+ ipv6_cidr_blocks = []
+ prefix_list_ids = []
+ protocol = "tcp"
+ security_groups = []
+ self = false
+ to_port = 22
},
]
+ name = "allow_ssh"
+ name_prefix = (known after apply)
+ owner_id = (known after apply)
+ revoke_rules_on_delete = false
+ tags_all = (known after apply)
+ vpc_id = (known after apply)
}
Plan: 1 to add, 0 to change, 0 to destroy.
이상없네요! 이대로 apply까지 해볼게요
Do you want to perform these actions?
Terraform will perform the actions described above.
resource "aws_key_pair" "web_admin" {
Only 'yes' will be accepted to approve.
Enter a value: yes
aws_security_group.ssh: Creating...
aws_security_group.ssh: Creation complete after 2s [id=sg-*]
6. VPC, EC2 인스턴스 생성
마지막으로 EC2 인스턴스를 한번 생성 해볼게요.
#aws_server.tf
data "aws_security_group" "default" {
name = "default" #기본 default VPC 사용
}
resource "aws_instance" "web" {
ami = "ami-00252d017d66f9cdd" #이미지
instance_type = "t2.micro" #t2.micro 선택
key_name = aws_key_pair.web_admin.key_name #작성되어있는 키 이름 기입
vpc_security_group_ids = [
aws_security_group.ssh.id, #security group에 필요한 정보 입력
data.aws_security_group.default.id
]
}
우선 사용가능한 ami 이미지 목록을 가져와볼게요. 저는 제일 상단에 있는 이미지를 넣었습니다.
$ aws ec2 describe-images --owners amazon --filters "Name=name,Values=amzn2-ami-hvm-*-x86_64-gp2" --query "Images[*].[ImageId,Name]" --output table
----------------------------------------------------------------------
| DescribeImages |
+------------------------+-------------------------------------------+
| ami-00252d017d66f9cdd | amzn2-ami-hvm-2.0.20240124.0-x86_64-gp2 |
| ami-00a08b445dc0ab8c1 | amzn2-ami-hvm-2.0.20231020.1-x86_64-gp2 |
| ami-0217b147346e48e84 | amzn2-ami-hvm-2.0.20240412.0-x86_64-gp2 |
| ami-022db573829bf517a | amzn2-ami-hvm-2.0.20240131.0-x86_64-gp2 |
| ami-01dc121da1bd8cc87 | amzn2-ami-hvm-2.0.20240223.0-x86_64-gp2 |
| ami-02428dc32a3b6596f | amzn2-ami-hvm-2.0.20230612.0-x86_64-gp2 |
| ami-01d0b412b1ee1415c | amzn2-ami-hvm-2.0.20230906.0-x86_64-gp2 |
| ami-01bc8f85a143385bc | amzn2-ami-hvm-2.0.20250123.4-x86_64-gp2 |
마찬가지로, terraform plan, terraform apply
를 적용하면 이상없이 적용되는 걸 볼 수 있습니다.
실제로 aws 콘솔에 리소스가 생성 된 걸 확인 할 수 있고, terraform console
를 사용해서 우리가 생성한 ec2 리소스의 ip를 가져 올 수 있습니다.
$ terraform console ✔ took 24s
> aws_instance.web.public_ip
"<EC2-IP>"
물론 접속은 ssh와 키를 사용해서 접속 할 수 있겠죠??
ssh -i ~/.ssh/web_admin ec2-user@<EC2-IP>
이렇게 terraform으로 EC2 인스턴스를 생성하고, ssh로 접속도 해봤습니다.
그럼 이제 삭제하는 방법도 알아보겠습니다!
7. 리소스 삭제
삭제는 간단합니다. 앞서 설명드린 내용중 terraform은 terraform.tfstate
를 통해 상태를 관리한다고 했습니다. 그럼 삭제도 해당 파일을 참고해서 삭제하면 되겠죠??
명령어는 간단합니다.
$ terraform destroy
. . .
Do you really want to destroy all resources?
Terraform will destroy all your managed infrastructure, as shown above.
There is no undo. Only 'yes' will be accepted to confirm.
Enter a value: yes
aws_instance.web: Destroying... [id=i-*****]
aws_instance.web: Still destroying... [id=i-*****, 10s elapsed]
aws_instance.web: Destruction complete after 14s
aws_key_pair.web_admin: Destroying... [id=web_admin]
aws_security_group.ssh: Destroying... [id=sg-*****]
aws_key_pair.web_admin: Destruction complete after 0s
aws_security_group.ssh: Destruction complete after 1s
Destroy complete! Resources: 3 destroyed.
이렇게 세 개의 리소스가 삭제되었습니다.
(실제 인스턴스 삭제를 확인하려면 바로 삭제되기보다, 일정 시간이 지나면 삭제가 됩니다. 참고하세요!)
Leave a Comment: