본문 바로가기
Terraform

테라폼

by 쑨토리 2023. 6. 22.
반응형

여러가지 환경에 유사한 인프라 구축 과정에서 반복되는 작업을 없애고 휴먼 에러를 줄이기.

코드를 통해 인프라 구성이 되므로 문서 최소화, 온보딩 기간을 단축

 

 

 

서버리스 테라폼. 

서비와 테라폼 파이프라인. 

개발자에게서 서버가 사라지고 호스팅플랫폼에서 알아서 관리를 해줌. 

얼마나 큰 용량의 ram을 사용할건지 예측해야되고 소프트웨어 관리 패치, 서버관리 모니터링 스케일링을 직접 해야했음. ㅅ항상 운영해야하기때문에 관리하기 어려웠음.

개발자는 코드를 구성하는 함수 하나를 만들고 내 함수를 언제 실행해야하는지만 알려주면됨.

리소스의 한계가 있다는 단점이 있다. 

너무 오래걸리고 무거운 일을 하기에는 적합하지 않음

 

다양한 형태의 서버리스 :

 

서버리스의 가장 큰 장점은

왜 테라폼인지?

 

 

 

멀티 클라우드와 하이브리드 클라우드는 사실상 다름. 

 

 

"멀티클라우드"와 "하이브리드 클라우드" 모두 둘 이상의 클라우드를 통합하는 클라우드 배포를 지칭합니다.이들은 포함하는 클라우드 인프라의 종류가 다릅니다.

하이브리드 클라우드 인프라는 두 가지 이상의 서로 다른 유형의 클라우드를 혼합하는 반면, 멀티클라우드는 동일한 유형의 서로 다른 클라우드를 혼합합니다. 하이브리드 클라우드는 사과와 오렌지를 결합하는 것과 같고 멀티클라우드는 다른 유형의 사과를 결합하는 것과 같습니다.

 


테라폼 실습하기

-vpc,ec2,autoscaling을 만들어보기

 

--- Terraform 이란?
과거 시스템 관리자는 인프라를 수동으로 구축하고 관리했습니다. 그리고 모든 서버, 데이터베이스, 로드 밸런서, 네트워크를 수작업으로 생성하고 관리했기 때문에 서버 다운, 구성 실수, 배포 오류가 자주 발생하였습니다. 테라폼은 간단한 선언적 언어를 사용하여 인프라를 코드로 정의합니다. 몇 가지 명령을 사용하여 AWS, Azure, GCP 같은 다양한 퍼블릭 클라우드 공급자와 오픈스택, ESXi 같은 프라이빗 클라우드와 가상화 플랫폼에서 해당 인프라를 배포 및 관리하게 합니다.

--- Terraform 작동 방식 (쓰고 계획하고 적용시키기)
테라폼은 해시코프사에서 Go언어로 개발한 오픈소스도구다. 운영체제마다 바이너리 파일이 존재하는데 Go 코드는 하나의 바이너리 파일로 컴파일되며 Terraform이라는 명령어로 실행할 수 있다. 이 Terraform 명령어를 사용하여 노트북, 데스크탑, 빌드 서버 또는 다른 컴퓨터에서든 인프라를 배포할 수 있으며 이를 위해 추가 인프라(마스터, 에이전트)를 생성할 필요가 없다. 즉 Terraform 명령어가 AWS, Azure, GCP, Openstack 등의 Provider
(매번 필요한 플러그인이 내려와 호출하는 것, 어떤 provider를 설정할 것인지 선택함) 대신해 API를 호출하여 리소스를 생성한다.
테라폼은 생성하려는 인프라 정보가 담겨 있는 텍스트로 이루어진 테라폼 구성 파일을 생성하여 API를 호출한다. 이러한 구성 값들이 '코드형 인프라'를 만드는 바로 그 '코드'이다. 팀의 누군가가 인프라를 수정하고자 할 때, 서버에 직접 접속하여 작업하거나 수작업으로 수정하는 대신 테라폼을 사용하여 구성 파일을 수정할 있다. 

 

테라폼으로는 물리적인 서버는 못만듬. 가상 서버는 가능. 

여기서 만들 수 있다는 서버란 가상 서버를 의미한다.

 

--- Terraform 주요 명령어 [ init > plan > apply ]
- *.tf 스크립트 작성 / tf=테라폼 
- terraform init (내가 사용하고 싶은 프로바이더의 플러그인을 내려받아 사용할 준비를 하는 것) : 사용자가 어느 환경에 할것인지 초기화 작업을 하는 것. terraform 명령어에는 테라폼의 기본 기능이 포함되어 있지만 모든 공급자(AWS, Azure, GCP 등)에 대한 코드가 포함되어 있지 않다. 필요할 때마다 내려 받아서 테라폼으로 명령을 통해 공급자가 제공해주는 환경에다 자원을 생성하는 것. 그렇게 때문에 terraform init 명령어를 실행하여 테라폼에 코드를 스캔하도록 지시하고 어느 공급자인지 확인하고, 필요한 코드를 다운로드하도록 해야 한다. 기본적으로 공급자 코드는 테라폼의 .terraform 폴더에 플러그인 형태로 다운로드된다.

- terraform plan (어떤 항목이 삭제되고 수정될 것인지 확인하는 것) : 코드가 온전한지 미리 확인하는 작업. 테라폼이 구성 파일을 사용하여 작업을 수행하기 전에 코드의 온전성을 검사할 수 있다. plan 명령어는 리눅스에서 쓰이는 diff 명령(파일 두개를 비교하는 명령. 리눅스의 명령어임. A와 B파일을 비교해서 둘의 차이점을 확인해주는 명령어임)의 결괏값과 유사하다. + 가 있는 항목은 추가되고, - 가 있는 항목은 삭제된다는 뜻이다. ~ 가 있는 항목은 수정된다. 

- terraform apply (실질적으로 자원이 생성되게끔 구성파일을 실행하는 것): 테라폼의 구성 파일을 실행하려면 terraform apply 명령어를 실행한다. 이 커맨드에 따라 자원이 만들어지는 것을 볼 수 있음. 

resource "<PROVIDER>_<TYPE>" "<NAME>" 

{ # PROVIDER는 aws 같은 공급자의 이름이고 TYPE은 instance 같이 해당 공급자에서 생성할 리소스 유형입니다. NAME은 테라폼 코드에서 이 리소스를 참조하기 위해 사용할 수 있는 example과 같은 '식별자'입니다. 

CONFIG는 특정 리소스에 대한 하나 이상의 인수(argument)로 구성됩니다. 내가 설정하고 싶은 자원들을 적어주기
  [CONFIG ...] 
}

resource "aws_vpc" "main" { 여기서 main은 cloudformation에서 내가 정할 수 있는 논리적 아이디임. 
  cidr_block = var.base_cidr_block 전체 아이디 범위를 적어줄때 이걸 사용
}

 


<BLOCK TYPE> "<BLOCK LABEL>" "<BLOCK LABEL>" {
  # Block body (여기에다가 정의하는 것임)
  <IDENTIFIER> = <EXPRESSION> # Argument
}

- 블록( { } )은 다른 콘텐츠의 컨테이너이며 일반적으로 리소스와 같은 일종의 개체 구성을 나타냅니다. 블록에는 블록 유형이 있고 , 0개 이상의 레이블이 있을 수 있으며 , 여러 인수와 중첩된 블록을 포함하는 본문이 있습니다. 대부분의 Terraform 기능은 구성 파일의 최상위 블록에 의해 제어됩니다.

- 인수는 이름에 값을 할당합니다. 블록 내에 나타납니다.

- 표현식은 문자 그대로 또는 다른 값을 참조하고 결합하여 값을 나타냅니다. 인수의 값으로 나타나거나 다른 표현식 내에 나타납니다.

 

테라폼 클라우드가 지원하는 열가지 장점 

아래 다섯가지가 가장 큰 장점.

조직의 특성을 고려한 레퍼런스 참조 필요!

 

 

▼  테라폼 설치 CLI

더보기
닫기

--- Terraform 설치
# yum install -y yum-utils
# yum-config-manager --add-repo https://rpm.releases.hashicorp.com/RHEL/hashicorp.repo
# yum -y install terraform

# wget https://releases.hashicorp.com/terraform/1.2.3/terraform_1.2.3_linux_amd64.zip
# wget https://releases.hashicorp.com/terraform/1.4.6/terraform_1.4.6_linux_amd64.zip
# unzip terraform_1.2.3_linux_amd64.zip
# unzip terraform_1.4.6_linux_amd64.zip
# mv terraform /usr/local/bin/
# terraform -version

export AWS_ACCESS_KEY_ID=(your access key id)
export AWS_SECRET_ACCESS_KEY=(your secret access key)

# mkdir tf-test && cd $_
# vi main.tf
provider "aws" {
  region = "ap-northeast-2"
}

resource "aws_instance" "example" {
  ami                    = "ami-035da6a0773842f64"
  instance_type          = "t2.micro"
  vpc_security_group_ids = [aws_security_group.instance.id]

  user_data = <<-EOF
              #cloud-boothook
              #!/bin/bash
              yum install -y httpd
              systemctl enable --now httpd
              echo "<h1>example</h1>" > /var/www/html/index.html
              EOF

  tags = {
    Name = "terraform-example"
  }
}

resource "aws_security_group" "instance" {

  name = var.security_group_name

  ingress {
    from_port   = 80
    to_port     = 80
    protocol    = "tcp"
    cidr_blocks = ["0.0.0.0/0"]
  }

  ingress {
    from_port   = 22
    to_port     = 22
    protocol    = "tcp"
    cidr_blocks = ["0.0.0.0/0"]
  }

  egress {
    from_port        = 0
    to_port          = 0
    protocol         = "-1"
    cidr_blocks      = ["0.0.0.0/0"]
  }

  tags = {
    Name = "tf-web"
  }

}

variable "security_group_name" {
  description = "The name of the security group"
  type        = string
  default     = "terraform-example-instance"
}

output "public_ip" {
  value       = aws_instance.example.public_ip
  description = "The public IP of the Instance"
}

# terraform init
# terraform apply
# terraform destroy

 

 

--- Terraform 설치
# yum install -y yum-utils

# yum-config-manager --add-repo https://rpm.releases.hashicorp.com/RHEL/hashicorp.repo

→ 저장소 주소 추가를 용이하게 만드는 명령어.이 저장소로 가야지만 패키지 설치가 가능해짐. 다만, 위에서 작성한 yum-utils 를 설치해야만 사용이 가능하다.

# yum -y install terraform

# terraform -version

 

 숨겨져 있는 폴더가 보임. 그 폴더로 넘어가기 

credentials파일이 있음.

이때 credentials를 삭제하면 로그아웃의 기능을 함.

 

# wget https://releases.hashicorp.com/terraform/1.2.3/terraform_1.2.3_linux_amd64.zip
# wget https://releases.hashicorp.com/terraform/1.4.6/terraform_1.4.6_linux_amd64.zip
# unzip terraform_1.2.3_linux_amd64.zip
# unzip terraform_1.4.6_linux_amd64.zip
# mv terraform /usr/local/bin/
# terraform -version

export AWS_ACCESS_KEY_ID=(your access key id)
export AWS_SECRET_ACCESS_KEY=(your secret access key)

→ 위의 두 값이 내 시스템 내에 변수로 지정이 됨. 단점은 exit를 치고 다시 들어가면 해당 데이터가 날아감. 변수기 때문에! 따라서 안전하게 키 관리를 할 수 있음. 

 

 

테라폼 실습을 위한 폴더 먼저 만들고, 그 안에서 여러 폴더를 만들어 볼 예정

 


# mkdir teraform && cd $_

→  terraform 폴더를 만들고, 그 안으로 이동을 함

 

 

# mkdir tf-test && cd $_

 먼저 ec2를 만들고, default vpc를 활용해서 만들 예정

main이라는 모듈 하나를 가지고 간단한 EC2를 만들어보기 

terraform 폴더 안에서 tf-test라는 폴더를 하나 만들기


# vi main.tf
provider "aws" {
  region = "ap-northeast-2"
}
 provider를 aws로 지정하겠다. {} 중괄호 하고 리전명을 적어주기!

 


resource "aws_instance" "example"

→ example은 논리적 아이디이기 때문에 내가 정할 수  있음.단  {aws_intance}는 정해져있는 것. 
  ami                    = "ami-035da6a0773842f64"
  instance_type          = "t2.micro"
  vpc_security_group_ids = [aws_security_group.instance.id]
 리소스라는 블록.

블록 안에는 컨테이너와 같아서 뭔가를 담는 공간임. 블록 바디 부분에 내용을 추가해줌. 스네이크 케이스가 있음. 

이미지, 인스턴스 타입, 보안그룹을 넣어주기.

 대괄호는 하나가 아니라 두개 이상의 값을 넣어줄 때 사용함. (,를 넣어서 여러개를 넣을 수 있음) 리스트 혹은 튜플. array가 됨. 여러가지 정보를 넣으려고 할때, 대괄호로 감싸주기!!!

aws_security_group.instance.id = id를 찍지 않고 참조하겠다는 의미임.

vpc 보안그룹의 아이디를 집어넣어야 되는데 밑에서 보안그룹이 만들어 지는 리소스를 참조해서 가져오겠다는 의미임..을 경계로 좌우로 확인을 함. → 그런데, 보안그룹을 먼저 만들고 ec2를 만드는게 맞지않아?terraform 은 똑똑해서 ec2만들때 보안그룹이 필요하다는 것을 안다. ec2인스턴스 읽다가 보안그룹 안만든거 확인해서 바로 보안그룹 만드는 곳으로 넘어가기. 그 이후에 보안그룹을 만들고 거기에 나오는 id를 가져와서 해당 대괄호에 id를 넣어주고 다시 순서대로 흘러감. 

aws_security_group 이미 정해져있는 자원의 이름. 

하나의 그룹 아이디만 넣을 것이기 때문에, 아래 부분에서 security_group이라는 그룹에서 추출을 해오면 됨. 

이 문장에서 내가 정할 수 있는 것은 instance라는 단어 하나 뿐

이미지 아이디 가져오기

아래서 부터 생성되는 보안그룹의 아이디가 가져온다는 뜻임.

 

 

  user_data = <<-EOF

→ <<-EOF는 쉽게 사용자 데이터를 입력하기 위해 사용. (End Of File) , AWS에다가 EC2를 사용하면서 그 안에 내가 넣고 싶은 코멘드를 정리해서 넣어줌. 직접 입력한 텍스트를 파일에 저장할 때 사용함. 처음에 cat <<EOF > 파일명 을 사용하여 시작하고 마지막에 EOF 단어로 파일 끝을 내고 저장함

              #cloud-boothook

→ 사용자 데이터 수정이 필요할때면 이 부분을 꼭 넣어주기!! 
              #!/bin/bash
              yum install -y httpd
              systemctl enable --now httpd
              echo "<h1>example</h1>" > /var/www/html/index.html
              EOF

  tags = {
    Name = "terraform-example"
  }
}
→ VPC 정보가 없고, 서브넷 정보가 없는 경우에는 디폴트에다가 만들겠다는 의미와 같음. 


resource "aws_security_group" "instance" {

  name = var.security_group_name
→ var. 는 변수로 정의되어 있는 이름을 가져와서 보안그룹 이름을 참조해서 가져와 정하겠다는 의미 variable이라고 하는 블록에서 정해져 있는 default라는 값을 가져와서 붙여넣기 하는 기능

그래서 이름이 terraform-example-instance 라는 이름이 붙게 됨.


  ingress {
    from_port   = 80
    to_port     = 80
    protocol    = "tcp"
    cidr_blocks = ["0.0.0.0/0"]
  }
→ 포트를 하나만 넣고 싶다면 from과 to port의 값을 똑같이 정해준다. 

cidr_blocks를 더 추가 하려면 ["0.0.0.0/0 , "10.24.0.0/16] 이런식으로대괄호와 쉼표로 써주면 된다. 


  ingress {
    from_port   = 22
    to_port     = 22
    protocol    = "tcp"
    cidr_blocks = ["0.0.0.0/0"]
  }

  egress {
    from_port        = 0
    to_port          = 0
    protocol         = "-1"
    cidr_blocks      = ["0.0.0.0/0"]
  }
→포트에 상관없이 모든 프로토콜을 -1로 표현. 안에서 바깥으로 나갈 수 있도록 아웃바운드를 허용하겠다는 뜻 


  tags = {
    Name = "tf-web"
  }
}

variable "security_group_name" {
  description = "The name of the security group"
  type        = string
  default     = "terraform-example-instance" 
}
 type을 꼭 넣어주어야 함. 디폴트에 명시된 문자들은 변수명에 따른 값을 가져옴. 


output "public_ip" {
  value       = aws_instance.example.public_ip
  description = "The public IP of the Instance"
}
→aws_instance.example(내가 정한 이름).public_ip 

퍼블릭 아이피를 가져오겠다는 의미

description 은 참고사항이기때문에 넣어도 되고 안넣어도 됨.



 

이걸 파일로 저장을 할 것임. 

 

# vi main.tf

위의 내용을 다 넣어주기! 

 

 

 

# terraform init

필요한 것들을 그때그때 마다 init를 통해서 plug in을 통해 자원을 제공 받아서 plan>apply 해준다.

# ls -al

# terraform plan (온전한지, 정상인지, 추가할 것과 뺄 것이 무엇인지 찾아봄)


# terraform apply

 

보안그룹도 설정한대로 잘 나왔는지 확인해보기

 

태그값을 고쳐보기

변경사항이 발생했으니 + 대신 change의 뜻인 ~이 보임.

 

과거에 수행했던 기록들이 고스란히 남아있음.

# cat terraform.tfstate

 

사용자 데이터 변경해주기

다만 아이피 바뀐건 늦게 반영되니까 EC2인스턴스 클릭후 퍼블릭 아이피로 들어가주기!!!

 

삭제하기

# terraform destroy

 

 

---------------
--- aws_set ---
---------------

vpc> subnet> internetgateway > router


# mkdir aws-set && cd $_

 

vpc> subnet> internetgateway > router

