Edited at

Terraformを使ってGKEクラスタを作成する


概要

あえてGoogle Cloud SDKを使わずにTerraformを使ってGKEクラスタを作成したので、そのときのメモ書きです。


前提

OS: macOS 10.14.4

Terraformバージョン: v0.11.13


事前知識


Terraformとは

クラウドプロバイダ上(AWSやGCPなど)のインフラ構成を管理・自動化できるツール。

例えばGCP上にインスタンスを作成したい場合、インスタンスの種類や数などの設定をファイルに定義しておいてそれを実行すれば自動でインスタンスを作成できます。

IaaSだけでなくPaaSやCaaSなども可能。


Kubernetesとは

公式サイトより。


Kubernetes (K8s)は、デプロイやスケーリングを自動化したり、コンテナ化されたアプリケーションを管理したりするための、オープンソースのシステムです。


Kubernetesは奥が深いので詳しい説明はここでは割愛。


GKEとは

Google Kubernetes Engine。

GCP上でKubernetes環境を利用できるようにしたマネージド型のサービス。

Web UI上から簡単に操作するだけでKubernetes環境を立ち上げることができます。

今回はその辺の操作をTerraformを使って自動化します。


今回作成するGKEクラスタ構成

料金を安く済ませることを軸に以下のように設定しました。

設定項目
設定値

マシンタイプ
f1-micro

プリエンプティブノード数
2

通常ノード数
1

ゾーン
us-west1-a

以下の記事を参考に算出。

これだけだとなぜこの設定値にしたのか不明なので少し解説。


マシンタイプ

マシンタイプは安く済ませるためと、後述するGCPのAlways Free枠を使って1台インスタンスを稼働させるために最低ランクのf1-microにしました。


ノードについて

今回は通常ノードとプリエンプティブノードの2種類を使ってクラスタを構成しました。

なぜ通常ノードだけではないかというと、プリエンプティブノードの料金が圧倒的に安いからです。

そもそもプリエンプティブノードとは、GCEの余ったリソースを使って立てられるインスタンスであり、他のタスクがリソースを必要とする場合は強制的にシャットダウンさせられます。そのため、使い勝手はあまり良くないです。

しかし、Kubernetesとして稼働させればKubernetesのオートヒーリング機能によって自動で復旧することができるので、そこまで不便に感じずに利用することができます。

ただし、全てプリエンプティブなノードにしてしまうと、全ノードが落ちたときに復旧できなくなるので、1台は常に稼働している通常ノードを確保しています。

そして、f1-microであればGCPのAlways Free枠で常に1台無料で利用できるため、通常ノードの1台をこれにあてています。

したがって今回はこのようなプリエンプティブなノードと通常ノードでの構成となりました。


ゾーン

GCPのAlways Free枠を利用するためにus-west1-aを指定します。


実際にやってみた


プロジェクトの作成

GCP上でプロジェクトを作成します。

そして発行されるプロジェクトIDを控えます。


Terraformのインストール

homebrewでインストールできるのでインストールします。

$ brew install terraform


設定ファイルの作成

GCP上にGKEクラスタを作成する設定内容をファイルに書いていきます。

Terraformでは*.tfという拡張子ファイルに設定を記述していきます。


プロバイダの設定

provider "google" {

project = "<プロジェクトID>"
region = "us-west1"
zone = "us-west1-a"
}

設定を適用するクラウドプロバイダの設定を記述します。

今回はGCPの設定を書きます。

ここで設定する項目はデフォルトの設定値となるため、後述するリソースに設定されていれば書かなくても問題はないです。

設定項目
内容

project
適用するデフォルトのプロジェクトID

region
適用するデフォルトのリージョン

zone
適用するデフォルトのゾーン


変数の設定

後述するリソースの設定で共通の設定値が出てくるので先に変数化しておきます。

Terraformではvariableブロックを使って変数を定義します。

variable "location" {

type = "string"
default = "us-west1-a"
}

変数を呼び出すときはvar.<変数名>という形で呼び出すことができます。


リソースの設定

クラスタ、通常ノード、プリエンプティブノードの3つの設定を書きます。


クラスタ

google_container_clusterリソースで設定します。

resource "google_container_cluster" "primary" {

name = "my-gke-cluster"
location = "${var.location}"

remove_default_node_pool = true
initial_node_count = 1

master_auth {
username = ""
password = ""
}
}

設定項目
内容

必須 or 任意

name
クラスタ名
string
必須

location
マスタクラスタのゾーンもしくはリージョンを指定
ゾーンの場合は1ゾーンのみでクラスタが作成される
リージョンの場合はその中の複数ゾーン跨る形でクラスタが作成される
string
任意

remove_default_node_pool
trueの場合クラスタ作成時にデフォルトのノードプールを削除する
bool
任意

