terraform

T101-Study-4Week

가시다님과 스터디를 한지도 5번째 이번엔 테라폼이다.

오늘 블로그를 쓰게된건 중간과제를 설명하기 위해서다.

바로 본론으로 들어간다. 내 GIT 이다

https://github.com/Cloud-Linuxer/T101/tree/main/4week

variable "availability_zone" {
        description = "Seoul region availability zone"
        type = list
        default = ["ap-northeast-2a", "ap-northeast-2b", "ap-northeast-2c", "ap-northeast-2d"]
}

variable "subnet_numbers" {
  type    = list
  default = [10, 20, 30, 40]
}
variable "az_count" {
  type    = list
  default = ["A", "B", "C", "D"]
}

나의 Variables는 이런식으로 구성되어있다. 모든 타입을 List로 선언하여 사용한다. 5주차에 할 테라폼 의 반복문을 사용하기 위한 형태다. 가장 중요한 부분은 subnet_numbers 부분이다. 10, 20, 30, 40 이 핵심이다.

resource "aws_subnet" "pub-common" {
        count = "${length(var.availability_zone)}"
        vpc_id = "${aws_vpc.default.id}"
        cidr_block = [
                for num in var.subnet_numbers:
                cidrsubnet(aws_vpc.default.cidr_block, 8, num)
                ][count.index]
        availability_zone = "${element(var.availability_zone, count.index)}"
        tags = {
                Name = "Linuxer-Dev-Pub-Common-${element(var.az_count, count.index)}"
        }
}

이 코드만 봐서는 이게 무엇을 뜻하는지 한눈에 보기 어렵다. 그럼 하나씩 설명하겠다. 하시코프에서는 cidrsubnet 이라는 Function 을 지원한다. 이 함수를 통해서 나는 /16비트의 서브넷을 24비트로 자를거다.

간단히 보여주자면 이렇다

terraform console
> cidrsubnet("10.0.0.0/16",8,10)
"10.0.10.0/24"
> cidrsubnet("10.0.0.0/16",8,20)
"10.0.20.0/24"
> cidrsubnet("10.0.0.0/16",8,30)
"10.0.30.0/24"
> cidrsubnet("10.0.0.0/16",8,40)
"10.0.40.0/24"

for로 list 에 담긴 subnet_numbers를 가져다가 CIDR 을 반환한다. 위처럼 24비트의 4개 서브넷이다.
위와같이 24비트로 나뉜 4개의 서브넷을 테라폼은 생성한다.
위의 리소스선언 한줄로 Subnet 4개를 생성하는 것이다.

서울 리전의 4개 AZ를 모두 사용하고, A zone은 10대역대 B Zone은 20대역대 C Zone은 30대역 D Zone은 40 대역인것이다.

이렇게 사용하면 장점이 있다. 한개의 존이 문제가 생긴것을 파악하기 쉽고, 아이피 대역대 만으로 서비스의 역할을 파악할수 있는 장점이 있는 것이다.

처음엔 리스트로 서브넷 선언도 모두 입력해서 하나의 리소스 선언으로 모든 서브넷을 생성하려했지만 그렇게 사용할 경우 리스트가 변경되면 모든 서브넷이 영향을 받는 이슈가 있어서 각 서브넷별 리소스 선언을 하는 방향으로 수정했다.

gcp terraform-3 vpc-nat create

vpc-nat 를 연결하기로 했다.
어젠 subnet 을 만들었고 오늘은 망분리 환경을 구성하기 위해 nat 를 넣었다.

main.tf

resource "google_compute_subnetwork" "us-central1-subnet" {
name = "${local.name_suffix}-us-central1-subnet"
ip_cidr_range = "10.2.0.0/16"
region = "us-central1"
network = "${google_compute_network.vpc.self_link}"
}
resource "google_compute_router" "us-central1-router" {
name = "${local.name_suffix}-us-central1-router"
region = google_compute_subnetwork.us-central1-subnet.region
network = google_compute_network.vpc.self_link
}
resource "google_compute_address" "address" {
count = 2
name = "${local.name_suffix}-nat-manual-ip-${count.index}"
region = google_compute_subnetwork.us-central1-subnet.region
}
resource "google_compute_router_nat" "nat_manual" {
name = "${local.name_suffix}-us-central1-router-nat"
router = google_compute_router.us-central1-router.name
region = google_compute_router.us-central1-router.region
nat_ip_allocate_option = "MANUAL_ONLY"
nat_ips = google_compute_address.address.*.self_link

source_subnetwork_ip_ranges_to_nat = "LIST_OF_SUBNETWORKS"
subnetwork {
name = "${local.name_suffix}-us-central1-subnet"
source_ip_ranges_to_nat = ["10.2.0.0/16"]
}
}

resource "google_compute_network" "vpc" {
name = "${local.name_suffix}-vpc"
auto_create_subnetworks = false
}

backing_file.tf

locals {
name_suffix = “linuxer”
}
provider “google” {
region = “us-central1”
zone = “us-central1-c”
}

vpc 와 nat nat route 까지 정상적으로 만들어져서 동작하는 것을 확인할 수 있었다.

