建立GKE的部署管道
首先
這是我建立GKE構建流程時的筆記。
由於這是我的個人備忘錄,所以與我參考的Qiita文章有很多重複的部分。
這次我使用了「Terraform」作為GKE構建工具,並使用「Github Actions」作為流程執行環境。
环境
关于在管道上使用的环境,由于源代码中有记录,只需在本地操作时写下所需的内容:
* macOS Catalina 版本 10.15.4
* fish (使用的 Shell)
* Homebrew 2.2.10
* Google Cloud SDK 272.0.0
* gsutil 版本: 4.46
* kubectl v1.15.5
事先准备
gcloud的安装
利用Homebrew进行安装。
$ brew cask install google-cloud-sdk
# 利用するシェルに応じたpathの設定
# fishの場合は、 ~/.config/fish/config.fshに以下の内容を記述
source /usr/local/Caskroom/google-cloud-sdk/latest/google-cloud-sdk/path.fish.inc
启用Kubernetes引擎API
gcloud services enable container.googleapis.com
Kubernetes Engine API 文件 (Kubernetes Engine API document)
谷歌云存储
为了使用Terraform来构建GKE,将GCS作为state文件的存储位置。
将创建一个名为tf-state-location的存储桶。
# バケットのタイプと名前を環境変数に設定
$ set GCS_CLASS multi_regional
$ set GCS_BUCKET_NAME tf-state-location
# タイプと名前を引数にバケットを作成
$ gsutil mb -p $GCP_PROJECT -c $GCS_CLASS -l us gs://$GCS_BUCKET_NAME/
服务账户
创建一个服务账号作为流水线的执行用户。
创建服务账号
将服务账户名称设置为gke-terraform-service-account。
# GCPにプロジェクト名を取得して環境変数に設定
$ set GCP_PROJECT (gcloud info --format='value(config.project)')
# サービスアカウント名を環境変数に設定
$ set TERRAFORM_SA gke-terraform-service-account
# プロジェクトと名前を引数にサービスアカウント を作成
$ gcloud iam service-accounts create $TERRAFORM_SA --project=$GCP_PROJECT --display-name $TERRAFORM_SA
# 作成したサービスアカウントのID情報を環境変数に設定(後の章利用する)
$ set TERRAFORM_SA_EMAIL (gcloud iam service-accounts list --project=$GCP_PROJECT --filter="displayName:$TERRAFORM_SA" --format='value(email)')
授予服务账号权限
为了让服务账号成为执行用户,需要为GCP授予必要的权限。
授予关于GKE创建的权限
$ 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
# 結果確認用
gcloud projects get-iam-policy $GCP_PROJECT \
--flatten="bindings[].members" \
--filter="bindings.members:serviceAccount:$TERRAFORM_SA_EMAIL" \
--format='table(bindings.members,bindings.role)'
授予对GCS存储空间的权限。
为了访问作为管道中的状态文件存储库而准备的GCS存储桶,需要授予服务帐号相应的权限。
# バケットに対するAdmin権限を付与する(serviceaccountがstorage.adminロールを持っているためやらなくても可)
$ gsutil iam ch serviceAccount:$TERRAFORM_SA_EMAIL:objectAdmin gs://$GCS_BUCKET_NAME/
创建服务帐户密钥文件(JSON)。
在执行 Terraform 时需要创建服务帐户的密钥。
# key作成場所のディレクトリ情報を環境変数に設定して、ディレクトリ作成
$ set TERRAFORM_SA_DEST ~/.gcp/terraform-service-account.json
$ mkdir -p (dirname $TERRAFORM_SA_DEST)
# サービスアカウントのkeyファイルを指定したディレクトリに作成
$ gcloud iam service-accounts keys create $TERRAFORM_SA_DEST --iam-account $TERRAFORM_SA_EMAIL
构建GKE部署流程
这一章介绍的代码已经在以下的Git仓库上公开。
readme中也包含了参考的官方页面等信息。
https://github.com/sabure500/gke-terraform
地球成形
可以根据以下的Terraform官方提供的GKE示例代码创建.tf文件。
google_container_cluster
环境变量的定义
在Terraform中定义用于使用的环境变量。
variable "project" {}
variable "cluster_name" {
default = "my-gke-cluster"
}
variable "location" {
default = "us-west1-a"
}
variable "machine_type" {
default = "f1-micro"
}
variable "preemptible_machine_type" {
default = "e2-small"
}
variable "network" {
default = "default"
}
variable "min_master_version" {
default = "1.15.11-gke.3"
}
variable "node_version" {
default = "1.15.11-gke.3"
}
GCP供应商信息的定义
provider "google" {
version = "3.17.0"
project = var.project
region = var.location
}
后端(tfstate文件的存储位置)的定义
定义一个后端来管理.tfstate文件。
指定存储桶名称为预先创建的GCS存储桶名称。
terraform {
backend "gcs" {
bucket = "tf-state-location"
prefix = "terraform/gke"
}
}
GKE的定义
请参阅Git存储库内的自述文件以获取有关描述的详细信息。
terraform {
required_version = "0.12.24"
}
resource "google_container_cluster" "primary" {
name = 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
monitoring_service = "none"
logging_service = "none"
master_auth {
username = ""
password = ""
client_certificate_config {
issue_client_certificate = false
}
}
}
resource "google_container_node_pool" "primary_nodes" {
name = "${var.cluster_name}-node-pool"
location = var.location
cluster = google_container_cluster.primary.name
node_count = 1
management {
auto_repair = true
}
node_config {
machine_type = var.machine_type
oauth_scopes = [
"https://www.googleapis.com/auth/devstorage.read_only",
"https://www.googleapis.com/auth/logging.write",
"https://www.googleapis.com/auth/monitoring"
]
}
}
resource "google_container_node_pool" "primary_preemptible_nodes" {
name = "${var.cluster_name}-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 = var.preemptible_machine_type
oauth_scopes = [
"https://www.googleapis.com/auth/devstorage.read_only",
"https://www.googleapis.com/auth/logging.write",
"https://www.googleapis.com/auth/monitoring",
]
}
}
Github Actions 是一种云原生工作流自动构建和部署的策略。
使用 Github Actions 运行利用上述.tf文件创建的 Terraform。
使用 Github Actions 执行 Terraform 参考以下官方示例。
Terraform Github Actions 入门指南。
创建用于测试的工作
在除了主分支以外的地方,创建一个执行terraform的init、validate和plan的工作。
name: 'terraform-test'
on:
push:
branches-ignore:
- master
env:
TERRAFORM_VERSION: 0.12.24
TF_VAR_project: ${{secrets.PROJECT}}
GOOGLE_CREDENTIALS: ${{secrets.GOOGLE_CREDENTIALS}}
jobs:
terraform:
name: 'terraform-test'
runs-on: ubuntu-latest
steps:
- name: 'Checkout'
uses: actions/checkout@v1
- name: 'Terraform Format'
uses: hashicorp/terraform-github-actions@master
with:
tf_actions_version: 0.12.24
tf_actions_subcommand: 'fmt'
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: 'Terraform Init'
uses: hashicorp/terraform-github-actions@master
with:
tf_actions_version: 0.12.24
tf_actions_subcommand: 'init'
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: 'Terraform Validate'
uses: hashicorp/terraform-github-actions@master
with:
tf_actions_version: 0.12.24
tf_actions_subcommand: 'validate'
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: 'Terraform Plan'
uses: hashicorp/terraform-github-actions@master
with:
tf_actions_version: 0.12.24
tf_actions_subcommand: 'plan'
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
应聘这份工作
创建一个当推送到主分支时执行terraform的init和apply的作业。
name: 'terraform-apply'
on:
push:
branches:
- master
# APIアクセスでイベント発火ができる条件
repository_dispatch:
types: [apply]
env:
TERRAFORM_VERSION: 0.12.24
TF_VAR_project: ${{secrets.PROJECT}}
GOOGLE_CREDENTIALS: ${{secrets.GOOGLE_CREDENTIALS}}
jobs:
terraform:
name: 'terraform-apply'
runs-on: ubuntu-latest
steps:
- name: 'Checkout'
uses: actions/checkout@v1
- name: 'Terraform Init'
uses: hashicorp/terraform-github-actions@master
with:
tf_actions_version: 0.12.24
tf_actions_subcommand: 'init'
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: 'Terraform Plan'
uses: hashicorp/terraform-github-actions@master
with:
tf_actions_version: 0.12.24
tf_actions_subcommand: 'plan'
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: 'Terraform Apply'
uses: hashicorp/terraform-github-actions@master
with:
tf_actions_version: 0.12.24
tf_actions_subcommand: 'apply'
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
用于删除集群的作业
为了准备这个GKE集群用于学习,我们需要准备一个任务,使其可以轻松地删除集群,而不需要将其推送到Git上。
name: 'terraform-destroy'
on:
# APIアクセスでイベント発火ができる条件
repository_dispatch:
types: [destroy]
env:
TERRAFORM_VERSION: 0.12.24
TF_VAR_project: ${{secrets.PROJECT}}
GOOGLE_CREDENTIALS: ${{secrets.GOOGLE_CREDENTIALS}}
jobs:
terraform:
name: 'terraform-apply'
runs-on: ubuntu-latest
steps:
- name: 'Checkout'
uses: actions/checkout@v1
- name: 'Terraform Init'
uses: hashicorp/terraform-github-actions@master
with:
tf_actions_version: 0.12.24
tf_actions_subcommand: 'init'
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: 'Terraform Plan Destroy'
uses: hashicorp/terraform-github-actions@master
with:
tf_actions_version: 0.12.24
tf_actions_subcommand: 'plan'
args: '-destroy -out=./destroy-plan'
- name: 'Terraform Apply Destroy'
uses: hashicorp/terraform-github-actions@master
with:
tf_actions_version: 0.12.24
tf_actions_subcommand: 'apply'
args: './destroy-plan'
这份工作不会在流水线上执行,可以通过以下命令直接调用Github的API来执行
(需要事先创建一个具有Github存储库权限的个人访问令牌)
curl -vv \
-H "Authorization: token $PERSONAL_ACCESS_TOKEN" \
-H "Accept: application/vnd.github.everest-preview+json" \
"https://api.github.com/repos/sabure500/gke-terraform/dispatches" \
-d '{"event_type": "destroy", "client_payload": {"target_brunch": "master"}}'
此外,为了在执行destroy命令时,也可以通过将Apply的event_type设置为apply来执行。
在 Github Actions 中设置使用的环境变量。
在上述的Job中,我们将以下两个点设置为从外部接收的环境变量。
-
- PROJECT : GCPのプロジェクト名
- GOOGLE_CREDENTIALS : サービスアカウントの章で作成したservice accountのKey
这些是为了凭据信息,使用以下步骤在Github上注册Secret功能。
-
- 在Github的存储库选择界面上,选择”设置”选项卡
-
- 在”选项”部分中,选择”秘密”选项
- 通过”添加新的秘密”创建所需的秘密
设定存储库操作规则
在上述提到的工作中,使用了在除了主分支以外的分支上执行测试并将其推送到主分支后实际应用的流程。因此,如果直接将更改推送到主分支,测试将不会被执行。为了防止这种情况发生,需要制定规则,即禁止直接推送到主分支,并且在发起拉取请求时,必须确保测试工作已经通过。
-
- 在Github的存储库选择页面上,选择“设置”选项卡
-
- 从“选项”菜单中选择“分支”
-
- 选择分支保护规则的“添加规则”
-
- 勾选“要求合并前通过状态检查”的复选框,并勾选“要求分支在合并前保持最新”的复选框
- 从显示的作业名称中选择要作为合并条件的“master”(本例中选择terraform-test)
确认GKE建设结果
检查集群
确认在管道创建后实际是否可以成功构建。
# kubectl の操作対象を GKE に切り替える
gcloud container clusters get-credentials --zone us-west1-a my-gke-cluster
# 結果確認用
kubectl config current-context
启动Sample应用程序
在搭建的GKE上运行示例应用
# サンプルアプリ用のNamespace作成
kubectl create namespace sample
# サンプルアプリのデプロイ
kubectl -n sample create deployment hello-server --image=gcr.io/google-samples/hello-app:1.0
# サンプルアプリ公開用のservice作成
kubectl -n sample expose deployment hello-server --type=LoadBalancer --port 8080
# 外部IPの取得
kubectl -n sample get service
执行上述命令后,使用获取的IP在以下位置访问:http://[EXTERNAL-IP]:8080
只需要提供一个中文选项。
-
- Terraform で GKE を構築する
-
- サービス アカウントのドキュメント
- Overview of kubectl
添加额外内容
根据我写的代码,出现了以下错误。
创建节点池出错:googleapi: 错误 400:由于内存不足,不支持 f1-micro 机器的节点池,badRequest
似乎从某个 Kubernetes 版本开始,f1-micro因为规格不足而无法运行。(以前可能是可以创建的,但实际上是不行的?)
对于我的学习目的,使用 e2-small 的一个节点已经足够,所以我将 f1-micro 的部分注释掉了。
参考:https://cloud.google.com/kubernetes-engine/docs/concepts/cluster-architecture#memory_cpu