cloudNet@ 팀의 가시다 님이 진행하는 테라폼 102 스터디 입니다. (테라폼으로 시작하는 IaC” (한빛미디어) 도서로 진행!)
- 리전 내에서 사용 가능한 가용영역 목록 가져오기를 사용한 VPC 리소스 생성 실습 진행 혹은 아무거나 데이터 소스를 사용한 실습 진행
provider "aws" {
region = "ap-northeast-2"
}
data "aws_availability_zones" "available" {
state = "available"
}
resource "aws_vpc" "monitoring-VPC" {
cidr_block = "10.10.0.0/16"
#dns확인 (원래 활성화 되어있음)
enable_dns_support = true
# dns호스트이름
enable_dns_hostnames = true
tags = {
Name = "monitoring-VPC"
}
}
resource "aws_subnet" "monitoring-pub-NAT-A-01" {
vpc_id = aws_vpc.monitoring-VPC.id
cidr_block = "10.10.10.0/24"
availability_zone = data.aws_availability_zones.available.names[0]
tags = {
Name = "monitoring-pub-NAT-A-01"
}
}
resource "aws_subnet" "monitoring-pub-NAT-C-01" {
vpc_id = aws_vpc.monitoring-VPC.id
cidr_block = "10.10.30.0/24"
availability_zone = data.aws_availability_zones.available.names[2]
tags = {
Name = "monitoring-pub-NAT-C-01"
}
}
- 위 3개 코드 파일 내용에 리소스의 이름(myvpc, mysubnet1 등)을 반드시! 꼭! 자신의 닉네임으로 변경해서 배포 실습해보세요! (원본 코드는 2추자 내용 참고 부탁합니다.)
vpc.tf 생성
-----------------
provider "aws" {
region = "ap-northeast-2"
}
data "aws_availability_zones" "available" {
state = "available"
}
resource "aws_vpc" "monitoring-VPC" {
cidr_block = "10.10.0.0/16"
#dns확인 (원래 활성화 되어있음)
enable_dns_support = true
# dns호스트이름
enable_dns_hostnames = true
tags = {
Name = "monitoring-VPC"
}
}
resource "aws_subnet" "monitoring-pub-NAT-A-01" {
vpc_id = aws_vpc.monitoring-VPC.id
cidr_block = "10.10.10.0/24"
availability_zone = data.aws_availability_zones.available.names[0]
tags = {
Name = "monitoring-pub-NAT-A-01"
}
}
resource "aws_subnet" "monitoring-pub-NAT-C-01" {
vpc_id = aws_vpc.monitoring-VPC.id
cidr_block = "10.10.30.0/24"
availability_zone = data.aws_availability_zones.available.names[2]
tags = {
Name = "monitoring-pub-NAT-C-01"
}
}
# aws 프로바이더 유형이 aws_internet_gateway 이다
resource "aws_internet_gateway" "monitoring-igw" {
vpc_id = aws_vpc.monitoring-VPC.id
tags = {
Name = "monitoring-igw"
}
}
#별도의 라우팅 테이블 만든다.
resource "aws_route_table" "monitoring-pub-A-rt" {
vpc_id = aws_vpc.monitoring-VPC.id
tags = {
Name = "monitoring-pub-A-rt"
}
}
# 두개의 서브넷이 연동되는 리소스를 각각 만들어 준다. / aws_route_table_association = 라우팅 테이블 연동
resource "aws_route_table_association" "myrtassociation1" {
subnet_id = aws_subnet.monitoring-pub-NAT-A-01.id
route_table_id = aws_route_table.monitoring-pub-A-rt.id
}
# 두개의 서브넷이 연동되는 리소스를 각각 만들어 준다.
resource "aws_route_table_association" "myrtassociation2" {
subnet_id = aws_subnet.monitoring-pub-NAT-C-01.id
route_table_id = aws_route_table.monitoring-pub-A-rt.id
}
resource "aws_route" "mydefaultroute" {
route_table_id = aws_route_table.monitoring-pub-A-rt.id
#destination_cidr_block은 목적지 IP 주소 범위를 CIDR 표기법으로 지정하는 속성
destination_cidr_block = "0.0.0.0/0"
gateway_id = aws_internet_gateway.monitoring-igw.id
}
sg.tf 파일 생성: 보안그룹 생성
------------------------------
resource "aws_security_group" "monitoring-ADMIN" {
vpc_id = aws_vpc.monitoring-VPC.id
name = "ADMIN"
description = "monitoring-ADMIN"
tags = {
Name = "ADMIN"
}
}
resource "aws_security_group_rule" "monitoring-ADMIN-inbound" {
#인바운드
type = "ingress"
#시작하는 포트 번호
from_port = 80
#끝 포트 번호로, 이 경우에서도 80입니다. 따라서 이 규칙은 포트 80에서 시작해서 포트 80에서 끝나는 범위가 됩니다.
to_port = 80
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
security_group_id = aws_security_group.monitoring-ADMIN.id
}
resource "aws_security_group_rule" "monitoring-ADMIN-outbound" {
#아웃바운드
type = "egress"
from_port = 0
to_port = 0
#해당 규칙이 적용되는 프로토콜을 지정합니다. 여기서는 "-1"을 사용하고 있어 모든 프로토콜이 해당 규칙에 대해 허용됩니다.
protocol = "-1"
cidr_blocks = ["0.0.0.0/0"]
security_group_id = aws_security_group.monitoring-ADMIN.id
}
ec2생성 (ec2.tf 생성)
---------------------
#데이터 소스 블록이 있으며 ami 유형이 있다 my_amazonlinux2 이건 이름이므로 자기 마음대로
data "aws_ami" "my_amazonlinux2" {
#최신 AMI를 사용하려면 true로 설정합니다
most_recent = true
#원하는 AMI를 찾기 위한 필터를 정의합니다
filter {
#첫 번째 필터에서 owner-alias를 "amazon"으로 설정하여 Amazon 소유의 이미지만 검색합니다.
name = "owner-alias"
values = ["amazon"]
}
#두 번째 필터에서 name을 "amzn2-ami-hvm-*-x86_64-ebs"로 설정하여 Amazon Linux 2의 특정 이미지를 검색합니다
filter {
name = "name"
values = ["amzn2-ami-hvm-*-x86_64-ebs"]
}
#이미지 소유자를 지정합니다. 여기서는 "amazon"만 포함됩니다.
owners = ["amazon"]
}
#위에라인들이 속성 값들이며, 데이터 소스를 선언하였다.
resource "aws_instance" "my" {
#리소스의 속성을 주입하지 않아도 두 리소스 간에 종속성이 필요한 경우에, depends_on 선언으로 적용 가능
#인터넷 게이트웨이가 있어야지만 그뒤로 넘어감
depends_on = [
aws_internet_gateway.monitoring-igw
]
#위에 속성 값들을 이용하여 하드 코딩안하고 data 값을 참하여 가져온다 (ami 직접 안적음)
#검색한 Amazon Linux 2 AMI ID를 사용합니다.
ami = data.aws_ami.my_amazonlinux2.id
#인스턴스에 공용 IP 주소를 연결하려면 true로 설정합니다.
associate_public_ip_address = true
instance_type = "t2.micro"
#시큐리티 그룹 id 가져옴
vpc_security_group_ids = ["${aws_security_group.monitoring-ADMIN.id}"]
# 서브넷은 두 개인대 1번 가져옴
subnet_id = aws_subnet.monitoring-pub-NAT-A-01.id
#유저데이터 이용
user_data = <<-EOF
#!/bin/bash
wget https://busybox.net/downloads/binaries/1.31.0-defconfig-multiarch-musl/busybox-x86_64
mv busybox-x86_64 busybox
chmod +x busybox
#ec2 메타데이터 이용해서 현제 ec2에 배포된 az와 인스턴스 id 프라이빗 ip 을 변수에 넣어주고 index.html 넣는다
RZAZ=$(curl http://169.254.169.254/latest/meta-data/placement/availability-zone-id)
IID=$(curl 169.254.169.254/latest/meta-data/instance-id)
LIP=$(curl 169.254.169.254/latest/meta-data/local-ipv4)
echo "<h1>RegionAz($RZAZ) : Instance ID($IID) : Private IP($LIP) : Web Server</h1>" > index.html
nohup ./busybox httpd -f -p 80 &
EOF
#인스턴스 사용자 데이터가 변경될 때 인스턴스를 다시 생성하려면 true로 설정합니다.
user_data_replace_on_change = true
tags = {
Name = "monitoring-pri-web-A-01"
}
}
#출력 섹션 output "myec2_public_ip": 생성된 인스턴스의 공용 IP 주소를 출력합니다. 이를 통해 생성된 인스턴스에 접근하거나 연결할 수 있습니다.
output "myec2_public_ip" {
value = aws_instance.my.public_ip
description = "The public IP of the Instance"
}
- 입력변수를 활용해서 리소스(어떤 리소스든지 상관없음)를 배포해보고, 해당 코드를 정리해주세요
#입력을 통하여 원하는 버킷을 생성합니다.
provider "aws" {
region = "ap-northeast-2"
}
# 변수 선언
variable "sr-aws_s3_bucket" {
type = string
}
resource "aws_s3_bucket" "test_bucket" {
bucket = "test-bucket-${var.sr-aws_s3_bucket}"
}
----
root@DESKTOP-9HBHD7U:/home/minho/3.3# terraform apply -auto-approve
var.sr-aws_s3_bucket
Enter a value: minho2
하지만 이러한 식으로 할경우 단점이 있습니다 아래를 볼경우
root@DESKTOP-9HBHD7U:/home/minho/3.3# terraform destroy -auto-approve
var.sr-aws_s3_bucket
Enter a value: minho2
삭제를 할때도 변수를 입력하여 주어야 합니다(변수값이 없기때문) 그럼으로 입력을 통하여 생성을 하기보다는 변수를 선언하고 참조 하는 방식을 권장 드립니다
수정본
main.tf [입력변수]
--------------------
provider "aws" {
region = "ap-northeast-2"
}
variable "sr-aws_s3_bucket" {
type = string
default = "minho2"
}
s3.tf 입력 변수를 참조하는 S3 리소스 생성
------------------------------------------
resource "aws_s3_bucket" "test_bucket" {
bucket = "test-bucket-${var.sr-aws_s3_bucket}"
}
#s3버전관리
resource "aws_s3_bucket_versioning" "var_bucket" {
bucket = aws_s3_bucket.test_bucket.id
versioning_configuration {
status = "Enabled"
}
}
- local를 활용해서 리소스(어떤 리소스든지 상관없음)를 배포해보고, 해당 코드를 정리해주세요
# 로컬 변수 값 정의
locals {
db_engine = "mysql" # 데이터베이스 엔진 (MySQL)
db_engine_version = "5.7" # 데이터베이스 엔진 버전
db_instance_class = "db.t3.micro" # 데이터베이스 인스턴스 클래스 (RDS 인스턴스 유형)
db_parameter_group_name = "default.mysql5.7" # 데이터베이스 파라미터 그룹 이름
}
# AWS RDS 인스턴스 리소스 생성
resource "aws_db_instance" "default" {
allocated_storage = 10 # 할당된 스토리지 크기 (GB)
db_name = "mtest23213" # 생성할 데이터베이스 이름
engine = local.db_engine # 로컬 변수에서 데이터베이스 엔진값 가져오기
engine_version = local.db_engine_version # 로컬 변수에서 엔진 버전값 가져오기
instance_class = local.db_instance_class # 로컬 변수에서 인스턴스 클래스값 가져오기
username = "foo" # 데이터베이스 사용자 이름
password = "foobarbaz" # 데이터베이스 비밀번호
parameter_group_name = local.db_parameter_group_name # 로컬 변수에서 파라미터 그룹 이름 가져오기
skip_final_snapshot = true # 인스턴스 삭제 시 최종 스냅샷 생략
}
생성할경우 아래와 같이 rds는 생성되지만 name이상 합니다 그 이유는 Terraform에서 aws_db_instance 리소스 사용 시, db_name 속성에 설정한 값이 실제 데이터베이스 이름에 반영되지 않는 경우라서 입니다 그럼으로 아래의 코드를 추가 및 재배포 합니다.
수정본
# 로컬 변수 값 정의
locals {
db_engine = "mysql" # 데이터베이스 엔진 (MySQL)
db_engine_version = "5.7" # 데이터베이스 엔진 버전
db_instance_class = "db.t3.micro" # 데이터베이스 인스턴스 클래스 (RDS 인스턴스 유형)
db_parameter_group_name = "default.mysql5.7" # 데이터베이스 파라미터 그룹 이름
}
# AWS RDS 인스턴스 리소스 생성
resource "aws_db_instance" "default" {
allocated_storage = 10 # 할당된 스토리지 크기 (GB)
identifier = "mtest23213-ss3d3e3-bb-db-name" # 이렇게 설정하면 RDS 인스턴스 식별자가 생성됩니다.
db_name = "mtest23213" # 생성할 데이터베이스 이름
engine = local.db_engine # 로컬 변수에서 데이터베이스 엔진값 가져오기
engine_version = local.db_engine_version # 로컬 변수에서 엔진 버전값 가져오기
instance_class = local.db_instance_class # 로컬 변수에서 인스턴스 클래스값 가져오기
username = "foo" # 데이터베이스 사용자 이름
password = "foobarbaz" # 데이터베이스 비밀번호
parameter_group_name = local.db_parameter_group_name # 로컬 변수에서 파라미터 그룹 이름 가져오기
skip_final_snapshot = true # 인스턴스 삭제 시 최종 스냅샷 생략
}
- count, for_each 반복문, for문, dynamic문 을 활용해서 리소스(어떤 리소스든지 상관없음)를 배포해보고, 해당 코드를 정리해주세요
count
provider "aws" {
region = "ap-northeast-2"
}
resource "aws_instance" "test-ins" {
count = 2
ami = "ami-0b7c737f668580ff1"
instance_type = "t2.micro"
tags = {
Name = "test-ins - ${count.index}"
}
}
for_each
variable "instances" {
type = list(string)
default = [
"test-ins-1",
"test-ins-2",
]
}
provider "aws" {
region = "ap-northeast-2"
}
resource "aws_instance" "test-ins" {
for_each = toset(var.instances) # for_each를 적용하여 var.instances에 있는 각 항목 별로 리소스를 반복하도록 설정
ami = "ami-0b7c737f668580ff1"
instance_type = "t2.micro"
tags = {
Name = "${each.key}" # 각 반복 별에 해당하는 인스턴스 이름을 사용
}
}
for
variable "instances" {
type = list(string)
default = [
"test-ins-1",
"test-ins-2",
]
}
provider "aws" {
region = "ap-northeast-2"
}
resource "aws_instance" "test-ins" {
for_each = { for s in var.instances : s => upper(s) } # var.instances의 각 문자열을 대문자로 변환한 값을 사용하여 인스턴스 생성
ami = "ami-0b7c737f668580ff1"
instance_type = "t2.micro"
tags = {
Name = "${each.value}" # each.value를 사용하여 대문자로 변환된 인스턴스 이름을 사용
}
}
소문자를 대문자로 변환 하였습니다