Terraform을 사용하여 GKE 생성하기

구글 인사이트

by Miyeon. Jo
준비하기
1. API 활성화하기

GKE를 생성하기 위해 아래 API를 활성화합니다.

  • Compute Engine API
  • Kubernetes Engine API
    $ gcloud services enable compute.googleapis.com container.googleapis.com
2. Service account 생성하기

아래 역할(Role)을 가지고 있는 Service account를 생성합니다.

  • Kubernetes Engine Admin
  •  Compute Network Admin
  •  Service Account User
3. Install
Terraform 파일 작성하기

GKE를 생성하기 위한 Terraform 파일을 작성

1. 자원 정의

terraform-gke 디렉토리를 생성
main.tf 파일을 생성합니다.

$ mkdir terraform-gke
$ cd terraform-gke
$ vi main.tf

1.1. Provider 선언
provider name: google
provider version: “~> 3.46”
project: var.project_id (GCP의 project 이름, “variables.tf”에 정의)
region: var.region (GCP의 region 이름, “variables.tf”에 정의)
provider "google" {
  version = "~> 3.400"
  project = var.project_id
  region  = var.region
}
1.2. Network : GKE를 생성할 network를 선언

1) VPC network

resource type: google_compute_network (생성할 resource type)
local name: vpc (local에서 참조할 이름)
auto_create_subnetworks: false (subnet 자동 생성 옵션)
resource "google_compute_network" "vpc" {
  name = "${var.project_id}-vpc"
  auto_create_subnetworks = "false"
}

2) Subnet network

ip_cidr_range: “10.10.0.0/24” (CIRD 범위)
resource "google_compute_subnetwork" "subnet" {
  name = "${var.project_id}-subnet"
  region = var.region
  network = google_compute_network.vpc.name
  ip_cidr_range = "10.10.0.0/24"
}
1.3. GKE cluster

1) GKE cluster

min_master_version: “1.23” (Master의 최소 버전)
remove_default_node_pool: true (Default node pool 삭제 여부)
initial_node_count: 1 (각 zone에 생성할 node 수)
resource "google_container_cluster" "primary" {
  name = "${var.project_id}-gke"
  location = var.region
  min_master_version = "1.23"
  remove_default_node_pool = true
  initial_node_count       = 1
  network    = google_compute_network.vpc.name
  subnetwork = google_compute_subnetwork.subnet.name
}

참고
“remove_default_node_pool”
Cluster는 default node pool 없이 생성이 불가능합니다 (일종의 template).
그래서 remove_default_node_pool 값을 “true”로 설정하면 default node pool을 작게 생성한 뒤 바로 삭제합니다.

2) Separately Managed Node Pool

node_count: var.gke_num_nodes (각 zone에 생성할 node 수, “variables.tf”에 정의)
node_config.oauth_scopes: API 접근 권한
node_config.metadata.disable-legacy-endpoints: true (Legacy endpoint 비활성화 여부)
resource "google_container_node_pool" "primary_nodes" {
  name       = "${google_container_cluster.primary.name}-node-pool"
  location   = var.region
  cluster    = google_container_cluster.primary.name
  node_count = var.gke_num_nodes
  node_config {
    oauth_scopes = [
      "https://www.googleapis.com/auth/logging.write",
      "https://www.googleapis.com/auth/monitoring",
    ]
    labels = {
      env = var.project_id
    }
    machine_type = var.gke_machine_type
    tags         = ["gke-node", "${var.project_id}-gke"]
    metadata = {
      disable-legacy-endpoints = "true"
    }
  }
}

[참고]
“node_count”는 각 zone에 생성할 node의 수입니다.
만약 이 값을 3으로 설정하고 region이 “asia-northeast3″라면 3개의 zone에 각각 3개의 node가 생성되어 총 9개의 node가 생성됩니다.

[참고]
GKE 1.12 버전 이상부터 “disable-legacy-endpoints” 값은 “true”가 기본으로 설정됩니다.
만약 metadata를 설정하고 “disable-legacy-endpoints”의 기본값을 선언하지 않으면, terraform은 이 값을 해제합니다. 이를 방지하기 위해서 “disable-legacy-endpoints” 값을 “true”로 설정해야합니다.

2. 변수 정의하기

variables.tf 파일을 생성
project_id, region, gke_num_nodes, gke_machine_type 변수를 선언

default 값이 있는 경우 정의해주고,
description 값에 변수에 대한 주석을 작성합니다.
이 변수는 terraform 명령 실행 시 다른 값으로 치환할 수 있습니다.