다시 위에 있던 파일 실행해주기. terraform 폴더 내에 aws-set 을 넣어서 따로 관리해주기



variables.tf


# vi variables.tf
variable "security_group_name" {
  description = "The name of the security group"
  type        = string
  default     = "terraform-example-instance"
}
→ variables 파일(변수 관리에 용이하게)을 미리 만들기

 

Input Variables

테라폼에서 사용하는 값(value)의 이름을 작성하거나 배포하기 위한 몇가지 블럭이 존재한다.

  • Input Variables은 테라폼 모듈의 파라미터 역할을 하여 사용자가 소스를 편집하지 않고 동작을 customize할 수 있다.
  • 이 기능을 사용하면 다양한 테라폼 구성에서 모듈을 공유할 수 있으므로 모듈을 구성 및 재사용할 수 있다.

 

main.tf

1) init

2) vpc

3) public_subnet

4) internet gateway
5) route table

5) route table association

 


1) init

 

// aws provider 

// data source : aws_availability_zones
# vi main.tf
provider "aws" {
  region = "ap-northeast-2"
}

 

data "aws_availability_zones" "available" {

  state = "available"

  서울 리전에 있는 가용영역 정보를 가져오기위해서 사용함. 사용 가능한 상태의 정보를 가져오라는 의미.

   가용 영역을 설정하기. abailable을 사용함으로써 사용가능한 모든 영역을 선택.

  내 계정에 존재하는 서울리전의 네개의 가용영역들을 lable로 집어넣게 됨. 


}

 

 


### vpc start ###
 주석이 허용이 되어서 #을 넣어 주석처리를 해줌.

 기본 프로바이더와 가용 영역을 설정해주었다

 프로바이더 구문에서 AWS ACCESS KEY와 SECRET KEY를 설정해도 된다

 


2) vpc

// vpc
resource "aws_vpc" "test_vpc" {
  cidr_block  = "192.168.0.0/16"

 cidr_block (필수) : VPC의 CIDR 블록

  enable_dns_hostnames = true

 이게 체크가 되어야 무료로 제공받는 dns 엔드포인트 주소를 받을 수 있음. 

 무료로 제공받은 dns 엔드포인트는 RDS 생성시 만들어지는 DNS 같은 것을 의미. 

 기본 값이 false라 true로 해줌. 
  enable_dns_support = true

 기본 값이 true라 그냥 두기. 없애도 됨. 
  instance_tenancy = "default"

  다른 사람들고 share하는 환경에서 운용을 할 것이라는 뜻


  tags = {
    Name = "test-vpc"

  Name 태그로 test-vpc이라고 이름 지정해주기

  }
}

 


3) subnet

 

퍼블릭 서브넷 설정해주기. 


resource "aws_subnet" "test-pub_2a" {

  "aws_subnet"는 정할 수 없는 정해진 이름" ,뒤에는 내가 정할 수 있는 서브넷 이름을 주기. 
  vpc_id = aws_vpc.test_vpc.id

  aws_vpc랑 .id 부분은 원래 픽스된 이름이고, 내가 만든 test_vpc는 내가 정하는 것 
  cidr_block = "192.168.0.0/20"

 사용할 사설 IP 대역
  map_public_ip_on_launch = true

→ 이 서브넷에서 시작하는 인스턴스들이 public ip를 가질지 아닐지 여부

-> Public Subnet이니까 true로 해줬다 (기본값은 false)
  availability_zone = data.aws_availability_zones.available.names[0]

→ 가용 영역 - inint파트에서 정의한 aws_availibility_zone데이터 available의 첫 번째 값을 가져오겠다. 

id가 아닌 names를 가져온 것임. 가져오려는 name[안에 있는 숫자] 가용영역이 몇번째 가용영역인지 순서를 의미함. 따라서 해당 names[0]은 2a를 의미한다. 

  tags = {
    Name = "test-pub-2a"
  }
}

더보기


resource "aws_subnet" "test-pub_2b" {
  vpc_id = aws_vpc.test_vpc.id
  cidr_block = "192.168.16.0/20"
  map_public_ip_on_launch = true
  availability_zone = data.aws_availability_zones.available.names[1]
  tags = {
    Name = "test-pub-2b"
  }
}

resource "aws_subnet" "test-pub_2c" {
  vpc_id = aws_vpc.test_vpc.id
  cidr_block = "192.168.32.0/20"
  map_public_ip_on_launch = true
  availability_zone = data.aws_availability_zones.available.names[2]
  tags = {
    Name = "test-pub-2c"
  }
}

resource "aws_subnet" "test-pub_2d" {
  vpc_id = aws_vpc.test_vpc.id
  cidr_block = "192.168.48.0/20"
  map_public_ip_on_launch = true
  availability_zone = data.aws_availability_zones.available.names[3]
  tags = {
    Name = "test-pub-2d"
  }
}


프라이빗 서브넷 설정해주기. 

 

resource "aws_subnet" "test-pvt_2a" {
  vpc_id = aws_vpc.test_vpc.id
  cidr_block = "192.168.64.0/20"
  map_public_ip_on_launch = false

  이 서브넷에서 시작하는 인스턴스 들이 public ip 를 가질지..?

프라이빗 서브넷이니까 true가 아님!!! 따라서 디폴트 값이 false이므로 지우거나 false 라고 명시해주기!
  availability_zone = data.aws_availability_zones.available.names[0]
  tags = {
    Name = "test-pvt_2a"
  }
}

 

 

더보기

resource "aws_subnet" "test-pvt_2b" {
  vpc_id = aws_vpc.test_vpc.id
  cidr_block = "192.168.80.0/20"
  map_public_ip_on_launch = false
  availability_zone = data.aws_availability_zones.available.names[1]
  tags = {
    Name = "test-pvt_2b"
  }
}

 

resource "aws_subnet" "test-pvt_2c" {
  vpc_id = aws_vpc.test_vpc.id
  cidr_block = "192.168.96.0/20"
  map_public_ip_on_launch = false
  availability_zone = data.aws_availability_zones.available.names[2]
  tags = {
    Name = "test-pvt_2c"
  }
}

 

resource "aws_subnet" "test-pvt_2d" {
  vpc_id = aws_vpc.test_vpc.id
  cidr_block = "192.168.112.0/20"
  map_public_ip_on_launch = false
  availability_zone = data.aws_availability_zones.available.names[3]
  tags = {
    Name = "test-pvt_2d"
  }
}

 


 

4) internet gateway

인터넷 게이트웨이 설정해주기. 

 

resource "aws_internet_gateway" "test_igw" {
  vpc_id = aws_vpc.test_vpc.id

  인터넷 게이트웨이 만들고 attach를 해야하는데 여기서는 생략이 됨. 사실상 생략 되었다기보다 이 안에 포함이 된것임.

그냥 여기서 vpc id를 변수 값으로 받아오기!
  tags = {
    Name = "test-igw"
  }
}


5) route table

라우트 테이블 설정해주기. 

 

resource "aws_route_table" "test_pub_rtb" {
  vpc_id = aws_vpc.test_vpc.id
  테이블을 만들면 로컬 정보가 자동으로 들어감. 그래서 따로 정의할 필요가 없음. 
  route {
    cidr_block = "0.0.0.0/0"

  인수 정해주기. 인수를 사용하면 직접 라우팅 설정이 가능.  

  로컬이 아닌 모든 아이피들은 어디에 길을 물어야하느냐. 인터넷 게이트웨이로 가라.
    gateway_id = aws_internet_gateway.test_igw.id

  인터넷 게이트 웨이로 가려고 시키기때문에 id를 꼭 넣어주기.
  }
  tags = {
    Name = "test-pub-rtb"

  test-pub 의 라우팅 테이블
  }
}

 

resource "aws_route_table" "test_pvt_rtb" {
  vpc_id = aws_vpc.test_vpc.id
  pvt는 internet gateway 연결할 일 없음.

  그래서 따로 라우팅 설정은 해주지 않았음. 
  tags = {
    Name = "test-pvt-rtb"

 }
}

 


5) route table association

테이블 설정해주기. 

 

Route Table은 트래픽을 규칙에 맞게 전달해주기 위해 필요한 일종의 테이블이다.

Route table은 여러 서브넷에서 동시에 사용할 수 있으며, 이렇게 연결하는 작업은 Association 이라고 한다.

Route Table은 aws_route_table 리소스를 생성하면 되고(위에서 실행함), 서브넷과 연결하실 때는 aws_route_table_association 을 사용하시면 된다.


resource "aws_route_table_association" "test-pub_2a_association" {
  subnet_id = aws_subnet.test-pub_2a.id
  route_table_id = aws_route_table.test_pub_rtb.id
}

더보기

resource "aws_route_table_association" "test-pub_2b_association" {
  subnet_id = aws_subnet.test-pub_2b.id
  route_table_id = aws_route_table.test_pub_rtb.id
}

resource "aws_route_table_association" "test-pub_2c_association" {
  subnet_id = aws_subnet.test-pub_2c.id
  route_table_id = aws_route_table.test_pub_rtb.id
}

resource "aws_route_table_association" "test-pub_2d_association" {
  subnet_id = aws_subnet.test-pub_2d.id
  route_table_id = aws_route_table.test_pub_rtb.id
}

 

resource "aws_route_table_association" "test-pvt_2a_association" {
  subnet_id = aws_subnet.test-pvt_2a.id
  route_table_id = aws_route_table.test_pvt_rtb.id
}

 

resource "aws_route_table_association" "test-pvt_2b_association" {
  subnet_id = aws_subnet.test-pvt_2b.id
  route_table_id = aws_route_table.test_pvt_rtb.id
}

 

resource "aws_route_table_association" "test-pvt_2c_association" {
  subnet_id = aws_subnet.test-pvt_2c.id
  route_table_id = aws_route_table.test_pvt_rtb.id
}

 

resource "aws_route_table_association" "test-pvt_2d_association" {
  subnet_id = aws_subnet.test-pvt_2d.id
  route_table_id = aws_route_table.test_pvt_rtb.id
}

 

 


### vpc end ###

 

 

 

ec2.tf

 

### ec2 start ###
1) aws_instance


resource "aws_instance" "example" {
  ami                    = "ami-035da6a0773842f64"


  instance_type          = "t2.micro"
  subnet_id              = aws_subnet.test-pub_2a.id

  ec2의 가용영역은 public 2a로 해줌. 
  vpc_security_group_ids = [aws_security_group.instance.id]
  key_name               = "test-key"

  테라폼으로 만들려고 하면 public key밖에 안만들어지기 때문에 이것저것 할게 많아서 골치아프니 AWS에서 만든 후 사용하자
  user_data              = file("user-data.sh")

  file로 가져오겠다는 뜻 cloudformation이랑은 좀 다름

  EC2에 넣을 user data이다. 테라폼의 히어닥 문법(EOF)를 사용했다


  tags = {
    Name = "terraform-example"
  }
}



<보안그룹 만들기>

2) aws_security_group


resource "aws_security_group" "instance" {
  vpc_id = aws_vpc.test_vpc.id

  vpc의 아이디를 뒤져서 나온 아이피를 참조할 것이라는 뜻. 
  name = var.security_group_name

  varieble에서 name을 가져와서 넣겠다는 의미

  ingress {
    from_port   = 80
    to_port     = 80

  클라이언트의 출발지 포트가 아님. source - destination port의미가 아님. range의 의미임!!!!!!! 만약 from_port가 80이고, to_port가 88이면 포트번호 80~88까지를 포함한다는 의미임!!!!!!!
    protocol    = "tcp"
    cidr_blocks = ["0.0.0.0/0"]
  }
  ingress {
    from_port   = 22
    to_port     = 22
    protocol    = "tcp"
    cidr_blocks = ["106.253.56.124/20"]


  }
  ingress {

  vm을 기준으로 들어오는 포트를 설정해 주는 코드

내가 만드는 서버가 목적지가 되어서 destination포트를 정의하는 것임
    from_port   = -1
    to_port     = -1

    protocol    = "icmp"
    cidr_blocks = ["0.0.0.0/0"]

  핑, 모든 아이피 허용
  }
  egress {
    from_port   = 0
    to_port     = 0
    protocol    = "-1"
    cidr_blocks = ["0.0.0.0/0"]

  목적지. destination(egress이기 때문에 vm을 기준으로 나가는 것이기 때문에)
  }
  tags = {
    Name = "terraform-sg"
  }
}

 


### ec2 end ###

 

 

s3로 가서 food.tar파일 올리기

 

- 유저데이터에 올릴 food.tar 파일을 S3에 업로드해서 적용하기 위함.

 

반드시 ACL (액세스 제어 목록) 설정 확인해주기!!!!


 

# vi user-data.sh 

사용자 파일에 다운로드 받기 위해 파일생성

yum install -y httpd wget

systemctl enable --now httpd

cd /tmp

wget [s3링크주소 복붙]

tar xvf food.tar -C /var/www/html

wget으로 받아오기!!!!

 

 

결과 정의하기

 

 

# vi outputs.tf

 아래 내용 넣어주기
output "public_ip" {
  value       = aws_instance.example.public_ip
  description = "The public IP of the Instance"
}

output "public_dns" {
  value       = aws_instance.example.public_dns
  description = "The Public dns of the Instance"
}

output "private_ip" {
  value       = aws_instance.example.private_ip
  description = "The Private_ip of the Instance"
}

 

 


# terraform init



# terraform plan



# terraform apply -auto-approve ( -auto-approve 옵션을 추가하면 yes 생략 가능)



# terraform output public_ip

 

위에서 정의한 결과 정의하는 파일인 outputs.tf에 있던 내용임!!!

output "public_ip" {
  value       = aws_instance.example.public_ip
  description = "The public IP of the Instance"
}

 

# terraform destroy (-auto-approve 옵션을 추가하면 yes 생략 가능)

 

 

 

 

 

ec2 alb

더보기

---------------
--- ec2 alb ---
---------------

# mkdir ec2-alb && cd $_

### vpc start ###

resource "aws_vpc" "test_vpc" {
  cidr_block  = "192.168.0.0/16"
  enable_dns_hostnames = true
  enable_dns_support = true
  instance_tenancy = "default"

  tags = {
    Name = "test-vpc"
  }
}

data "aws_availability_zones" "available" {
  state = "available"
}

resource "aws_subnet" "test-pub_2a" {
  vpc_id = aws_vpc.test_vpc.id
  cidr_block = "192.168.0.0/20"
  map_public_ip_on_launch = true
  availability_zone = data.aws_availability_zones.available.names[0]
  tags = {
    Name = "test-pub-2a"
  }
}

resource "aws_subnet" "test-pub_2b" {
  vpc_id = aws_vpc.test_vpc.id
  cidr_block = "192.168.16.0/20"
  map_public_ip_on_launch = true
  availability_zone = data.aws_availability_zones.available.names[1]
  tags = {
    Name = "test-pub-2b"
  }
}

resource "aws_subnet" "test-pub_2c" {
  vpc_id = aws_vpc.test_vpc.id
  cidr_block = "192.168.32.0/20"
  map_public_ip_on_launch = true
  availability_zone = data.aws_availability_zones.available.names[2]
  tags = {
    Name = "test-pub-2c"
  }
}

resource "aws_subnet" "test-pub_2d" {
  vpc_id = aws_vpc.test_vpc.id
  cidr_block = "192.168.48.0/20"
  map_public_ip_on_launch = true
  availability_zone = data.aws_availability_zones.available.names[3]
  tags = {
    Name = "test-pub-2d"
  }
}

resource "aws_subnet" "test-pvt_2a" {
  vpc_id = aws_vpc.test_vpc.id
  cidr_block = "192.168.64.0/20"
  map_public_ip_on_launch = false
  availability_zone = data.aws_availability_zones.available.names[0]
  tags = {
    Name = "test-pvt_2a"
  }
}



resource "aws_subnet" "test-pvt_2b" {
  vpc_id = aws_vpc.test_vpc.id
  cidr_block = "192.168.80.0/20"
  map_public_ip_on_launch = false
  availability_zone = data.aws_availability_zones.available.names[1]
  tags = {
    Name = "test-pvt_2b"
  }
}



resource "aws_subnet" "test-pvt_2c" {
  vpc_id = aws_vpc.test_vpc.id
  cidr_block = "192.168.96.0/20"
  map_public_ip_on_launch = false
  availability_zone = data.aws_availability_zones.available.names[2]
  tags = {
    Name = "test-pvt_2c"
  }
}



resource "aws_subnet" "test-pvt_2d" {
  vpc_id = aws_vpc.test_vpc.id
  cidr_block = "192.168.112.0/20"
  map_public_ip_on_launch = false
  availability_zone = data.aws_availability_zones.available.names[3]
  tags = {
    Name = "test-pvt_2d"
  }
}

resource "aws_internet_gateway" "test_igw" {
  vpc_id = aws_vpc.test_vpc.id
  tags = {
    Name = "test-igw"
  }
}

resource "aws_route_table" "test_pub_rtb" {
  vpc_id = aws_vpc.test_vpc.id

  route {
    cidr_block = "0.0.0.0/0"
    gateway_id = aws_internet_gateway.test_igw.id
  }
  tags = {
    Name = "test-pub-rtb"
  }
}

resource "aws_route_table_association" "test-pub_2a_association" {
  subnet_id = aws_subnet.test-pub_2a.id
  route_table_id = aws_route_table.test_pub_rtb.id
}

resource "aws_route_table_association" "test-pub_2b_association" {
  subnet_id = aws_subnet.test-pub_2b.id
  route_table_id = aws_route_table.test_pub_rtb.id
}

resource "aws_route_table_association" "test-pub_2c_association" {
  subnet_id = aws_subnet.test-pub_2c.id
  route_table_id = aws_route_table.test_pub_rtb.id
}

resource "aws_route_table_association" "test-pub_2d_association" {
  subnet_id = aws_subnet.test-pub_2d.id
  route_table_id = aws_route_table.test_pub_rtb.id
}



### vpc end ###

# vi main.tf
provider "aws" {
  region = "ap-northeast-2"
}

