GKEの中に稼働されるアプリケーションからどうやってGCPサービスにアクセスしたり、データ連携したりするか?という疑問がある方々に回答する記事をまとめました。
Pub/Subサービスを使って、サンプルとして作成しました。
手順まとめ
- サービスアカウント作成&アクセス用の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ロールを付与します。
# ロールをサービスアカウトに付与。下記のコマンドを実施するため、オーナー権限必要
# 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にアクセスするためプログラムは使います。この設定はポイントとなります。
アプリケーションをGKEにデプロイします。
kubectl apply -f deployment.sampleapp.yaml
8. 稼働検証
TopicにメッセージのPublishを行います。
go run tools/publish_to_topic.go --project-id=project-abc123 --topic-id=sample-app-topic
本記事で利用したソースコードはこちら [https://github.com/dssolutioninc/dss_gke/tree/master/accesspubsub](https://github.com/dssolutioninc/dss_gke/tree/master/accesspubsub)
最後まで読んで頂き、どうも有難う御座います! DSS 橋本