はじめに
GKE を構築する際、実際に適用されている設定を管理したいので Terraform を使って GKE を構築していきます。
Terraform には Module として GKE が提供されていますが、今回は素の Terraform で構築していきます。
本記事の作成に当たって JapanContainerDays v18.12 で企画された「showKs」の Terraform のリポジトリが非常に参考になりました。
ありがとうございます。
GitHub - containerdaysjp/showks-terraform: Terraform configurations to provision showk environments.
他にもクラウドネイティブな要素の詰まったリポジトリがあるので非常に参考になると思います。
それでは、Teraform を使って GKE の構築と Guestbook アプリケーションをデプロイして動作確認までを試してみます。
環境
- macOS High Sierra Version 10.13.6
- Terraform v0.11.13
- Homebrew 2.0.6
- Google Cloud SDK 240.0.0
Google Cloud SDK をインストールする
以下のドキュメントを参考に Google Cloud SDK をインストールし、プロジェクトの設定をしてください。
Google Cloud SDK documentation
API を有効にする
以下の API を有効にします。
- Kubernetes Engine API
以下のコマンドで API を有効にします。
$ gcloud services enable \
container.googleapis.com
Terraform のインストール
Terraform をインストールします。
今回は Mac 環境なので、Homebrew でインストールしていきます。
$ brew install terraform
Terraform のサービスアカウントを作成する
Terraform が使用するサービスアカウントを作成します。
$ GCP_PROJECT=$(gcloud info --format='value(config.project)')
$ TERRAFORM_SA=terraform-service-account
$ gcloud iam service-accounts create $TERRAFORM_SA \
--project=$GCP_PROJECT \
--display-name $TERRAFORM_SA
作成した Terraform のサービスアカウントに以下のロールを付与します。
roles/iam.serviceAccountUser
roles/compute.admin
roles/storage.admin
roles/container.clusterAdmin
$ TERRAFORM_SA_EMAIL=$(gcloud iam service-accounts list \
--project=$GCP_PROJECT \
--filter="displayName:$TERRAFORM_SA" \
--format='value(email)')
$ gcloud projects add-iam-policy-binding $GCP_PROJECT \
--role roles/iam.serviceAccountUser \
--member serviceAccount:$TERRAFORM_SA_EMAIL
$ gcloud projects add-iam-policy-binding $GCP_PROJECT \
--role roles/compute.admin \
--member serviceAccount:$TERRAFORM_SA_EMAIL
$ gcloud projects add-iam-policy-binding $GCP_PROJECT \
--role roles/storage.admin \
--member serviceAccount:$TERRAFORM_SA_EMAIL
$ gcloud projects add-iam-policy-binding $GCP_PROJECT \
--role roles/container.clusterAdmin \
--member serviceAccount:$TERRAFORM_SA_EMAIL
.tfstate ファイルを管理する Google Cloud Storage のバケットを作成する
Terraform では、管理しているリソース状態を .tfstate
という拡張子を持つファイルに管理します。
デフォルトではローカルに保存されますが、共有できないためリモートに管理します。
今回は、Google Cloud Storage(GCS)をリモート先として .tfstate
を管理するため GCS バケットを作成します。
バケット名は、GCS 全体で一意である必要があることに注意してください。
サンプルとして tf-state-prod
という名前で作成しています。
$ GCS_CLASS=multi_regional
$ GCS_BUCKET=tf-state-prod
$ gsutil mb -p $GCP_PROJECT -c $GCS_CLASS -l asia gs://$GCS_BUCKET/
.tf ファイルを作成する
変数を定義する
各リソースで必要な変数を定義する variables.tf
ファイルを作成します。
GKE のバージョンは、執筆時点(2019/03)の最新 1.12.6-gke.7
を使用します。
variable "project" {}
variable "cluster_name" {
default = "cluster"
}
variable "location" {
default = "asia-northeast1-a"
}
variable "network" {
default = "default"
}
variable "primary_node_count" {
default = "3"
}
variable "machine_type" {
default = "n1-standard-1"
}
variable "min_master_version" {
default = "1.12.6-gke.7"
}
variable "node_version" {
default = "1.12.6-gke.7"
}
GCP のプロバイダ情報を定義する
GCP のプロバイダを利用するに当たって provider.tf
ファイルを作成します。
provider "google" {
project = "${var.project}"
region = "${var.location}"
}
Backend を定義する
.tfstate
ファイルを管理するための Backend を定義する backend.tf
ファイルを作成します。
今回は、GCS を Backend に利用します。
バケット名は、事前に作成した GCS バケット名を指定します。
terraform {
backend "gcs" {
bucket = "tf-state-prod"
prefix = "terraform/state"
}
}
GKE を定義する
GKE を定義するための gke.tf
ファイルを作成します。
resource "google_container_cluster" "primary" {
name = "primary-${var.cluster_name}"
location = "${var.location}"
remove_default_node_pool = true
initial_node_count = 1
network = "${var.network}"
min_master_version = "${var.min_master_version}"
node_version = "${var.node_version}"
master_auth {
username = ""
password = ""
client_certificate_config {
issue_client_certificate = false
}
}
}
resource "google_container_node_pool" "primary_nodes" {
name = "primary-${var.cluster_name}-nodes"
location = "${var.location}"
cluster = "${google_container_cluster.primary.name}"
node_count = "${var.primary_node_count}"
management {
auto_repair = true
}
node_config {
oauth_scopes = [
"https://www.googleapis.com/auth/devstorage.read_only",
"https://www.googleapis.com/auth/logging.write",
"https://www.googleapis.com/auth/monitoring",
"https://www.googleapis.com/auth/service.management.readonly",
"https://www.googleapis.com/auth/servicecontrol",
"https://www.googleapis.com/auth/trace.append",
]
machine_type = "${var.machine_type}"
metadata {
disable-legacy-endpoints = "true"
}
}
}
GKE 作成
Terraform のサービスアカウントの json ファイルを作成します。
$ TERRAFORM_SA_DEST=~/.gcp/terraform-service-account.json
$ mkdir -p $(dirname $TERRAFORM_SA_DEST)
$ TERRAFORM_SA_EMAIL=$(gcloud iam service-accounts list \
--filter="displayName:$TERRAFORM_SA" \
--format='value(email)')
$ gcloud iam service-accounts keys create $TERRAFORM_SA_DEST \
--iam-account $TERRAFORM_SA_EMAIL
作成したサービスアカウントの json ファイルのパスを GOOGLE_APPLICATION_CREDENTIALS
の環境変数にセットします。
$ export GOOGLE_APPLICATION_CREDENTIALS=$TERRAFORM_SA_DEST
Terraform の設定を元に初期セットアップを行います。
この時点で .tfstate
ファイルが GCS に展開されます。
$ terraform init
GKE を作成する前に variables.tf
ファイルで default 値を定義していない値を環境変数にセットします。
default 値を定義していない変数はコマンドライン引数や terraform.tfvars
ファイルから渡すことも可能です。
環境変数の場合は、変数名の prefix に TF_VAR_
が必要です。
$ export TF_VAR_project=$GCP_PROJECT
まずは、terraform plan
コマンドで変更内容の確認をします。
$ terraform plan
問題なければ terraform apply
コマンドで GKE を作成します。
yes
で実行します。
$ terraform apply
Guestbook アプリケーションをデプロイして確認する
Terraform で作成した GKE に対して以下のリポジトリに存在する Guestbook アプリケーションをデプロイします。
GitHub - kubernetes/examples: Kubernetes application example tutorials
デプロイする前に作成した GKE クラスタの認証情報を取得します。
$ gcloud container clusters get-credentials primary-cluster
Redis master をセットアップする
Guestbook アプリケーションは Redis を使用しています。
Redis master にデータを書き込み、Redis worker からデータを読み込む構成です。
Redis master のデプロイ
Redis master をデプロイします。
$ kubectl apply -f https://raw.githubusercontent.com/kubernetes/examples/master/guestbook/redis-master-deployment.yaml
作成した Pod が 1/1 Running
になるまで待機します。
$ kubectl get po
NAME READY STATUS RESTARTS AGE
redis-master-57fc67768d-75dlf 1/1 Running 0 22s
表示した Pod 名から Redis master のログが表示されていることを確認します。
$ kubectl logs -f redis-master-57fc67768d-75dlf
Redis master のサービスを作成
Redis master のサービスを作成します。
$ kubectl apply -f https://raw.githubusercontent.com/kubernetes/examples/master/guestbook/redis-master-service.yaml
Redis master のサービスが作成されたことを確認します。
$ kubectl get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 10.55.240.1 <none> 443/TCP 22m
redis-master ClusterIP 10.55.245.172 <none> 6379/TCP 52s
Redis worker をセットアップする
Redis worker は、複数のレプリカを作成し可用性を高めています。
Redis worker のデプロイ
Redis worker をデプロイします。
$ kubectl apply -f https://raw.githubusercontent.com/kubernetes/examples/master/guestbook/redis-slave-deployment.yaml
作成した Pod が 1/1 Running
になるまで待機します。
$ kubectl get po
NAME READY STATUS RESTARTS AGE
redis-master-57fc67768d-75dlf 1/1 Running 0 15m
redis-slave-57f9f8db74-fx2d7 1/1 Running 0 14s
redis-slave-57f9f8db74-gwmgk 1/1 Running 0 14s
Redis worker のサービスを作成
Redis master のサービスを作成します。
$ kubectl apply -f https://raw.githubusercontent.com/kubernetes/examples/master/guestbook/redis-slave-service.yaml
Redis master のサービスが作成されたことを確認します。
$ kubectl get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 10.55.240.1 <none> 443/TCP 28m
redis-master ClusterIP 10.55.245.172 <none> 6379/TCP 6m41s
redis-slave ClusterIP 10.55.255.148 <none> 6379/TCP 12s
Guestbook のフロントエンドアプリケーションをセットアップする
Guestbook のウェブサーバーを起動します。
フロントエンドは、PHP でできたアプリケーションです。
読み書きに応じて Redis master や Redis worker と通信します。
フロントエンドアプリケーションのデプロイ
フロントエンドアプリケーションをデプロイします。
$ kubectl apply -f https://raw.githubusercontent.com/kubernetes/examples/master/guestbook/frontend-deployment.yaml
作成した Pod が 1/1 Running
になるまで待機します。
$ kubectl get po -l app=guestbook -l tier=frontend
NAME READY STATUS RESTARTS AGE
frontend-654c699bc8-4qjpc 1/1 Running 0 37s
frontend-654c699bc8-rqznb 1/1 Running 0 37s
frontend-654c699bc8-txsvq 1/1 Running 0 37s
フロントエンドアプリケーションのサービスを作成
Guestbook のフロントエンドは外部に公開する必要があります。
そこで外部からリクエストできるようにサービスの設定を type: LoadBalancer
に指定します。
以下のように frontend-service.yaml
をダウンロードして、type: LoadBalancer
のコメントアウトを解除、type: NodePort
をコメントアウトします。
$ wget https://raw.githubusercontent.com/kubernetes/examples/master/guestbook/frontend-service.yaml
$ sed -i "" -e "s/# type: LoadBalancer/type: LoadBalancer/" frontend-service.yaml
$ sed -i "" -e "s/type: NodePort/# type: NodePort/" frontend-service.yaml
編集した frontend-service.yaml
でサービスを作成します。
$ kubectl apply -f frontend-service.yaml
フロントエンドアプリケーションのサービスが作成されたことを確認します。
作成したサービスの EXTERNAL-IP
が表示されるまで待機します。
$ kubectl get svc frontend
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
frontend LoadBalancer 10.55.244.103 35.187.206.29 80:31533/TCP 47s
Guestbook アプリケーションにアクセスする
EXTERNAL-IP
の IP アドレスに対してブラウザから接続すると以下のような Guestbook アプリケーションが表示されます。
以上で Terraform で GKE を構築し、Guestbook アプリケーションが動作することを確認しました。
作成したリソースの削除
作成したリソースを削除します。
Guestbook アプリケーションの削除
フロントエンドアプリケーションのサービスを削除します。
$ kubectl delete svc frontend
削除コマンド実行後サービスが削除されるまで時間が掛かるので、以下のコマンドで削除されるまで確認します。
$ gcloud compute forwarding-rules list
GKE クラスタの削除
Terraform で作成した GKE クラスタを削除します。
yes
で削除します。
$ terraform destroy
GCS バケットの削除
GCS バケットを削除します。
$ gsutil rm -r gs://$GCS_BUCKET/
サービスアカウントの削除
サービスアカウントに紐付けたロールを削除します。
$ gcloud projects remove-iam-policy-binding $GCP_PROJECT \
--role roles/iam.serviceAccountUser \
--member serviceAccount:$TERRAFORM_SA_EMAIL
$ gcloud projects remove-iam-policy-binding $GCP_PROJECT \
--role roles/compute.admin \
--member serviceAccount:$TERRAFORM_SA_EMAIL
$ gcloud projects remove-iam-policy-binding $GCP_PROJECT \
--role roles/storage.admin \
--member serviceAccount:$TERRAFORM_SA_EMAIL
$ gcloud projects remove-iam-policy-binding $GCP_PROJECT \
--role roles/container.clusterAdmin \
--member serviceAccount:$TERRAFORM_SA_EMAIL
サービスアカウントを削除します。
y
で削除します。
$ gcloud iam service-accounts delete $TERRAFORM_SA_EMAIL
参考
Provider: Google Cloud Platform - Terraform by HashiCorp
Terraform で GCP 環境を構築してみる | GMO アドパートナーズグループ TECH BLOG byGMO
Cloud Storage documentation | Cloud Storage
Create a Guestbook with Redis and PHP | Kubernetes Engine Tutorials
GitHub - containerdaysjp/showks-terraform: Terraform configurations to provision showk environments.