ラベル GCS の投稿を表示しています。 すべての投稿を表示
ラベル GCS の投稿を表示しています。 すべての投稿を表示

2024/01/14

ビルドエラー "ERROR: failed to initialize analyzer: getting previous image" の対処 [GAE]

事象

久しぶりにGAEのプロジェクトをビルドすると、mavenで以下のエラーに遭遇しました。
このプロジェクトはappengine-maven-pluginを利用してビルドしています。

[INFO] ------------------------------------------------------------------------
[INFO] BUILD FAILURE
[INFO] ------------------------------------------------------------------------
[INFO] Total time:  01:27 min
[INFO] Finished at: 2024-01-xxTxx:xx:xx+09:00
[INFO] ------------------------------------------------------------------------
[ERROR] Failed to execute goal com.google.cloud.tools:appengine-maven-plugin:2.5.0:deploy (default-cli) on project プロジェクトID.サービスID: App Engine application deployment failed: com.google.cloud.tools.appengine.operations.cloudsdk.process.ProcessHandlerException: com.google.cloud.tools.appengine.AppEngineException: Non zero exit: 1 -> [Help 1]
[ERROR]
[ERROR] To see the full stack trace of the errors, re-run Maven with the -e switch.
[ERROR] Re-run Maven using the -X switch to enable full debug logging.
[ERROR]
[ERROR] For more information about the errors and possible solutions, please read the following articles:
[ERROR] [Help 1] http://cwiki.apache.org/confluence/display/MAVEN/MojoExecutionException


Cloud Buildを確認すると以下のエラーが出てしました。

ERROR: failed to initialize analyzer: getting previous image: getting config file for image "asia.gcr.io/プロジェクトID/app-engine-tmp/app/サービスID/xxxxxx:latest": GET https://storage.googleapis.com/asia.artifacts.プロジェクトID.appspot.com/containers/images/sha256:xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx?access_token=REDACTED: unexpected status code 404 Not Found: <error><code>NoSuchKey</code><message>The specified key does not exist.</message><details>No such object: asia.artifacts.プロジェクトID.appspot.com/containers/images/sha256:xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx</details></error>


調査

「差分ビルドしているけど前回のビルドイメージが見つからない」と言っているようです。だいぶ前ですが、Cloud Storageのビルドイメージを保存しているバケットにライフサイクルを適用して、生成から14日を過ぎたものは削除するように設定しています。その当時は14日以上空けてビルドしても問題なく再ビルド可能でした。また手作業でCloud Storageのビルドイメージを消してからのビルドも可能でした。それに差分ビルドによるビルド時間短縮の効果もわずかでした。

その後ビルド方法が変更されて差分ビルドしかしてくれなくなったようです。

ネットで探してみると「GAEのデプロイが失敗する: ERROR: (gcloud.app.deploy) Error Response: [9] Cloud build xxxxx status: FAILURE」が見つかりました。まったく同じ状況です。


解決方法

gcloud app deploy のケース

Goで作成しているサービスは上記の記事と同じくgcloud app deploy --no-cacheで回避できました。


maven appengine:deploy のケース

Javaで作成しているサービスはデプロイまでmvn appengine:deployで行っています。appengine-maven-pluginに--no-cacheと同様のパラメータがないか探してみたのですが、見当たりません。serviceAccountKeyFileという怪しいタグがありますがweb上に全く説明が見つからず、またタグ名から推測される動作も異なります。

なぜかJavaで書いたサービスはgcloud app deployだとビルド・デプロイは成功するものの、生成されるwarに依存ライブラリが含まれないので使っていませんでした。

しかし一旦gcloud app deploy --no-cacheでデプロイすればビルドイメージができるので、その後はmvn appengine:deployでデプロイできるようになりました。


2023/05/07

GCSからHTMLテンプレートを読み込んでHTTPレスポンスで返す [Go]

 ほぼ自分用の忘備録です。


背景

 Go+Gin構成のwebアプリでは、ファイルとして用意したテンプレートをHTTPレスポンスで返すのは簡単です。以下のようなスニペットになります。


func main() {
    router := gin.Default()
    router.LoadHTMLFiles("HTMLテンプレートファイルのパス")
    router.GET("リクエストエンドポイントのuri", handler)
}

func handler(ginctx *gin.Context) {
    ginctx.HTML(http.StatusOK, "HTMLテンプレートファイル", gin.H{
        キー: バリュー
    })
}


課題

 HTMLテンプレートをGoogle Cloud Storage(以下GCSと略)に置いておき、そこから読み込んで返したい場合、直接GCSから取得してくれる関数はGinにはありません。


解決

 以下のスニペットで可能になりました。エラー処理のコードは省略しています。これでいいのかちょっと不安な箇所もありますが、とりあえず期待動作はしています。


func main() {
    router := gin.Default()
    router.GET("リクエストエンドポイントのuri", handler)
}

