기존의 포트값 = 기존과 동일한 인스턴스의 사용 → destory작업이 전혀 없음
Terraform을 이용한 단일서버 배포 실습
VSCode에서 ssh로 가상머신에 연결하여 작업( 권장 )
Terraform 코드는 확장자가 .tf 인 파일에 HCL(HashiCorp 구성 언어)로 작성 ( main.tf ) 이때 tf파일에는 ACESS_KEY등의 개인정보를 입력하지 않도록 함 ( 노출의 위험 )
(1) 공급자 구성
provider "aws" {
region = "ap-northeast-2"
}
Terraform에 AWS를 공급자로 사용할 것이며 인프라를 ap-northeast-2 지역에 배포할 것임을 선언
- aws provider를 사용하겠다는 선언 → aws 전용 바이너리를 다운받아서 사용가능
- region을 고정하여 프로비저닝 되는 리소스들의 region값을 고정한다
(2) 리소스 생성
리소스 생성 형식 : provider( aws,gcp .. ) + type( resource, vpc .. ) + “name”
resource "<PROVIDER>_<TYPE>" "<NAME>" {
[ CONFIG ...]
}
- provider : 공급자 이름 공급자별로 사용하는 바이너리는 호환되지 않음 → 명확하게 프로바이더를 지정
- type : 생성할 리소스 유형 ( vpc, subnet, instance …. )
- name : 테라폼 코드 전체에서 리소스를 참조할때 사용할 수 있는 식별자 클라우드에서 리소스의 이름을 지정하여 만드는 것이 아니라 테라폼에서 리소스를 관리할때 메타데이터로 활용하는 이름
resource "aws_instance" "example" {
ami = "ami-0f3a440bbcff3d043"
instance_type = "t2.micro"
}
aws_instance 리소스 ⇒ ami & instance_type 두개의 인수만 설정
- ami : EC2 인스턴스에서 실행할 Amazon 머신 이미지(AMI)
ami는 리전마다 다르고, 업데이트가 발생하면서 변경가능 ⇒ 필요시마다 정확하게 찾아서 넣어야함( aws cli를 이용하거나 콘솔의 AMI 카탈로그 )
Amazon Linux 2023 AMI ↔ Amazon Linux2 AMI(HVM) : 호환성이 전혀 안됨(2) AWS 콘솔 AMI 카탈로그에서 AMI번호 검색
(1) aws ec2 describe-images : CLI 명령어를 이용해 AMI 번호 찾기
(2) AWS 콘솔 AMI 카탈로그에서 AMI번호 검색
- instance_type : 실행할 EC2 인스턴스 유형 → 서로 다른 양의 CPU, 메모리, 디스크 공간 및 네트워킹 용량을 제공
[ init 명령 ]
tf파일이 작성된 working directory에서 init명령을 수행
terraform init
- 테라폼 코드를 스캔하고 사용중인 공급자를 파악하여 해당 바이너리 코드를 다운받도록 지시함 ⇒ 스크래치 디렉터리인 .terraform 폴더에 다운로드
- 다운로드한 공급자 코드에 대한 정보를 .terraform.lock.hcl 파일에 기록( 해시값 ) ⇒ init을 여러번 실행하도 멱등성을 보장
Initializing provider plugins : provider API로 요청을 보낼 수 있는 바이너리를 설치하는 작업( 프로바이더의 플러그인 바이너리를 다운로드 )
[ plan 명령 ]
실제로 변경하기 전에 Terraform이 수행할 작업을 확인
terraform plan
현재 pwd의 tf파일을 모두 읽어서 조합된 리소스 생성을 인식 → 자동으로 순서구성, 사용자에게 보고
더하기 기호(+) 항목은 모두 생성, 빼기 기호(-) 항목은 모두 삭제, 물결표 기호(~) 항목은 모두 수정
known after apply : 만들고 난 이후에 확인가능한 값
plan의 속성일부( key_name 등 )은 tf파일에서 지정가능
[ apply 명령 ]
terraform apply
이름 없는 EC2가 생성
terraform apply -auto-approve옵션을 사용할경우 yes를 입력하지 않아도됨
alias tfa='terraform apply -auto-approve'
alias tfd='terraform destroy -auto-approve'
alias를 지정하여 편하게 사용하기
~/.bashrc에 저장 ⇒ 적용 source ~/.bashrc ( 세션이 종료되어도 이용가능 )
[ cache directory ]
./.terraform : 바이너리를 다운로드 받는 위치
동일한 벤더의 프로바이더를 사용하는 다른 프로젝트에서는 새롭게 다운로드 받아서 개별적으로 사용하는 것보다(630M) 바이너리를 공유하는 것이 효율적임 → 공유가능한 cache directory구축하여 사용
cache directory : 다른 프로젝트 dir에서도 이곳의 바이너리를 참조하여 사용가능, 추가적인 다운로드 필요없음
.terraformrc 파일 : Terraform CLI의 설정 파일로, Terraform의 동작 방식을 사용자 정의할 수 있는 설정 옵션을 포함( 사용자 환경에 맞게 플러그인 캐싱, 인증 정보, 리모트 작업 설정 등을 관리 ) 설정에 따라 현재 디렉터리의 .terraform/plugins가 아닌 지정된 캐시 디렉터리($HOME/.terraform.d/plugin-cache)에서 플러그인을 다운로드하고 참조
Terraform을 이용한 단일 웹서버 배포
#!/bin/bash
echo "Hello, World" > index.html
nohub busybox httpd -f -p 8080 &
- nohup : 터미널 종료와 상관없이 프로세스가 계속 실행 ( 로그는 nohup.out 파일에 저장 )
-f 옵션으로 실시간 로그확인(데몬 프로세스화X) + &옵션으로 터미널 즉시 반환 - busybox : 리눅스 에뮬레이터, 각종 테스트 도구 탑재 → 내장된 busybox httpd서버 실행
[ 스크립트를 바로 실행하기 위한 EC2 인스턴스를 생성 ]
provider "aws" {
region = "ap-northeast-2"
}
resource "aws_instance" "example" {
ami = "ami-024ea438ab0376a47"
instance_type = "t2.micro"
user_data = <<-EOF
#!/bin/bash
echo "Hello, World" > index.html
nohup busybox httpd -f -p 8080 &
EOF
user_data_replace_on_change = true
tags = {
Name = "terraform-example"
}
}
- 인스턴스의 user data로 해당 스크립트를 입력 Terraform 코드에서 user_data 인수를 설정하여 사용자 데이터에 셸 스크립트를 전달
- <<-EOF 및 EOF : Terraform의 heredoc 구문으로, 여기저기에 \n 문자를 삽입하지 않고도 여러 줄 문자열을 생성
- user_data_replace_on_change = true : user_data(초기화 스크립트)가 변경되면 EC2 인스턴스를 교체 ( 구성의 변경이나 업데이트시 새로운 것으로 대체 ) ⇒ user_data는 첫번째 부팅시에만 실행되고 이미 부팅을 거친 인스턴스에서는 수정시에 실행될 수 없기에 이와같이 지정한다.
- AWS 콘솔에서 리소스를 구분하기 위해 사용되는 tag를 추가 ( EC2 인스턴스에 Name 태그를 지정하여 식별 )
[ 보안그룹 리소스 추가 ]
resource "aws_security_group" "instance" {
name = "terraform-example-instance"
ingress {
from_port = 8080
to_port = 8080
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
}
}
- AWS 콘솔에서 보이는 Security Group의 이름은 instance(테라폼 코드 내부 식별용)가 아니라 terraform-example-instance로 지정된다.
- ingress {} 블록: 인바운드 트래픽 규칙을 정의
- from_port( 허용 트래픽의 시작포트번호 ) ~ to_port( 허용 트래픽의 끝포트 번호 )
- protocol : 트래픽의 프로토콜 지정 & cidr_blocks : 트래픽의 CIDR 블록 범위를 지정
- TCP 프로토콜로 8080 포트에 대해 모든 IP 주소(0.0.0.0/0)에서 인바운드 트래픽이 허용
[ 보안그룹 적용 ]
보안 그룹의 ID를 aws_instance 리소스의 vpc_security _group_ids 인수에 전달하여 EC2 인스턴스에 실제로 사용하도록 지시
vpc_security_groups_ids = [aws_security_group.instance.id] : 해당 보안그룹의 ID를 참조하도록 한다 ⇒ security group의 적용은 가상머신의 삭제, 재기동 없이 자동으로 이루어짐
( ** 테라폼 표현식 : <PROVIDER>_<TYPE> . <NAME> . <ATTRIBUTE> → 해당 값을 반환 )
적용이전에 default security group이 지정됨
적용이후 terraform-example-instance 보안그룹이 지정됨
publicIP:지정포트로 인스턴스에 접속가능
provider "aws" {
region = "ap-northeast-2"
}
resource "aws_instance" "example" {
ami = "ami-024ea438ab0376a47"
instance_type = "t2.micro"
vpc_security_groups_ids = [aws_security_group.instance.id]
user_data = <<-EOF
#!/bin/bash
echo "hello world" > index.html
nohup busybox httpd -f -p 8080 &
EOF
user_data_replace_on_change = true
tags = {
Name = "terraform-example"
}
}
resource "aws_security_group" "instance" {
name = "terraform-example-instance"
ingress {
from_port = 8080
to_port = 8080
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
}
}
Terraform을 이용한 구성가능한 웹서버 배포
DRY(Don’t Repeat Yourself- 반복하지 않는다) 원칙에 따라 반복되는 값은 변수로 정의 → 관리 및 업데이트 용이
[ 입력변수 : variable 키워드 ]
variable "NAME" {
[CONFIG ...]
}
다양한 config설정
- type : 변수 유형 제약조건
number, string, bool, list(인덱스와 데이터로 구성), map(키와 값으로 구성), object(객체유형, 내부속성의 유형제약조건 ) - description : 변수의 목적, 사용법
- default : 기본값 → 명령줄, 파일, 환경변수 등으로 값을 제공받아 대체가능
- validation : 입력변수에 대한 사용자 정의 유효성 검사 규칙 정의
- sensitive : terrform plan, terraform apply 시에 기록하지 않음 ⇒ 비밀값( 비밀번호, API 키 ) 등에 적용
[ 예시 ] 중복된 포트값(8080)을 server_port라는 변수로 지정하여 활용
provider "aws" {
region = "ap-northeast-2"
}
resource "aws_instance" "example" {
vpc_security_group_ids = [aws_security_group.instance.id]
ami = "ami-024ea438ab0376a47"
instance_type = "t2.micro"
user_data = <<-EOF
#!/bin/bash
echo "hello world" > index.html
nohup busybox httpd -f -p ${var.server_port} &
EOF
user_data_replace_on_change = true
tags = {
Name = "terraform-example"
}
}
resource "aws_security_group" "instance" {
name = "terraform-example-instance"
ingress {
from_port = var.server_port
to_port = var.server_port
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
}
}
variable "server_port" {
description = "The port. the server will user for HTTP requests"
type = number
}
- 변수 선언 : variable키워드로 server_port라는 변수 선언 ( 숫자타입 ) ( * 이는 리소스가 아님 )
- 변수 참조식
- var.<VARIABLE_NAME> : from_port, to_port의 값을 var.server_port로 지정 ( “”을 사용하지 않으면 참조의 의미 )
- ${ var.<VARIABLE_NAME> } : userdata에서는 변수 랜더링이 필요함 ${ var.server_port }
- 다양한 변수 값 지정 방식
- terraform apply 작업시에 프롬프트로 해당값을 입력받음( 어떤 변수에서도 설정하지 않음 )
- -var 명령줄 옵션으로 값 지정 terraform plan -var "server_port=8080"
- 환경변수 TF_VAR_<name>으로 값 설정 ( export ) export TF_VAR_server_port=8080
- default 값으로 설정
포트를 변수화하여 변경하고 apply할때 → 테라폼의 판단으로 일부 리소스는 수정, 일부는 삭제 후 재생성
- 기존의 ec2인스턴스(aws_instance.example)는 destory되고 새로운 포트의 인스턴스가 생성
- 기존의 보안그룹(aws_security_group.instance)은 단순히 업데이트만 이루어짐( modifying )
기존의 인스턴스는 종료되고 새롭게 생긴 인스턴스의 보안그룹 포트는 8888임
새로운 퍼블릭주소를 가진 인스턴스에 8888포트로 접속
[ 출력변수 : output 키워드 ]
프로비저닝의 목표 : 리소스 생성 + 즉시제공 ( terraform이 프로비저닝 이후 사용자가 즉시 리소스를 활용하도록 정보를 전달 )
output "<NAME>" {
value = <VALUE>
[CONFIG ...]
}
value값은 생성된 리소스의 속성값으로 지정 <PROVIDER>_<TYPE> . <NAME> . <ATTRIBUTE>
[ 예시 ] 새롭게 할당된 public ip를 프로비저닝후 즉시 제공
provider "aws" {
region = "ap-northeast-2"
}
resource "aws_instance" "example" {
vpc_security_group_ids = [aws_security_group.instance.id]
ami = "ami-024ea438ab0376a47"
instance_type = "t2.micro"
user_data = <<-EOF
#!/bin/bash
echo "hello world" > index.html
nohup busybox httpd -f -p ${var.server_port} &
EOF
user_data_replace_on_change = true
tags = {
Name = "terraform-example"
}
}
resource "aws_security_group" "instance" {
name = "terraform-example-instance"
ingress {
from_port = var.server_port
to_port = var.server_port
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
}
}
variable "server_port" {
description = "The port. the server will user for HTTP requests"
type = number
}
output "public_ip" {
value = aws_instance.example.public_ip
description = "The public IP address of the web server"
}
기존의 포트값 = 기존과 동일한 인스턴스의 사용 → destory작업이 전혀 없음
+) output 변수값 활용하기
생성후 추후에도 그 값들을 열람가능( terraform output )
특정 output변수만 열람가능( terraform output <output_NAME> )
output변수를 참조가능 ( terraform output -raw <NAME> )
output 값에 대한 테스트 ⇒ 스크립트를 생성하여 활용가능
#!/bin/bash
curl $(terraform output -raw public_ip):8888
#!/bin/bash
curl $(terraform output -raw public_ip):8888
if [ $? == 0 ]
then
echo "success";
fi
⇒ 파이프라인 형식을 구축하여 순차적으로 개발, 검증 등의 프로세스를 수행할 수 있다. ( CI/CD의 핵심은 자동화된 테스트 )
⇒ input을 투입하면 파이프라인 과정을 거쳐서 원하는 output이 자동으로 생성된다.
'CLOUDWAVE' 카테고리의 다른 글
IaC : Terraform - 테라폼 상태관리 및 상태파일(tfstate) (1) | 2025.02.07 |
---|---|
IaC : Terraform 실습 - 웹클러스터 배포, 로드밸런서 배포, 자원반환 (0) | 2025.02.07 |
IaC : Terraform - 테라폼 소개, 테라폼 환경 구축 (0) | 2025.02.07 |
IaC : Ansible 변수관리 및 작업제어 (0) | 2025.02.01 |
IaC : Ansible 구성요소 - config file, Inventory file, Playbook (0) | 2025.02.01 |