initial_node_count
デフォルトのノードプールに作成されるノード数
remove_default_node_poolをtrueにした場合は1以上を設定する必要がある
number
任意

master_auth.username
Kubernetes masterにアクセスするときのbasic認証に使用するユーザ名を指定する
string
任意

master_auth.password
Kubernetes masterにアクセスするときのbasic認証に使用するパスワードを指定する
string
任意


通常ノード

google_container_node_poolリソースで設定します。

resource "google_container_node_pool" "primary_nodes" {

name = "my-gke-node-pool"
location = "${var.location}"
cluster = "${google_container_cluster.primary.name}"
node_count = 1

management {
auto_repair = true
}

node_config {
machine_type = "f1-micro"

metadata {
disable-legacy-endpoints = "true"
}

oauth_scopes = [
"https://www.googleapis.com/auth/logging.write",
"https://www.googleapis.com/auth/monitoring",
]
}
}

設定項目
内容

必須 or 任意

name
ノードプール名
string
任意

cluster
ノードプールを作成するクラスタ名
string
必須

location
クラスタが存在するリージョンもしくはゾーンを指定
string
任意

node_count
ノード数
number
任意

management.auto_repair
trueの場合ノードが自動修復される
bool
任意

node_config.machine_type
GCEのマシンタイプを指定
string
任意

node_config.metadata
クラスタ内のインスタンスに渡すメタデータをkey/value形式で指定する
object
任意

node_config.oauth_scopes
デフォルトサービスアカウントが利用できるGoogle APIのスコープを書く
list
任意


プリエンプティブノード

google_container_node_poolリソースで設定します。

設定項目はほとんど通常ノードと同じですが、唯一node_config.preemtpible項目をtrueに設定しています。

resource "google_container_node_pool" "primary_preemptible_nodes" {

name = "my-gke-preemptible-node-pool"
location = "${var.location}"
cluster = "${google_container_cluster.primary.name}"
node_count = 2

management {
auto_repair = true
}

node_config {
preemptible = true
machine_type = "f1-micro"

metadata {
disable-legacy-endpoints = "true"
}

oauth_scopes = [
"https://www.googleapis.com/auth/logging.write",
"https://www.googleapis.com/auth/monitoring",
]
}
}

設定項目
内容

必須 or 任意

node_config.preemptible
trueの場合プリエンプティブなノードとなる
デフォルトはfalse
bool
任意


最終的なtfファイル


gke.tf

provider "google" {

project = "<プロジェクトID>"
region = "us-west1"
zone = "us-west1-a"
}

variable "location" {
type = "string"
default = "us-west1-a"
}

resource "google_container_cluster" "primary" {
name = "my-gke-cluster"
location = "${var.location}"

remove_default_node_pool = true
initial_node_count = 1

master_auth {
username = ""
password = ""
}
}

resource "google_container_node_pool" "primary_nodes" {
name = "my-gke-node-pool"
location = "${var.location}"
cluster = "${google_container_cluster.primary.name}"
node_count = 1

management {
auto_repair = true
}

node_config {
machine_type = "f1-micro"

metadata {
disable-legacy-endpoints = "true"
}

oauth_scopes = [
"https://www.googleapis.com/auth/logging.write",
"https://www.googleapis.com/auth/monitoring",
]
}
}

resource "google_container_node_pool" "primary_preemptible_nodes" {
name = "my-gke-preemptible-node-pool"
location = "${var.location}"
cluster = "${google_container_cluster.primary.name}"
node_count = 2

management {
auto_repair = true
}

node_config {
preemptible = true
machine_type = "f1-micro"

metadata {
disable-legacy-endpoints = "true"
}

oauth_scopes = [
"https://www.googleapis.com/auth/logging.write",
"https://www.googleapis.com/auth/monitoring",
]
}
}



サービスアカウントの作成

TerraformがGCP APIを叩く用のサービスアカウントをこちらから作成します。

作成後、JSONファイルをダウンロードし、パスを環境変数にセットします。


.zshrc

export GOOGLE_CLOUD_KEYFILE_JSON={{path}}



初期化

リソースを操作するためのプラグインを導入するために最初だけ初期化をしてあげる必要があります。

tfファイルがある配下で以下コマンドを実行します。

$ terraform init

すると、直下に.terraformディレクトリが作成されます。これが作成されれば初期化は完了です。


実行計画

実際に適用する時のdry run的なものを確認できます。

$ terraform plan

実行すると以下のように表示されるので、これを見て実行内容が正しいか確認します。

Refreshing Terraform state in-memory prior to plan...

The refreshed state will be used to calculate this plan, but will not be
persisted to local or remote state storage.

------------------------------------------------------------------------