data "aws_availability_zones" "available" {
  state = "available"
}
resource "aws_vpc" "test_vpc" {
  cidr_block  = "192.168.0.0/16"
  enable_dns_hostnames = true
  enable_dns_support = true
  instance_tenancy = "default"

  tags = {
    Name = "test-vpc"
  }
}
resource "aws_subnet" "test-pub_2a" {
  vpc_id = aws_vpc.test_vpc.id
  cidr_block = "192.168.0.0/20"
  map_public_ip_on_launch = true
  availability_zone = data.aws_availability_zones.available.names[0]
  tags = {
    Name = "test-pub-2a"
  }
}
resource "aws_subnet" "test-pub_2b" {
  vpc_id = aws_vpc.test_vpc.id
  cidr_block = "192.168.16.0/20"
  map_public_ip_on_launch = true
  availability_zone = data.aws_availability_zones.available.names[1]
  tags = {
    Name = "test-pub-2b"
  }
}
resource "aws_subnet" "test-pub_2c" {
  vpc_id = aws_vpc.test_vpc.id
  cidr_block = "192.168.32.0/20"
  map_public_ip_on_launch = true
  availability_zone = data.aws_availability_zones.available.names[2]
  tags = {
    Name = "test-pub-2c"
  }
}
resource "aws_subnet" "test-pub_2d" {
  vpc_id = aws_vpc.test_vpc.id
  cidr_block = "192.168.48.0/20"
  map_public_ip_on_launch = true
  availability_zone = data.aws_availability_zones.available.names[3]
  tags = {
    Name = "test-pub-2d"
  }
}
resource "aws_internet_gateway" "test_igw" {
  vpc_id = aws_vpc.test_vpc.id
  tags = {
    Name = "test-igw"
  }
}
resource "aws_route_table" "test_pub_rtb" {
  vpc_id = aws_vpc.test_vpc.id

  route {
    cidr_block = "0.0.0.0/0"
    gateway_id = aws_internet_gateway.test_igw.id
  }
  tags = {
    Name = "test-pub-rtb"
  }
}
resource "aws_route_table_association" "test-pub_2a_association" {
  subnet_id = aws_subnet.test-pub_2a.id
  route_table_id = aws_route_table.test_pub_rtb.id
}
resource "aws_route_table_association" "test-pub_2b_association" {
  subnet_id = aws_subnet.test-pub_2b.id
  route_table_id = aws_route_table.test_pub_rtb.id
}
resource "aws_route_table_association" "test-pub_2c_association" {
  subnet_id = aws_subnet.test-pub_2c.id
  route_table_id = aws_route_table.test_pub_rtb.id
}
resource "aws_route_table_association" "test-pub_2d_association" {
  subnet_id = aws_subnet.test-pub_2d.id
  route_table_id = aws_route_table.test_pub_rtb.id
}

variable "security_group_name" {
  description = "The name of the security group"
  type        = string
  default     = "test-sg-alb"
}

resource "aws_security_group" "test_web_sg_alb" {
  name   = var.security_group_name
#  vpc_id = data.aws_vpc.test_vpc.id
  vpc_id = aws_vpc.test_vpc.id
  ingress {
    from_port   = 80
    to_port     = 80
    protocol    = "tcp"
    cidr_blocks = ["0.0.0.0/0"]
  }
  ingress {
    from_port   = 443
    to_port     = 443
    protocol    = "tcp"
    cidr_blocks = ["0.0.0.0/0"]
  }
  egress {
    from_port   = 0
    to_port     = 0
    protocol    = "-1"
    cidr_blocks = ["0.0.0.0/0"]
  }
  tags = {
    Name = "test-sg-alb"
  }
}

resource "aws_lb" "frontend" {
  name               = "alb-example"
  internal           = false
  load_balancer_type = "application"
  security_groups    = [aws_security_group.test_web_sg_alb.id]
  subnets            = [
    aws_subnet.test-pub_2a.id,
    aws_subnet.test-pub_2c.id
  ]

  tags = {
    Name = "test-alb"
  }

  lifecycle { create_before_destroy = true }
}


resource "aws_instance" "alb_vm_01" {
  ami                    = "ami-0fd0765afb77bcca7"
  instance_type          = "t2.micro"
  subnet_id              = aws_subnet.test-pub_2a.id
  vpc_security_group_ids = [aws_security_group.test_web_sg_alb.id]
  key_name  = "test-key"
  user_data = <<-EOF
              #! /bin/bash
              yum install -y httpd
              systemctl enable --now httpd
              echo "Hello, Terraform01" > /var/www/html/index.html
              EOF

  tags = {
    Name = "ALB01"
  }
}

resource "aws_instance" "alb_vm_02" {
  ami                    = "ami-0fd0765afb77bcca7"
  instance_type          = "t2.micro"
  subnet_id              = aws_subnet.test-pub_2c.id
  vpc_security_group_ids = [aws_security_group.test_web_sg_alb.id]
  key_name  = "test-key"
  user_data = <<-EOF
              #! /bin/bash
              yum install -y httpd
              systemctl enable --now httpd
              echo "Hello, Terraform02" > /var/www/html/index.html
              EOF

  tags = {
    Name = "ALB02"
  }
}

resource "aws_lb_target_group" "tg" {
  name        = "TargetGroup"
  port        = 80
  target_type = "instance"
  protocol    = "HTTP"
  vpc_id      = aws_vpc.test_vpc.id

  health_check {
    path                = "/"
    protocol            = "HTTP"
    matcher             = "200"
    interval            = 15
    timeout             = 3
    healthy_threshold   = 2
    unhealthy_threshold = 2
  }
}
resource "aws_alb_target_group_attachment" "tgattachment01" {
  target_group_arn = aws_lb_target_group.tg.arn
  target_id        = aws_instance.alb_vm_01.id
  port             = 80
}
resource "aws_alb_target_group_attachment" "tgattachment02" {
  target_group_arn = aws_lb_target_group.tg.arn
  target_id        = aws_instance.alb_vm_02.id
  port             = 80
}

resource "aws_lb_listener" "front_end" {
  load_balancer_arn = aws_lb.frontend.arn
  port              = "80"
  protocol          = "HTTP"

  default_action {
    type             = "forward"
    target_group_arn = aws_lb_target_group.tg.arn
  }
}
output "lb_dns_name" {
  description = "The DNS name of the load balancer."
  value       = aws_lb.frontend.dns_name
}

# terraform init
# terraform validate (구성만 참조하고 원격 상태, 공급자 API 등과 같은 원격 서비스에 액세스하지 않고 디렉터리의 구성 파일을 유효성 검사합니다.)
# terraform plan
# terraform apply -auto-approve
# terraform output lb_dns_name
# terraform destroy -auto-approve

 

 

main.tf

1) init

2) vpc

3) public_subnet

4) internet gateway
5) route table

5) route table association


1) init

# vi main.tf
provider "aws" {
  region = "ap-northeast-2"
}


2) vpc


### vpc start ###

resource "aws_vpc" "test_vpc" {
  cidr_block  = "192.168.0.0/16"
  enable_dns_hostnames = true
  enable_dns_support = true
  instance_tenancy = "default"

  tags = {
    Name = "test-vpc"
  }
}

data "aws_availability_zones" "available" {
  state = "available"
}

 


3) public_subnet


resource "aws_subnet" "test-pub_2a" {
  vpc_id = aws_vpc.test_vpc.id
  cidr_block = "192.168.0.0/20"
  map_public_ip_on_launch = true
  availability_zone = data.aws_availability_zones.available.names[0]
  tags = {
    Name = "test-pub-2a"
  }
}

 

더보기

resource "aws_subnet" "test-pub_2b" {
  vpc_id = aws_vpc.test_vpc.id
  cidr_block = "192.168.16.0/20"
  map_public_ip_on_launch = true
  availability_zone = data.aws_availability_zones.available.names[1]
  tags = {
    Name = "test-pub-2b"
  }
}

resource "aws_subnet" "test-pub_2c" {
  vpc_id = aws_vpc.test_vpc.id
  cidr_block = "192.168.32.0/20"
  map_public_ip_on_launch = true
  availability_zone = data.aws_availability_zones.available.names[2]
  tags = {
    Name = "test-pub-2c"
  }
}

resource "aws_subnet" "test-pub_2d" {
  vpc_id = aws_vpc.test_vpc.id
  cidr_block = "192.168.48.0/20"
  map_public_ip_on_launch = true
  availability_zone = data.aws_availability_zones.available.names[3]
  tags = {
    Name = "test-pub-2d"
  }
}

 



resource "aws_subnet" "test-pvt_2a" {
  vpc_id = aws_vpc.test_vpc.id
  cidr_block = "192.168.64.0/20"
  map_public_ip_on_launch = false
  availability_zone = data.aws_availability_zones.available.names[0]
  tags = {
    Name = "test-pvt_2a"
  }
}

 

더보기

resource "aws_subnet" "test-pvt_2b" {
  vpc_id = aws_vpc.test_vpc.id
  cidr_block = "192.168.80.0/20"
  map_public_ip_on_launch = false
  availability_zone = data.aws_availability_zones.available.names[1]
  tags = {
    Name = "test-pvt_2b"
  }
}



resource "aws_subnet" "test-pvt_2c" {
  vpc_id = aws_vpc.test_vpc.id
  cidr_block = "192.168.96.0/20"
  map_public_ip_on_launch = false
  availability_zone = data.aws_availability_zones.available.names[2]
  tags = {
    Name = "test-pvt_2c"
  }
}



resource "aws_subnet" "test-pvt_2d" {
  vpc_id = aws_vpc.test_vpc.id
  cidr_block = "192.168.112.0/20"
  map_public_ip_on_launch = false
  availability_zone = data.aws_availability_zones.available.names[3]
  tags = {
    Name = "test-pvt_2d"
  }
}

 




4) internet gateway 생성

resource "aws_internet_gateway" "test_igw" {
  vpc_id = aws_vpc.test_vpc.id
  tags = {
    Name = "test-igw"
  }
}

 


5) route table 생성 / 퍼블릭은 route연결해주고, private은 그냥 명시만 해줘도 됨. 아니면 아예 하지말기


resource "aws_route_table" "test_pub_rtb" {
  vpc_id = aws_vpc.test_vpc.id

  route {
    cidr_block = "0.0.0.0/0"
    gateway_id = aws_internet_gateway.test_igw.id
  }
  tags = {
    Name = "test-pub-rtb"

→ public route table을 생성해줌
  }
}

 


5) route table association


resource "aws_route_table_association" "test-pub_2a_association" {
  subnet_id = aws_subnet.test-pub_2a.id
  route_table_id = aws_route_table.test_pub_rtb.id
}

resource "aws_route_table_association" "test-pub_2b_association" {
  subnet_id = aws_subnet.test-pub_2b.id
  route_table_id = aws_route_table.test_pub_rtb.id
}

resource "aws_route_table_association" "test-pub_2c_association" {
  subnet_id = aws_subnet.test-pub_2c.id
  route_table_id = aws_route_table.test_pub_rtb.id
}

resource "aws_route_table_association" "test-pub_2d_association" {
  subnet_id = aws_subnet.test-pub_2d.id
  route_table_id = aws_route_table.test_pub_rtb.id
}

 

위와 달리 여기서는 route table을 public 용 하나만 만들었기 때문에.. 명시적 연결은 한번만 해도 됨.

 

 

보안 그룹 생성해주기



variable "security_group_name" {
  description = "The name of the security group"
  type        = string
  default     = "test-sg-alb"
}

resource "aws_security_group" "test_web_sg_alb" {
  name   = var.security_group_name
#  vpc_id = data.aws_vpc.test_vpc.id

→ 이미 있는 data를 가져와서 참고할 수도있음.
  vpc_id = aws_vpc.test_vpc.id
  ingress {
    from_port   = 80
    to_port     = 80
    protocol    = "tcp"
    cidr_blocks = ["0.0.0.0/0"]

→ 누구든지 내가 만든 곳으로 접근 가능. 
  }

  ingress {
    from_port   = 443
    to_port     = 443
    protocol    = "tcp"
    cidr_blocks = ["0.0.0.0/0"]
  }

 alb를 위한 보안그룹임. 

따라서 http ( 80번 )포트, https ( 443번 )포트가 열려있으면 됨. ssh ( 22번 )포트가 열려있어봤자 접근이 불가능. 그래서 굳이 안염
  egress {
    from_port   = 0
    to_port     = 0
    protocol    = "-1"
    cidr_blocks = ["0.0.0.0/0"]
  }
  tags = {
    Name = "test-sg-alb"
  }
}

resource "aws_lb" "frontend" {

 자원의 이름 aws_lb 내 식별자는 frontend 
  name               = "alb-example"

 로드벨런서가 가지고 있는 원래 이름인 alb-example로 줌. 

  internal           = false

 인터넷 facing 은 디폴트 값인 true를 false로 바꿔줌.
  load_balancer_type = "application"

 로브벨런서의 타입은 클래식, 네트워크, 애플리케이션이 있는데, alb를 사용함. 

  security_groups    = [aws_security_group.test_web_sg_alb.id]

 security 그룹은 앞서 만든 aws_security_group,자원의 이름.id 으로 가져옴
  subnets            = [

 alb는 퍼블릭 서브넷 어딘가에 있어야함. 외부와 내부를 이어주는 다리역할을 해야하기때문에 public에 위치하게 설정.
    aws_subnet.test-pub_2a.id,
    aws_subnet.test-pub_2c.id
  ]

  tags = {
    Name = "test-alb"

 태그값은 test-alb로 지정.

  }

  lifecycle { create_before_destroy = true }

→ 코드 의미는 내가 이것을 지우고 만들려고 할때, 지워지기 전에 먼저 만들어야한다고 정해줌.

즉 디스토리하기 전에 먼저 만들으라는 라이프사이클을 만들어줌. 
}

lifecycle

lifecycle meta-argument 는 resource 의 create, update, destroy 에 관여하여 해당 동작의 수행을 우리가 원하는 방식으로 변경할때 사용하는 argument 이다.
lifecycle 내에서 사용할 수 있는 argument 에는 총 3가지가 있다.

create_before_destroy

Terraform 에서는 특정 resource 에 대해 update 를 해야하나 제약사항에 의해 update 가 불가능한 경우,

만들어진 resource 를 삭제하고 update 된 resource 를 새로 만드는 것이 기본 동작이다.
create_before_destroy argument 는 bool 값을 가지며 true 로 설정하면 이런 경우 먼저 update 된 resource 를 생성하고 기존의 resource 를 삭제하는 방식으로 동작하도록 할 수 있다.
단 이 동작을 수행하고자 하는 resource 의 type 에 따라 unique constraint 등 다른 제약들이 있어 불가능한 경우가 있으니, 사용전 확인해보고 사용을 하는걸 추천한다.

prevent_destroy

Terraform 을 사용하여 생성된 resource 들 중 destroy 가 되는걸 방지하고 할때 사용하는 argument 이다.
prevent_destroy 는 bool 값을 가지며 true 로 설정하면 resource 가 destroy 되려고 할때 error 를 던진다. (terraform destroy 시에도 적용이 된다.)

ignore_changes

Terraform 을 사용하여 infrastructure 구축 시 terraform 은 실제 적용되어 있는 resource 들의 값과 code 로 작성되어 적용하고자 하는 값들을 비교하여 해당 resource 의 create, update, destroy 를 결정한다.
만약 특정 resource 가 terraform 으로도 관리되고, console 이나 다른 곳에서도 함께 관리를 하고 있다고 생각해보자.(물론 이렇게 관리되는건 추천하지 않는다. Terraform 을 사용한다면 Terraform 을 통해서만 관리하는게 가장 좋은 방법이다.)
누군가가 console 을 통해 resource 의 어떤 값을 바꿧다면 terraform 수행시에 terraform 은 해당 값이 변경된 것을 확인하고 code 에 있는 값으로 다시 원복 시키려 할 것이다.
이런 불상사를 방지하기 위해 사용되는 argument 가 ignore_changes 이다. (물론 다른 여러 이유로도 사용이 필요한 경우가 있을 것이다.)
ignore_changes 는 list 값을 가지며 list 에 적은 arguments 를 terraform 이 비교하는 대상에서 제외시켜 update 를 하지 않는다.
비교 대상에서 제외하고자 하는 값을 list 안에 넣어주면 되고, 혹시 모든 arguments 를 비교대상에서 제외하고자 한다면 example4 의 예처럼 list 대신 all 값을 선언해주면 된다

resource "aws_instance" "alb_vm_01" {
  ami                    = "ami-035da6a0773842f64"
  instance_type          = "t2.micro"
  subnet_id              = aws_subnet.test-pub_2a.id
  vpc_security_group_ids = [aws_security_group.test_web_sg_alb.id]

 alb가 이용했던 보안그룹을 같이 사용하는 명령어. 

  key_name  = "test-key"
  user_data = <<-EOF
              #! /bin/bash
              yum install -y httpd
              systemctl enable --now httpd
              echo "Hello, Terraform01" > /var/www/html/index.html
              EOF

  tags = {
    Name = "ALB01"
  }
}

resource "aws_instance" "alb_vm_02" {
  ami                    = "ami-035da6a0773842f64"
  instance_type          = "t2.micro"
  subnet_id              = aws_subnet.test-pub_2c.id
  vpc_security_group_ids = [aws_security_group.test_web_sg_alb.id]
  key_name  = "test-key"
  user_data = <<-EOF
              #! /bin/bash
              yum install -y httpd
              systemctl enable --now httpd
              echo "Hello, Terraform02" > /var/www/html/index.html
              EOF

  tags = {
    Name = "ALB02"
  }
}

resource "aws_lb_target_group" "tg" {
  name        = "TargetGroup"
  port        = 80
  target_type = "instance"

 아이피로 들어가는게 아니라 인스턴스로 들어갈 것임. 
  protocol    = "HTTP"
  vpc_id      = aws_vpc.test_vpc.id

 alb를 설치하는 과정에서 vpc를 잘 생성해주기.

  health_check {
    path                = "/"
    protocol            = "HTTP"
    matcher             = "200"
    interval            = 15

 15초 간격으로 
    timeout             = 3
    healthy_threshold   = 2

 두번 이상 나오면 다시 정상
    unhealthy_threshold = 2
  }
}
resource "aws_alb_target_group_attachment" "tgattachment01" {
  target_group_arn = aws_lb_target_group.tg.arn
  target_id        = aws_instance.alb_vm_01.id
  port             = 80
}

 alb_vm_01의 아이디를 가져오기