$ vi variables.tf
variable "project_id" {
  description = "project id"
}

variable "region" {
  description = "region"
}

variable "gke_num_nodes" {
  default     = 3
  description = "number of gke nodes"
}

variable "gke_machine_type" {
  default     = "n1-standard-4"
  description = "machine type of gke nodes"
}
3. 결과 정의하기

자원을 생성한 후 추출해야하는 값이 있는 경우 “output” block에 선언합니다.
이 값은 terraform apply 실행 시 사용자에게 보여집니다.
“kubernetes_cluster_name”는 이 output의 식별자이고 value는 생성한 자원의 이름입니다.

$ vi outputs.tf
output "kubernetes_cluster_name" {
  value = google_container_cluster.primary.name
  description = "GKE Cluster Name"
}
4. 버전 정의하기

필요한 버전을 선언합니다.

$ vi version.tf
terraform {
  required_version = ">= 0.12"
}
Terraform workspace 초기화하기
$ terraform init
...
Terraform has been successfully initialized!

$ ls -al
drwxr-xr-x  4 ...  ... .terraform

$ cat .terraform/environment 
default

workspace를 초기화하면 기본값으로 “default 값이 생성됩니다.

workspace 목록을 조회

$ terraform workspace list
* default

“*” 표시(활성화된 workspace)를 확인

$ cat .terraform/plugins/selections.json 
{
  "registry.terraform.io/hashicorp/google": {
    "hash": "h1:UIugsEPd4efky7G86YVdjkW5wwMIIW/WWeFod7RsbbQ=",
    "version": "3.47.0"
  }
}

“main.tf”의 “provider.version”에 선언한 대로 plugin을 설치한 것을 확인할 수 있습니다.

모듈을 불러오기 위한 설정

$ ls -all .terraform/plugins/registry.terraform.io/hashicorp/google/3.47.0/darwin_amd64
...
-rwxr-xr-x  1 ...  ... terraform-provider-google_v3.47.0_x5
GKE cluster 생성하기
1. 환경 변수 설정하기

variabes.tf 파일을 작성
terraform.tf vars파일에 아래와 같이 선언

project_id = "my-project-gke"
region     = "asia-northeast3"

민감한 정보가 있는 경우 OS 환경변수에 정의 (git 에 업로드 하지 않는게 보안상 좋음)

GOOGLE_APPLICATION_CREDENTIALS: 생성한 service account json file의 경로 입력

## "GOOGLE_APPLICATION_CREDENTIALS" is a file's path exported from service account.
export GOOGLE_APPLICATION_CREDENTIALS="REPLACE_ME"
export PROJECT_ID="REPLACE_ME"
export REGION="REPLACE_ME"

## e.g
export GOOGLE_APPLICATION_CREDENTIALS="/home/user/.gcp/gke-service-account.json"
export PROJECT_ID="my-project"
export REGION="asia-northeast3"
2. 검증하기

자원을 생성하기전 먼저 검증을 할 수 있습니다.
인프라 자원을 변경하는 것은 매우 조심스러운 작업인데 실수로 지워버린다던가 하는
위험성을 줄여주는 좋은 기능입니다. main.tf에서 정의한대로 vpc network, subnet network, gke cluster, gke node pool이 어떤식으로 생성될지 미리 보여줍니다.

$ terraform plan \
    -var "project_id=$PROJECT_ID" \
    -var "region=$REGION" \
    -var "gke_num_nodes=1"