func handler(ginctx *gin.Context) {
    // GCSからHTMLテンプレートをロード
    ctx := context.Background()
    storageclient, _ := storage.NewClient(ctx)
    reader, _ := storageclient.Bucket("バケット名")
    	.Object("HTMLテンプレートのオブジェクト名").NewReader(ctx)
    content_bin, _ := io.ReadAll(reader)
    reader.Close()
    
    // GCSから読み出した結果はバイナリなので文字列に変換
    content_str, _ := *(*string)(unsafe.Pointer(&content_bin)
    
    // テンプレートとして登録
    router := gin.Default()
    template, _ := template.New("").Delims("{{", "}}").Funcs(router.FuncMap).Parse(content_str)
    router.SetHTMLTemplate(template)

    // レスポンスで返す
    html := router.HTMLRender.Instance("", gin.H{
        キー: バリュー
    })
    ginctx.Render(http.StatusOK, html)
}

 バイナリ→文字列の変換には「忘れがちなGoでbyteをstringに変換する方法をベンチマークしてみた。」を参考にしました。

2023/01/13

データストアの選択

世の中には データを保存しておく製品にも、いろいろと選択肢が用意されています。GCPでも目的に応じて特徴の異なる複数のサービスが用意されています。その中でもBigQueryって特徴的で判りやすいと(個人的には)思っていたのですが、最近になってGCPにかかわりながらもBigQueryがどういうものなのかを未だに知らない人に遭遇しました。

ここでGCPのデータの保存目的に使えるサービスを比較しておきたいと思います。


一覧

GCPに用意されたサービスの一覧です。
名称略称概要スケーラブルマネージド
Firestore(特になし)NoSQL、ドキュメント指向データベース。
Cloud SQL(特になし)SQLのリレーショナルデータベース。
Cloud SpannerSpannerSQLのリレーショナルデータベース。
Cloud BigtableBigtableNoSQL・低レイテンシのデータベース。
MemorystoreMemstoreオンメモリで高速動作。
BigQuery(特になし)検索に特化したデータウェアハウス。
Cloud StorageGCS非構造化データ用のストレージ。

「略称」はGoogleが決めた正式なものではないですが、開発者の間でよく使われている呼称です。
「マネージド」の〇はフルマネージド、△はフルではないマネージドを表します。

これら以外にもFirebaseのサービスもあるのですが、それらに関しては割愛します。

各サービスの特徴

サービスを比較・選択するうえで参考としていただけるように、ざっくりと説明します。詳細はGoogleの各サービスをご覧ください。

Firestore

スケーラブルなので負荷が増えても重くなる心配がありません。むしろアクセスが少ないと優先順位が下げられて待ちが長くなる感じさえあります。フルマネージドなのでメンテナンスフリーです。
スキーマレスでドキュメント指向です。自分で各ドキュメントの構造を同じにして使えば、テーブルとして使えます。検索用のインデックスが付いた連想配列の様な感じですが、インデックスによる検索機能は貧弱です。柔軟な検索が必要なら、ElasticSearchやGAEのSearch APIと組み合わせる必要があります。
強整合性でトランザクションにも対応しています。
費用は主に保存容量に対して発生し、無料枠もあるので、ランニングコストは低めです。
SQLしか経験のない方には理解しにくいかもしれませんが、「Not only SQL」なデータベースです。
過去には似たようなDatastoreというサービスがありましたが、それが廃止されてFirestoreのDatastore互換モードとなりました。Firestoreにはネイティブモードもあり、こちらはドキュメントを階層構造にすることもできます。

Cloud SQL

MySQL/PostgreSQL/SQL Serverのいずれかから選んで使用します。これらを自分でGCEに乗せなくても、予めGoogleが用意してくれていると理解すればいいと思います。
なので利点も欠点もMySQL/PostgreSQL/SQL Serverを引き継ぎます。スケーリングに関しては設定した範囲内に限定され、無限ではありません。幸いフルマネージドでメンテフリーで使えます。
費用は主に保存容量とCPUに対して発生します。CPUはGCEと同等なので、ランニングコストはそれなりに発生します。

Cloud Spanner

スケーラブルなので負荷が増えても重くなる心配なし、フルマネージドでメンテナンスフリー、強整合性と、ここまではFirestoreと同じです。こちらはドキュメント指向でありません。SQLでリレーショナルデータベースを使いたい人にとっては、Cloud SQLとFirestore/Bigtableの「良いとこ取り」の様な感じになります。GCPではコスト以外はほぼ最強ではないでしょうか。
費用は主に保存容量とコンピューティングインスタンスに対して発生します。「Cloud Spanner vs Cloud SQL」も参考になると思います。

Cloud Bigtable

スケーラブル、フルマネージド、NoSQLと、ここまではFirestoreと同じです。低レイテンシが最大の売りでしょうか。
GCPに昔からあるサービスで、他のデータベース/ストレージの基盤となるサービスだと聞いたことがあります。(今GoogleのWeb上のドキュメントを探してもそのような説明は見当たらないのですが、当時詳しい人だったかGoogle日本法人の人から聞いた話なので、嘘ではないはず)
費用は主に保存容量とコンピューティングに使われるノードに対して発生します。ノードは事実上GCEと同じなので、たぶんそこそこかかるはず。

Memorystore

Redis/Memcachedのいずれかから選んで使用します。たぶんそれらをGCPに乗せただけと思います。オンメモリなので速いはず。しかもスケーラブル。
速さを活かしてキャッシュや書き換えの集中するデータの保存に向きます。