この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。
はじめに
おはようございます、加藤です。Google Kubernetes Engine(以降、GKE)の中からGoogle Cloud SQL(以降、Cloud SQL)を作成し、サンプルAPIを動作させてみました。
前提
- GCPのアカウントがセットアップされている
- 検証用の新規GCPプロジェクトを作成している
- 検証用のGKEクラスタを作成している
- n1-standard-1 * 3 (リソース不足にならないようにこれぐらい確保しましょう)
- gcloudが認証済み(ログイン済み)である
- kubectlコマンドでgkeと通信ができる
環境
- macOS Mojave 10.14.2(18C54
- Homebrew 1.8.6
- go version go1.11 darwin/amd64
- 1.10以上
- Google Cloud SDK 228.0.0
- GKE
- 1.11.5-gke.5
- n1-standard-1(vCPU x 1、メモリ 3.75 GB)
- サイズ 3
$ kubectl version
Client Version: version.Info{Major:"1", Minor:"13", GitVersion:"v1.13.1", GitCommit:"eec55b9ba98609a46fee712359c7b5b365bdd920", GitTreeState:"clean", BuildDate:"2018-12-13T19:44:19Z", GoVersion:"go1.11.2", Compiler:"gc", Platform:"darwin/amd64"}
Server Version: version.Info{Major:"1", Minor:"10+", GitVersion:"v1.10.9-gke.5", GitCommit:"d776b4deeb3655fa4b8f4e8e7e4651d00c5f4a98", GitTreeState:"clean", BuildDate:"2018-11-08T20:33:00Z", GoVersion:"go1.9.3b4", Compiler:"gc", Platform:"linux/amd64"}
cfssl, cfssljson のインストール
cloudflare/cfssl: CFSSL: Cloudflare's PKI and TLS toolkit
cfsslをインストールするには、Go 1.10以上が必要です。
# インストール
go get -u github.com/cloudflare/cfssl/cmd/...
# PATHが通っていることを確認する
which cfssl
which cfssljson
cluster-adminロール
k8sクラスタに対してcluster-admin
のロールをgcloudが使用するアカウントに付与します。
# ロールの付与
kubectl create clusterrolebinding cluster-admin-binding --clusterrole=cluster-admin --user=$(gcloud config get-value account)
gcloud Beta Commands のインストールと認証
Beta CommandsのインストールとGoogle Cloud SDK の認証を行います。
gcloud components install beta
gcloud auth login
gcloud auth application-default login
Service Catalog(sc)のインストール
ローカル端末でscコマンドを実行できるようにします。
# インストール
go get -u github.com/GoogleCloudPlatform/k8s-service-catalog/installer/cmd/sc
# 確認
sc check | tail -n 1
# Dependency check passed. You are good to go.
k8sクラスタに対してscをインストールします。
# インストール
sc install
# 確認(全てがAVAILABLE)
kubectl get deployment -n service-catalog
#NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE
#apiserver 1 1 1 1 1m
#controller-manager 1 1 1 1 1m
#etcd-cluster-backup-sidecar 1 1 1 1 1m
#etcd-operator 1 1 1 1 1m
# Service Broker を Kubernetes Service Catalog に登録
# APIの有効化などを行います、時間がかかります
sc add-gcp-broker
# 確認
kubectl get clusterservicebrokers -o 'custom-columns=BROKER:.metadata.name,STATUS:.status.conditions[0].reason'
# BROKER STATUS
# gcp-broker FetchedCatalog
cloudservicesにオーナー役割(roles/owner)を付与して、IAMの発行を行えるようにします。
GCP_PROJECT_ID=$(gcloud config get-value project)
GCP_PROJECT_NUMBER=$(gcloud projects describe $GCP_PROJECT_ID --format='value(projectNumber)')
gcloud projects add-iam-policy-binding ${GCP_PROJECT_ID} \
--member serviceAccount:${GCP_PROJECT_NUMBER}@cloudservices.gserviceaccount.com \
--role=roles/owner
Service Catalog CLIのインストール
作業時の確認などでsvcat
を使用するので、インストールします。
# インストール
brew update
brew install kubernetes-service-catalog-client
# 確認
svcat get classes
やってみた
サンプルAPIの構築
ネームスペースの作成
作業用ネームスペースの作成します。削除を簡単に行う為に作成しましょう。
kubectl create namespace cloud-mysql
Cloud SQL(MySQL)の作成
k8sのカスタムリソースServiceInstance
を使用して、Cloud SQLを作成します。
ServiceInstance
の役割はリソース作成であって情報の取得は別途行う必要があります。ここではDBを作成していますが、その接続情報は受け取りません。
cloud_sql.yaml
apiVersion: servicecatalog.k8s.io/v1beta1
kind: ServiceInstance
metadata:
name: cloudsql-instance
namespace: cloud-mysql
spec:
clusterServiceClassExternalName: cloud-sql-mysql
clusterServicePlanExternalName: beta
parameters:
instanceId: practice-dbinstance
region: us-central1
databaseVersion: MYSQL_5_7
settings:
tier: db-n1-standard-1
# Cloud SQL(MySQL)の作成
kubectl apply -f cloud_sql.yaml
# StatusがReadyになることを確認
# watchコマンドを使って見ると便利です
# watch -n 10 svcat describe instance --namespace cloud-mysql cloudsql-instance
svcat get instance --namespace cloud-mysql cloudsql-instance
Cloud SQLが作成されています。
Service Accountの作成
ServiceInstance
を使用して、Service Accountを作成します。
Cloud SQLの場合と同じく、情報の取得は別途行います。
service-account.yaml
apiVersion: servicecatalog.k8s.io/v1beta1
kind: ServiceInstance
metadata:
name: service-account
namespace: cloud-mysql
spec:
clusterServiceClassExternalName: cloud-iam-service-account
clusterServicePlanExternalName: beta
parameters:
accountId: cloud-sql-user-service-account
displayName: "A service account for Cloud SQL sample"
kubectl apply -f service-account.yaml
# StatusがReadyになることを確認
svcat get instance --namespace cloud-mysql service-account
サービスアカウントが作成されています。
Service Accountの取得
k8sのカスタムリソースServiceBinding
を使用して、Service Accountの情報を取得します。
取得した情報はSecretに格納されます。この時名前は省略する事が可能です、省略するとmetadata.name
で指定した名前が使用されます。
下記のYAMLはSecret: service-account
に、Service Accountの情報を格納します。
service-account-binding.yaml
apiVersion: servicecatalog.k8s.io/v1beta1
kind: ServiceBinding
metadata:
name: service-account
namespace: cloud-mysql
spec:
instanceRef:
name: service-account
kubectl apply -f service-account-binding.yaml
# StatusがReadyになることを確認
svcat get binding --namespace cloud-mysql service-account
# base64エンコードされたprivateKeyDataとserviceAccountが確認できます
# user-deployment.yamlで、privateKeyDataを利用します
kubectl get secret --namespace cloud-mysql service-account -oyaml
Secretの内容をbase64デコードして確認してみました。
privateKeyData
{
"type": "service_account",
"project_id": "k8s-practice-******",
"private_key_id": "************************************",
"private_key": "-----BEGIN PRIVATE KEY-----\***...***\n-----END PRIVATE KEY-----\n",
"client_email": "cloudsql-user-service-account@k8s-practice-******.iam.gserviceaccount.com",
"client_id": "******************",
"auth_uri": "https://accounts.google.com/o/oauth2/auth",
"token_uri": "https://oauth2.googleapis.com/token",
"auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs",
"client_x509_cert_url": "https://www.googleapis.com/robot/v1/metadata/x509/cloudsql-user-service-account%40k8s-practice-******.iam.gserviceaccount.com"
}
cloudsql-user-service-account@k8s-practice-******.iam.gserviceaccount.com
Cloud SQL 接続情報の取得
ServiceBinding
を使用して、Cloud SQLの接続情報を取得します。
作成したCloud SQL(cloudsql-instance)の情報をcloudsql-user-service-account
の権限を使って取得しています。
Secretの名前はcloudsql-credentials
で定義しました。
cloud_sql-binding.yaml
# Copyright 2018 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
apiVersion: servicecatalog.k8s.io/v1beta1
kind: ServiceBinding
metadata:
name: cloudsql-binding
namespace: cloud-mysql
spec:
instanceRef:
name: cloudsql-instance
secretName: cloudsql-credentials
parameters:
roles:
- roles/cloudsql.client
serviceAccount: cloud-sql-user-service-account
kubectl apply -f cloud_sql-binding.yaml
# StatusがReadyになることを確認
svcat get binding --namespace cloud-mysql cloudsql-binding
# base64エンコードされたconnectionNameとserviceAccountが確認できます
# user-deployment.yamlで、connectionNameを利用します
kubectl get secret --namespace cloud-mysql -o yaml cloudsql-credentials
同様にbase64デコードしてみました。
connectionName
k8s-practice-******:us-central1:my-service-broker-practice
cloudsql-user-service-account@k8s-practice-******.iam.gserviceaccount.com
ここでSecretcloudsql-credentials
に登録されている内容に認証情報が無いことを意識しておいてください。
実際に接続する際には、cloudsql-credentials
だけでは不十分です。
サンプルAPIの作成
Cloud SQLにデータを読み書きするサンプルAPIを作成して、正しくCloud SQLにアクセスできるか確認します。
Container: web
は自身でCloud SQLへの書き込み権限を持たず、Container: cloudsql-proxy
経由でアクセスします。
cloudsql-proxy
には環境変数にconnectionName
が格納され、/secrets/cloudsql
にService Accountの情報がマウントされます。
user-deployment.yaml
# Copyright 2018 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
apiVersion: apps/v1beta2
kind: Deployment
metadata:
name: musicians
namespace: cloud-mysql
labels:
app: musicians
spec:
selector:
matchLabels:
app: musicians
template:
metadata:
labels:
app: musicians
spec:
containers:
- name: web
image: gcr.io/google-samples/service-catalog/cloud-sql-mysql-user:latest
ports:
- containerPort: 8080
env:
- name: DB_HOST
value: 127.0.0.1:3306
# These secrets are required to start the pod.
- name: DB_USER
value: root
- name: DB_PASSWORD
value: ""
- name: DB_DBNAME
value: musicians
- name: cloudsql-proxy
image: gcr.io/cloudsql-docker/gce-proxy:1.11
env:
- name: CONNECTION_NAME
valueFrom:
secretKeyRef:
name: cloudsql-credentials
key: connectionName
command:
[
"/cloud_sql_proxy",
"-instances=$(CONNECTION_NAME)=tcp:3306",
"-credential_file=/secrets/cloudsql/privateKeyData",
]
volumeMounts:
- name: service-account
mountPath: /secrets/cloudsql
readOnly: true
volumes:
- name: service-account
secret:
secretName: service-account
- name: cloudsql
emptyDir:
---
apiVersion: v1
kind: Service
metadata:
name: cloudsql-user-service
namespace: cloud-mysql
labels:
app: musicians
spec:
selector:
app: musicians
ports:
- port: 80
targetPort: 8080
type: LoadBalancer
デプロイします。
kubectl apply -f user-deployment.yaml
# EXTERNAL-IPが表示されるのを待ちます
kubectl get service --namespace cloud-mysql
# EXTERNAL-IPを環境変数に格納します
IP=$(kubectl get service --namespace cloud-mysql cloudsql-user-service -o=jsonpath='{.status.loadBalancer.ingress[0].ip}')
動作をテストします。
# Create (or reset) musicians table:
curl -X POST http://${IP}/reset
# Query the musician information (will return empty result):
curl http://${IP}/musicians
# Create new musicians:
curl http://${IP}/musicians -d '{"name": "John", "instrument": "Guitar"}'
curl http://${IP}/musicians -d '{"name": "Paul", "instrument": "Bass Guitar"}'
curl http://${IP}/musicians -d '{"name": "Ringo", "instrument": "Drums"}'
curl http://${IP}/musicians -d '{"name": "George", "instrument": "Lead Guitar"}'
# Query the musicians again:
curl http://${IP}/musicians
ハマったこと
- Cloud SQLのインスタンス名が削除しても最大1週間は使用できないという事を知らなかった
- 試行錯誤しながらだったので詰まった...
あとがき
存在は知っていたものの、実際に触ったことの無かったService Catalogを使ってのパブリッククラウドへのリソース作成をやってみました。
自分が慣れていない事もあり、「あれ?この名前ってどこで定義した奴を入れればいいんだ?」と参考文献をさまよいながらの作業でした。
まだベータなので仕方ないと思いますが、気になったポイントは作成したマニフェストファイルは完了を待ってから適用していく必要がある事です。例えばCloudSQLが作成完了(Readyになる)前にServiceBinding
使用とするとSTATUS: ErrorInstanceNotReady
となりリトライが行われません。
参考
- Service Catalog のインストール | Kubernetes Engine | Google Cloud
- GCP サービスの検出と使用 | Kubernetes Engine | Google Cloud
- 【GKE】Kubernetes Service Catalog を試してみた - kawabatas技術ブログ
- Open Service Broker for さくらのクラウドでKubernetes + Service Catalog出来るようになりました - febc技術メモ
- kubernetes-engine-samples/service-catalog/cloud-sql-mysql at master · GoogleCloudPlatform/kubernetes-engine-samples