resource "aws_alb_target_group_attachment" "tgattachment02" {
  target_group_arn = aws_lb_target_group.tg.arn
  target_id        = aws_instance.alb_vm_02.id
  port             = 80
}

resource "aws_lb_listener" "front_end" {

 타겟그룹 안에다가 리스너를 넣어주기
  load_balancer_arn = aws_lb.frontend.arn
  port              = "80"
  protocol          = "HTTP"

  default_action {
    type             = "forward"
    target_group_arn = aws_lb_target_group.tg.arn

 정의된 타겟그룹을 넣어주기 / 로드벨런서랑 타겟그룹은 arn으로 매칭시켜준다.

  }
}
output "lb_dns_name" {
  description = "The DNS name of the load balancer."
  value       = aws_lb.frontend.dns_name
}

 

왜 cloudformation 이랑 테라폼이랑 ec2만들때 도쿄로 만드는 과정이 테라폼이 더 쉬운지

 


# terraform init
# terraform validate (구성만 참조하고 원격 상태, 공급자 API 등과 같은 원격 서비스에 액세스하지 않고 디렉터리의 구성 파일을 유효성 검사합니다.)

 구성파일에 논리적인 문제가 없는지 있는지 유효성 검사를 함. 버전 관리등 configuration 이 유효하다는 등의 검사를 해줌. 

# terraform plan

 apply에도 plan기능이 있기 때문에 필수가 아님.
# terraform apply -auto-approve
# terraform output lb_dns_name


# terraform destroy -auto-approve

 

굳이 내가 management 콘솔에 들어가지 않아도 terrafom 에서 깃허브에서 저장해둔 코드들을 쉽게 가져다가 사용. 

 

 

The lifecycle Meta-Argument - Configuration Language | Terraform | HashiCorp Developer

The meta-arguments in a lifecycle block allow you to customize resource behavior.

developer.hashicorp.com

 

 


 

오토스케일링 그룹 만들기 

더보기

오토스케일링 그룹 만들기


---------------
--- ec2 asg ---
---------------

# mkdir ec2-asg && cd $_
# vi variables.tf
variable "instance_security_group_name" {
  description = "The name of the security group for the EC2 Instances"
  type        = string
  default     = "terraform-example-instance"
}

variable "http_port" {
  description = "The port the server will use for HTTP requests"
  type        = number
  default     = 80
}

variable "ssh_port" {
  description = "The port the server will use for SSH requests"
  type        = number
  default     = 22
}

variable "alb_name" {
  description = "The name of the ALB"
  type        = string
  default     = "terraform-asg-example"
}

variable "alb_security_group_name" {
  description = "The name of the security group for the ALB"
  type        = string
  default     = "terraform-example-alb"
}

# vi main.tf
provider "aws" {
  region = "ap-northeast-2"
}

### test-vpc ###

resource "aws_vpc" "test_vpc" {
  cidr_block  = "192.168.0.0/16"
  enable_dns_hostnames = true
  enable_dns_support = true
  instance_tenancy = "default"

  tags = {
    Name = "test-vpc"
  }
}

data "aws_availability_zones" "available" {
  state = "available"
}

resource "aws_subnet" "test-pub_2a" {
  vpc_id = aws_vpc.test_vpc.id
  cidr_block = "192.168.0.0/20"
  map_public_ip_on_launch = true
  availability_zone = data.aws_availability_zones.available.names[0]
  tags = {
    Name = "test-pub-2a"
  }
}

resource "aws_subnet" "test-pub_2b" {
  vpc_id = aws_vpc.test_vpc.id
  cidr_block = "192.168.16.0/20"
  map_public_ip_on_launch = true
  availability_zone = data.aws_availability_zones.available.names[1]
  tags = {
    Name = "test-pub-2b"
  }
}

resource "aws_subnet" "test-pub_2c" {
  vpc_id = aws_vpc.test_vpc.id
  cidr_block = "192.168.32.0/20"
  map_public_ip_on_launch = true
  availability_zone = data.aws_availability_zones.available.names[2]
  tags = {
    Name = "test-pub-2c"
  }
}

resource "aws_subnet" "test-pub_2d" {
  vpc_id = aws_vpc.test_vpc.id
  cidr_block = "192.168.48.0/20"
  map_public_ip_on_launch = true
  availability_zone = data.aws_availability_zones.available.names[3]
  tags = {
    Name = "test-pub-2d"
  }
}

resource "aws_internet_gateway" "test_igw" {
  vpc_id = aws_vpc.test_vpc.id
  tags = {
    Name = "test-igw"
  }
}

resource "aws_route_table" "test_pub_rtb" {
  vpc_id = aws_vpc.test_vpc.id

  route {
    cidr_block = "0.0.0.0/0"
    gateway_id = aws_internet_gateway.test_igw.id
  }
  tags = {
    Name = "test-pub-rtb"
  }
}

resource "aws_route_table_association" "test-pub_2a_association" {
  subnet_id = aws_subnet.test-pub_2a.id
  route_table_id = aws_route_table.test_pub_rtb.id
}

resource "aws_route_table_association" "test-pub_2b_association" {
  subnet_id = aws_subnet.test-pub_2b.id
  route_table_id = aws_route_table.test_pub_rtb.id
}

resource "aws_route_table_association" "test-pub_2c_association" {
  subnet_id = aws_subnet.test-pub_2c.id
  route_table_id = aws_route_table.test_pub_rtb.id
}

resource "aws_route_table_association" "test-pub_2d_association" {
  subnet_id = aws_subnet.test-pub_2d.id
  route_table_id = aws_route_table.test_pub_rtb.id
}

### asg ###

resource "aws_security_group" "instance" {
  name   = var.instance_security_group_name
  vpc_id = aws_vpc.test_vpc.id

  ingress {
    from_port   = var.http_port
    to_port     = var.http_port
    protocol    = "tcp"
    cidr_blocks = ["0.0.0.0/0"]
  }
  ingress {
    from_port   = 22
    to_port     = 22
    protocol    = "tcp"
    cidr_blocks = ["0.0.0.0/0"]
  }
  ingress {
    from_port   = -1
    to_port     = -1
    protocol    = "icmp"
    cidr_blocks = ["0.0.0.0/0"]
  }
  egress {
    from_port   = 0
    to_port     = 0
    protocol    = "-1"
    cidr_blocks = ["0.0.0.0/0"]
  }
}

resource "aws_launch_configuration" "example" {
  image_id        = "ami-035da6a0773842f64"
  instance_type   = "t2.micro"
  security_groups = [aws_security_group.instance.id]
  key_name        = "test-key"
  user_data       = file("user-data.sh")

  # Required when using a launch configuration with an auto scaling group.
  lifecycle {
    create_before_destroy = true
  }
}

resource "aws_autoscaling_group" "example" {
  launch_configuration = aws_launch_configuration.example.name
  vpc_zone_identifier  = [
    aws_subnet.test-pub_2a.id,
    aws_subnet.test-pub_2c.id
  ]

  target_group_arns = [aws_lb_target_group.asg.arn]
  health_check_type = "ELB"

  min_size         = 2
  desired_capacity = 2
  max_size         = 4

  tag {
    key                 = "Name"
    value               = "terraform-asg-example"
    propagate_at_launch = true
  }
}

resource "aws_lb" "example" {

  name               = var.alb_name

  load_balancer_type = "application"
  subnets            = [
    aws_subnet.test-pub_2a.id,
    aws_subnet.test-pub_2b.id,
    aws_subnet.test-pub_2c.id,
    aws_subnet.test-pub_2d.id
  ]
  security_groups    = [aws_security_group.alb.id]
}

resource "aws_lb_listener" "http" {
  load_balancer_arn = aws_lb.example.arn
  port              = var.http_port
  protocol          = "HTTP"

  default_action {
    type             = "forward"
    target_group_arn = aws_lb_target_group.asg.arn
  }
}

resource "aws_lb_target_group" "asg" {

  name = var.alb_name

  port     = var.http_port
  protocol = "HTTP"
  vpc_id   = aws_vpc.test_vpc.id

  health_check {
    path                = "/"
    protocol            = "HTTP"
    matcher             = "200"
    interval            = 15
    timeout             = 3
    healthy_threshold   = 2
    unhealthy_threshold = 2
  }
}

resource "aws_security_group" "alb" {
  vpc_id = aws_vpc.test_vpc.id
  name   = var.alb_security_group_name

  # Allow inbound HTTP requests
  ingress {
    from_port   = var.http_port
    to_port     = var.http_port
    protocol    = "tcp"
    cidr_blocks = ["0.0.0.0/0"]
  }

  # Allow all outbound requests
  egress {
    from_port   = 0
    to_port     = 0
    protocol    = "-1"
    cidr_blocks = ["0.0.0.0/0"]
  }
}
resource "aws_autoscaling_policy" "scale_in" {
  name                   = "ScaleInPolicy"
  autoscaling_group_name = aws_autoscaling_group.example.name
  adjustment_type        = "ChangeInCapacity"
  scaling_adjustment     = -1
  cooldown               = 300
}

resource "aws_cloudwatch_metric_alarm" "scale_in" {
  alarm_description   = "Monitors CPU utilization for Terramino ASG"
  alarm_actions       = [aws_autoscaling_policy.scale_in.arn]
  alarm_name          = "ScaleInAlarm"
  comparison_operator = "LessThanOrEqualToThreshold"
  namespace           = "AWS/EC2"
  metric_name         = "CPUUtilization"
  threshold           = "30"
  evaluation_periods  = "1"
  period              = "300"
  statistic           = "Average"

  dimensions = {
    AutoScalingGroupName = aws_autoscaling_group.example.name
  }
}
resource "aws_autoscaling_policy" "scale_out" {
  name                   = "ScaleOutPolicy"
  autoscaling_group_name = aws_autoscaling_group.example.name
  adjustment_type        = "ChangeInCapacity"
  scaling_adjustment     = 1
  cooldown               = 300
}

resource "aws_cloudwatch_metric_alarm" "scale_out" {
  alarm_description   = "Monitors CPU utilization for Terramino ASG"
  alarm_actions       = [aws_autoscaling_policy.scale_out.arn]
  alarm_name          = "ScaleOutAlarm"
  comparison_operator = "GreaterThanOrEqualToThreshold"
  namespace           = "AWS/EC2"
  metric_name         = "CPUUtilization"
  threshold           = "70"
  evaluation_periods  = "1"
  period              = "300"
  statistic           = "Average"

  dimensions = {
    AutoScalingGroupName = aws_autoscaling_group.example.name
  }
}

# vi outputs.tf
output "alb_dns_name" {
  value       = aws_lb.example.dns_name
  description = "The domain name of the load balancer"
}

# terraform init
# terraform validate
# terraform plan
# terraform apply -auto-approve
# terraform output alb_dns_name
# terraform destroy -auto-approve

 

 

 

 

 

---------------
--- ec2 asg ---
---------------

테라폼으로 먼저 vpc를 꾸미고 rds꾸밀 것. 


# mkdir ec2-asg && cd $_
# vi variables.tf


variable "instance_security_group_name" {

→ 변수의 값을 저장해둠. 
  description = "The name of the security group for the EC2 Instances"
  type        = string
  default     = "terraform-example-instance"
}

variable "http_port" {
  description = "The port the server will use for HTTP requests"
  type        = number
  default     = 80

 타입의 값을 어떻게 표현할 것이냐.  
}
정확히 variable의 뜻이 뭐지?


variable "ssh_port" {
  description = "The port the server will use for SSH requests"
  type        = number
  default     = 22
}

variable "alb_name" {
  description = "The name of the ALB"
  type        = string
  default     = "terraform-asg-example"
}

variable "alb_security_group_name" {
  description = "The name of the security group for the ALB"
  type        = string
  default     = "terraform-example-alb"
}

# vi main.tf


provider "aws" {
  region = "ap-northeast-2"
}

### test-vpc ###

### vpc start ###

resource "aws_vpc" "test_vpc" {
  cidr_block  = "192.168.0.0/16"
  enable_dns_hostnames = true
  enable_dns_support = true
  instance_tenancy = "default"

  tags = {
    Name = "test-vpc"
  }
}

data "aws_availability_zones" "available" {
  state = "available"
}

resource "aws_subnet" "test-pub_2a" {
  vpc_id = aws_vpc.test_vpc.id
  cidr_block = "192.168.0.0/20"
  map_public_ip_on_launch = true
  availability_zone = data.aws_availability_zones.available.names[0]
  tags = {
    Name = "test-pub-2a"
  }
}

resource "aws_subnet" "test-pub_2b" {
  vpc_id = aws_vpc.test_vpc.id
  cidr_block = "192.168.16.0/20"
  map_public_ip_on_launch = true
  availability_zone = data.aws_availability_zones.available.names[1]
  tags = {
    Name = "test-pub-2b"
  }
}

resource "aws_subnet" "test-pub_2c" {
  vpc_id = aws_vpc.test_vpc.id
  cidr_block = "192.168.32.0/20"
  map_public_ip_on_launch = true
  availability_zone = data.aws_availability_zones.available.names[2]
  tags = {
    Name = "test-pub-2c"
  }
}

resource "aws_subnet" "test-pub_2d" {
  vpc_id = aws_vpc.test_vpc.id
  cidr_block = "192.168.48.0/20"
  map_public_ip_on_launch = true
  availability_zone = data.aws_availability_zones.available.names[3]
  tags = {
    Name = "test-pub-2d"
  }
}

resource "aws_subnet" "test-pvt_2a" {
  vpc_id = aws_vpc.test_vpc.id
  cidr_block = "192.168.64.0/20"
  map_public_ip_on_launch = false
  availability_zone = data.aws_availability_zones.available.names[0]
  tags = {
    Name = "test-pvt_2a"
  }
}



resource "aws_subnet" "test-pvt_2b" {
  vpc_id = aws_vpc.test_vpc.id
  cidr_block = "192.168.80.0/20"
  map_public_ip_on_launch = false
  availability_zone = data.aws_availability_zones.available.names[1]
  tags = {
    Name = "test-pvt_2b"
  }
}



resource "aws_subnet" "test-pvt_2c" {
  vpc_id = aws_vpc.test_vpc.id
  cidr_block = "192.168.96.0/20"
  map_public_ip_on_launch = false
  availability_zone = data.aws_availability_zones.available.names[2]
  tags = {
    Name = "test-pvt_2c"
  }
}



resource "aws_subnet" "test-pvt_2d" {
  vpc_id = aws_vpc.test_vpc.id
  cidr_block = "192.168.112.0/20"
  map_public_ip_on_launch = false
  availability_zone = data.aws_availability_zones.available.names[3]
  tags = {
    Name = "test-pvt_2d"
  }
}


인터넷 게이트웨이 


resource "aws_internet_gateway" "test_igw" {
  vpc_id = aws_vpc.test_vpc.id
  tags = {
    Name = "test-igw"
  }
}


 

라우팅 테이블 퍼블릭 rtb만들기

resource "aws_route_table" "test_pub_rtb" {
  vpc_id = aws_vpc.test_vpc.id

  route {
    cidr_block = "0.0.0.0/0"
    gateway_id = aws_internet_gateway.test_igw.id

→ gateway = next hop
  }
  tags = {
    Name = "test-pub-rtb"
  }
}



resource "aws_route_table_association" "test-pub_2a_association" {
  subnet_id = aws_subnet.test-pub_2a.id
  route_table_id = aws_route_table.test_pub_rtb.id
}

resource "aws_route_table_association" "test-pub_2b_association" {
  subnet_id = aws_subnet.test-pub_2b.id
  route_table_id = aws_route_table.test_pub_rtb.id
}

resource "aws_route_table_association" "test-pub_2c_association" {
  subnet_id = aws_subnet.test-pub_2c.id
  route_table_id = aws_route_table.test_pub_rtb.id
}

resource "aws_route_table_association" "test-pub_2d_association" {
  subnet_id = aws_subnet.test-pub_2d.id
  route_table_id = aws_route_table.test_pub_rtb.id
}

pvt는 안해줘도 됨?


### vpc end ###



### asg ###

resource "aws_security_group" "instance" {
  name   = var.instance_security_group_name
  vpc_id = aws_vpc.test_vpc.id

  ingress {
    from_port   = var.http_port
    to_port     = var.http_port

 숫자가 들어갈 자리에다가 variable을 이용해서 사용할 수 있따. 


    protocol    = "tcp"
    cidr_blocks = ["0.0.0.0/0"]
  }
  ingress {
    from_port   = 22
    to_port     = 22
    protocol    = "tcp"
    cidr_blocks = ["0.0.0.0/0"]
  }
  ingress {
    from_port   = -1
    to_port     = -1
    protocol    = "icmp"
    cidr_blocks = ["0.0.0.0/0"]
  }
  egress {
    from_port   = 0
    to_port     = 0
    protocol    = "-1"
    cidr_blocks = ["0.0.0.0/0"]
  }
}


교수님은 시작 템플릿이 아니라, 시작 구성으로 준비하셨음. 

시작 구성은 버전관리가 안됨...목적은 오토스케일링 그룹으로 빠르게 생성하기 위함임. 


resource "aws_launch_configuration" "example" {
  image_id        = "ami-035da6a0773842f64"
  instance_type   = "t2.micro"
  security_groups = [aws_security_group.instance.id]
  key_name        = "test-key"
  user_data       = file("user-data.sh") 

→내가 이미지를 만들면 유저데이터가 필요가 없어짐...!  주석처리 했다가 그냥 사용.

aws-set 폴터에 만들어둔 user-data를 가져왔음.

cp ../aws-set/user-data.sh ./

cp ../aws-set/user-data.sh ./


  # Required when using a launch configuration with an auto scaling group.
  lifecycle {
    create_before_destroy = true

 뭔가 만들어지면 수정이 불가능한 것들이 많음. 그중에서 시작템플릿이나 alb들은 지우고 다시 만들어야함. 기존 것을 남겨두고 만들 것임. 그래서 create_before_destroy 를 true라고함 (지우기 전에 새롭게 만들고 지우자는 뜻)
  }
}

