테라폼 기본 사용
테라폼은 hashcorp사에서 공개한 너무나도 유명한 IaC 도구입니다.
테라폼 설치
mac os를 기준, 설치 방법입니다. tfenv는 테라폼의 다양한 버전을 사용할 수 있게 해 주는 도구입니다.
- 테라폼 설치 버전 : 1.8.1
- 테라폼 자동완성 설치
# tfenv 설치
brew install tfenv
# 설치 가능 버전 리스트 확인
tfenv list-remote
# 테라폼 1.5.1 버전 설치
tfenv install 1.8.1
# 테라폼 1.5.1 버전 사용 설정
tfenv use 1.8.1
# tfenv로 설치한 버전 확인
tfenv list
# 테라폼 버전 정보 확인
terraform version
# 자동완성
terraform -install-autocomplete
## 참고 .zshrc 에 아래 추가됨
cat ~/.zshrc
autoload -U +X bashcompinit && bashcompinit
complete -o nospace -C /usr/local/bin/terraform terraform
리소스
리소스는 테라폼을 통해 관리되는 인프라 구성 요소를 정의하는 핵심 요소입니다.
리소스 형식
리소스 블록이 생성할 리소스 유형을 정의합니다. 리소스 유형은 프로바이더가 제공하는 다양한 리소스 유형이 존재합니다. 이름은 사용자가 자유롭게 정의하는 이름입니다.
resource "<리소스 유형>" "<이름>" {
<인수> = <값>
}
resource "local_file" "abc" {
content = "123"
filename = "${path.module}/abc.txt"
}
리소스 실습
AWS 프로바이더의 EC2 인스턴스를 생성하는 리소스를 실습합니다.
# main.tf 파일 작성
resource "local_file" "abc" {
content = "123"
filename = "${path.module}/abc.txt"
}
resource "aws_instance" "web" {
ami = "ami-a1b2c3d4"
instance_type = "t2.micro"
}
# init 시 프로바이더 선언 없이도 리소스 추가로 자동 인식된 프로바이더 요구사항과 초기화
terraform init
terraformr apply
(실습 사진 )
종속성
인프라 프로비저닝을 하다 보면, 종속성이 있는 인프라 간에 작업 실행 순서에 따라 영향을 끼치는 경우가 많습니다.
테라폼 종속성은 resource,module 선언으로 프로비저닝 되는 각 요소의 생성 순서를 구분짓습니다.(테라폼 코드 실행 순서)
종속성 실습
다음은 정의한 content 내용의 로컬 파일을 생성하는 테라폼 코드입니다. 서로 관계없는 다른 파일을 생성하는 로직으로, 병렬로 동시에 실행이 됩니다.
# main.tf
resource "local_file" "abc" {
content = "123!"
filename = "${path.module}/abc.txt"
}
resource "local_file" "def" {
content = "456!"
filename = "${path.module}/def.txt"
}
#
terraform apply -auto-approve
# 리소스 확인
ls *.txt
terraform state list
local_file.abc
local_file.def
abc 파일의 내용을 가져와 def 파일의 내용을 참조하는 종속성이 있는 리소스입니다.
테라폼은 기본적으로 암시적으로 종속성부여하여 처리합니다. graph 명령어를 통해 의존성을 그래프로 확인할 수도 있습니다.
resource "local_file" "abc" {
content = "123!"
filename = "${path.module}/abc.txt"
}
resource "local_file" "def" {
content = local_file.abc.content
filename = "${path.module}/def.txt"
}
#
terraform apply -auto-approve
... abc 먼저 만들고 def 파일을 만듬
Plan: 2 to add, 0 to change, 0 to destroy.
local_file.abc: Refreshing state... [id=5f30576af23a25b7f44fa7f5fdf70325ee389155]
local_file.def: Refreshing state... [id=5f30576af23a25b7f44fa7f5fdf70325ee389155]
ls *.txt
terraform state list
cat abc.txt
cat def.txt
diff abc.txt def.txt
# graph 확인 > graph-2.dot 파일 선택 후 오른쪽 상단 DOT 클릭
terraform graph
terraform graph > graph-2.dot
depends_on
리소스의 속성을 주입하지 않아도 두 리소스 간에 종속성이 필요한 경우에, depends_on 선언으로 적용 가능합니다.
resource "local_file" "abc" {
content = "123!"
filename = "${path.module}/abc.txt"
}
resource "local_file" "def" {
depends_on = [
local_file.abc
]
content = "456!"
filename = "${path.module}/def.txt"
}
리소스 속성 참조
Terraform에서 리소스 속성 참조는 다른 리소스나 리소스 속성을 참조하여 특정 리소스의 속성 값을 설정하거나 사용하는 것을 말합니다. 이는 인프라 구성을 정의할 때 특히 유용합니다. 다른 리소스의 ID 또는 속성을 가져와 사용하여 연결하거나 구성할 수 있습니다.
예를 들어, 쿠버네티스 프로바이더의 Namespace 리소스를 생성하고 이후 Secret을 해당 Namespace에 생성하고 싶다고 가정할 때, 활용할 수 있습니다. 시크릿은 네임스페이스의 리소스를 참조하여 가져오기 때문에 휴먼 에러를 줄일 뿐만 아니라, 유지보수에도 용이합니다.
resource "kubernetes_namespace" "example" {
metadata {
annotations = {
name = "example-annotation"
}
name = "terraform-example-namespace"
}
}
resource "kubernetes_secret" "example" {
metadata {
namespace = kubernetes_namespace.example.metadata.0.name # namespace 리소스 인수 참조
name = "terraform-example"
}
data = {
password = "P4ssw0rd"
}
}
데이터 소스 구성
데이터 소스는 테라폼으로 정의되지 않은 외부 리소스 또는 저장된 정보를 테라폼 내에서 참조할 때 사용합니다.
데이터 소스 선언 방식
# Terraform Code
data "<리소스 유형>" "<이름>" {
<인수> = <값>
}
# 데이터 소스 참조
data.<리소스 유형>.<이름>.<속성>
데이터 소스 실습
데이터 소스를 활용해서 AWS의 가용영역 인수를 정의하고, 리전 내에서 사용 가능한 가용 영역을 목록에 가져와서 사용할 수 있습니다.
vpc를 생성하고 각 서브넷을 생성할 때 가용영역을 다르게 설정합니다.
# [ main.tf ]
# 데이터 소스 정의
data "aws_availability_zones" "available" {
state = "available"
}
resource "aws_vpc" "myvpc" {
cidr_block = "10.10.0.0/16"
enable_dns_support = true
enable_dns_hostnames = true
tags = {
Name = "t101-study"
}
}
resource "aws_subnet" "mysubnet1" {
vpc_id = aws_vpc.myvpc.id
cidr_block = "10.10.1.0/24"
# e.g. ap-northeast-2a
availability_zone = data.aws_availability_zones.available.names[0]
tags = {
Name = "t101-subnet1"
}
}
resource "aws_subnet" "mysubnet2" {
vpc_id = aws_vpc.myvpc.id
cidr_block = "10.10.2.0/24"
# e.g. ap-northeast-2b
availability_zone = data.aws_availability_zones.available.names[1]
tags = {
Name = "t101-subnet2"
}
}
#
terraform apply -auto-approve
terraform state list
AWS 콘솔과 테라폼 콘솔에서 확인해 보면 가용영역이 다르게 서브넷이 잘 생성됨을 볼 수 있습니다.
변수
테라폼에서 변수는 Terraform 구성 파일에서 사용되는 값을 저장하고 관리하는 데 사용됩니다. 이러한 변수를 사용하면 Terraform 구성을 보다 유연하게 만들 수 있습니다. 변수를 사용하여 리소스의 값들을 동적으로 설정하거나 재사용 가능한 코드를 작성할 수 있습니다
변수 선언 방식
변수는 variable로 시작되는 블록으로 구성됩니다. 변수 블록 뒤의 이름값은 동일 모듈 내 모든 변수 선언에서 고유해야 하며, 이 이름으로 다른 코드 내에서 참조됩니다.
테라폼 예약 변수 이름으로 사용 불가능 : source, version, providers, count, for_each, lifecycle, depends_on, locals
# variable 블록 선언의 예
variable "<이름>" {
<인수> = <값>
}
variable "image_id" {
type = string
}
변수 사용 실습
패스워드를 입력 변수로 받아 코드 변경 없이 사용할 수 있습니다.
#
terraform init -upgrade
terraform apply -auto-approve
var.my_password
Enter a value: qwe123
...
# 확인
terraform state list
terraform state show local_file.abc
cat abc.txt ; echo
# 해당 파일에 다른 내용으로 변경해보기
terraform apply -auto-approve
var.my_password
Enter a value: t101mypss
...
# 확인
cat abc.txt ; echo
변수 우선순위
테라폼 변수를 사용하는 다양한 방법에는 우선순위가 존재합니다.
우선순위 수준 1 : 실행 후 입력
# 실행
terraform apply -auto-approve
var.my_var
Enter a value: var1
...
# 확인
terraform state show local_file.abc
cat abc.txt ; echo
우선순위 수준 2 : variable 블록의 default 값
variable "my_var" {
default = "var2"
}
resource "local_file" "abc" {
content = var.my_var
filename = "${path.module}/abc.txt"
}
# 실행
terraform apply -auto-approve
# 확인
terraform state show local_file.abc
cat abc.txt ; echo
우선순위 수준 3 : 환경 변수 (TF_VAR 변수 이름)
시스템 환경 변수의 접두사에 TF_VAR_ 가 포함되면 그 뒤의 문자열을 변수 이름으로 인식합니다.
# Linux/macOS
export TF_VAR_my_var=var3
terraform apply -auto-approve
# 확인
cat abc.txt ; echo
우선순위 수준 4 : terraform.tfvars에 정의된 변수 선언
루트 모듈의 main.tf 파일과 같은 위치에 terraform.tfvars 파일을 생성해 변수에 대한 값을 추가하고 앞서 선언한 변수 선언과 비교해 우선순위를 확인합니다.
#
echo 'my_var="var4"' > terraform.tfvars
cat terraform.tfvars
#
terraform apply -auto-approve
# 확인
cat abc.txt ; echo
우선순위 수준 5 : *. auto.tfvars에 정의된 변수 선언
# a.auto.tfvars 파일 생성
echo 'my_var="var5_a"' > a.auto.tfvars
ls *.tfvars
#
terraform apply -auto-approve
# 확인
cat abc.txt ; echo
# b.auto.tfvars 파일 생성
echo 'my_var="var5_b"' > b.auto.tfvars
ls *.tfvars
#
terraform apply -auto-approve
# 확인
cat abc.txt ; echo
우선순위 수준 6 : *. auto.tfvars.json에 정의된 변수 선언
*. auto.tfvars와 같이 파일명의 정렬에 따라 우선순위가 적용됩니다.
# a.auto.tfvars.json 파일 생성
cat <<EOF > a.auto.tfvars.json
{
"my_var" : "var6_a"
}
EOF
ls *.tfvars ; ls *.json
#
terraform apply -auto-approve
# 확인
cat abc.txt ; echo
# c.auto.tfvars.json 파일 생성
cat <<EOF > c.auto.tfvars.json
{
"my_var" : "var6_c"
}
EOF
ls *.tfvars ; ls *.json
#
terraform apply -auto-approve
# 확인
cat abc.txt ; echo
[우선순위 수준 7] CLI 실행 시 -var 인수에 지정 또는 -var-file로 파일 지정
여러 인수가 선언되는 경우 나중에 선언된 변수의 우선순위가 높습니다.
#
terraform apply -auto-approve -var=my_var=var7
cat abc.txt ; echo
#
terraform apply -auto-approve -var=my_var=var7 -var=my_var=var8
cat abc.txt ; echo
*. tfvars와 같은 형식의 내용의 파일이라면 -var-file로 지정할 수 있습니다.
# var9.txt 파일 생성
echo 'my_var="var9"' > var9.txt
#
terraform apply -auto-approve -var=my_var=var7 -var-file="var9.txt"
cat abc.txt ; echo
Output
output은 테라폼 코드의 프로비저닝 수행 후의 결과 속성 값을 확인하는 용도로 사용합니다.
Output 활용
abspath : 파일 시스템 경로를 포함하는 문자열을 가져와 절대 경로로 변환하는 함수입니다.
resource "local_file" "abc" {
content = "abc123"
filename = "${path.module}/abc.txt"
}
output "file_id" {
value = local_file.abc.id
}
output "file_abspath" {
value = abspath(local_file.abc.filename)
}
모듈
테라폼 모듈은 재사용 가능한 인프라 구성 요소를 정의하고 구성하기 위한 도구로, 코드의 재사용성과 추상화를 통해 인프라 관리를 단순화합니다. 모듈은 대부분의 프로그래밍 언어에서 쓰이는 라이브러리나 패키지와 역할이 비슷합니다.
Terraform으로 EKS 배포
코드 작성
EKS 모듈을 활용하여 아래와 같이 4개의 EKS 테라폼 코드를 작성합니다.
mkdir myeks
cd myeks
ls
eks.tf irsa.tf var.tf vpc.tf
var.tf
EKS의 필요한 변수를 정의하는 파일입니다.
variable "KeyName" {
description = "Name of an existing EC2 KeyPair to enable SSH access to the instances."
type = string
}
variable "ClusterBaseName" {
description = "Base name of the cluster."
type = string
default = "myeks"
}
variable "KubernetesVersion" {
description = "Kubernetes version for the EKS cluster."
type = string
default = "1.29"
}
variable "WorkerNodeInstanceType" {
description = "EC2 instance type for the worker nodes."
type = string
default = "t3.medium"
}
variable "WorkerNodeCount" {
description = "Number of worker nodes."
type = number
default = 3
}
variable "WorkerNodeVolumesize" {
description = "Volume size for worker nodes (in GiB)."
type = number
default = 30
}
variable "TargetRegion" {
description = "AWS region where the resources will be created."
type = string
default = "ap-northeast-2"
}
variable "availability_zones" {
description = "List of availability zones."
type = list(string)
default = ["ap-northeast-2a", "ap-northeast-2b", "ap-northeast-2c"]
}
variable "VpcBlock" {
description = "CIDR block for the VPC."
type = string
default = "192.168.0.0/16"
}
variable "public_subnet_blocks" {
description = "List of CIDR blocks for the public subnets."
type = list(string)
default = ["192.168.1.0/24", "192.168.2.0/24", "192.168.3.0/24"]
}
variable "private_subnet_blocks" {
description = "List of CIDR blocks for the private subnets."
type = list(string)
default = ["192.168.11.0/24", "192.168.12.0/24", "192.168.13.0/24"]
}
eks.tf
eks 프로비저닝에 필요한 주요 리소스가 정의되어 있는 파일입니다.(EKS 모듈 사용)
data "aws_caller_identity" "current" {}
resource "aws_iam_policy" "external_dns_policy" {
name = "${var.ClusterBaseName}ExternalDNSPolicy"
description = "Policy for allowing ExternalDNS to modify Route 53 records"
policy = jsonencode({
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"route53:ChangeResourceRecordSets"
],
"Resource": [
"arn:aws:route53:::hostedzone/*"
]
},
{
"Effect": "Allow",
"Action": [
"route53:ListHostedZones",
"route53:ListResourceRecordSets"
],
"Resource": [
"*"
]
}
]
})
}
resource "aws_iam_role_policy_attachment" "external_dns_policy_attach" {
role = "${var.ClusterBaseName}-node-group-eks-node-group"
policy_arn = aws_iam_policy.external_dns_policy.arn
depends_on = [module.eks]
}
resource "aws_security_group" "node_group_sg" {
name = "${var.ClusterBaseName}-node-group-sg"
description = "Security group for EKS Node Group"
vpc_id = module.vpc.vpc_id
tags = {
Name = "${var.ClusterBaseName}-node-group-sg"
}
}
module "eks" {
source = "terraform-aws-modules/eks/aws"
version = "~>20.0"
cluster_name = var.ClusterBaseName
cluster_version = var.KubernetesVersion
cluster_endpoint_private_access = false
cluster_endpoint_public_access = true
cluster_addons = {
coredns = {
most_recent = true
}
kube-proxy = {
most_recent = true
}
vpc-cni = {
most_recent = true
}
}
vpc_id = module.vpc.vpc_id
enable_irsa = true
subnet_ids = module.vpc.public_subnets
eks_managed_node_groups = {
default = {
name = "${var.ClusterBaseName}-node-group"
use_name_prefix = false
instance_type = var.WorkerNodeInstanceType
desired_size = var.WorkerNodeCount
max_size = var.WorkerNodeCount + 2
min_size = var.WorkerNodeCount - 1
disk_size = var.WorkerNodeVolumesize
subnets = module.vpc.public_subnets
key_name = var.KeyName
vpc_security_group_ids = [aws_security_group.node_group_sg.id]
iam_role_name = "${var.ClusterBaseName}-node-group-eks-node-group"
iam_role_use_name_prefix = false
iam_role_additional_policies = {
"${var.ClusterBaseName}ExternalDNSPolicy" = aws_iam_policy.external_dns_policy.arn
}
}
}
access_entries = {
admin = {
kubernetes_groups = []
principal_arn = "${data.aws_caller_identity.current.arn}"
policy_associations = {
myeks = {
policy_arn = "arn:aws:eks::aws:cluster-access-policy/AmazonEKSClusterAdminPolicy"
access_scope = {
namespaces = []
type = "cluster"
}
}
}
}
}
tags = {
Environment = "${var.ClusterBaseName}-lab"
Terraform = "true"
}
}
vpc.tf
EKS에서 사용하는 VPC를 정의한 파일입니다. vpc 모듈을 사용합니다.
provider "aws" {
region = var.TargetRegion
}
module "vpc" {
source = "terraform-aws-modules/vpc/aws"
version = "~>5.7"
name = "${var.ClusterBaseName}-VPC"
cidr = var.VpcBlock
azs = var.availability_zones
enable_dns_support = true
enable_dns_hostnames = true
public_subnets = var.public_subnet_blocks
private_subnets = var.private_subnet_blocks
enable_nat_gateway = true
single_nat_gateway = true
one_nat_gateway_per_az = false
map_public_ip_on_launch = true
igw_tags = {
"Name" = "${var.ClusterBaseName}-IGW"
}
nat_gateway_tags = {
"Name" = "${var.ClusterBaseName}-NAT"
}
public_subnet_tags = {
"Name" = "${var.ClusterBaseName}-PublicSubnet"
"kubernetes.io/role/elb" = "1"
}
private_subnet_tags = {
"Name" = "${var.ClusterBaseName}-PrivateSubnet"
"kubernetes.io/role/internal-elb" = "1"
}
tags = {
"Environment" = "${var.ClusterBaseName}-lab"
}
}
irsa.tf
eks에서 사용하는 irsa 보안에 대한 내용을 정의한 파일입니다.
provider "aws" {
region = var.TargetRegion
}
module "vpc" {
source = "terraform-aws-modules/vpc/aws"
version = "~>5.7"
name = "${var.ClusterBaseName}-VPC"
cidr = var.VpcBlock
azs = var.availability_zones
enable_dns_support = true
enable_dns_hostnames = true
public_subnets = var.public_subnet_blocks
private_subnets = var.private_subnet_blocks
enable_nat_gateway = true
single_nat_gateway = true
one_nat_gateway_per_az = false
map_public_ip_on_launch = true
igw_tags = {
"Name" = "${var.ClusterBaseName}-IGW"
}
nat_gateway_tags = {
"Name" = "${var.ClusterBaseName}-NAT"
}
public_subnet_tags = {
"Name" = "${var.ClusterBaseName}-PublicSubnet"
"kubernetes.io/role/elb" = "1"
}
private_subnet_tags = {
"Name" = "${var.ClusterBaseName}-PrivateSubnet"
"kubernetes.io/role/internal-elb" = "1"
}
tags = {
"Environment" = "${var.ClusterBaseName}-lab"
}
}
첫 번째 EKS 배포
각자의 키페어를 변수를 지정하고 eks 클러스터를 배포합니다.
ls
eks.tf irsa.tf var.tf vpc.tf
# terraform 환경 변수 저장
export TF_VAR_KeyName=[각자 ssh keypair]
export TF_VAR_KeyName=jdg-keypair
echo $TF_VAR_KeyName
#
terraform init
terraform plan
# 10분 후 배포 완료
terraform apply -auto-approve
terraform을 통해 배포된 자원을 확인합니다.
- 주요 생성 자원 : VPC, Subnet, IGW, NATGW, Routing Table, EKS, EKS SG
배포 정보 확인
kubectl로 클러스터 및 노드 정보를 확인합니다.
CLUSTER_NAME=myeks
aws eks update-kubeconfig --region ap-northeast-2 --name $CLUSTER_NAME
kubectl config rename-context "arn:aws:eks:ap-northeast-2:$(aws sts get-caller-identity --query 'Account' --output text):cluster/$CLUSTER_NAME" "Aews-Labs"
#
kubectl cluster-info
kubectl get node --label-columns=node.kubernetes.io/instance-type,eks.amazonaws.com/capacityType,topology.kubernetes.io/zone
kubectl get pod -A
Added new context arn:aws:eks:ap-northeast-2:089224560468:cluster/myeks to /Users/spjang/.kube/config
Context "arn:aws:eks:ap-northeast-2:089224560468:cluster/myeks" renamed to "Aews-Labs".
Kubernetes control plane is running at https://B5CA06E2226C59A76427D95D8B993BC4.gr7.ap-northeast-2.eks.amazonaws.com
CoreDNS is running at https://B5CA06E2226C59A76427D95D8B993BC4.gr7.ap-northeast-2.eks.amazonaws.com/api/v1/namespaces/kube-system/services/kube-dns:dns/proxy
To further debug and diagnose cluster problems, use 'kubectl cluster-info dump'.
NAME STATUS ROLES AGE VERSION INSTANCE-TYPE CAPACITYTYPE ZONE
ip-192-168-1-94.ap-northeast-2.compute.internal Ready <none> 11m v1.29.0-eks-5e0fdde t3.medium ON_DEMAND ap-northeast-2a
ip-192-168-2-183.ap-northeast-2.compute.internal Ready <none> 11m v1.29.0-eks-5e0fdde t3.medium ON_DEMAND ap-northeast-2b
ip-192-168-3-169.ap-northeast-2.compute.internal Ready <none> 11m v1.29.0-eks-5e0fdde t3.medium ON_DEMAND ap-northeast-2c
NAMESPACE NAME READY STATUS RESTARTS AGE
kube-system aws-node-4kdkv 2/2 Running 0 10m
kube-system aws-node-8s628 2/2 Running 0 10m
kube-system aws-node-xdt22 2/2 Running 0 10m
kube-system coredns-6bddb7676-frzgn 1/1 Running 0 10m
kube-system coredns-6bddb7676-pj4t5 1/1 Running 0 10m
kube-system kube-proxy-k7kqj 1/1 Running 0 10m
kube-system kube-proxy-njdz8 1/1 Running 0 10m
kube-system kube-proxy-qb5bh 1/1 Running 0 10m
클러스터 삭제
terraform destroy -auto-approve
두 번째 EKS 배포 (코드 재사용)
이전 EKS 배포 테라폼 코드를 재사용하여 클러스터를 하나 더 배포합니다.
#
mkdir myeks2
cd ../myeks/*.tf .
ls
eks.tf irsa.tf var.tf vpc.tf
#
terraform init
terraform apply -auto-approve -var=ClusterBaseName=myeks2 -var=KubernetesVersion="1.28"
# EKS 클러스터 인증 정보 가져오기
CLUSTER_NAME2=myeks2
aws eks update-kubeconfig --region ap-northeast-2 --name $CLUSTER_NAME2 --kubeconfig ./myeks2config
# EKS 클러스터 정보 확인
kubectl --kubeconfig ./myeks2config get node
kubectl --kubeconfig ./myeks2config get pod -A
배포 정보 확인
두 번째 클러스터 또한, 매개변수로 지정한 쿠버네티스 버전 역시 잘 적용되어 배포되었음을 확인할 수 있습니다.
클러스터 삭제
terraform destroy -auto-approve -var=ClusterBaseName=myeks2 -var=KubernetesVersion="1.28"
'AWS > EKS' 카테고리의 다른 글
EKS CI/CD - AEWS 7주차 (1) | 2024.04.20 |
---|---|
EKS 보안(Security) - AEWS 6주차 (1) | 2024.04.14 |
EKS 오토스케일링(Autoscaling) - AEWS 5주차 (0) | 2024.04.07 |
EKS 옵저버빌리티(Obsivability) - AEWS 4주차 (0) | 2024.03.31 |
EKS 노드그룹(Nodegroup) - AEWS 3주차 2 (0) | 2024.03.23 |