...
Terraform will perform the following actions:
  ...
  # google_compute_network.vpc will be created
  + resource "google_compute_network" "vpc" {
  ...
  # google_container_cluster.primary will be created
  + resource "google_container_cluster" "primary" {
  ...
  # google_container_node_pool.primary_nodes will be created
    + resource "google_container_node_pool" "primary_nodes" {
  …
Plan: 4 to add, 0 to change, 0 to destroy.
3. 생성하기
$ terraform apply \
    -var "project_id=$PROJECT_ID" \
    -var "region=$REGION" \
    -var "gke_num_nodes=1"
...
Plan: 4 to add, 0 to change, 0 to destroy.

##plan 명령과 다른 점은 실제로 이 명령을 수행할 것인지 한번 더 물어봅니다.
Do you want to perform these actions?
  Terraform will perform the actions described above.
  Only 'yes' will be accepted to approve.

  Enter a value: yes

##인프라 자원 생성 시작
google_compute_network.vpc: Creating...
google_compute_network.vpc: Still creating... [13s elapsed]
google_compute_network.vpc: Creation complete after 22s
...
google_compute_subnetwork.subnet: Creation complete after 15s
...
##전체 단계가 완료되면 outputs.tf 정의한 값이 출력됩니다.
Outputs:
  + kubernetes_cluster_name = "my-project-gke"
  + region                  = "asia-northeast3"

Apply complete! Resources: 4 added, 0 changed, 0 destroyed.
생성한 자원 확인하기

gcloud CLI를 통해 credential 정보를 저장합니다.

$ gcloud container clusters get-credentials my-project-gke \
  --region asia-northeast3 \
  --project my-project
Fetching cluster endpoint and auth data.
kubeconfig entry generated for my-project-gke.

node-pools의 정보 조회

$ gcloud container node-pools list \
  --cluster=$PROJECT_ID-gke \
  --project=$PROJECT_ID \
  --region=$REGION
NAME                         MACHINE_TYPE  DISK_SIZE_GB  NODE_VERSION
my-project-gke-node-pool     n1-standard-4     100           1.23.13-gke.900

3개의 node 정보를 정상적으로 가져오는것을 확인할 수 있습니다.

$ kubectl get nodes
NAME                                    STATUS   ROLES    AGE   VERSION
gke-asia--default-pool-23b72450-009z    Ready    <none>   10d   v1.22.15-gke.2500
gke-asia--default-pool-23b72450-7f6p    Ready    <none>   10d   v1.22.15-gke.2500
gke-asia--default-pool-23b72450-7xsi    Ready    <none>   10d   v1.22.15-gke.2500
변경하기

이번에는 GKE cluster의 설정을 변경해보겠습니다.
Machine type : n1-standard-4 -> n1-highmem-4

적용전에 검증을 합니다.
기존 machine type의 node_pool을 삭제하고 새로운 node_pool이 추가되는 것을 확인.

$ terraform plan \
    -var "project_id=$PROJECT_ID" \
    -var "region=$REGION" \
    -var "gke_num_nodes=1" \
    -var "gke_machine_type=n1-highmem-4"
...
Terraform will perform the following actions:
  # google_container_node_pool.primary_nodes must be replaced
  ~ machine_type      = "n1-standard-4" -> "n1-highmem-4" # forces replacement

Plan: 1 to add, 0 to change, 1 to destroy.
$ terraform apply \
    -var "project_id=$PROJECT_ID" \
    -var "region=$REGION" \
    -var "gke_num_nodes=1" \
    -var "gke_machine_type=n1-highmem-4"
...
Plan: 1 to add, 0 to change, 1 to destroy.

Do you want to perform these actions?
  Terraform will perform the actions described above.
  Only 'yes' will be accepted to approve.

  Enter a value: yes

google_container_node_pool.primary_nodes: Destroying... [id=projects/my-project/locations/asia-northeast3/clusters/my-project-gke/nodePools/my-project-gke-node-pool]
...
google_container_node_pool.primary_nodes: Creation complete after 1m22s [id=projects/my-project/locations/asia-northeast3/clusters/my-project-gke/nodePools/my-project-gke-node-pool]
...
Apply complete! Resources: 1 added, 0 changed, 1 destroyed.

Outputs:

kubernetes_cluster_name = my-project-gke

기존 node pool을 삭제하고 새로운 node pool을 생성하는것이 확인됩니다.

참고
node pool이 삭제되면서 실행중인 pod도 전부 삭제됩니다.
실제 개발/운영 환경이라면 node pool을 여러개 만들어 놓고 변경 작업이 일어나는 node의 pod를 모두 다른 node로 migration하는 작업이 선행되어야 합니다.

변경 작업이 완료되면 node pool을 다시 조회해봅니다.
Machine type이 n1-highmem-4로 변경되었습니다.

$ gcloud container node-pools list \
  --cluster=$PROJECT_ID-gke \
  --project=$PROJECT_ID \
  --region=$REGION
NAME                        MACHINE_TYPE   DISK_SIZE_GB    NODE_VERSION
my-project-gke-node-pool    n1-highmem-4       100       1.23.13-gke.900
삭제하기

## cluster삭제

$ terraform destroy \
    -var "project_id=$PROJECT_ID" \
    -var "region=$REGION"
...
Do you really want to destroy all resources?
  Terraform will destroy all your managed infrastructure, as shown above.
  There is no undo. Only 'yes' will be accepted to confirm.

  Enter a value: yes
  ...
Destroy complete! Resources: 4 destroyed.
문의하기 베스픽 구독하기
궁금한 점이 있다면 클릭해주세요.