resource "aws_autoscaling_group" "example" {
  launch_configuration = aws_launch_configuration.example.name

→시작구성에는 참고를 통해 이름을 가져오도록 시킴.
  vpc_zone_identifier  = [
    aws_subnet.test-pub_2a.id,
    aws_subnet.test-pub_2c.id

→ 어느 영역에다가 만들 것이냐를 정의. 

  ]

  target_group_arns = [aws_lb_target_group.asg.arn]
  health_check_type = "ELB"
→ 타겟그룹에 있는 대상으로 서비스를 하게됨. ec2가 죽으면 scale out 을 하든지 함. 이 부분은 내결함성을 위해 새로운 ec2르만들어냄. 그걸 ELB차원에서 healthcheck하면 ec2는 살아있는데 어플이 죽었거나 내용물에 문제가 생긴 것을 확인하려면 ELB 차원에서 추가로 서버에 전달해야함. 


  min_size         = 2

→ 최소 
  desired_capacity = 2

→ 평소 사이즈
  max_size         = 4

→ 최대 

  tag {
    key                 = "Name"
    value               = "terraform-asg-example"
    propagate_at_launch = true

→ 인스턴스가 만들어질 때 정보를 전파(propagate) , 넣어주겠다.

→ 단 매번 같은 이름을 넣게 됨.
  }
}

resource "aws_lb" "example" {

  name               = var.alb_name

→var.alb_name을 뒤져서 이름을 넣어줌.

→자원들을 만들어서 연동할 것임.

→시작구성  > 오토스케일링 세팅 > 로드벨런스 만들기

  load_balancer_type = "application"
  subnets            = [
    aws_subnet.test-pub_2a.id,
    aws_subnet.test-pub_2b.id,
    aws_subnet.test-pub_2c.id,
    aws_subnet.test-pub_2d.id

→서브넷은 네개를 다 써주기 (기존에는 보통 2a,2c를 이용했지만 실무와 비슷하게하려고 네개를 다 넣어주기.

→alb가 외부의 사용자로부터 요청사항을 다 잡아서 트래픽을 전달하는데, 받아들이는 쪽이 네개의 서브넷에서 랜덤하게 받아서 넘기는 것임. 만약에 2a에서 신호를 받다가 2a에 문제가 생긴다면? 2a 영역만 사용했으면 문제가 없고, 네개를 사용했다면 다른 하나를 선택해주면됨. 가용성이 좋다고 할 수 있음. 

→ 접속자가 외부가 아닌 내부일경우에는 public대신 private을 선택해주기.

→ 접속 포인트가 내부가 아닌 외부!

→디비 서버를 복제해서 가용성을 높이는 작업을 할때, ( ex 갈레라 클러스터 ) 그들간에 서로 복제를 해두고 internal로 alb꾸며놓고 내부적으로 붙어야 할 것들은 웹서버임. 

→인터넷 페이싱이 디폴트값이라 인터넷 경계라는 세팅이 안됨. 
  ]
  security_groups    = [aws_security_group.alb.id]

→ alb의 보안그룹의 아이디를 넣어주면 됨. 

}

resource "aws_lb_listener" "http" {

→ port번호는 환경변수에서 80포트를 가져올 것인데 var.http_port라는 표현으로 가져올 것.

  load_balancer_arn = aws_lb.example.arn
  port              = var.http_port
  protocol          = "HTTP"

  default_action {
    type             = "forward"
    target_group_arn = aws_lb_target_group.asg.arn
  }
}

resource "aws_lb_target_group" "asg" {



  name = var.alb_name

  port     = var.http_port
  protocol = "HTTP"
  vpc_id   = aws_vpc.test_vpc.id

  health_check {
    path                = "/"
    protocol            = "HTTP"
    matcher             = "200"
    interval            = 15

→15초 인터벌 3번 타임아웃 
    timeout             = 3
    healthy_threshold   = 2
    unhealthy_threshold = 2

→ 헬스체크 조건 
  }
}

resource "aws_security_group" "alb" {
  vpc_id = aws_vpc.test_vpc.id
  name   = var.alb_security_group_name
→ alb를 위한 보안그룹이 정의됨.


  # Allow inbound HTTP requests
  ingress {
    from_port   = var.http_port
    to_port     = var.http_port

→80포트만 열려고 함. 
    protocol    = "tcp"
    cidr_blocks = ["0.0.0.0/0"]
  }

  # Allow all outbound requests

→나가는 트래픽을 왜 계속 만들지?

web UI에서는 디폴트이지만, 안쓰면 egress에 대한 규칙이 없는 상태로 모두 만들어짐.
  egress {
    from_port   = 0
    to_port     = 0
    protocol    = "-1"
    cidr_blocks = ["0.0.0.0/0"]
  }
}



resource "aws_autoscaling_policy" "scale_in" {
  name                   = "ScaleInPolicy"
  autoscaling_group_name = aws_autoscaling_group.example.name
  adjustment_type        = "ChangeInCapacity"

→ 용량을 변하게 만들기
  scaling_adjustment     = -1

→ 조절 타입은 하나가 주는 것으로 
  cooldown               = 300

  유예시간은 300초로 설정
}

 


resource "aws_cloudwatch_metric_alarm" "scale_in" {

→  클라우드 워치에서 주시하고 있다가 메트릭 값을 cpu값으로 정하고 알람을 울리게 하려는 설정.

  클라우드 와치 메트릭 알람을 주기.

  cpu는 메트릭 중에서 가장 빠르게 확인 할 수 있는 것임.
  alarm_description   = "Monitors CPU utilization for Terramino ASG"
  alarm_actions       = [aws_autoscaling_policy.scale_in.arn]
  alarm_name          = "ScaleInAlarm"
  comparison_operator = "LessThanOrEqualToThreshold"

  연산자. 보다 작거나 같음을 의미. (=이하)
  namespace           = "AWS/EC2"

  metric_name         = "CPUUtilization"

 EC2안에 CPUUtiliztion

  threshold           = "30"

 이것 보다 이해가 되면 알람을 울림.
  evaluation_periods  = "1"
  period              = "300"

 300초 동안 딱 한번 지속된다.
  statistic           = "Average"

 평균 300초 동안 1번 지속되어야함. 

  dimensions = {
    AutoScalingGroupName = aws_autoscaling_group.example.name
  }
}
resource "aws_autoscaling_policy" "scale_out" {
  name                   = "ScaleOutPolicy"
  autoscaling_group_name = aws_autoscaling_group.example.name
  adjustment_type        = "ChangeInCapacity"
  scaling_adjustment     = 1
  cooldown               = 300

 300초 이후에 또하나를 추가하겠다는 뜻.
}

resource "aws_cloudwatch_metric_alarm" "scale_out" {

 scale-out이라는 cloud watch 메트릭 정하기

  alarm_description   = "Monitors CPU utilization for Terramino ASG"
  alarm_actions       = [aws_autoscaling_policy.scale_out.arn]
  alarm_name          = "ScaleOutAlarm"

  지금 만드는 알람의 이름은 ScaleOutAlarm 
  comparison_operator = "GreaterThanOrEqualToThreshold"
  namespace           = "AWS/EC2"

  metric_name         = "CPUUtilization"

  threshold           = "70"

 EC2의 CPU사용률을 평균 70% 이상의 CPU 사용량으로 세팅

  evaluation_periods  = "1"
  period              = "300"
  statistic           = "Average"

  dimensions = {
    AutoScalingGroupName = aws_autoscaling_group.example.name
  }
}

# vi outputs.tf
output "alb_dns_name" {
  value       = aws_lb.example.dns_name
  description = "The domain name of the load balancer"
→ 오토스케일링의 엔드포인트 주소 가져다가 보여달라는 의미
}



# terraform init


# terraform validate



# terraform plan


# terraform apply -auto-approve
# terraform output alb_dns_name


# terraform destroy -auto-approve

 

 


 

--- Azure CLI
# mkdir azure_cli && cd $_


# yum install -y https://packages.microsoft.com/config/rhel/7/packages-microsoft-prod.rpm


# echo -e "[azure-cli]
name=Azure CLI
baseurl=https://packages.microsoft.com/yumrepos/azure-cli
enabled=1
gpgcheck=1
gpgkey=https://packages.microsoft.com/keys/microsoft.asc" | sudo tee /etc/yum.repos.d/azure-cli.repo

 

 echo -e 를 해주면 큰 따옴표에 있는 명령들이 | 뒤에 있는 위치로 들어감. [ ] 설치하려는 패키지의 파일 이름.

앞서 정의된repository에 가서 [ ]안에 있는 이름을 뒤져서 설치를 해줌. 

→ 애저 cli 는 그냥 yum install로 설치가 되는 것이 아니기 때문에 지정먼저 해주고 그곳에 있는  [azure-cli]를 설치해 주는 과정으로 설치를 해주어야 함. 

 

 

# yum install -y azure-cli

 

 

 

최종 프로젝트 할 때, 테라폼 쿠버네티스 가장 중요함. (우리가 수업에 했던 기본적인 내용은 다 들어가야함.)

 


테라폼에서 NAT / RDS 만들기

 

 

 

#provider.tf

provider "aws" {
  region = "ap-northeast-2"
}

 

 

인터넷 게이트웨이가 아니라 나트게이트웨이를 만들 것 같으면

natgateway는 external과 internal로 나눠야 되는데 external은 반드시 공인 아이피가 있어야 함. 

탄력적 아이피를 만들어야함. 

resource "aws_eip" "lb" {
  instance = aws_instance.web.id
  vpc      = true
}

code 1 - eip를 만들겠다.

resource "aws_eip" "ngw" {

}

이제 가져와서 nat gateway와 연결. 

 

resource "aws_nat_gateway" "test_ngw" {

allocation_id = aws_eip.ngw.id

→나트게이트 웨이나 나트 인스턴스는 반드시 퍼블릭이어야 함.

route {
    cidr_block = "0.0.0.0/0"
    gateway_id = aws_internet_gateway.test_igw.id
  }

subnet_id = aws_subnet.test-pub_2a.id

tags = {

   Name = "test-ngw"

 }

}

 

nat gateway를 송신만 되는 게이트 웨이라는 라우트 테이블을 넣어주기

 

egress {
    from_port   = 0
    to_port     = 0
    protocol    = "-1"
    cidr_blocks = ["0.0.0.0/0"]
  }

Out Bound 빼먹으면 안됨.

 

 

유저데이터. 워드프레스를 설치할 수 있는 최신 방법을 설치해주기

 

 

 

추가한 부분 nat 부분

이대로만 가면 default 서브넷, default vpc에 만들어지게 됨. 이걸 내가 만든 test vpc에 만들어야함...

그래서 

vpc_security_group_ids

amazon resource number

 

 


--------------------
--- ec2 asg ---
---------------------

여기에 NAT와 RDS를 곁들인...

# mkdir ec2-asg && cd $_

 


variables.tf


# vi variables.tf
variable "instance_security_group_name" {
  description = "The name of the security group for the EC2 Instances"
  type        = string
  default     = "terraform-example-instance"
}

 

variable "alb_security_group_name" {
  description = "The name of the security group for the ALB"
  type        = string
  default     = "terraform-example-alb"
}

variable "http_port" {
  description = "The port the server will use for HTTP requests"
  type        = number
  default     = 80
}

variable "ssh_port" {
  description = "The port the server will use for SSH requests"
  type        = number
  default     = 22
}

variable "alb_name" {
  description = "The name of the ALB"
  type        = string
  default     = "terraform-asg-example"
}

 

variable "rds_name" {
  description = "The SG name of the RDS"
  type        = string
  default     = "test-sg-rds"
}

 

main.tf

1) init

2) vpc

3) public_subnet

4) internet gateway
5) route table

6) route table association

7) sercurity group

 



# vi main.tf

1) init
provider "aws" {
  region = "ap-northeast-2"
}

data "aws_availability_zones" "available" {
  state = "available"
}
### test-vpc ###



### vpc start ###
2) vpc
resource "aws_vpc" "test_vpc" {
  cidr_block  = "192.168.0.0/16"
  enable_dns_hostnames = true
  enable_dns_support = true
  instance_tenancy = "default"

  tags = {
    Name = "test-vpc"
  }
}


3) public_subnet
resource "aws_subnet" "test-pub_2a" {
  vpc_id = aws_vpc.test_vpc.id
  cidr_block = "192.168.0.0/20"
  map_public_ip_on_launch = true
  availability_zone = data.aws_availability_zones.available.names[0]
  tags = {
    Name = "test-pub-2a"
  }
}

 

더보기

resource "aws_subnet" "test-pub_2b" {
  vpc_id = aws_vpc.test_vpc.id
  cidr_block = "192.168.16.0/20"
  map_public_ip_on_launch  = true
  availability_zone = data.aws_availability_zones.available.names[1]
  tags = {
    Name = "test-pub-2b"
  }
}

resource "aws_subnet" "test-pub_2c" {
  vpc_id = aws_vpc.test_vpc.id
  cidr_block = "192.168.32.0/20"
  map_public_ip_on_launch = true
  availability_zone = data.aws_availability_zones.available.names[2]
  tags = {
    Name = "test-pub-2c"
  }
}

resource "aws_subnet" "test-pub_2d" {
  vpc_id = aws_vpc.test_vpc.id
  cidr_block = "192.168.48.0/20"
  map_public_ip_on_launch = true
  availability_zone = data.aws_availability_zones.available.names[3]
  tags = {
    Name = "test-pub-2d"
  }
}




resource "aws_subnet" "test-pvt_2a" {
  vpc_id = aws_vpc.test_vpc.id
  cidr_block = "192.168.64.0/20"
  map_public_ip_on_launch = false
  availability_zone = data.aws_availability_zones.available.names[0]
  tags = {
    Name = "test-pvt_2a"
  }
}

더보기

resource "aws_subnet" "test-pvt_2b" {
  vpc_id = aws_vpc.test_vpc.id
  cidr_block = "192.168.80.0/20"
  map_public_ip_on_launch = false
  availability_zone = data.aws_availability_zones.available.names[1]
  tags = {
    Name = "test-pvt_2b"
  }
}



resource "aws_subnet" "test-pvt_2c" {
  vpc_id = aws_vpc.test_vpc.id
  cidr_block = "192.168.96.0/20"
  map_public_ip_on_launch = false
  availability_zone = data.aws_availability_zones.available.names[2]
  tags = {
    Name = "test-pvt_2c"
  }
}



resource "aws_subnet" "test-pvt_2d" {
  vpc_id = aws_vpc.test_vpc.id
  cidr_block = "192.168.112.0/20"
  map_public_ip_on_launch = false
  availability_zone = data.aws_availability_zones.available.names[3]
  tags = {
    Name = "test-pvt_2d"
  }
}

 


4) internet gateway

resource "aws_internet_gateway" "test_igw" {
  vpc_id = aws_vpc.test_vpc.id
  tags = {
    Name = "test-igw"
  }
}

 


5) route table

 

resource "aws_route_table" "test_pub_rtb" {
  vpc_id = aws_vpc.test_vpc.id

  route {
    cidr_block = "0.0.0.0/0"
    gateway_id = aws_internet_gateway.test_igw.id
  }
  tags = {
    Name = "test-pub-rtb"
  }
}

5) route table association


resource "aws_route_table_association" "test-pub_2a_association" {
  subnet_id = aws_subnet.test-pub_2a.id
  route_table_id = aws_route_table.test_pub_rtb.id
}

resource "aws_route_table_association" "test-pub_2b_association" {
  subnet_id = aws_subnet.test-pub_2b.id
  route_table_id = aws_route_table.test_pub_rtb.id
}

resource "aws_route_table_association" "test-pub_2c_association" {
  subnet_id = aws_subnet.test-pub_2c.id
  route_table_id = aws_route_table.test_pub_rtb.id
}

resource "aws_route_table_association" "test-pub_2d_association" {
  subnet_id = aws_subnet.test-pub_2d.id
  route_table_id = aws_route_table.test_pub_rtb.id
}



### vpc end ###

 

7) security group
### auto scaling group ###

resource "aws_security_group" "instance" {
  name   = var.instance_security_group_name
  vpc_id = aws_vpc.test_vpc.id

  ingress {
    from_port   = var.http_port
    to_port     = var.http_port
    protocol    = "tcp"
    cidr_blocks = ["0.0.0.0/0"]
  }
  ingress {
    from_port   = 22
    to_port     = 22
    protocol    = "tcp"
    cidr_blocks = ["0.0.0.0/0"]
  }
  ingress {
    from_port   = -1
    to_port     = -1
    protocol    = "icmp"
    cidr_blocks = ["0.0.0.0/0"]
  }
  egress {
    from_port   = 0
    to_port     = 0
    protocol    = "-1"
    cidr_blocks = ["0.0.0.0/0"]
  }
}

 

 [Auto Scaling

 

Auto Scaling : EC2에서 운용되는 애플리케이션의 부하를 적절하게 처리할 수 있도록 지정한 수로 EC2 인스턴스를 생성, 삭제 하도록 자동으로 구성하는 서비스

 

8번 시작 전에 꼭 기준이 될 Sample EC2가 준비가 되어야함. 준비가 완료된 인스턴스로 AMI를 만들기!

 

8)AMI Imaging을 통한 Auto Scaling용 Template 생성

resource "aws_ami_from_instance" "test-asg-template-ami" {

  name = "AutoScalingIMA"

  source_instance_id = aws_intance.

 

9) launch_configuration  [시작 템플릿 / 시작 구성] 


resource "aws_launch_configuration" "example" {
  image_id        = "ami-035da6a0773842f64"
  instance_type   = "t2.micro"
  security_groups = [aws_security_group.instance.id]
  key_name        = "test-key"
  user_data       = file("user-data.sh")

  # Required when using a launch configuration with an auto scaling group.
  lifecycle {
    create_before_destroy = true
  }
}

