Service Catalogを使って、KubernetesからGoogle Cloud SQLを作成して使ってみた
はじめに
おはようございます、加藤です。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を作成していますが、その接続情報は受け取りません。
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の場合と同じく、情報の取得は別途行います。
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の情報を格納します。
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デコードして確認してみました。
{ "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
で定義しました。
# 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デコードしてみました。
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の情報がマウントされます。
# 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