GKEの中に稼働されるアプリケーションからどうやってGCPサービスにアクセスしたり、データ連携したりするか?という疑問がある方々に回答する記事をまとめました。
Pub/Subサービスを使って、サンプルとして作成しました。
目次
Toggle手順のまとめ
- サービスアカウント作成&アクセス用のaccount.jsonファイル発行
- Pub/SubのTopic&Subscription作成
- Pub/SubをSubscriptionアプリケーションの準備
- ローカルで稼働確認
- Cloudbuildでアプリケーションのイメージビルド
- GKEのCluster準備
- GKEにアプリケーションをデプロイ
- 稼働検証
accesspubsub ├── README.md ├── app │ ├── handler │ │ └── sample_handler.go │ └── sample_app.go ├── cloudbuild.sampleapp.yaml ├── deployment.sampleapp.yaml ├── go.mod ├── go.sum ├── sampleapp.Dockerfile ├── secret │ └── account.json └── tool └── publish_to_topic.go
1. サービスアカウント作成&アクセス用のaccount.jsonファイル発行
サービスアカウント作成
# set work project gcloud config set project [PROJECT_ID] # create service account gcloud iam service-accounts create service-account \ --display-name "Account using to call GCP service"
account.jsonファイル発行
# create service account's credential file gcloud iam service-accounts keys create {{path_to_save/account.json}} \ --iam-account service-account@[PROJECT_ID].iam.gserviceaccount.com
サービスアカウント権限付与
# ロールをサービスアカウトに付与。下記のコマンドを実施するため、オーナー権限必要 # editor権限付与 gcloud projects add-iam-policy-binding [PROJECT_ID] \ --member serviceAccount:service-account@[PROJECT_ID].iam.gserviceaccount.com \ --role roles/editor
GCPのサービスを利用権限のまとめ
2. Pub/SubのTopic&Subscription作成
データ連携用のPub/SubのTopicとSubscriptionを作成する。
# Topic作成 gcloud pubsub topics create [TOPIC_NAME] # 例 gcloud pubsub topics create sample-app-topic # Topicのsubscription作成 gcloud pubsub subscriptions create [SUB_NAME] --topic=[TOPIC_NAME] # 例 gcloud pubsub topics create sample-app-topic-sub
3. Pub/SubをSubscriptionアプリケーションの準備
package main import ( "log" "os" "github.com/itdevsamurai/gke/accesspubsub/app/handler" ) func main() { log.Println("Application Started.") // projectID is identifier of project projectID := os.Getenv("PROJECT_ID") // pubsubSubscriptionName use to hear the comming request pubsubSubscriptionName := os.Getenv("PUBSUB_SUBSCRIPTION_NAME") err := handler.SampleHandler{}.StartWaitMessageOn(projectID, pubsubSubscriptionName) if err != nil { log.Println("Got Error.") } log.Println("Application Finished.") }
package handler import ( "context" "fmt" "log" "cloud.google.com/go/pubsub" ) type SampleHandler struct { } // StartWaitMessageOn // projectID := "my-project-id" // subName := projectID + "-example-sub" func (h SampleHandler) StartWaitMessageOn(projectID, subName string) error { log.Println(fmt.Sprintf("StartWaitMessageOn [Project: %s, Subscription Name: %s]", projectID, subName)) ctx := context.Background() client, err := pubsub.NewClient(ctx, projectID) if err != nil { return err } sub := client.Subscription(subName) err = sub.Receive(ctx, processMessage) if err != nil { return err } return nil } // processMessage implement callback function to process received message data var processMessage = func(ctx context.Context, m *pubsub.Message) { log.Println(fmt.Sprintf("Message ID: %s\n", m.ID)) log.Println(fmt.Sprintf("Message Time: %s\n", m.PublishTime.String())) log.Println(fmt.Sprintf("Message Attributes:\n %v\n", m.Attributes)) log.Println(fmt.Sprintf("Message Data:\n %s\n", m.Data)) m.Ack() }
このアプリケーションはPub/Subの指定Subscriptionをヒアリングして、メッセージがきたら、処理を行います。
処理はメッセージの内容を印刷するだけのシンプル処理となります。
4. ローカルで稼働確認
稼働を検証するため、Pub/SubにメッセージをPublishするツールを準備します。
package main import ( "context" "encoding/json" "flag" "fmt" "log" "cloud.google.com/go/pubsub" ) var ( topicID = flag.String("topic-id", "sample-topic", "Specify topic to publish message") projectID = flag.String("project-id", "sample-project", "Specify GCP project you want to work on") ) func main() { flag.Parse() err := publishMsg(*projectID, *topicID, map[string]string{ "user": "Hashimoto", "message": "more than happy", "status": "bonus day!", }, nil) if err != nil { log.Fatalf("Failed to create client: %v", err) } } func publishMsg(projectID, topicID string, attr map[string]string, msg map[string]string) error { // projectID := "my-project-id" // topicID := "my-topic" // msg := message data publish to topic // attr := attribute of message ctx := context.Background() client, err := pubsub.NewClient(ctx, projectID) if err != nil { return fmt.Errorf("pubsub.NewClient: %v", err) } bMsg, err := json.Marshal(msg) if err != nil { return fmt.Errorf("Input msg error : %v", err) } t := client.Topic(topicID) result := t.Publish(ctx, &pubsub.Message{ Data: bMsg, Attributes: attr, }) // ID is returned for the published message. id, err := result.Get(ctx) if err != nil { return fmt.Errorf("Get: %v", err) } fmt.Printf("Published message with custom attributes; msg ID: %v\n", id) return nil }
# GCPサービスにアクセスためのアカウントJSONファイルを環境変数に設定 # Windowsを使う方は環境変数の設定画面から行ってください。 export GOOGLE_APPLICATION_CREDENTIALS="/path/to/account.json" # アップリケーションを実行 export PROJECT_ID="project-abc123" && \ export PUBSUB_SUBSCRIPTION_NAME="sample-app-topic" && \ go run ./app/sample_app.go # 別のターミナルを開いて、テストツールを実行 # テストのメッセージをTopicにPublishする go run tool/publish_to_topic.go --project-id=project-abc123 --topic-id=sample-app-topic
ローカル稼働のコンソールログ
5. Cloudbuildでアプリケーションのイメージビルド
Dockerfile作成
FROM alpine:latest RUN apk --no-cache add ca-certificates WORKDIR /app COPY ./sample_app /app ENTRYPOINT ["./sample_app"]
Pub/Subにアクセスするため、サービスアカウントのJSONファイルで認証します。
「alpine」イメージのみはライブラリーが足りなくて、認証仕組みはエラーとなります。
「ca-certificates」ライブラリーを追加する必要です。これは注意点となります。
options: env: - GO111MODULE=on volumes: - name: go-modules path: /go steps: # go test - name: golang:1.12 dir: . args: ['go', 'test', './...'] # go build - name: golang:1.12 dir: . args: ['go', 'build', '-o', 'sample_app', 'app/sample_app.go'] env: ["CGO_ENABLED=0"] # docker build - name: 'gcr.io/cloud-builders/docker' dir: . args: [ 'build', '-t', '${_GCR_REGION}/${_GCR_PROJECT}/${_GCR_IMAGE_NAME}:${_GCR_TAG}', '-f', 'sampleapp.Dockerfile', '--cache-from', '${_GCR_REGION}/${_GCR_PROJECT}/${_GCR_IMAGE_NAME}:${_GCR_TAG}', '.' ] # push image to Container Registry - name: 'gcr.io/cloud-builders/docker' args: ["push", '${_GCR_REGION}/${_GCR_PROJECT}/${_GCR_IMAGE_NAME}'] substitutions: # # Project ID _GCR_PROJECT: project-abc123 # # GCR region name to push image _GCR_REGION: asia.gcr.io # # Image name _GCR_IMAGE_NAME: sample-pubsub-usage-app # # Image tag _GCR_TAG: latest
gcloud builds submit --config cloudbuild.sampleapp.yaml
ビルド完了となったらContainer Registryで確認する。
Cloudbuildについてさらに確認したい場合、この記事にご参考(CloudbuildでDockerイメージビルドとContainer Registryに登録)
6. GKEのCluster準備
# クラスタ作成 gcloud container clusters create ds-gke-small-cluster \ --project ds-project \ --zone asia-northeast1-b \ --machine-type n1-standard-1 \ --num-nodes 1 \ --enable-stackdriver-kubernetes # k8sコントロールツールをインストール gcloud components install kubectl kubectl version # GKEのクラスタにアクセスするため、credentialsを設定 gcloud container clusters get-credentials --zone asia-northeast1-b ds-gke-small-cluster
7. GKEにアプリケーションをデプロイ
アカウントJSONファイルを「secret generic」ボリュームとしてクラスタに登録します。
kubectl create secret generic service-account-credential \ --from-file=./secret/account.json
デプロイ定義ファイルの準備
apiVersion: extensions/v1beta1 kind: Deployment metadata: name: sample-pubsub-usage-app spec: replicas: 1 template: metadata: labels: app: sample-pubsub-usage-app spec: volumes: - name: service-account-credential secret: secretName: service-account-credential containers: - name: sample-pubsub-usage-app-container image: asia.gcr.io/project-abc123/sample-pubsub-usage-app:latest # environment variables for the Pod env: - name: PROJECT_ID value: "project-abc123" - name: PUBSUB_SUBSCRIPTION_NAME value: "sample-app-topic-sub" - name: GOOGLE_APPLICATION_CREDENTIALS value: /app/secret/account.json volumeMounts: - mountPath: /app/secret name: service-account-credential readOnly: true
【デプロイ定義の説明】
作成できた「secret generic」ボリュームをデプロイ定義にMount設定して、account.jsonファイルパスを環境変数に渡す。
「GOOGLE_APPLICATION_CREDENTIALS」の環境変数はPub/Subにアクセスするためプログラムは使います。この設定はポイントとなります。
kubectl apply -f deployment.sampleapp.yaml
GKE上のデプロイできたアプリケーションを確認
8. 稼働検証
go run tools/publish_to_topic.go --project-id=project-abc123 --topic-id=sample-app-topic
GKE中のアプリケーションの稼働ログを確認
本記事の利用ソースコードはこちら
https://github.com/itdevsamurai/gke/tree/master/accesspubsub
最後まで読んで頂き、どうも有難う御座います。!
DevSamurai 橋本