더보기

ASG는 시작구성 정보를 참조하여 인스턴스를 생성 하는데, 여기서 한가지 문제가 발생한다.

시작구성 즉 launch configuration은 변경할 수 없으므로 시작 구성 정보를 변경하면 테라폼은 이를 대체하려고 한다. 일반적으로 리소스를 교체할때 테라폼은 이전 리소스를 먼저 삭제 후 대체 리소스를 생성한다. 그러나 ASG에 이전 리소스에 대한 참조정보가 존재하기 때문에 테라폼은 해당 리소스를 삭제할수 없게 된다.

 

이 문제를 해결하기 위해 테라폼은 수명주기(lifecycle)설정을 지원한다. 특히 create_before_destroy는 유용하게 사용할 수 있는 수명주기 설정인데 해당 설정을 true로 하게되면 테라폼은 리소스 교체 순서를 반대로 하여 교체 리소스를 먼저 생성 후 기존 리소스를 삭제 한다. 아래와 같이 launch configuration에 create_before_destroy옵션을 추가해 본다.

ASG 생성 부분 코드 (create_before_destroy옵션 추가)


10) aws_autoscaling_group [오토스케일링 그룹 생성해주기]

- 원본 EC2 AMI Imaging(Template 생성) -> 시작 구성(Launch Configuration) 설정 -> Auto Scaling Group 생성

 


resource "aws_autoscaling_group" "example" {
  launch_configuration = aws_launch_configuration.example.name
  vpc_zone_identifier  = [
    aws_subnet.test-pub_2a.id,
    aws_subnet.test-pub_2c.id
  ]

  target_group_arns = [aws_lb_target_group.asg.arn]
  health_check_type = "ELB"

 

더보기

 health_check_type을 보면 기본은 EC2인데 여기서는 ELB로 설정 하였다.

기본 설정인 EC2는 인스턴스가 완전히 다운되었다고 판단될 경우에만 인스턴스를 비정상 상태라고 간주 하지만, ELB로 설정하면 ASG가 대상그룹의 상태를 확인하고 비정상이라고 판별될 경우 인스턴스를 자동으로 교체하도록 지시 한다.

 

이는 인스턴스가 다운되었거나 메모리 부족 및 중요 프로세스 중단이 경우에도 인스턴스가 교체 되기 때문에 EC2 옵션보다 강력하다고 볼 수 있다.


  min_size         = 2
  desired_capacity = 2
  max_size         = 4

  tag {
    key                 = "Name" 
    value               = "terraform-asg-example"
    propagate_at_launch = true
  }
}

resource "aws_lb" "example" {
→ aws 로드벨런서 설정해주기. 타입은 application타입으로 설정 / 서브넷도 정해주기
  name               = var.alb_name

  load_balancer_type = "application"
  subnets            = [
    aws_subnet.test-pub_2a.id,
    aws_subnet.test-pub_2b.id,
    aws_subnet.test-pub_2c.id,
    aws_subnet.test-pub_2d.id
  ]
  security_groups    = [aws_security_group.alb.id]
}


alb 타겟그룹 생성해주기 


resource "aws_lb_target_group" "asg" {

  name = var.alb_name

  port     = var.http_port

 변수 설정에서 설정해준 http_port를 불러오기
  protocol = "HTTP"
  vpc_id   = aws_vpc.test_vpc.id

  health_check {

 타겟그룹 생성해줄때 health check 설정도 같이 해준다. 
    path                = "/"

 만약 php파일만있는wordpress를 구동하려면, health체크용 폴더 및 파일을 생성해줘야 함. 

그럴때는 /health/ 라고 경로 생성해주면 만들어둔 health 체크용 파일로 알아서 감.

    protocol            = "HTTP"
    matcher             = "200"

→ 200 ok 를 받지 못하면 fail.
    interval            = 15
    timeout             = 3
    healthy_threshold   = 2
    unhealthy_threshold = 2
  }
}

 


로드벨런서 리스너 설정해주기


resource "aws_lb_listener" "http" {

 aws 로드벨런서 리스너 설정해주기. 포트는 http 80포트로 설정해주었음. 

 이때 타겟그룹은 autoscaling group 타겟그룹을 가져오기!
  load_balancer_arn = aws_lb.example.arn
  port              = var.http_port
  protocol          = "HTTP"

  default_action {
    type             = "forward"
    target_group_arn = aws_lb_target_group.asg.arn
  }
}

 


resource "aws_security_group" "alb" {
  vpc_id = aws_vpc.test_vpc.id
  name   = var.alb_security_group_name

  # Allow inbound HTTP requests
  ingress {

 http 80포트만 오픈.
    from_port   = var.http_port
    to_port     = var.http_port
    protocol    = "tcp"
    cidr_blocks = ["0.0.0.0/0"]
  }

  # Allow all outbound requests
  egress {  나가는 건 다 허용~
    from_port   = 0
    to_port     = 0
    protocol    = "-1"
    cidr_blocks = ["0.0.0.0/0"]
  }
}


resource "aws_autoscaling_policy" "scale_in" {
  name                   = "ScaleInPolicy"
  autoscaling_group_name = aws_autoscaling_group.example.name

 아이디가 아닌 이름으로 오토스케일링 그룹을 통보하기.
  adjustment_type        = "ChangeInCapacity"

→조절 타입 설정 
  scaling_adjustment     = -1

 하나씩 없애줌
  cooldown               = 300
}

resource "aws_cloudwatch_metric_alarm" "scale_in" {

 해당 알람에 의해 위의 policy가 활성화.
  alarm_description   = "Monitors CPU utilization for Terramino ASG"
  alarm_actions       = [aws_autoscaling_policy.scale_in.arn]

 알람이 울리면 취할 액션에 대한 정보를 arn으로 정의하기
  alarm_name          = "ScaleInAlarm"
  comparison_operator = "LessThanOrEqualToThreshold"

 연산자는 보다 작거나 같은으로 설정해주기.
  namespace           = "AWS/EC2"
  metric_name         = "CPUUtilization"

 메모리는 CPUUtilization
  threshold           = "30"
  evaluation_periods  = "1"
  period              = "300"
  statistic           = "Average"

  dimensions = {
    AutoScalingGroupName = aws_autoscaling_group.example.name

 클라우드 워치로 이동해보면, 만들어져있음.
  }
}
resource "aws_autoscaling_policy" "scale_out" {
  name                   = "ScaleOutPolicy"
  autoscaling_group_name = aws_autoscaling_group.example.name
  adjustment_type        = "ChangeInCapacity"
  scaling_adjustment     = 1
  cooldown               = 300
}

resource "aws_cloudwatch_metric_alarm" "scale_out" {
  alarm_description   = "Monitors CPU utilization for Terramino ASG"
  alarm_actions       = [aws_autoscaling_policy.scale_out.arn]
  alarm_name          = "ScaleOutAlarm"
  comparison_operator = "GreaterThanOrEqualToThreshold"
  namespace           = "AWS/EC2"
  metric_name         = "CPUUtilization"
  threshold           = "70"
  evaluation_periods  = "1"
  period              = "300"

  statistic           = "Average"

  dimensions = {
    AutoScalingGroupName = aws_autoscaling_group.example.name
  }
}

 

 

 

DB


resource "aws_db_subnet_group" "test_rds_subnet" {
  name       = "main"
  subnet_ids = [aws_subnet.test-pvt_2a.id, aws_subnet.test-pvt_2c.id]
→ rds는 private 서브넷에 넣어주는게 좋음. 

  tags = {
    Name = "test-rds-subnet"
  }
}
 보안그룹이 없기때문에 db서버를 위한 보안그룹을 만들어주기

resource "aws_security_group" "test_sg_rds" {
  name   = var.rds_name
  vpc_id = aws_vpc.test_vpc.id


  ingress {

  MYSQL 3306 포트 열어주기
    from_port   = 3306
    to_port     = 3306
    protocol    = "tcp"
    cidr_blocks = ["0.0.0.0/0"]
  }
 
  egress {
    from_port   = 0
    to_port     = 0
    protocol    = "-1"
    cidr_blocks = ["0.0.0.0/0"]
  }
}

 



resource "aws_db_instance" "test_rds" {
  allocated_storage    = 20
  db_name              = "wordpress"
  engine                 = "mysql"
  engine_version       = "5.7"
  instance_class        = "db.t2.micro"
  username             = "ssoontory"
  password             = "torytory"
  parameter_group_name = "default.mysql5.7"
  skip_final_snapshot  = true
  db_subnet_group_name = aws_db_subnet_group.test_rds_subnet.name
  vpc_security_group_ids= [aws_security_group.test_sg_rds.id]

 rds를 위한 보안그룹 만들기.

 여러개의 아이디가 나올 수 있기 때문에 대괄호로 감싸고, ids라고 해주기.
}

 

# vi outputs.tf
output "alb_dns_name" {
  value       = aws_lb.example.dns_name
  description = "The domain name of the load balancer"
}

 

output "rds_endpoint" {
  value       = aws_lb_instance.test_rds.endpoint
  description = "The endpoint of the rds"
}

위에서 만든 자원에서 endpoint를 추출하기.

 


# terraform init

→ 새로운 플러그인이 생겼는지 확인해주기
# terraform validate
# terraform plan

 apply안에 plan기능도 있어서 그냥 plan 생략해도 됨. 
# terraform apply -auto-approve
# terraform output alb_dns_name
# terraform destroy -auto-approve

 

 

db식별자를 만들고 있음.

그런데 이 작업도 테라폼으로도 만들 수 있음.

 

 

ec2가 두개가 만들어짐. health check 통과하지 못했기 때문임. 

유저데이터에 아래와 같은 내용 추가해주기

 

 

 

상태검사 경로도 바뀐 것을 확인할 수 있음


모바, 연결버튼으로 접속, CloudShell 로 연결하는 방법 이렇게 세가지가 있음. 

 

시드니에서 접속하는 클라우드 쉘로 새로운 인스턴스 접속하기.

키를 먼저 가져오기. 모바에서 test-key.pem 선택하고 다운로드 아이콘 선택.

 

 

데이터베이스 호스트는 RDS 엔드포인트로!!!!!

 

 

 

 

이미지 > 스냅샷 >  ami 아이디 복사

메모장에다가 asg launch configuration image_id 에 넣어주기!

사용자 데이터 주석처리도 해주기!


 

 

이제 nat gateway  활용하기 

주석 제거해주기!

variable에서는 그냥 건들게 없고, main 부분에서 vpc.data, subnet 패스 

aws_eip 주석처리했던 내용들 다 지워주기 

nat 활성화해주기

전 > 후 
전 > 후 (주석삭제)

 

aoutoscaling 그룹 바꾸기 

wordpress를 autoscling을 이용해서 배포

퍼블릭에 배포하는게 아니라 privat에 배포가 되도록 하기.

 

 

 

ELB의  최소 사이즈 , desired_capacity  만들기

샘플 뜨기 위해서 11 로 만들어 둔것임. 

 

 

 

다시 main.tf 수정후 복붙

 

bastion 추가로 생성해주기!!!

 

#!/bin/bash

cd /tmp

curl "https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip" -o "awscliv2.zip"

unzip awscliv2.zip 

./aws/install 

 

 

scp는 ssh와 같아서 scp -i 하고 키를 집어넣어줌. 

 

scp -i test-key.pem test-key.pem ec2-user@전송하려는 아이피

scp -i test-key.pem test-key.pem ec2-user@13.125.96.101:/home/ec2-user

 

 

오토스케일링 ScaleOut 이 잘 되는 것을 볼 수 있음. 

 

sudo pkill -9 yes

pkill 명령으로 부하 낮추고 다시 원래대로 ec2인스턴스가 줄어드는지 확인하기.

 

Scale In 된거 확인하구 destory하기!

IaC에서 꼭 따라붙는 자동화란 이런것! 한번에 지워줌

 


 

여기까지 

더보기


---------------
--- ec2 asg ---
---------------

# mkdir ec2-asg && cd $_
# vi variables.tf
variable "instance_security_group_name" {
  description = "The name of the security group for the EC2 Instances"
  type        = string
  default     = "terraform-example-instance"
}

variable "http_port" {
  description = "The port the server will use for HTTP requests"
  type        = number
  default     = 80
}

variable "ssh_port" {
  description = "The port the server will use for SSH requests"
  type        = number
  default     = 22
}

variable "alb_name" {
  description = "The name of the ALB"
  type        = string
  default     = "terraform-asg-example"
}

variable "rds_name" {
  description = "The SG name of the RDS"
  type        = string
  default     = "test-sg-rds"
}

variable "alb_security_group_name" {
  description = "The name of the security group for the ALB"
  type        = string
  default     = "terraform-example-alb"
}

# vi main.tf
provider "aws" {
  region = "ap-northeast-2"
}

### test-vpc ###

### vpc start ###

resource "aws_vpc" "test_vpc" {
  cidr_block  = "192.168.0.0/16"
  enable_dns_hostnames = true
  enable_dns_support = true
  instance_tenancy = "default"

  tags = {
    Name = "test-vpc"
  }
}

data "aws_availability_zones" "available" {
  state = "available"
}

resource "aws_subnet" "test-pub_2a" {
  vpc_id = aws_vpc.test_vpc.id
  cidr_block = "192.168.0.0/20"
  map_public_ip_on_launch = true
  availability_zone = data.aws_availability_zones.available.names[0]
  tags = {
    Name = "test-pub-2a"
  }
}

resource "aws_subnet" "test-pub_2b" {
  vpc_id = aws_vpc.test_vpc.id
  cidr_block = "192.168.16.0/20"
  map_public_ip_on_launch = true
  availability_zone = data.aws_availability_zones.available.names[1]
  tags = {
    Name = "test-pub-2b"
  }
}

resource "aws_subnet" "test-pub_2c" {
  vpc_id = aws_vpc.test_vpc.id
  cidr_block = "192.168.32.0/20"
  map_public_ip_on_launch = true
  availability_zone = data.aws_availability_zones.available.names[2]
  tags = {
    Name = "test-pub-2c"
  }
}

resource "aws_subnet" "test-pub_2d" {
  vpc_id = aws_vpc.test_vpc.id
  cidr_block = "192.168.48.0/20"
  map_public_ip_on_launch = true
  availability_zone = data.aws_availability_zones.available.names[3]
  tags = {
    Name = "test-pub-2d"
  }
}

resource "aws_subnet" "test-pvt_2a" {
  vpc_id = aws_vpc.test_vpc.id
  cidr_block = "192.168.64.0/20"
  availability_zone = data.aws_availability_zones.available.names[0]
  tags = {
    Name = "test-pvt-2a"
  }
}

resource "aws_subnet" "test-pvt_2b" {
  vpc_id = aws_vpc.test_vpc.id
  cidr_block = "192.168.80.0/20"
  availability_zone = data.aws_availability_zones.available.names[1]
  tags = {
    Name = "test-pvt-2b"
  }
}

resource "aws_subnet" "test-pvt_2c" {
  vpc_id = aws_vpc.test_vpc.id
  cidr_block = "192.168.96.0/20"
  availability_zone = data.aws_availability_zones.available.names[2]
  tags = {
    Name = "test-pvt-2c"
  }
}

resource "aws_subnet" "test-pvt_2d" {
  vpc_id = aws_vpc.test_vpc.id
  cidr_block = "192.168.112.0/20"
  availability_zone = data.aws_availability_zones.available.names[3]
  tags = {
    Name = "test-pvt-2d"
  }
}

resource "aws_internet_gateway" "test_igw" {
  vpc_id = aws_vpc.test_vpc.id
  tags = {
    Name = "test-igw"
  }
}

resource "aws_eip" "ngw" {
}

resource "aws_nat_gateway" "test_ngw" {
  allocation_id = aws_eip.ngw.id
  subnet_id     = aws_subnet.test-pub_2d.id
  tags = {
    Name = "test-ngw"
  }
}  

resource "aws_route_table" "test_pub_rtb" {
  vpc_id = aws_vpc.test_vpc.id

  route {
    cidr_block = "0.0.0.0/0"
    gateway_id = aws_internet_gateway.test_igw.id
  }
  tags = {
    Name = "test-pub-rtb"
  }
}

resource "aws_route_table" "test_pvt_rtb" {
  vpc_id = aws_vpc.test_vpc.id
    route {
    cidr_block = "0.0.0.0/0"
    nat_gateway_id = aws_nat_gateway.test_ngw.id
  }

  tags = {
    Name = "test-pvt-rtb"
  }
}

resource "aws_route_table_association" "test-pub_2a_association" {
  subnet_id = aws_subnet.test-pub_2a.id
  route_table_id = aws_route_table.test_pub_rtb.id
}

resource "aws_route_table_association" "test-pub_2b_association" {
  subnet_id = aws_subnet.test-pub_2b.id
  route_table_id = aws_route_table.test_pub_rtb.id
}

resource "aws_route_table_association" "test-pub_2c_association" {
  subnet_id = aws_subnet.test-pub_2c.id
  route_table_id = aws_route_table.test_pub_rtb.id
}

resource "aws_route_table_association" "test-pub_2d_association" {
  subnet_id = aws_subnet.test-pub_2d.id
  route_table_id = aws_route_table.test_pub_rtb.id
}

resource "aws_route_table_association" "test-pvt_2a_association" {
  subnet_id = aws_subnet.test-pvt_2a.id
  route_table_id = aws_route_table.test_pvt_rtb.id
}

resource "aws_route_table_association" "test-pvt_2b_association" {
  subnet_id = aws_subnet.test-pvt_2b.id
  route_table_id = aws_route_table.test_pvt_rtb.id
}

resource "aws_route_table_association" "test-pvt_2c_association" {
  subnet_id = aws_subnet.test-pvt_2c.id
  route_table_id = aws_route_table.test_pvt_rtb.id
}

resource "aws_route_table_association" "test-pvt_2d_association" {
  subnet_id = aws_subnet.test-pvt_2d.id
  route_table_id = aws_route_table.test_pvt_rtb.id
}