An execution plan has been generated and is shown below.
Resource actions are indicated with the following symbols:
+ create

Terraform will perform the following actions:

+ google_container_cluster.primary
id: <computed>
additional_zones.#: <computed>
addons_config.#: <computed>
cluster_autoscaling.#: <computed>
cluster_ipv4_cidr: <computed>
enable_binary_authorization: <computed>
enable_kubernetes_alpha: "false"
enable_legacy_abac: "false"
enable_tpu: <computed>
endpoint: <computed>
initial_node_count: "1"
instance_group_urls.#: <computed>
ip_allocation_policy.#: <computed>
location: "us-west1-a"
logging_service: <computed>
master_auth.#: "1"
master_auth.0.client_certificate: <computed>
master_auth.0.client_key: <computed>
master_auth.0.cluster_ca_certificate: <computed>
master_version: <computed>
monitoring_service: <computed>
name: "my-gke-cluster"
network: "default"
network_policy.#: <computed>
node_config.#: <computed>
node_locations.#: <computed>
node_pool.#: <computed>
node_version: <computed>
project: <computed>
region: <computed>
remove_default_node_pool: "true"
zone: <computed>

+ google_container_node_pool.primary_nodes
id: <computed>
cluster: "my-gke-cluster"
initial_node_count: <computed>
instance_group_urls.#: <computed>
location: "us-west1-a"
management.#: "1"
management.0.auto_repair: "true"
management.0.auto_upgrade: "false"
max_pods_per_node: <computed>
name: "my-gke-node-pool"
name_prefix: <computed>
node_config.#: "1"
node_config.0.disk_size_gb: <computed>
node_config.0.disk_type: <computed>
node_config.0.guest_accelerator.#: <computed>
node_config.0.image_type: <computed>
node_config.0.local_ssd_count: <computed>
node_config.0.machine_type: "f1-micro"
node_config.0.metadata.%: "1"
node_config.0.metadata.disable-legacy-endpoints: "true"
node_config.0.oauth_scopes.#: "2"
node_config.0.oauth_scopes.1277378754: "https://www.googleapis.com/auth/monitoring"
node_config.0.oauth_scopes.172152165: "https://www.googleapis.com/auth/logging.write"
node_config.0.preemptible: "false"
node_config.0.service_account: <computed>
node_count: "1"
project: <computed>
region: <computed>
version: <computed>
zone: <computed>

+ google_container_node_pool.primary_preemptible_nodes
id: <computed>
cluster: "my-gke-cluster"
initial_node_count: <computed>
instance_group_urls.#: <computed>
location: "us-west1-a"
management.#: "1"
management.0.auto_repair: "true"
management.0.auto_upgrade: "false"
max_pods_per_node: <computed>
name: "my-gke-preemptible-node-pool"
name_prefix: <computed>
node_config.#: "1"
node_config.0.disk_size_gb: <computed>
node_config.0.disk_type: <computed>
node_config.0.guest_accelerator.#: <computed>
node_config.0.image_type: <computed>
node_config.0.local_ssd_count: <computed>
node_config.0.machine_type: "f1-micro"
node_config.0.metadata.%: "1"
node_config.0.metadata.disable-legacy-endpoints: "true"
node_config.0.oauth_scopes.#: "2"
node_config.0.oauth_scopes.1277378754: "https://www.googleapis.com/auth/monitoring"
node_config.0.oauth_scopes.172152165: "https://www.googleapis.com/auth/logging.write"
node_config.0.preemptible: "true"
node_config.0.service_account: <computed>
node_count: "2"
project: <computed>
region: <computed>
version: <computed>
zone: <computed>

Plan: 3 to add, 0 to change, 0 to destroy.

------------------------------------------------------------------------


実行

実際に適用します。

途中でDo you want to perform these actions?と聞かれるので問題ない場合はyesと答えます。

$ terraform apply

最後に以下のように表示されれば成功です。

Apply complete! Resources: 3 added, 0 changed, 0 destroyed.


補足情報


tfstateファイルについて

Terraformは*.tfstateという拡張子のファイルで現在の環境を認識します。

そのため、tfstateファイルは削除すると実際の環境情報と差異が出てしまうので絶対に削除してはいけません

tfstateファイルはクラウドストレージなどリモートで保管することが推奨されています。

GCSで管理するやり方をこちらにまとめてあります。


リソースの破棄

リソースの破棄は以下コマンドで実現できます。

$ terraform destroy

dry run的に確認する場合は以下で実現できます。

$ terraform plan -destroy


tfファイルのフォーマットに関するvimプラグイン

tfファイルをvimで修正する場合、以下プラグインを入れるとフォーマットや色付けがされて便利です。

hashivim/vim-terraform: basic vim/terraform integration

以上