리전당 nat는 1개를 꼭만들어야 했다.

현재 생성한 tf는 subnet 하나에 대한 설정이다. 다른 리전으로도 네임만 수정을 적절히 하면 수정해서 쓸수 있다.

gcp-terrafrom-2 with VPC create

이전 포스팅에서 cloud shell 을 이용해서 terraform 을 사용하는 방법을 포스팅 했다.

이번에는 VPC 를 생성하는 방법을 포스팅 하기로 하였다.

https://www.terraform.io/docs/providers/google/r/compute_subnetwork.html

다음 docs 를 참고하였다.

resource name -실제 vpc name -에 대문자가 들어가면
Error: Error creating Network: googleapi: Error 400: Invalid value for field 'resource.name'
에러가 발생한다 참고하자.

이걸 몰라서 한참..테스트를 했다.

main.tf

resource "google_compute_subnetwork" "us-central1-subnet" {
name = "${local.name_suffix}-us-central1-subnet"
ip_cidr_range = "10.2.0.0/16"
region = "us-central1"
network = google_compute_network.linuxer-VPC.self_link
}
resource "google_compute_subnetwork" "europe-west1-subnet" {
name = "${local.name_suffix}-europe-west1-subnet"
ip_cidr_range = "10.3.0.0/16"
region = "europe-west1"
network = google_compute_network.linuxer-VPC.self_link
}
resource "google_compute_network" "linuxer-VPC" {
name = "${local.name_suffix}-vpc"
auto_create_subnetworks = false
}

backing_file.tf - provider 에서 리전을 지정하지 않아도 된다고 하는데 지정해주었다.

locals {
name_suffix = "linuxer"
}
provider "google" {
region = "us-central1"
zone = "us-central1-c"
}

VPC : linuxer-vpc
linuxer-us-central1-subnet us-central1 / 10.2.0.0/16
linuxer-europe-west1-subnet europe-west1 / 10.3.0.0/16

dellpa34@cloudshell:~/docs-examples/subnetwork_basic$ terraform plan
Error: Error locking state: Error acquiring the state lock: resource temporarily unavailable
Lock Info:
ID: 640725d0-1fad-c74e-7cff-35baf4c72937
Path: terraform.tfstate
Operation: OperationTypeApply
Who: dellpa34@cs-6000-devshell-vm-3de0c123-93a9-4a2f-a584-d94918d8801a
Version: 0.12.18
Created: 2020-01-04 12:07:10.301086954 +0000 UTC
Info:
Terraform acquires a state lock to protect the state from being written
by multiple users at the same time. Please resolve the issue above and try
again. For most commands, you can disable locking with the "-lock=false"
flag, but this is not recommended.

테스트중에 캔슬 한번했더니 프로세스가 종료되지 않아서 자꾸 -lock=false 옵션을 주라고 떳다. 귀찮아서 그냥 죽였다. kill -9 4120

dellpa34 284 0.0 0.3 23080 6800 pts/1 S<s 18:01 0:00 _ -bash
dellpa34 4120 0.0 1.7 151504 29856 pts/1 T<l 21:07 0:00 _ terraform destroy
dellpa34 4123 0.1 3.0 153232 52824 pts/1 T<l 21:07 0:01 | _ /usr/local/bin/terraform destroy
dellpa34 4179 0.0 2.1 153020 37296 pts/1 T<l 21:07 0:00 | _ /home/dellpa34/docs-examples/subnetwork_basic/.terraform/plugins/linux_amd64/terraform-provider-google_v3.3.0_x5
dellpa34 4186 0.0 1.3 124688 22536 pts/1 T<l 21:07 0:00 | _ /home/dellpa34/docs-examples/subnetwork_basic/.terraform/plugins/linux_amd64/terraform-provider-random_v2.2.1_x4
dellpa34 4462 0.0 0.1 38304 3200 pts/1 R<+ 21:17 0:00 _ ps afxuwww
dellpa34@cloudshell:~/docs-examples/subnetwork_basic$ kill -9 4120

프로세스를 죽이고 apply 하여 정상적으로 생성되는것을 확인하였다.

대문자..-_-;;

일단 테라폼에서 vpc 생성할때 대문자는 안된다.

GUI에서도 대문자 사용은 불가하네..좋은걸 알았다..

내두시간..!

gcp-terrafrom-1 with google cloud shell

gcp 스터디를 위해서 테라폼의 사용을 익히려고 한다.
그러기 위해선 먼저 테라폼을 gcp cloudshell 에서 사용하는것이 우선이라 생각했다.

테라폼으로 aws내 에선 테스트 경험이 있으므로 gcp 의 네트워크 구성과 환경에 맞춰서 테라폼을 설정하는 방법을 익혀야 했다.

gcp 에서 테라폼을 사용하려면 cloudshell 을 사용하는 방법과 인스턴스를 생성하여 사용하는 방법 아니면 클라이언트 PC에서 사용하는 방법 이렇게 3가지가 있는데 나는 cloudshell 을 매우 좋아하므로 cloudshell 로 진행 할것이다.

먼저 cloud shell 에서 테라폼을 사용하려면 몇가지 단계를 거쳐야 했다.