### vpc end ###

## bastion host ##
resource "aws_instance" "test_bastion" {
  ami                    = "ami-035da6a0773842f64"
  instance_type          = "t2.micro"
  subnet_id              = aws_subnet.test-pub_2a.id
  vpc_security_group_ids = [aws_security_group.instance.id]
  key_name               = "test-key"
  user_data              = file("bastion-data.sh")

  tags = {
    Name = "test-bastion"
  }
}

### asg ###

resource "aws_security_group" "instance" {
  name   = var.instance_security_group_name
  vpc_id = aws_vpc.test_vpc.id

  ingress {
    from_port   = var.http_port
    to_port     = var.http_port
    protocol    = "tcp"
    cidr_blocks = ["0.0.0.0/0"]
  }
  ingress {
    from_port   = 22
    to_port     = 22
    protocol    = "tcp"
    cidr_blocks = ["0.0.0.0/0"]
  }
  ingress {
    from_port   = -1
    to_port     = -1
    protocol    = "icmp"
    cidr_blocks = ["0.0.0.0/0"]
  }
  egress {
    from_port   = 0
    to_port     = 0
    protocol    = "-1"
    cidr_blocks = ["0.0.0.0/0"]
  }
}

resource "aws_launch_configuration" "example" {
  image_id        = "ami-0709c369f2c726d0a"
  instance_type   = "t2.micro"
  security_groups = [aws_security_group.instance.id]
  key_name        = "test-key"
#  user_data       = file("user-data.sh")

  # Required when using a launch configuration with an auto scaling group.
  lifecycle {
    create_before_destroy = true
  }
}

resource "aws_autoscaling_group" "example" {
  launch_configuration = aws_launch_configuration.example.name
  vpc_zone_identifier  = [
    aws_subnet.test-pvt_2a.id,
    aws_subnet.test-pvt_2c.id
  ]

  target_group_arns = [aws_lb_target_group.asg.arn]
  health_check_type = "ELB"

  min_size         = 2
  desired_capacity = 2
  max_size         = 4

  tag {
    key                 = "Name"
    value               = "terraform-asg-example"
    propagate_at_launch = true
  }
}

resource "aws_lb" "example" {

  name               = var.alb_name

  load_balancer_type = "application"
  subnets            = [
    aws_subnet.test-pub_2a.id,
    aws_subnet.test-pub_2b.id,
    aws_subnet.test-pub_2c.id,
    aws_subnet.test-pub_2d.id
  ]
  security_groups    = [aws_security_group.alb.id]
}

resource "aws_lb_listener" "http" {
  load_balancer_arn = aws_lb.example.arn
  port              = var.http_port
  protocol          = "HTTP"

  default_action {
    type             = "forward"
    target_group_arn = aws_lb_target_group.asg.arn
  }
}

resource "aws_lb_target_group" "asg" {

  name = var.alb_name

  port     = var.http_port
  protocol = "HTTP"
  vpc_id   = aws_vpc.test_vpc.id

  health_check {
    path                = "/health/"
    protocol            = "HTTP"
    matcher             = "200"
    interval            = 15
    timeout             = 3
    healthy_threshold   = 2
    unhealthy_threshold = 2
  }
}

resource "aws_security_group" "alb" {
  vpc_id = aws_vpc.test_vpc.id
  name   = var.alb_security_group_name

  # Allow inbound HTTP requests
  ingress {
    from_port   = var.http_port
    to_port     = var.http_port
    protocol    = "tcp"
    cidr_blocks = ["0.0.0.0/0"]
  }

  # Allow all outbound requests
  egress {
    from_port   = 0
    to_port     = 0
    protocol    = "-1"
    cidr_blocks = ["0.0.0.0/0"]
  }
}
resource "aws_autoscaling_policy" "scale_in" {
  name                   = "ScaleInPolicy"
  autoscaling_group_name = aws_autoscaling_group.example.name
  adjustment_type        = "ChangeInCapacity"
  scaling_adjustment     = -1
  cooldown               = 300
}

resource "aws_cloudwatch_metric_alarm" "scale_in" {
  alarm_description   = "Monitors CPU utilization for Terramino ASG"
  alarm_actions       = [aws_autoscaling_policy.scale_in.arn]
  alarm_name          = "ScaleInAlarm"
  comparison_operator = "LessThanOrEqualToThreshold"
  namespace           = "AWS/EC2"
  metric_name         = "CPUUtilization"
  threshold           = "30"
  evaluation_periods  = "1"
  period              = "300"
  statistic           = "Average"

  dimensions = {
    AutoScalingGroupName = aws_autoscaling_group.example.name
  }
}
resource "aws_autoscaling_policy" "scale_out" {
  name                   = "ScaleOutPolicy"
  autoscaling_group_name = aws_autoscaling_group.example.name
  adjustment_type        = "ChangeInCapacity"
  scaling_adjustment     = 1
  cooldown               = 300
}

resource "aws_cloudwatch_metric_alarm" "scale_out" {
  alarm_description   = "Monitors CPU utilization for Terramino ASG"
  alarm_actions       = [aws_autoscaling_policy.scale_out.arn]
  alarm_name          = "ScaleOutAlarm"
  comparison_operator = "GreaterThanOrEqualToThreshold"
  namespace           = "AWS/EC2"
  metric_name         = "CPUUtilization"
  threshold           = "70"
  evaluation_periods  = "1"
  period              = "300"
  statistic           = "Average"

  dimensions = {
    AutoScalingGroupName = aws_autoscaling_group.example.name
  }
}

resource "aws_db_subnet_group" "test_rds_subnet" {
  name       = "main"
  subnet_ids = [aws_subnet.test-pvt_2a.id, aws_subnet.test-pvt_2c.id]

  tags = {
    Name = "test-rds-subnet"
  }
}

resource "aws_security_group" "test_sg_rds" {
  name   = var.rds_name
  vpc_id = aws_vpc.test_vpc.id

  ingress {
    from_port   = 3306
    to_port     = 3306
    protocol    = "tcp"
    cidr_blocks = ["0.0.0.0/0"]
  }
  egress {
    from_port   = 0
    to_port     = 0
    protocol    = "-1"
    cidr_blocks = ["0.0.0.0/0"]
  }
}

resource "aws_db_instance" "test_rds" {
  allocated_storage    = 20
  db_name              = "wordpress"
  engine                 = "mysql"
  engine_version       = "5.7"
  instance_class        = "db.t2.micro"
  username             = "ssoontory"
  password             = "torytory"
  parameter_group_name = "default.mysql5.7"
  skip_final_snapshot  = true
  db_subnet_group_name = aws_db_subnet_group.test_rds_subnet.name
  vpc_security_group_ids= [aws_security_group.test_sg_rds.id]
}

# vi outputs.tf
output "alb_dns_name" {
  value       = aws_lb.example.dns_name
  description = "The domain name of the load balancer"
}

output "rds_endpoint" {
  value       = aws_db_instance.test_rds.endpoint
  description = "The endpoint of the rds"
}

# terraform init
# terraform validate
# terraform plan
# terraform apply -auto-approve
# terraform output alb_dns_name
# terraform destroy -auto-approve

 

 

 --- GCP CLI

애저는 패스하고 GCP CLI를 설치하기

자격증명도 해주기!

 

# mkdir gcp_cli && cd $_

 

# tee -a /etc/yum.repos.d/google-cloud-sdk.repo << EOM

→gcp 는 tee라는 명령을 주고 그 밑에다가 여러줄의 파일을 집어넣기 위한 방법을 이렇게 씀. 여러줄을 넣기 위해 <<EOM 명령을 이용해서 사용! EOM 사이의 내용들이 다 들어감. 
[google-cloud-cli]
name=Google Cloud CLI
baseurl=https://packages.cloud.google.com/yum/repos/cloud-sdk-el8-x86_64
enabled=1
gpgcheck=1
repo_gpgcheck=0
gpgkey=https://packages.cloud.google.com/yum/doc/yum-key.gpg
       https://packages.cloud.google.com/yum/doc/rpm-package-key.gpg
EOM

 

위에서 지정한 경로에 cat명령어를 넣어 내용이 잘 들어갔는지 확인해주기.

GCP 들어가서 프로젝트 만들기


# yum install -y google-cloud-cli

→ 
# gcloud --version


# gcloud init --console-only

내가 만든 프로젝트로 넘어가기


asia-northeast3-a
# gcloud compute networks create test-vpc

해당 명령어에서 y를 눌러주는 것이 Compute Engine API 에서 사용 눌러서 활성화 하는 것과 같은 의미를 가진다.

 

전체 vpc를 만들어주었으니까 다음으로는 서브넷 만들어주기

# gcloud compute networks subnets create test-subnet --network=test-vpc --range=192.168.0.0/16 --region=asia-northeast3


# gcloud compute firewall-rules list

내부에서는 모두 통신이 가능하게 되어있고, rdp원격 데스크탑 프로토콜이 이미 열려있고, ssh로 접근할 수 있도록 ssh포트도 열려있음. icmp도 열려있음!
# gcloud compute firewall-rules create test-vpc-allow-ssh --allow=tcp:22 --description="Allow incoming traffic on TCP port 22" --direction=INGRESS --network=test-vpc --source-ranges 0.0.0.0/0

이미 열려있으니까 추가할 필요 없음! 내비두기!!!

위에 있는데 왜했음? -> 잘보면 NETWORK 가 default임. 그래서 우리는 test-vpc 에 firewall 넣어주기 위해 다시 진행해줌.

 


# gcloud compute firewall-rules create test-vpc-allow-http --allow=tcp:80 --description="Allow incoming traffic on TCP port 80" --direction=INGRESS --network=test-vpc --source-ranges 0.0.0.0/0

→ create 뒤에 있는 것은 내 규칙의 이름임 (ex test-vpc-allow-http)

 direction 뭘 허용할거냐. 주인공인 vm을 향해서 들어오는 것을 허용 한다는 뜻

  출발지 아이피 범위(source-range)는 어디로 할것이냐? = anywhere 0.0.0.0/0

  내 아이피로 할 수 있음 curl ipconfig.io  로 아이피알아내서 내 아이피로 세팅할 수 있음. 단, 집에서 접속이 안될 불편함이 있지만 안전하기는 함.

# gcloud compute firewall-rules create test-vpc-allow-icmp --allow=icmp --description="Allow incoming traffic on ICMP" --direction=INGRESS --network=test-vpc --source-ranges 0.0.0.0/0


# gcloud compute images list


# gcloud compute images describe centos-7-v20230509 --project=centos-cloud

 이미지가 검색해서 나오면 상세 내역을 보여줌. 최소 디스크의 크기가 20기가 이상은 되어야 한다는 것을 알 수 있다.


# gcloud compute machine-types list --filter="zone:( asia-northeast3-a )"

→ a라고 하는 가용영역에서 만들 수 있는 machine type을 보겠다는 의미.

 aws의 인스턴스 타입과 같은 머신타입을 볼 수 있다.

이미지를 만들기 위해서 머신타입을 집어넣어야 함.


# vi httpd-gcp.txt
#!/bin/bash
yum install -y httpd
systemctl enable --now httpd
echo "Hello GCP CLI" > /var/www/html/index.html

이렇게 하려다가 aws s3에서 food.tar파일 가져와보기

tmp폴더로 가서 wget명령어로 내려받고 tar xvf명령으로 압축을 풀어주기!!!

#!/bin/bash
setenforce 0
yum install -y httpd wget
systemctl enable --now httpd
cd /tmp
wget https://s3.ap-northeast-2.amazonaws.com/seoul.ssoontory.shop/food.tar
tar xvf food.tar -C /var/www/html



# gcloud compute instances create web01 \

 vm 이름임
    --image=centos-7-v20230509 \
    --image-project=centos-cloud \
    --machine-type=e2-micro \
    --network=test-vpc \
    --subnet=test-subnet \
    --tags http-server,https-server \

 기본적인 방화벽 정보가 있는데 그 정보에서 가져오는 것을 의미

  서버에 80포트, 443 포트를 통해 외부에서 접근할 수 있도록 함. 
    --zone=asia-northeast3-a \

 asia-northeast3-a에 만든다는 의미.
    --metadata-from-file=startup-script=httpd-gcp.txt

 사용자 데이터를 정의. 

 metadata-from-file=startup-scriprt는 옵션임.

 

# gcloud compute instances create foodwagon\
    --image=centos-7-v20230509 \
    --image-project=centos-cloud \
    --machine-type=e2-micro \
    --network=test-vpc \
    --subnet=test-subnet \
    --tags http-server,https-server \
    --zone=asia-northeast3-a \
    --metadata-from-file=startup-script=httpd-gcp.txt


여기까지하고 끝내주기

# gcloud compute instances delete foodwagon

 

 

--- GCP CLI
# mkdir gcp_cli && cd $_
# tee -a /etc/yum.repos.d/google-cloud-sdk.repo << EOM
[google-cloud-cli]
name=Google Cloud CLI
baseurl=https://packages.cloud.google.com/yum/repos/cloud-sdk-el8-x86_64
enabled=1
gpgcheck=1
repo_gpgcheck=0
gpgkey=https://packages.cloud.google.com/yum/doc/yum-key.gpg
       https://packages.cloud.google.com/yum/doc/rpm-package-key.gpg
EOM

# yum install -y google-cloud-cli
# gcloud --version

# gcloud init --console-only
asia-northeast3-a
# gcloud compute networks create test-vpc
# gcloud compute networks subnets create test-subnet --network=test-vpc --range=192.168.0.0/16 --region=asia-northeast3
# gcloud compute firewall-rules list

→ 디폴트 네트워크에 포함된 firewall-rules가 보임.
# gcloud compute firewall-rules create test-vpc-allow-ssh --allow=tcp:22 --description="Allow incoming traffic on TCP port 22" --direction=INGRESS --network=test-vpc --source-ranges 0.0.0.0/0

 보안그룹 같은 느낌의 방화벽은 허용/거부가 가능하다. source-range(출발지 ip)는 누구나 다 들어올 수 있도록 설정.
# gcloud compute firewall-rules create test-vpc-allow-http --allow=tcp:80 --description="Allow incoming traffic on TCP port 80" --direction=INGRESS --network=test-vpc --source-ranges 0.0.0.0/0

# gcloud compute firewall-rules create test-vpc-allow-icmp --allow=icmp --description="Allow incoming traffic on ICMP" --direction=INGRESS --network=test-vpc --source-ranges 0.0.0.0/0
# gcloud compute images list
# gcloud compute images describe centos-7-v20220621 \
    --project=centos-cloud
# gcloud compute machine-types list --filter="zone:( asia-northeast3-a )"
# vi httpd-gcp.txt
#!/bin/bash
yum install -y httpd
systemctl enable --now httpd
echo "Hello GCP CLI" > /var/www/html/index.html


#!/bin/bash
setenforce 0
yum install -y httpd wget
systemctl enable --now httpd
cd /tmp
wget https://s3.ap-northeast-2.amazonaws.com/seoul.ssoontory.shop/food.tar
tar xvf food.tar -C /var/www/html


# gcloud compute instances create foodwagon \
    --image=centos-7-v20230509 \
    --image-project=centos-cloud \
    --machine-type=e2-micro \
    --network=test-vpc \
    --subnet=test-subnet \
    --tags http-server,https-server \

 이렇게하면 80포트와 방화벽포트가 오픈됨
    --zone=asia-northeast3-a \

 서울리전에 넣기. 
    --metadata-from-file=startup-script=httpd-gcp.txt

# ssh-keygen -t rsa -f /root/.ssh/ssoontory-C johnlee -b 2048

 -C는 키를 이용해서 로그인할때 사용되는 아이디를 정의하는 명령어

  키 방식에다가 또 패스워드를 넣는것임. 그래서 그냥 바로 엔터만 넣기!

  내가 정하는 이름으로 키를 만들어보았다. .pub이 공개키 그냥 ssoontory.는 개인키

 


# vi /root/.ssh/ssoontory.pub
ssoontory:ssh-rsa

  만들어진 키로 넘어가서 vi 편집기로 해당 명령어 수행해주기

  그냥 ssh-rsa 앞에 붙여주기만하면 됨!

안해주면 이런 오류뜸


# gcloud compute os-login ssh-keys add \
    --key-file=/root/.ssh/ssoontory.pub \

  내가 가지고 있는 퍼블릭 키를 
    --project=terraform-ssoontory \

  terraform-ssoontory라는 프로젝트에
    --ttl=365d

  365일의 기간동안 퍼블릭 키를 이용하겠다는 의미

 

프로젝트 아이디 가져오기


# gcloud compute instances add-metadata foodwagon --metadata-from-file ssh-keys=/root/.ssh/ssoontory.pub

메타데이터에 키를 넣어주기


# gcloud compute instances describe foodwagon


# curl 34.64.155.3
# ssh -i /root/.ssh/ssoontory ssoontory@34.64.155.3
# gcloud compute instances delete foodwagon

  지워주기


# gcloud compute firewall-rules list
# gcloud compute firewall-rules delete test-vpc-allow-http

  firewall-rules지워주기
# gcloud compute firewall-rules delete test-vpc-allow-ssh

# gcloud compute firewall-rules delete test-vpc-allow-icmp


# gcloud compute networks subnets delete test-subnet
# gcloud compute networks delete test-vpc



---------------
--- gcp_set ---
---------------

  CLI 작업보다 Template으로 하면 더 쉽게 만들 수 있다는 것을 느껴보기

  gcp는 credenctials을 넣어주게끔 만들어져있음. 주석처리 해주기

  괄호 안에 자격증명 키가 들어가 있어야 함. 


# vi provider.tf
provider "google" {
  #credentials = file("credentials.json")

  GCP에서 생성을 해줘야 하는 키 파일이라고 볼 수 있음. 지금은 비활성화 시키고 진행해보기!(오류 나는지 확인)
  project = "terraform-ssoontory"

  프로젝트 아이디 넣어주기! 키 관리할 때 넣었던 그 아이디로 넣으면 됨. 
  region = "asia-northeast3"

  서울 리전으로 넣어주기
  zone = "asia-northeast3-a"
}

