Go言語 で Google App Engine のローカル開発環境から Google Cloud Storage へアクセスする

久保田です。

AppEngine、いいですよね〜

コードを書くだけでWeb上にアプリケーションが速攻で立ち上がるので初めてやった時は感動さえ覚えました。

さらにローカル環境で開発する用意もされており、簡単に開発を始めることもできます。

そこで今回は、App EngineからCloudStorageへアクセスするアプリケーションをローカル環境に作ってみます。

ローカル環境の設定

僕は以下を参考に整えました。

https://cloud.google.com/appengine/docs/standard/go/download

流れは、
1, Google Cloud SDKを入れる
2, App Engine SDK for Goを入れる
3, 認証し、ローカルからAPIを叩けるようにする。
4, プロジェクトを作成し、設定ファイル、プログラムを用意
5, App Engine SDK for Go内のdev_appserver.pyを使ってサーバーを立てる

といった流れです。

Google Cloud SDKを使ってgcloudコマンド経由でローカル環境でもAPIが叩けるように認証したり、必要なパッケージの管理もでき、App Engine SDK for Goでgo用の環境を手に入れることができます。

ただ、僕の場合はUbuntuでやったからか、App Engine SDK for Goがgcloudコマンド経由で入れられませんでした。ので、直接wgetで落としてくる方法で入れました。

パッケージの用意ができたら、APIがローカル環境から使えるように認証をしてあげます。
ブラウザが使える環境ならば

$ gcloud init

をやると色々と設定ができるようですが、僕はCLI環境だったので、

アカウントの認証と Application Default Credentials (ADC) を別々に取得する必要があります。

$ gcloud auth login

https://cloud.google.com/sdk/gcloud/reference/auth/login

でアカウントの認証をし、

$ gcloud auth application-default login

https://cloud.google.com/sdk/gcloud/reference/auth/application-default/login

でADCを取得します。 どちらも、ホームディレクトリの.config/gcloud以下に収められているはずです。大切に扱いましょう。

ちなみに、ADCとは、

The Application Default Credentials provide a simple way to get authorization credentials for use in calling Google APIs.

と書いてある通り、簡単にAPIを使うの方法なようです。
https://developers.google.com/identity/protocols/application-default-credentials

ここまでやるとGoogleのAPIをコマンドから叩けるようになっているので、確認します。

$ gsutil ls

これでログイン時に指定したプロジェクトにあるストレージのバケット情報が出力されればOKです。

実装

まずはapp.yamlというプロジェクトの設定を書いたyamlファイルが必要です。

application: プロジェクト名
runtime: go
api_version: go1

handlers:
- url: /.*
  script: _go_app

次に実際に動かすプログラムです。 ストレージに入っている.mdファイルの一覧を取得し、表示します。

package main

import (
    "html/template"
    "log"
    "net/http"
    "regexp"

    "google.golang.org/api/iterator"
    "google.golang.org/appengine"

    "cloud.google.com/go/storage"
)

func init() {
    http.HandleFunc("/", handler)
}

type MdFiles struct {
    Files []string
}

func handler(w http.ResponseWriter, r *http.Request) {
    t, _ := template.ParseFiles("templates/index.html")
    files := MdFiles{Files: getMdFiles(r)}
    t.Execute(w, files)
}

func getMdFiles(r *http.Request) []string {
    ctx := appengine.NewContext(r)
    client, err := storage.NewClient(ctx)

    if err != nil {
        log.Fatalf("Failed to create client: %v", err)
    }

    it := client.Bucket(ストレージの名前 string).Objects(ctx, nil)
    files := make([]string, 0)
    for {
        objAttrs, err := it.Next()
        if err == iterator.Done {
            break
        }
        if err != nil {
            log.Fatalf("err: %v", err)
        }

        r := regexp.MustCompile(`\.md`)
        if r.MatchString(objAttrs.Name) {
            files = append(files, objAttrs.Name)
        }
    }

    return files
}

上の例では、templates/index.htmlというファイルを作り、
htmlを出力していますが、お好きな出力方法をお選びください。

これでストレージの中にあるファイルにアクセスできます。
また、このままapp engineにデプロイすればそのまま使えるので、非常に楽ですね。

データをストレージにためておくと簡単に色々とできると思うので、ぜひ試してみてください。