Github를 통해 코드 관리
https://github.com/chadness12/Terraform-101-Study/tree/main/week3
1. 도전과제
1) 조건문을 활용하여 AWS 리소스를 배포하는 코드를 작성해보자
- 지정된 이름으로만 인스턴스를 생상가능하게 하는 AWS 리로스 배포 코드 입니다
(1) variable.tf
# 이름 체크를 위한 변수
variable "check_name" {
type = list(string)
description = "which name we need to allow"
default = ["chad", "megan", "jason"]
}
# 이름을 입력하기 위한 변수
variable "input_name" {
type = list(string)
description = "which name we input"
default = ["chad", "test", "jason"]
}
(2) main.tf - 조건문 사용 확인
# amazon linux2 ami이미지
data "aws_ami" "myamzonlinux2" {
most_recent = true
filter {
name = "owner-alias"
values = ["amazon"]
}
filter {
name = "name"
values = ["amzn2-ami-hvm-*-x86_64-ebs"]
}
owners = ["amazon"]
}
resource "aws_instance" "Challenge1" {
instance_type = "t2.micro"
count = length(var.input_name)
# (a) : check_name 변수 안에 input_name의 값이 존재하지 않으면 ec2를 생성하지 않음
ami = contains(var.check_name, var.input_name[count.index]) ? data.aws_ami.myamzonlinux2.id : "error"
tags = { Name = var.input_name[count.index] }
# (b) : check_name의 길이와 input_name의 길이가 같지 않으면 오류 생성
lifecycle {
precondition {
condition = length(var.input_name) == length(var.check_name)
error_message = "The number of your inputs is not the same as the number of check_name"
}
}
}
- (a) : check_name 변수 안에 input_name의 값이 존재하지 않으면 ec2를 생성하지 않음
- (b) : check_name의 길이와 input_name의 길이가 같지 않으면 오류 생성
(3) Termianl & Console 확인
a. Termianl 확인
- input_name 의 2번 째 인덱스인 test가 check_name 에 없기 때문에 에러가 뜨는것을 확인할 수 있음
b. Console 확인
- chad, jason만 생성된 것을 확인 가능
2) 내장 함수를 활용하여 리소스를 배포
- 특정한 네이밍 규칙에 따라 이름을 지정해야지만 subnet이 생성가능한 AWS 리소스 배포 코드입니다.
(1) variable.tf - regex , can 내장함수 사용 확인
variable "subnet_name" {
validation {
# (a) can - error가 출력되는 상황이라면 bool값을 false로 반환해주는 함수
# (b) regex - 입력값이 정규표현식과 매칭되는지 확인해주는 함수
condition = can(regex("^terraform-(public|private)-(az_a|az_b|az_c|az_d)-subnet", var.subnet_name))
error_message = "your subnet name is not match with naming-rule"
}
}
- (a) can - error가 출력되는 상황이라면 bool값을 false로 반환해주는 함수
- (b) regex - 입력값이 정규표현식과 매칭되는지 확인해주는 함수
- 네이밍 규칙을 세우기 위해 함수를 사용하였다
- 위의 코드에서는 terraform-(publcir, private)-(az_a, az_b, az_c, az_d)-subnet 으로 Subnet이름을 지정하지않는다면 에러를 출력한다.
(2) main.tf
#vpc 선언
resource "aws_vpc" "Challange2_vpc" {
cidr_block = "192.168.0.0/16"
tags = {
Name = "Challange2"
}
}
#data 소스를 활용하여 리전내 가용영역을 가져옴
data "aws_availability_zones" "available" {
state = "available"
}
#availability_zones_a 에 subnet 영역 생성
resource "aws_subnet" "Challange2_subnet_a" {
vpc_id = aws_vpc.Challange2_vpc.id
cidr_block = "192.168.0.0/24"
availability_zone = data.aws_availability_zones.available.names[0]
tags = {
Name = var.subnet_name
}
}
(3) Terminal 확인
a. 정규식에 맞게 변수를 설정하였을때
- 정상적으로 배포가 되는 것을 확인할 수 있음
b. 정규식에 맞지 않게 변수를 설정하였을때
- 설정한 에러 메세지가 출력되는 것을 확인할 수 있음
3) AWS_EC2를 remote-exec/file 프로비저너를 활용하여 배포해보기
- 프로비저너를 활용하여 웹서버를 배포하는 코드입니다.
(1) main.tf - file, remoete-exec 사용 확인
data "aws_ami" "myamzonlinux2" {
most_recent = true
filter {
name = "owner-alias"
values = ["amazon"]
}
filter {
name = "name"
values = ["amzn2-ami-hvm-*-x86_64-ebs"]
}
owners = ["amazon"]
}
resource "aws_instance" "Challenge3" {
instance_type = "t2.micro"
ami = data.aws_ami.myamzonlinux2.id
key_name = "enterprise"
tags = { Name = "Challenge3" }
# (a) ec2와 연결할 방식에 대한 설명
connection {
type = "ssh"
user = "ec2-user"
private_key = file("./enterprise.pem")
host = self.public_ip
}
# (b) file 프로비저너를 사용하여 쉘스크립트를 전송함
provisioner "file" {
source = "html.sh"
destination = "/home/ec2-user/html.sh"
}
# (c) remote-exec 프로비저너를 사용하여 해당 쉘스크립트를 실행함
provisioner "remote-exec" {
inline = ["bash /home/ec2-user/html.sh"]
}
}
- (a) ec2와 연결할 방식에 대한 설명
- (b) file 프로비저너를 사용하여 쉘스크립트를 전송함
- (c) remote-exec 프로비저너를 사용하여 해당 쉘스크립트를 실행함
(2) html.sh
- 웹서버를 실행시키는 코드
#!/bin/bash
sudo yum update -y
sudo yum install httpd -y
sudo systemctl start httpd
sudo systemctl enable httpd
sleep 10
sudo tee /var/www/html/index.html <<EOF
<h1>remote-exe </h1>
EOF
sudo systemctl restart httpd
(3) Console , 웹페이지 확인
a. Console 및 서버 내부 html.sh 파일 존재 여부 확인
b. 웹페이지 확인
4) terraform_data 리소스와 trigger_replace 를 사용한 배포
- ec2에 대해서 ssh 포트를 지속해서 변경하여 배포하는 코드입니다. variable.tf 만 수정한다면 자동으로 ec2 내부 ssh 포트 변경, inbound 포트를 변경합니다.
(1) variable.tf
- index - 1번 값만 바꿔준다면 ssh 포트 변경이 가능합니다
- list를 사용한 이유는 terraform_data에서 remote 프로비저너를 사용시 이전 포트 정보가 존재해야하기 때문입니다.
variable ssh_port { default = [22,22] }
(2) vpc.tf
#vpc 선언
resource "aws_vpc" "Challange4_vpc" {
cidr_block = "192.168.0.0/16"
tags = {
Name = "Challange4"
}
}
data "aws_availability_zones" "available" {
state = "available"
}
#availability_zones_a 에 subnet 영역 생성
resource "aws_subnet" "Challange4_subnet_a" {
vpc_id = aws_vpc.Challange4_vpc.id
cidr_block = "192.168.0.0/24"
availability_zone = data.aws_availability_zones.available.names[0]
tags = {
Name = "Challange4_subnet_a"
}
}
#internet gateway 생성
resource "aws_internet_gateway" "Challange4_igw" {
vpc_id = aws_vpc.Challange4_vpc.id
tags = {
Name = "Challange4_igw"
}
}
#라우팅 테이블 생성
resource "aws_route_table" "Challange4_rtb" {
vpc_id = aws_vpc.Challange4_vpc.id
tags = {
Name = "Challange4_rtb_Public_a"
}
}
resource "aws_route" "igw" {
route_table_id = aws_route_table.Challange4_rtb.id
destination_cidr_block = "0.0.0.0/0"
gateway_id = aws_internet_gateway.Challange4_igw.id
}
#라우팅 테이블 과 subnet_a 와 연결
resource "aws_route_table_association" "asso_with_subnet_a" {
subnet_id = aws_subnet.Challange4_subnet_a.id
route_table_id = aws_route_table.Challange4_rtb.id
}
resource "aws_security_group" "Challange4_sg" {
vpc_id = aws_vpc.Challange4_vpc.id
name = "Challange4_sg"
}
# (a) var.ssh_port[1]을 참조하여 인바운드 포트 지정
resource "aws_security_group_rule" "Challange4_inbound" {
type = "ingress"
from_port = var.ssh_port[1]
to_port = var.ssh_port[1]
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
security_group_id = aws_security_group.Challange4_sg.id
}
resource "aws_security_group_rule" "Challange4_outbound" {
type = "egress"
from_port = 0
to_port = 0
protocol = "-1"
cidr_blocks = ["0.0.0.0/0"]
security_group_id = aws_security_group.Challange4_sg.id
}
- (a) var.ssh_port[1]을 참조하여 인바운드 포트 지정
(3) main.tf - terraform_data 사용 확인
resource "aws_instance" "Challange4_ec2" {
ami = "ami-00d253f3826c44195"
associate_public_ip_address = true
instance_type = "t2.micro"
subnet_id = aws_subnet.Challange4_subnet_a.id
vpc_security_group_ids = ["${aws_security_group.Challange4_sg.id}"]
key_name = "enterprise"
tags = {
Name = "Challange4_ec2"
}
user_data = <<-EOF
#!/bin/bash
touch /etc/ssh/sshd_config.d/Port.conf
EOF
}
# (a) terraform apply 가 실행될 때마다 실행되는 terraform_data
resource "terraform_data" "test" {
triggers_replace = [
timestamp()
]
connection {
type = "ssh"
port= var.ssh_port[0]
user = "ec2-user"
private_key = file("./enterprise.pem")
host = aws_instance.Challange4_ec2.public_ip
}
provisioner "remote-exec" {
inline = [
"echo 'Port = ${var.ssh_port[1]}' | sudo tee /etc/ssh/sshd_config.d/Port.conf",
"sudo systemctl restart sshd"
]
}
provisioner "local-exec" {
command = "echo 'variable ssh_port { default = [${var.ssh_port[1]}, ${var.ssh_port[1]}] > ./variable.tf }' "
}
}
- (a) terraform apply 가 실행될 때마다 실행되는 terraform_data
- connetion.port = var.ssh_port[0] 을 참조하는 이유 : var.ssh_port[1] 이 변경되어 apply 가 실행된다면 connection이 이루어 질 수 없음
- provisioner "remote-exec" : ec2내의 ssh 설정을 var.ssh_port[1]을 참조하여 변경
- provisioner "local-exec" : 변경된 포트 설정을 모두 variable.tf 에 저장
(4) Console 확인 및 ssh 접속 테스트
a. 22번 포트로 설정 시
- Console 확인
- ssh 접속 확인
b. 2222번 포트 설정시
- Console 확인
- inbound 포트 2222 변경 확인
- ssh 접속 테스트
- 2222번 포트로 접속 가능함을 확인할 수 있음
5) moved 블록을 사용한 테라폼 코드 리팩터링
(1) variable.tf
variable "cidr_list" {
default = {
subnet_a = {
az = "ap-northeast-2a"
cidr_block = "192.168.0.0/24"
name = "subnet_a"
}
subnet_b = {
az = "ap-northeast-2b"
cidr_block = "192.168.1.0/24"
name = "subnet_b"
}
}
}
(2) main.tf - moved 사용확인
- 기존에 생성했던 단일 서브넷 리소스를 다중 서브넷 리소스이 포함하게하는 moved 블록 활용입니다.
data "aws_availability_zones" "available" {
state = "available"
}
resource "aws_vpc" "Challange5_vpc" {
cidr_block = "192.168.0.0/16"
tags = {
Name = "Challange5"
}
}
# #availability_zones_a 에 subnet 영역 생성
# resource "aws_subnet" "Challange5_subnet" {
# vpc_id = aws_vpc.Challange5_vpc.id
# cidr_block = "192.168.0.0/24"
# availability_zone = data.aws_availability_zones.available.names[0]
# tags = {
# Name = "Challange5_subnet_a"
# }
# }
resource "aws_subnet" "Challange5_subnet" {
for_each = var.cidr_list
vpc_id = aws_vpc.Challange5_vpc.id
cidr_block = each.value.cidr_block
availability_zone = each.value.az
tags = {
Name = "Challange5_${each.value.name}"
}
}
# (a) 기존에 생성했넌 subent을 aws_subnet.Challange5_subnet["subnet_a"]으로 옮김
moved {
from = aws_subnet.Challange5_subnet
to = aws_subnet.Challange5_subnet["subnet_a"]
}
(3) moved 블록 적용 확인
a. 적용전 state
b. 정상적용 확인
- state 확인 - subnet_a 의 arn이 적용전 subnet의 arn과 같음을 확인 가능
6) AWS 2개의 리전에 s3 배포
- AWS 도쿄, 서울 리전 각각에 s3를 배포하는 코드입니다
(1) provider.tf
terraform {
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 4.0"
}
}
}
provider "aws" {
alias = "region-1"
region = "ap-northeast-2"
}
provider "aws" {
alias = "region-2"
region = "ap-northeast-1"
}
(2) main.tf
resource "aws_s3_bucket" "region_1-s3" {
provider = aws.region-1
bucket = "leechad-korea-s3"
}
resource "aws_s3_bucket" "region_2-s3" {
provider = aws.region-2
bucket = "leechad-japan-s3"
}
(3) Console 확인
7. GCP 프로바이더를 활용하여 리소스 배포
- gcp 프로바이더를 활용하여 vm하나를 띄우는 코드입니다.
(1) provider.tf
provider "google" {
credentials = "${file("./chadness12-int-230214-0a219cbc7a0e.json")}"
project = "chadness12-int-230214"
region = "us-central1"
}
(2) main.tf
resource "google_compute_instance" "default" {
name = "terraform"
machine_type = "f1-micro"
zone = "us-central1-a"
boot_disk {
initialize_params {
image = "debian-cloud/debian-11"
}
}
network_interface {
network = "default"
access_config {
}
}
}
(3) Console 확인
'Terraform > Study' 카테고리의 다른 글
Terraform-101-Study Week7 - [워크플로] (0) | 2023.08.19 |
---|---|
Terraform-101-Study Week6 - [협업, TFC] (0) | 2023.08.13 |
Terraform-101-Study Week4 - [State, 모듈] (0) | 2023.07.29 |
Terraform-101-Study Week2 [data, Variable, local, 반복문] (0) | 2023.07.15 |