• Home
  • About
    • lahuman photo

      lahuman

      열심히 사는 아저씨

    • Learn More
    • Facebook
    • LinkedIn
    • Github
  • Posts
    • All Posts
    • All Tags
  • Projects

#7-1 책 예제 따라하기

04 Dec 2022

Reading time ~11 minutes

책 예제 따라하기

  • 참고 링크
    • Code Github - 원서
    • 버전 관리 tfenv - 링크

배경 : 책 뒤로 갈 수록 앞 부분의 실습 환경에서 점점 더 복잡해지는 코드 구성으로 현재 최신 테라폼 버전이나, 한국 리전으로 코드 변경의 어려움 → 여유 시간도 없다..

목표 : 책의 실습 환경(미국 동부 오하이오 리전, 테라폼 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
    


terraformstudy Share Tweet +1