책 예제 따라하기
배경
: 책 뒤로 갈 수록 앞 부분의 실습 환경에서 점점 더 복잡해지는 코드 구성으로 현재 최신 테라폼 버전이나, 한국 리전으로 코드 변경의 어려움 → 여유 시간도 없다..
목표
: 책의 실습 환경(미국 동부 오하이오 리전, 테라폼 v1.2.3 버전)으로 실습을 진행
사전 준비
-
기존 설치된 테라폼 삭제
# (옵션) 아래 두 줄 있다면 삭제 sudo vi ~/.zshrc autoload -U +X bashcompinit && bashcompinit complete -o nospace -C /usr/local/bin/terraform terraform # 삭제 brew remove terraform
-
tfenv 설치 : 테라폼 버전 관리 툴 - 링크
# 설치(Mac) brew install tfenv # 설치 가능 버전 확인 tfenv list-remote | head 1.4.0-alpha20221109 1.3.6 ... # 현재 설치된 버전 확인 tfenv list No versions available. Please install one with: tfenv install # 특정 버전 설치 #(옵션) export TFENV_ARCH=arm64 # mac Apple silicon M1/M2 tfenv install 1.2.3 tfenv list # 특정 버전 사용 tfenv use 1.2.3 Switching default version to v1.2.3 Default version (when not overridden by .terraform-version or TFENV_TERRAFORM_VERSION) is now: 1.2.3 **** # 테라폼 버전 확인 terraform version Terraform v1.2.3 on darwin_amd64
-
자격 증명의 리전을 오하이오로 설정 - 링크
# 방안1 **aws configure** AWS Access Key ID [****************JG7Y]: AWS Secret Access Key [****************l9Et]: Default region name [ap-northeast-2]: us-east-2 Default output format [json]: # 방안2 export AWS_DEFAULT_REGION=us-east-2
-
책 실습 코드 다운로드
# git clone https://github.com/brikis98/terraform-up-and-running-code.git cd terraform-up-and-running-code/code/terraform tree # cat .terraform-version 1.2.3
-
EC2 배포 해보기
# [터미널1] EC2 생성 모니터링 export AWS_PAGER="" while true; do **aws ec2 describe-instances** --query "Reservations[*].Instances[*].{PublicIPAdd:PublicIpAddress,InstanceName:Tags[?Key=='Name']|[0].Value,Status:State.Name}" --filters Name=instance-state-name,Values=running --output text ; echo "------------------------------" ; sleep 1; done # [터미널2] cd 00-preface/hello-world # 코드 확인 cat main.tf terraform { required_version = ">= 1.0.0, < 2.0.0" required_providers { aws = { source = "hashicorp/aws" version = "~> 4.0" } } } provider "aws" { region = "us-east-2" } resource "aws_instance" "example" { ami = "ami-0fb653ca2d3203ac1" instance_type = "t2.micro" } # 배포 terraform init terraform plan terraform apply yes # EC2 생성 확인 후 삭제 terraform destroy -auto-approve cd ~/terraform-up-and-running-code/code/terraform
Chapter 02-intro-to-terraform-syntax
실습 구성
graph LR; F(((User))) --> A; A[Elastic Load \nBalancer]; A --> B(EC2 Instance); A --> C(EC2 Instance); A --> D(EC2 Instance); A --> E(EC2 more...); subgraph AWS; A & B & C & D & E; end;
실습
# [터미널2]
cd 02-intro-to-terraform-syntax/webserver-cluster
cat main.tf variables.tf
# 배포
terraform init
terraform plan
terraform apply -auto-approve
# 배포 완료 후 ALB 접속 확인
ALBDNS=$(terraform output -raw alb_dns_name)
while true; do curl --connect-timeout 1 http://$ALBDNS/ ; echo; echo "------------------------------"; date; sleep 1; done
# 삭제
terraform destroy -auto-approve
cd ~/terraform-up-and-running-code/code/terraform
Chapter 03-terraform-state
실습 구성
: ELB + ASG + RDS
graph LR; F(((User))) --> A; A[Elastic Load \nBalancer]; A --> B(EC2 Instance); A --> C(EC2 Instance); A --> D(EC2 Instance); A --> E(EC2 more...); B & C & D & E --> G((MySQL \non RDS)); subgraph AWS; A & B & C & D & E & G; end;
.
├── global
│ └── s3
│ ├── README.md
│ ├── main.tf
│ ├── outputs.tf
│ ├── terraform.tfstate
│ ├── terraform.tfstate.backup
│ └── variables.tf
└── stage
├── data-stores
│ └── mysql
│ ├── README.md
│ ├── main.tf
│ ├── outputs.tf
│ └── variables.tf
└── services
└── webserver-cluster
├── README.md
├── main.tf
├── outputs.tf
├── user-data.sh
└── variables.tf
- S3/DynamoDB 생성
- S3/DynamoDB 생성을 위한 환경변수 지정
# 환경변수에 지정 export TF_VAR_bucket_name=<각자 닉네임>-tfstate export TF_VAR_table_name=<각자 닉네임>-t101-locks export TF_VAR_bucket_name=gasida-t101-tfstate export TF_VAR_table_name=gasida-t101-locks # 환경변수 확인 export | grep TF_VAR_ # (옵션) 환경변수 지정 삭제 unset TF_VAR_bucket_name unset TF_VAR_table_name
- 배포
# cd 03-terraform-state/file-layout-example/global/s3 cat main.tf variables.tf # 초기화 및 검증 : 환경변수 적용 확인 terraform init && terraform plan # 배포 terraform apply -auto-approve # 확인 aws s3 ls aws dynamodb list-tables --output text # 이동 cd ../..
-
RDS 배포
# [터미널1] RDS 생성 모니터링 while true; do **aws rds describe-db-instances** --query "*[].[Endpoint.Address,Endpoint.Port,MasterUsername]" --output text ; echo "------------------------------" ; sleep 1; done # [터미널2] cd stage/data-stores/mysql cat main.tf variables.tf # 환경변수에 지정 export TF_VAR_db_username='cloudneta' export TF_VAR_db_password='cloudnetaQ!' # 환경변수 확인 export | grep TF_VAR_ # main.tf 에 백엔드 부분 수정 vi main.tf backend "s3" { # This backend configuration is filled in automatically at test time by Terratest. If you wish to run this example # manually, uncomment and fill in the config below. bucket = "gasida-t101-tfstate" key = "stage/data-stores/mysql/terraform.tfstate" region = "us-east-2" dynamodb_table = "gasida-t101-locks" # encrypt = true } # 초기화 및 검증 : 환경변수 적용 확인 terraform init && terraform plan # 배포 : RDS는 생성 시 6분 정도 시간 소요 terraform apply -auto-approve terraform output aws s3 ls s3://$TF_VAR_bucket_name --recursive --human-readable --summarize # 이동 cd ../..
-
웹서버 클러스터 배포
# cd services/webserver-cluster cat main.tf variables.tf # 환경변수에 지정 export TF_VAR_db_remote_state_bucket=$TF_VAR_bucket_name # description = "The name of the S3 bucket used for the database's remote state storage" export TF_VAR_db_remote_state_key='stage/data-stores/mysql/terraform.tfstate' # description = "The name of the key in the S3 bucket used for the database's remote state storage" # 환경변수 확인 export | grep TF_VAR_ # 초기화 및 검증 : 환경변수 적용 확인 terraform init && terraform plan # 배포 terraform apply -auto-approve # ALB DNS주소로 curl 접속 확인 ALBDNS=$(terraform output -raw alb_dns_name) while true; do curl --connect-timeout 1 http://$ALBDNS ; echo; echo "------------------------------"; date; sleep 1; done curl -s http://$ALBDNS # 삭제 # 각 폴더에서 리소스 삭제 stage/services/webserver-cluster$ terraform destroy -auto-approve stage/data-stores/mysql$ terraform destroy -auto-approve global/s3$ terraform destroy -auto-approve # 이동 cd ~/terraform-up-and-running-code/code/terraform
Chapter 04-terraform-module
실습 구성
: Staging 와 Production 환경 배포에 모듈 활용
graph LR; F(((Employee))) --> A; A[Elastic Load \nBalancer]; A --> B(EC2 Instance); A --> C(EC2 Instance); A --> D(EC2 Instance); A --> E(EC2 more...); B & C & D & E --> G((MySQL \non RDS)); subgraph AWS-Staging; A & B & C & D & E & G; end; style AWS-Staging fill:#68B984,stroke:#333,stroke-width:4px; H(((User))) --> I; I[Elastic Load \nBalancer]; I --> J(EC2 Instance); I --> K(EC2 Instance); I --> L(EC2 Instance); I --> M(EC2 more...); J & K & L & M --> N((MySQL \non RDS)); subgraph AWS-Production; I & J & K & L & M & N; end; style AWS-Production fill:#F7A4A4,stroke:#333,stroke-width:4px;
.
├── module-example
│ ├── modules
│ │ └── services
│ │ └── webserver-cluster
│ │ ├── README.md
│ │ ├── main.tf
│ │ ├── outputs.tf
│ │ ├── user-data.sh
│ │ └── variables.tf
│ ├── prod
│ │ ├── data-stores
│ │ │ └── mysql
│ │ │ ├── README.md
│ │ │ ├── main.tf
│ │ │ ├── outputs.tf
│ │ │ └── variables.tf
│ │ └── services
│ │ └── webserver-cluster
│ │ ├── README.md
│ │ ├── main.tf
│ │ ├── outputs.tf
│ │ └── variables.tf
│ └── stage
│ ├── data-stores
│ │ └── mysql
│ │ ├── README.md
│ │ ├── main.tf
│ │ ├── outputs.tf
│ │ └── variables.tf
│ └── services
│ └── webserver-cluster
│ ├── README.md
│ ├── main.tf
│ ├── outputs.tf
│ └── variables.tf
└── multi-repo-example
└── live
├── prod
│ ├── data-stores
│ │ └── mysql
│ │ ├── README.md
│ │ ├── main.tf
│ │ ├── outputs.tf
│ │ └── variables.tf
│ └── services
│ └── webserver-cluster
│ ├── README.md
│ ├── main.tf ==> modules/services/webserver-cluster 이용
│ ├── outputs.tf
│ └── variables.tf
└── stage
├── data-stores
│ └── mysql
│ ├── README.md
│ ├── main.tf
│ ├── outputs.tf
│ └── variables.tf
└── services
└── webserver-cluster
├── README.md
├── main.tf ==> modules/services/webserver-cluster 이용
├── outputs.tf
└── variables.tf
- S3/DynamoDB 생성
- S3/DynamoDB 생성을 위한 환경변수 지정
# 환경변수에 지정 export TF_VAR_bucket_name=gasida-t101-tfstate export TF_VAR_table_name=gasida-t101-locks # 환경변수 확인 export | grep TF_VAR_ # (옵션) 환경변수 지정 삭제 unset TF_VAR_bucket_name unset TF_VAR_table_name
- 배포
# cd 03-terraform-state/file-layout-example/global/s3 cat main.tf variables.tf # 초기화 및 검증 : 환경변수 적용 확인 terraform init && terraform plan # 배포 terraform apply -auto-approve # 확인 aws s3 ls aws dynamodb list-tables --output text # 이동 cd ~/terraform-up-and-running-code/code/terraform
-
Staging RDS 배포
# [터미널1] RDS 생성 모니터링 while true; do **aws rds describe-db-instances** --query "*[].[Endpoint.Address,Endpoint.Port,MasterUsername]" --output text ; echo "------------------------------" ; sleep 1; done # [터미널2] cd 04-terraform-module/module-example/stage/data-stores/mysql cat main.tf variables.tf # 환경변수에 지정 export TF_VAR_db_username='cloudneta' export TF_VAR_db_password='cloudnetaQ!' # 환경변수 확인 export | grep TF_VAR_ # main.tf 에 백엔드 부분 수정 vi main.tf backend "s3" { # This backend configuration is filled in automatically at test time by Terratest. If you wish to run this example # manually, uncomment and fill in the config below. bucket = "gasida-t101-tfstate" key = "stage/data-stores/mysql/terraform.tfstate" region = "us-east-2" dynamodb_table = "gasida-t101-locks" # encrypt = true } # 초기화 및 검증 : 환경변수 적용 확인 terraform init && terraform plan # 배포 : RDS는 생성 시 6분 정도 시간 소요 terraform apply -auto-approve terraform output aws s3 ls s3://$TF_VAR_bucket_name --recursive --human-readable --summarize # 이동 cd ../../
-
모듈을 활용하여 Staging 웹서버 클러스터 배포
# cd services/webserver-cluster cat main.tf variables.tf # 환경변수에 지정 export TF_VAR_db_remote_state_bucket=$TF_VAR_bucket_name # description = "The name of the S3 bucket used for the database's remote state storage" export TF_VAR_db_remote_state_key='stage/data-stores/mysql/terraform.tfstate' # description = "The name of the key in the S3 bucket used for the database's remote state storage" # 환경변수 확인 export | grep TF_VAR_ # 초기화 및 검증 : 환경변수 적용 확인 terraform init && terraform plan # 배포 terraform apply -auto-approve # ALB DNS주소로 curl 접속 확인 ALBDNS=$(terraform output -raw alb_dns_name) while true; do curl --connect-timeout 1 http://$ALBDNS ; echo; echo "------------------------------"; date; sleep 1; done curl -s http://$ALBDNS # 삭제 # 각 폴더에서 리소스 삭제 stage/services/webserver-cluster$ terraform destroy -auto-approve stage/data-stores/mysql$ terraform destroy -auto-approve 03-terraform-state/file-layout-example/global/s3$ terraform destroy -auto-approve # 아래 Production 실습을 이어서 할 경우에는 실습 완료 후 삭제 할 것 # 이동 cd ~/terraform-up-and-running-code/code/terraform
동일한 방법으로 Production 환경의 “RDS + 웹 서버 클러스터”를 배포해보자!
- Production RDS 배포
- 모듈을 활용하여 Production 웹서버 클러스터 배포
Chapter 05-tips-and-tricks
실습 구성
: Zero-Downtime Deployment 무중단 배포
graph LR; F(((Employee))) --> A; A[Elastic Load \nBalancer]; A --> B(EC2 Instance); A --> E(EC2 more...); B & E --> G((MySQL \non RDS)); subgraph AWS; A & B & E & G; end;
graph LR; F(((Employee))) --> A; A[Elastic Load \nBalancer]; A --> B(EC2 Instance); A --> E(EC2 more...); B & E --> G((MySQL \non RDS)); C(EC2 Instance); D(EC2 more...); subgraph AWS; A & B & E & G & C & D; end; style C fill:#68B984,stroke:#333,stroke-width:4px; style D fill:#68B984,stroke:#333,stroke-width:4px;
graph LR; F(((Employee))) --> A; A[Elastic Load \nBalancer]; A --> B(EC2 Instance); A --> E(EC2 more...); A --> C(EC2 Instance); A --> D(EC2 more...); B & E & C & D --> G((MySQL \non RDS)); subgraph AWS; A & B & E & G & C & D; end; style C fill:#68B984,stroke:#333,stroke-width:4px; style D fill:#68B984,stroke:#333,stroke-width:4px;
graph LR; F(((Employee))) --> A; A[Elastic Load \nBalancer]; B(EC2 Instance); E(EC2 more...); A --> C(EC2 Instance); A --> D(EC2 more...); C & D --> G((MySQL \non RDS)); subgraph AWS; A & B & E & G & C & D; end; style C fill:#68B984,stroke:#333,stroke-width:4px; style D fill:#68B984,stroke:#333,stroke-width:4px;
graph LR; F(((Employee))) --> A; A[Elastic Load \nBalancer]; A --> C(EC2 Instance); A --> D(EC2 more...); C & D --> G((MySQL \non RDS)); subgraph AWS; A & G & C & D; end; style C fill:#68B984,stroke:#333,stroke-width:4px; style D fill:#68B984,stroke:#333,stroke-width:4px;
- S3/DynamoDB 생성
- S3/DynamoDB 생성을 위한 환경변수 지정
# 환경변수에 지정 export TF_VAR_bucket_name=gasida-t101-tfstate export TF_VAR_table_name=gasida-t101-locks # 환경변수 확인 export | grep TF_VAR_
- 배포
# cd 03-terraform-state/file-layout-example/global/s3 cat main.tf variables.tf # 초기화 및 검증 : 환경변수 적용 확인 terraform init && terraform plan # 배포 terraform apply -auto-approve # 확인 aws s3 ls aws dynamodb list-tables --output text # 이동 cd ~/terraform-up-and-running-code/code/terraform
-
Staging RDS 배포
# [터미널1] RDS 생성 모니터링 while true; do **aws rds describe-db-instances** --query "*[].[Endpoint.Address,Endpoint.Port,MasterUsername]" --output text ; echo "------------------------------" ; sleep 1; done # [터미널2] cd 05-tips-and-tricks/module-example/stage/data-stores/mysql cat main.tf variables.tf # 환경변수에 지정 export TF_VAR_db_username='cloudneta' export TF_VAR_db_password='cloudnetaQ!' # 환경변수 확인 export | grep TF_VAR_ # main.tf 에 백엔드 부분 수정 vi main.tf backend "s3" { # This backend configuration is filled in automatically at test time by Terratest. If you wish to run this example # manually, uncomment and fill in the config below. bucket = "gasida-t101-tfstate" key = "stage/data-stores/mysql/terraform.tfstate" region = "us-east-2" dynamodb_table = "gasida-t101-locks" # encrypt = true } # 초기화 및 검증 : 환경변수 적용 확인 terraform init && terraform plan # 배포 : RDS는 생성 시 6분 정도 시간 소요 terraform apply -auto-approve terraform output aws s3 ls s3://$TF_VAR_bucket_name --recursive --human-readable --summarize # 이동 cd ../../
-
모듈을 활용하여 Staging 웹서버 클러스터 배포 후 무중단 업그레이드
# cd services/webserver-cluster cat main.tf variables.tf # 환경변수에 지정 export TF_VAR_db_remote_state_bucket=$TF_VAR_bucket_name # description = "The name of the S3 bucket used for the database's remote state storage" export TF_VAR_db_remote_state_key='stage/data-stores/mysql/terraform.tfstate' # description = "The name of the key in the S3 bucket used for the database's remote state storage" # 환경변수 확인 export | grep TF_VAR_ # 초기화 및 검증 : 환경변수 적용 확인 terraform init && terraform plan -var server_text='Old server text' # 배포 terraform apply -auto-approve -var server_text='Old server text' # ALB DNS주소로 curl 접속 확인 ALBDNS=$(terraform output -raw alb_dns_name) while true; do curl --connect-timeout 1 http://$ALBDNS ; echo; echo "------------------------------"; date; sleep 1; done curl -s http://$ALBDNS # [터미널1] ALBDNS=<직접입력> while true; do curl --connect-timeout 1 http://$ALBDNS ; echo; echo "------------------------------"; date; sleep 1; done # [터미널2] while true; do aws ec2 describe-instances --query "Reservations[*].Instances[*].{PublicIPAdd:PublicIpAddress,InstanceName:Tags[?Key=='Name']|[0].Value,Status:State.Name}" --filters Name=instance-state-name,Values=running --output text ; echo "------------------------------" ; sleep 1; done # 무중단 업그레이드 배포 : 환경변수 수정 적용 >> 오토스케일링그룹 2개중 기존 그룹은 5분 정도 후에 EC2가 삭제됨(오래 걸리니 맘 편히 기다리자) terraform plan -var server_text='NEW server text' terraform apply -auto-approve -var server_text='NEW server text' # 삭제 # 각 폴더에서 리소스 삭제 stage/services/webserver-cluster$ terraform destroy -auto-approve stage/data-stores/mysql$ terraform destroy -auto-approve 03-terraform-state/file-layout-example/global/s3$ terraform destroy -auto-approve # 이동 cd ~/terraform-up-and-running-code/code/terraform