1 terrafrom install
2 gcp api setup
3 config setting

이 단계를 간단하게 줄여주는 페이지가 있어서 먼저 테스트 해봤다.

https://www.hashicorp.com/blog/kickstart-terraform-on-gcp-with-google-cloud-shell/  

https://github.com/terraform-google-modules/docs-examples

두개의 URL 을 참고하시기 바란다.

URL 을 따라서 진행하던중 terraform init 에서 에러가 발생하였다.

Provider "registry.terraform.io/-/google" v1.19.1 is not compatible with Terraform 0.12.18.
Provider version 2.5.0 is the earliest compatible version. Select it with
the following version constraint:

version = "~> 2.5"
Terraform checked all of the plugin versions matching the given constraint:
~> 1.19.0
Consult the documentation for this provider for more information on
compatibility between provider and Terraform versions.
Downloading plugin for provider "random" (hashicorp/random) 2.2.1…
Error: incompatible provider version

error 는 backing_file.tf 파일에서 발생하고 있었다.
간단하게 version 차이..

cloud shell 의 terrafrom version 은

dellpa34@cloudshell:~/docs-examples/oics-blog$ terraform -version
Terraform v0.12.18
provider.google v2.20.1
provider.random v2.2.1

provider.google v2.20.1 로 1.19보다 많이 높은 상태였다. 일단 진행해 보기로 했으니.. backing_file.tf 수정

provider "google" {
version = "~> 1.19.0"
region = "us-central1"
zone = "us-central1-c"
}

provider "google" {
version = "~> 2.5"
region = "us-central1"
zone = "us-central1-c"
}

수정후에 다시 terraform init 을 실행 하였다.

Initializing provider plugins…
Checking for available provider plugins…
Downloading plugin for provider "google" (hashicorp/google) 2.20.1…
Terraform has been successfully initialized!
You may now begin working with Terraform. Try running "terraform plan" to see
any changes that are required for your infrastructure. All Terraform commands
should now work.
If you ever set or change modules or backend configuration for Terraform,
rerun this command to reinitialize your working directory. If you forget, other
commands will detect it and remind you to do so if necessary.

정상적으로 실행 되는것을 확인하였다.

init 후에 apply 하니 다시 Warning 과 함께 error 가 발생하였다.

Warning: Interpolation-only expressions are deprecated
on main.tf line 9, in resource "google_compute_instance" "instance":
9: image = "${data.google_compute_image.debian_image.self_link}"
Error: Error loading zone 'us-central1-a': googleapi: Error 403: Access Not Configured. Compute Engine API has not been used in project 45002 before or it is disabled. Enable it by visiting https://console.developers.google.com/apis/api/compute.googleapis.com/overview?project=304102002 then retry. If you enabled this API recently, wait a few minutes for the action to propagate to our systems and retry., accessNotConfigured
on main.tf line 1, in resource "google_compute_instance" "instance":
1: resource "google_compute_instance" "instance" {

이건 이전에도 겪은 케이스 같다...functions api 셋팅할때 발생한 거였는데...googleapi 관련 에러다. cloudshell 에서 컴퓨팅쪽의 api를 사용할 수 없어서 발생하는 에러로 로그에 보이는 페이지로 이동해서 그냥 허용해 준다.

Enter a value: yes
google_compute_instance.instance: Creating…
google_compute_instance.instance: Still creating… [10s elapsed]
google_compute_instance.instance: Creation complete after 10s [id=vm-instance-optimum-badger]
Apply complete! Resources: 1 added, 0 changed, 0 destroyed.

허용후에 다시 terraform apply 를 치면 정상적으로 실행이 된다. 그럼 확인해 보자.

인스턴스가 생성이 됬다. 그렇다면 이젠 간단히 생성하는것 까지 완료했으므로. 이젠 기본 템플릿을 이용한 구성을 만들것이다. 생성한 테라폼은 terraform destroy 명령어로 삭제 했다.

google_compute_instance.instance: Destroying… [id=vm-instance-optimum-badger]
google_compute_instance.instance: Still destroying… [id=vm-instance-optimum-badger, 10s elapsed]
google_compute_instance.instance: Still destroying… [id=vm-instance-optimum-badger, 20s elapsed]
google_compute_instance.instance: Still destroying… [id=vm-instance-optimum-badger, 30s elapsed]
google_compute_instance.instance: Destruction complete after 38s
random_pet.suffix: Destroying… [id=optimum-badger]
random_pet.suffix: Destruction complete after 0s

정상적으로 삭제되는것을 확인할수 있었다.

gcp cloud shell 에서 terraform 을 사용하는 방법을 테스트해 보았다.
다음엔 VPC 구성과 인스턴스 그룹 생성 로드벨런서 구성까지 한방에 진행할것이다.

여담으로 cloud shell은 진짜 강력한 도구이다.

스크린샷과 같이 shell을 지원하면서 동시에 에디터도 지원한다.

vi 에 익숙한 나같은경우에는 그냥 vi 로 작업하지만 익숙하지 않은 사용자의 경우에는 우와할정도다..

쓸수록 감탄하는 cloudshell...........