# vi main.tf
resource "google_compute_subnetwork" "network-with-private-ip-ranges" {

  "제공자(google)_자원이름(coumput_subnetwork)"  > 바꿀 수 없음. 

  "network-with-private-ip-ranges" > 내가 정할 수 있는 리소스 이름. 

  name          = "test-subnet"
  ip_cidr_range = "192.168.0.0/16"
  region        = "asia-northeast3"
  network       = google_compute_network.custom-test.id

  자원의 이름.내가 정한 이름.(네트워크의)id
}

 

VPC 정의

resource "google_compute_network" "custom-test" {
  name                    = "test-vpc"
  auto_create_subnetworks = false
}

 


Instance 정의
resource "google_compute_instance" "default" {
  name         = "foodwagon"

  vm의 이름을 명시해주기 / aws의 이름과 태그가 별도로 있었는데 gcp는 적어도 리소스의 이름은 존재함. 
  machine_type = "e2-micro"
  zone         = "asia-northeast3-a"

  boot_disk {
    initialize_params {
      image = "ubuntu-os-cloud/ubuntu-1804-lts"

  # gcloud compute images list 명령어로 원하는 이미지 찾아봄

  작성하는 방법은 해당 리스트의 PROJECT/FAMILY 이렇게 쳐줌

  디스크의 사이즈는 디폴트 사이즈로 설정이 됨. 

ubuntu-os-cloud/ubuntu-1804-lts

   }
  }


  vm의 네트워크 세팅을 위해 세팅을 해준다. 

  network_interface {
    network = "test-vpc"
    subnetwork = "test-subnet"

    access_config {

  외부에서 퍼블릭 아이피를 부여하겠다는 세팅이 여기 항목으로 들어가줌. 

  그대로 비어있는 공간으로 냅두면 외부에서 external id를 생성해줌
      // Include this section to give the VM an external ip address
    }
  }



    metadata_startup_script = file("/root/gcp_cli/httpd-gcp.txt")

  사용자 데이터 세팅

    // Apply the firewall rule to allow external IPs to access this instance
    tags = ["http-server", "https-server", "ssh-server"]

  태그 부분은 http-server만 넣어줌. 

  태그에 넣어서 간단히 가능. 체크박스의 체크를 간단하게 해주면서 방화벽을 열어주는 느낌으로 세팅을 해줌. 

  여러개가 들어가므로 리스트에 대괄호가 들어감. 

  두개의 포트번호가 오픈되어있음. 

  명시적으로 열 수 있는 포트들을 정의해서 넣어둠

}

 

 


resource "google_compute_firewall" "http-server" {

  firewall 을 지운 상태에서 만드는 과정이기 때문에 룰도 다 만들어줌

  앞서 세팅했던 cli로 세팅을 했던 내용들이 아래 다 나와있음. 
  name    = "test-vpc-allow-http-terraform"
  network = "test-vpc"

  allow {
    protocol = "tcp"
    ports    = ["80"]
  }

  // Allow traffic from everywhere to instances with an http-server tag
  source_ranges = ["0.0.0.0/0"]
  target_tags   = ["http-server"]
}

 

resource "google_compute_firewall" "https-server" {
  name    = "test-vpc-allow-http-terraform"
  network = "test-vpc"

  allow {
    protocol = "tcp"
    ports    = ["443"]
  }

  // Allow traffic from everywhere to instances with an http-server tag
  source_ranges = ["0.0.0.0/0"]
  target_tags   = ["https-server"]
}

 

resource "google_compute_firewall" "ssh-server" {
  name    = "test-vpc-allow-ssh-terraform"
  network = "test-vpc"

  allow {
    protocol = "tcp"
    ports    = ["22"]
  }

  // Allow traffic from everywhere to instances with an ssh-server tag
  source_ranges = ["0.0.0.0/0"]
  target_tags   = ["ssh-server"]
}


# vi output.tf
output "ip" {
  value = "${google_compute_instance.default.network_interface.0.access_config.0.nat_ip}"

  퍼블릭 아이피를 부여할 수 있도록 세팅해놨던 과정에서 넣어주었던 값.

이걸 읽어들인것임.

  nat_ip는 퍼블릭 아이피다. 

}

 

앞서 provider.tf 부분에 credentials 파일을 만들어서 링크 파일을 넣어줌. 

provider.tf파일에 아이디,패스워드 키 등이 절대 직접적으로 들어가면 안됨. 

gcp의 경우 credential파일을 만들어서 자격증명을 증명해야함. 

해당 정보가 들어가지 않으면 실행이 안됨. (aws와 다름_ aws는 별도의 자격증명이 필요없었음.)

그리하여 주석을 없애주기!!!

그래서 credential파일을 만들어야 함. 

gcp콘솔로 이동하기.

AIM으로 들어가기.

credencials 파일을 집어넣어주기

 

Service Accounts 로 들어오기

+Create Service Account 클릭해서 만들어주기

 

 

vm도 만들고 다양한 리소스를 생성해줘야하기때문에 역할을 높은 걸로 설정해주기!

역할 선택 클릭

뷰어는 읽기 권한정도만 있기때문에 패스

소유자는 root사용자에 준하는 전체 권한을 의미

탐색자 리소스를 탐색할 수 있음 

편집자 소유자보다 밑임. 소유자가 할 수 있는 것의 일부를 못함.

(대부분의 구글클라우드 리소스를 확인, 생성, 업데이트, 삭제를 함. 소유자보다 권한이 조금 부족)

편집자가 소유자의 아이디를 지운다는 등의 역할을 못함. 

 

 

소유자는 너무 높아서 편집자로 역할을 선택.

여기까지 해주고 완료 클릭해주기

 

서비스 계정을 만들어 준 것임.

이제 얘를 가져다가 credential파일로 만들어줄 것임. 

 

 

작업 목록 보고 키관리 클릭해주기

httpd-gcp.txt바꾸기

 

#!/bin/bash
#setenforce 0
#yum install -y httpd wget
#systemctl enable --now httpd
apt update
apt install -y apache2
cd /tmp
wget https://s3.ap-northeast-2.amazonaws.com/seoul.ssoontory.shop/food.tar
tar xvf food.tar -C /var/www/html

 

 

setenforce 0는 없음

yum 없음

아파치 설치가 되면 

 

 

 


# terraform init
# terraform plan
# terraform apply
# terraform output ip

 

 

 


 

앤서블의 3가지 요소
앤서블은 크게 3가지인 인벤토리, 플레이북, 모듈로 이루어져있음.
1) 인벤토리는 어디서 수행할 것인지?
관리할 서버의 ip리스트를 저장하는 곳= 호스트 파일
2) 플레이북은 무엇을 수행할 것인지?
> 내 150대 정도 되는 서버에 아파치 웹서버를 어떻게 설치할 것인지 미리 설정해둔 템플릿을 의미.
아파치를 설치한 명령어 등이 거기 포함됨. 

3) 모듈은 어떻게 수행할 것인지?
> 모듈이 모든걸 다함. 모듈은 이미 만들어둔 플러그인 같은 기능이다.
>하나하나 다 만들어 두어야 할 것들을 가져다 활용하면 되는 것들을 의미 

테라폼에서는 모듈을 플러그인이랑 비슷
앤서블에서는 ec2를 관리하고 생성하는 모듈이 상당히 어렵게 느껴짐. 

마치 테라폼의 플러그인 덕분인 것 같음. 

중복 실행이 되지 않도록 쓰이게 만들어주는 것들이 모듈이 하는 일임. 
모듈 덕분에 중복 작업 안해도 됨

 

인벤토리 (inventory)
인벤토리는 앤서블에 의해 제어될 대상을 정의. 일반적으로 host.ini파일에 정의해 사용하며, 여러 서버들의 SSH 접근 ip, 포트, 리눅스 사용자와 같은 접속 정보를 정의함.  내가 관리할 아이피, 도메인만 엔서블로 저장. 


내가 관리하고 싶은 리스트를 아이피 또는 도메인 형식으로 적는 것 

 

 

플레이북 플레이북 (각본)은 인벤토리 파일에서 정의한 대상들이 무엇을 정의할 것인지 확인하기 위한 역할을 함. ymal 포멧으로 설정. 앤서블을 사용사려면 이 playsbook을 잘 다룰 줄알아야함. 

앞서 테라폼에서 본 것 처럼 정해져있는 스크립트를 yaml파일로 정해두고 그 순서에 따라 정해두는 것을 의미

 

yaml파일의 규칙. 
정식이면 세개의 -로 시작 ---

befome : true > root로 들어가겠다는 의미
yum = 모듈


yum :
name: nginx
state : installed

yum install -y nginx

앤서블 이해하기

Ansible(앤서블로 발음)은 여러개의 서버를 효율적으로 관리할 수 있게 해주는 환경 구성 자동화 도구다. 
2012년에 마이클 데한이라는 개발자가 만들어 소스코드를 공개한 오픈소스의 소프트웨어다.
앤서블은 2015에 오픈소스 업계 큰손인 레드헷이 인수했다. 
앤서블은 플레이북이라는 파일에 실행할 구성을 선언해놓으면 필요할때마다 자동으로 실행시킬 수 있는것이 가장 큰 특징이다. 웹 서버의 구성과 DB 서버의 구성을 선언해두면 관리자들은 필요할 때마다 그 구성대로 설정을 배포할 수 있게 해준다. 템플릿 파일을 실행시키듯 플레이북이라는 파일을 실행시킴. 코드를 가지고 인프라를 만듬

기존 리눅스에서 동일한 환경을 구성하기 위해서 Bash 쉘 스크립트 패키지의 설치, 설정파일 등을 나열하여 이를 실행하는것이 일반적이었ㅇ므. IT의 기술력이 진보함에 따라 인프라 환경도 기존 Data center에서 cloud 환경응로 변화하고 잇고, 한명의 관리자가 (Admin) 관리해야 하는 서버의 숫자가 증가하게 되었다.

 

 

 

베이그런트
kvm 에서 vm을 쉽게 만들어 주라고 만든 것. 베이그런트로 만들면 베잍그런트에 특화되어있기 때문에 vm을 만드는 것은 쉽지만 vm을 다루는 것들이 제한적으로 닫혀있는 느낌이 심함.  따라서 베이그런트에 종속 된 것처럼 베이그런트의 지시에 따라야 함. 베이그런트에 의존해서 ip세팅을 따라가는 등의 종속 된 느낌으로 설정해줌. 
그리고 vm을 만든다 > 생성된다 이런 개념은 쉬운데 그 중간에 걸리는 시간등이 관리하는게 불편하고 오래걸림.

virtual box에 특화되어있음. 
보통 만들어지면 nat아이피로 세팅을해서 외부에서 들어가려면 포트포워딩을 하는등의 번거로운 작업들을 함. 
vm을 자동으로 만들어주는 시스템이랑 같음. 
테라폼이 제일 잘하는 것을 클라우드 형태의 플랫폼에서 vm을 만듬



테라폼 init하듯이 베이그런트 init

 

centos/7이라는 이미지를 내려받음. 단 이때의 이미지는 베이그런트만이 사용할 수 있는 이미지를 베이그런트가 운영하는 저장소로부터 내려 받음. 우리가 다운받는 kakao.mirror에서 얻는 이미지는 아님.

 

제한적이다. 개발자 관점에서는 어쩔지 몰라도 앤지니어 관점에서는 너무 제한적임.

 

 

init > 파일 생성

수정 > os , network정보 > 등등

실행  > apply가 아닌 vagrant up

접속 > 베이그런트 가상 머신에 접속 (vagrant ssh)

 

CentOS와 Ubuntu 는 관리를 위해서 만들어봄.

우분투 설치먼저 해보기

 

중첩된 가상화 (네스티드 VT-x) 사용

앤서블

 

 

ubuntu 설치과정

더보기

우선 keyboard No로 설정

 

 

 

yes

continue > enter

 

 

 

infra as cod = 앤서블 

파일 

 

가상 시스템 가져오기

 

 

 

 

파이썬이 다 있음.  모듈들이 다 파이썬으로 구성됨.

ㅇ우분투 백업하기

power off

파일 > 가상 시스템 내보내기

 


 

 

 

 

우분투 centos7 스냅샷 찍어두고 앤서블 실습 시작


--- 앤서블 실습 환경 (cpu, ram 용량)
ansible-server 1c 1g
centos-node01 1c 1g
ubuntu-node01 1c 1g

--- 앤서블 서버 설치
# yum install epel-release -y


# yum --enablerepo=epel -y install ansible
# ansible --version
앤서블 문서 사이트 https://docs.ansible.com/ansible/latest/index.html
앤서블 모듈 사이트 https://docs.ansible.com/ansible/2.9/modules/list_of_all_modules.html

 

 

All modules — Ansible Documentation

 

docs.ansible.com

 

 

 

앤서블은 에이전트가 없음. 셰프라는 도구와 퍼펫이라는 도구는 에이전트가 없음. 관리하는 도구에 에이전트를 설치해서 진행. 앤서블의 에이전트는 파이썬이라고 볼 수 있음. 

 

 


--- 앤서블의 CLI
# vi /etc/ansible/hosts
[centos]
192.168.1.221

[ubuntu]
192.168.1.199

그룹을 짓는 과정임. centos와 ubuntu는 명령어가 다르기때문에 그룹을 지어준다.

 

 

# ansible all -m ping
# ansible all -m ping -k # ask password
 ( antible ubuntu -m ping -k --user ssoontory )
# sudo passwd root 
 루트 계정의 패스워드를 넣어주기.
# ansible centos -m ping -k
# ansible ubuntu -m ping -k

ansible all -m(module) ping(우리가 알고 있는 google.com 치는 ping도구인 icmp프로토콜을 이용한게 아니라, 파이썬으로만들어진 ansible을 위한 도구/ 내가 관리하려하는 호스트 안에 있는 모든 서버들한테 ssh로 다 접속을해봐서 ping이라고하는 모듈을 실행시킴/각 서버들마다 파이썬이라는 도구가 있어서 가능 / 실행 시킨 뒤 다시 나한테 돌아옴/ 내가 관리하려고 했던 서버들이 python을 설치하고 있는가 확인하는 경우 사용된다. )

/etc/ansible/hosts 전체를 의미

 

진짜 ssh로 접속을 하는 것을 확인할 수 있음. = yes 넣어주기

그런데 두가지의 질문이 겹쳐서 두번의 첫번째 질문이 묻혀서 yes 넣어주고 error같은 것 떠도 다시 yes넣어주기!

 

 

ansible all -m ping -k

(-k는 패스워드를 넣어준다는 뜻)

 

all 은 centos는 root이기 때문에 그냥 진행함. 우분투는 root계정의 패스워드가 없음. 그래서 일반 사용자 명이 있기 때문에

 

# antible ubuntu -m ping -k --user ssoontory

 

sudo passwd root 

 

ssh root@ubuntu 안됨. 

로컬에서는 root 로 가능함. 

root 계정은 아무리 털려도 실제 화면 앞으로 오지않는 이상 접근할 수 없음

 

 

sudo vi /etc/ssh/sshd_config

루트계정을 사용하게하거나 못하게 만드는 명령

 

 

 


 

 

 

# echo "192.168.1.221" >> inventory.list
# echo "192.168.1.199" >> inventory.list

ansible all -i inventory.list -m ping -k

 

방금 내가 만든 inventory.list 아이피에 따른 서버에 ping을 보내서 살아있는지 확인

 

엇! 위에서 inventory에 잘못 추가해서 ping이 오류가 뜸. 

192.168.1.250이 아니라 192.168.1.221을 넣어줘야함. 

그럴때는 vi 편집기로 inventory.list를 수정해줄 수 있음.

 

 

 

ansible 192.168.1.250 -i inventory.list -m ping -k

하나씩 확인도 가능

 

 

 

# ansible all --list-hosts

hosts파일안에 어떤 리스트가 있는지 보여줌..

 

 

# ansible all -m shell -a "uptime" -k

→ uptime = 명령어 지속 시간을 의미

 

 이웃되어 있는 hosts 파일에 있는 서버들의 uptime을 가져온다.

 

# ansible all -m shell -a "df -h" -k

  두대의 서버의 disk 사용량을 보겠다는 의미

  큰 따옴표를 하는 이유는 df 명령어처럼 한칸을 띄우고 -h를 줘야하는데 ""가 없으면 df의 옵션인지 -의 옵션,  ansible의 옵션인지 모르기때문에 씀.


# ansible all -m shell -a "free -h" -k

  free -h 메모리 사용량을 보여주는 명령

일반적인 bash shell 명령어도 쓸 수 있다.

ansible all -m shell -a "ls -al" -k

 

 


# ansible all -m shell -a "mkdir test" -k

다시 한 번 써주면 이미 존재한다고 나옴. 

 



# ansible all -m user -a "name=kosa" -k

  user라는 모듈의 기능임 "name"이라는 키를 주고 name=kosa라는 value가 입력이 됨.

  사용자를 생성해줄 수 있음.



# ansible all -m shell -a "tail -n 1 /etc/passwd" -k

  맨 밑줄에 있는 라인을 본다는 것임.

  내가 추가한 코사라는 사용자가 추가가 되었는지 확인해볼 수 있는 명령어임.

  x 는 패스워드임! 감춰져있음.

 



# ansible all -m user -a "name=kosa state=absent" -k

  사용자가 퇴사하거나 해서 이제 user목록에서 삭제해야할 때 쓰는 명렁어임

  absent로 바꿔주기!  present는 설치!  absent는 remove의 의미와 같음

 



# ansible all -m shell -a "tail -n 1 /etc/passwd" -k

  사용자가 삭제된 것을 확인할 수 있음. 

--- 센토스 아파치 애드혹 관리
# ansible centos -m yum -a "name=httpd state=present" -k    (= CentOS 의 # yum install -y httpd )

  CentOS만 적용이 가능. 우분투는 사용이 불가. 그래서 우분투만 적용시켜주기

 

 

'Terraform' 카테고리의 다른 글

테라폼 개념 정리  (0) 2023.07.12