4つのサービスを繋いで
保存・権限・処理・通知を
ひとつのパイプラインにする。
写真管理アプリ「Memories」を題材に、Cloud Storage・IAM・Cloud Functions・Pub/Sub を組み合わせたイベント駆動サーバーレス環境をゼロから構築します。各サービスを「定義 → なぜ使うか → 具体例 → コード → ベストプラクティス」の順で解説し、最後に Challenge Lab(GSP315)で統合します。
このガイドについて
1.1スコープに関する注記
Google Skills(旧 Google Cloud Skills Boost)の個別ラボページは、受講登録済みアカウントでのサインインが必須のため、ラボ ID 単位(/labs/592541 〜 /labs/592550)での本文取得はできません。そのため本ガイドは、以下の情報源を根拠として再構成しています。
- コース
course_templates/637の公式コース概要に明記された技術スコープ:Cloud Storage、IAM、Cloud Functions、Pub/Sub - 本コース末尾の Challenge Lab(
labs/592550)である GSP315 の公開シナリオ・タスク構成 - 各サービスの Google Cloud 公式ドキュメント(ベストプラクティスページ)
一般的にこの構成のコースは、①Cloud Storage の基本操作、②IAM によるアクセス制御、③Cloud Functions(現行の Cloud Run functions)のデプロイ、④Pub/Sub のメッセージング、という4つの実習を経て、最後にこれらを統合する Challenge Lab(GSP315)で総仕上げを行います。本ガイドはこの流れに沿って各サービスを解説します。
1.2提供された参照 URL の位置づけ
| # | URL(末尾) | 位置づけ(推定) |
|---|---|---|
| 1 | labs/592541 | コース前半:Cloud Storage 実習 |
| 2 | labs/592542 | Cloud Storage 実習(CLI/SDK) |
| 3 | labs/592543 | Cloud IAM 実習 |
| 4 | labs/592544 | Cloud Functions 実習(コンソール) |
| 5 | labs/592545 | Cloud Functions 実習(コマンドライン) |
| 6 | labs/592546 | Pub/Sub 実習(コンソール) |
| 7 | labs/592547 | Pub/Sub 実習(コマンドライン) |
| 8 | labs/592548 | Pub/Sub 実習(補足/言語別クライアント) |
| 9 | labs/592549 | 復習クイズ/知識確認 |
| 10 | labs/592550 | Challenge Lab(GSP315)※確認済み |
コース全体像とラーニングパス
このコースは「写真管理アプリ Memories」というシナリオを軸に、ストレージ・権限管理・サーバーレス処理・非同期通知という、モダンなアプリ開発環境の基本4要素を一気通貫で学びます。
Fig 2.1 — 学習パイプラインの全体像
2.1なぜこの順番で学ぶのか
| 順番 | サービス | このコースにおける役割 |
|---|---|---|
| 1 | Cloud Storage | 画像などの非構造化データを保存する「置き場」を作る |
| 2 | IAM | 誰が・どのリソースに・何をできるかを制御する土台を理解する |
| 3 | Cloud Functions | アップロードをトリガーに自動処理(サムネイル生成など)を実行する |
| 4 | Pub/Sub | 処理結果を他システムに非同期で通知する |
| 5 | Challenge Lab | 上記すべてを組み合わせ、実務に近いシナリオを自力で完成させる |
この流れは「ストレージにファイルが置かれる → 権限に基づいてイベントが検知される → 関数が起動して加工する → 完了をメッセージングで知らせる」という、サーバーレスなイベント駆動アーキテクチャの典型パターンそのものです。
Cloud Storage — オブジェクトストレージの基礎
3.1定義
Cloud Storage は、任意の量の非構造化データ(画像・動画・ログ・バックアップなど)をオブジェクトとして保存できるフルマネージドのストレージサービスです。データは「バケット」と呼ばれるコンテナに格納され、各バケットはプロジェクトに属します。
3.2なぜ使うか
- サーバーの容量管理が不要で、ペタバイト級までシームレスにスケールする
- 99.999999999%(イレブンナイン)の年間耐久性を持つ
- Standard/Nearline/Coldline/Archive の4クラスでアクセス頻度に応じたコスト最適化ができる
- Cloud Functions や Pub/Sub とイベント連携しやすい(本コースの核心)
3.3具体例(コンソールでの操作フロー)
Fig 3.1 — バケット作成〜アップロードの流れ
バケット名はグローバルネームスペースで一意である必要がありますが、オブジェクト名はバケット内でのみ一意であれば構いません。
3.4コード例(gcloud CLI)
# 環境変数の準備
export PROJECT_ID=$(gcloud config get-value project)
export BUCKET_NAME="${PROJECT_ID}-photos"
export REGION="asia-northeast1"
# リージョンバケットを作成
gcloud storage buckets create gs://${BUCKET_NAME} \
--project=${PROJECT_ID} \
--location=${REGION} \
--uniform-bucket-level-access
# オブジェクトをアップロード
gcloud storage cp ./sample.jpg gs://${BUCKET_NAME}/
# バケット内の一覧を確認
gcloud storage ls gs://${BUCKET_NAME}/gcloud storage コマンドは従来の gsutil の後継で、より高速かつ一貫性のある挙動をします。新規学習では gcloud storage を使うのがおすすめです。3.5ベストプラクティス
| # | 項目 | ✅ 推奨 | ❌ 避けるべき |
|---|---|---|---|
| 1 | バケット命名 | 機密情報を含まない推測されにくい名前にする | mysecret-prod-bucket のように機密情報を露出させる |
| 2 | アクセス制御 | 均一バケットレベルアクセス(IAMのみ)を有効化し最小権限で運用 | オブジェクトごとにACLを個別設定して管理を複雑化させる |
| 3 | 公開設定 | 公開が必要なオブジェクトだけを明示的に許可する | バケット全体をうっかり公開設定にする |
| 4 | ストレージクラス | アクセス頻度に応じて4クラスを使い分ける | すべて Standard のまま高コストを放置する |
| 5 | 再試行戦略 | 新規コネクションでの再試行やヘッジドリクエストを実装する | 同一パスへの単純リトライのみで「サーバー固着」を起こす |
| 6 | オブジェクト名 | ランダム性のあるプレフィックスでホットスポットを回避する | 連番やタイムスタンプのみの命名で書き込みを集中させる |
| 7 | ライフサイクル | ルールで古いデータを自動的に低コスト化・削除する | 不要データを手動管理のまま放置しコストを増大させる |
Cloud IAM — アクセス制御の基礎
4.1定義
IAM(Identity and Access Management)は「誰が(Principal)」「どのリソースに(Resource)」「何をできるか(Permission)」を、ロールの付与によって制御する仕組みです。Google Cloud では権限を直接付与せず、権限をまとめた「ロール」を主体に紐づけます。
Fig 4.1 — Principal / Role / Permission / Resource の関係
4.2なぜ使うか
- 誤操作や不正アクセスの被害範囲(ブラストラディウス)を最小化できる
- Owner/Editor/Viewer の広範な基本ロールに頼らず、事前定義ロール(
roles/storage.objectViewerなど)で細かく制御できる - 退職者や異動者のアクセスを確実に取り消せる(Challenge Lab でも実施)
4.3具体例
このコースでは、プロジェクトに参加している「前任のクラウドエンジニア」のアクセス権を確認し、不要になった時点で削除する、実務でも頻出のシナリオを扱います。
Fig 4.2 — 前任エンジニアのアクセス権を取り消す
4.4コード例(gcloud CLI)
# 現在のIAMポリシーを確認
gcloud projects get-iam-policy ${PROJECT_ID}
# 特定ユーザーの roles/viewer を削除(最小権限の原則の実践)
gcloud projects remove-iam-policy-binding ${PROJECT_ID} \
--member="user:previous-engineer@example.com" \
--role="roles/viewer"
# バケット単位で最小権限を付与する例(リソース単位に絞る)
gcloud storage buckets add-iam-policy-binding gs://${BUCKET_NAME} \
--member="serviceAccount:thumbnail-fn@${PROJECT_ID}.iam.gserviceaccount.com" \
--role="roles/storage.objectViewer"4.5ベストプラクティス
| # | 項目 | ✅ 推奨 | ❌ 避けるべき |
|---|---|---|---|
| 1 | 最小権限の原則 | タスク遂行に必要な最小限の権限のみを付与する | とりあえず roles/editor や roles/owner を付与 |
| 2 | 付与範囲 | バケットや関数などリソース単位でロールを絞り込む | プロジェクト全体に広いロールを付与する |
| 3 | サービスアカウント | 用途ごとに専用SAを作成し機能を分離する | すべての関数で同一の高権限SAを共有する |
| 4 | 定期棚卸し | IAM Recommender で未使用権限を定期的に削除する | 付与した権限を放置し「権限の肥大化」を起こす |
| 5 | 監査 | Cloud Audit Logs で IAM 変更を継続的に監視する | 権限変更を記録・追跡せず放置する |
| 6 | グループ活用 | 多数ユーザーへの付与はグループ単位で行う | ユーザーを1人ずつ列挙して管理コストを増やす |
Cloud Functions(Cloud Run functions)
5.1定義
Cloud Functions は、サーバー管理不要でイベント(HTTP リクエストや Cloud Storage への書き込みなど)に応じて単一目的のコードを実行できるサーバーレス実行環境です。第2世代(Gen2)は Cloud Run 上で稼働し、現在は「Cloud Run functions」という製品名に統合されています。内部的には Cloud Run サービスと Eventarc トリガーの組み合わせとして構成されます。
Fig 5.1 — アップロードをトリガーにしたイベント処理パイプライン
5.2なぜ使うか
- インフラのプロビジョニング不要で、コードをデプロイするだけで即座にスケールする
- Cloud Storage・Pub/Sub・Firestore など多様なイベントソースと直接連携できる
- 使った分だけの課金(リクエストが来ない間はコストが発生しない)
5.3具体例(コンソールでのデプロイ手順)
- 関数名・リージョン・トリガー種別(Cloud Storage の
finalizedイベント)を設定する - 対象バケットを指定する
- エントリポイント(実行される関数名)とランタイム(例:Node.js 22)を設定する
- ソースコード(
index.jsとpackage.json)を記述してデプロイする
5.4コード例(Node.js/概念コード)
Cloud Storage への画像アップロードをトリガーにサムネイルを生成し、完了を Pub/Sub に通知する処理の概念的な骨組みです。
const functions = require(@google-cloud/functions-framework);const { Storage } = require(@google-cloud/storage);const { PubSub } = require(@google-cloud/pubsub);const { pipeline } = require(stream/promises);const sharp = require(sharp);const storage = new Storage();const pubsub = new PubSub();functions.cloudEvent(generateThumbnail, async (cloudEvent) => {const event = cloudEvent.data;const { bucket: bucketName, name: fileName } = event;// 冪等性の確保:既にサムネイルなら再処理しない。拡張子なしのサムネイル名(例:xxx_thumb)も含むif (fileName.includes('_thumb') || fileName.endsWith('_thumb')) {console.log(`Skip: ${fileName} is already a thumbnail`);return;}const bucket = storage.bucket(bucketName);const dotIndex = fileName.lastIndexOf('.');const thumbName = dotIndex !== -1 ? `${fileName.slice(0, dotIndex)}_thumb${fileName.slice(dotIndex)}` : `${fileName}_thumb`;await pipeline(bucket.file(fileName).createReadStream(),sharp().resize(64, 64),bucket.file(thumbName).createWriteStream());await pubsub.topic(process.env.TOPIC_NAME).publishMessage({data: Buffer.from(JSON.stringify({ thumbnail: thumbName })),});});
# デプロイ例(Gen2 / Cloud Storage トリガー)
gcloud functions deploy generateThumbnail \
--gen2 \
--runtime=nodejs22 \
--region=${REGION} \
--source=. \
--entry-point=generateThumbnail \
--trigger-event-filters="type=google.cloud.storage.object.v1.finalized" \
--trigger-event-filters="bucket=${BUCKET_NAME}" \
--set-env-vars=TOPIC_NAME=${TOPIC_NAME} \
--max-instances=25.5ベストプラクティス
| # | 項目 | ✅ 推奨 | ❌ 避けるべき |
|---|---|---|---|
| 1 | 冪等性 | 同じイベントで複数回呼ばれても同じ結果になるよう設計する | 副作用のある処理を無条件に繰り返し実行する |
| 2 | 無限ループ防止 | 生成物が自分自身をトリガーしないようファイル名等でガードする | 生成物が再度トリガー対象になり無限ループが発生する |
| 3 | コールドスタート対策 | 依存を最小化し、重い初期化はグローバルスコープで1回だけ | 毎回の呼び出しで重い処理を再初期化する |
| 4 | 権限 | 関数専用SAを作り必要な権限のみ付与する | デフォルトSA(Editor相当)をそのまま使う |
| 5 | 依存の固定 | package-lock.json 等でバージョンを固定する | バージョン未指定で環境ごとに挙動が変わる |
| 6 | エラーハンドリング | 例外を捕捉しログ出力、必要に応じ再試行ポリシーを設定 | 未処理の例外でクラッシュし原因追跡が困難になる |
Pub/Sub — 非同期メッセージング
6.1定義
Pub/Sub は、メッセージの送信者(Publisher)と受信者(Subscriber)を分離する非同期メッセージングサービスです。Publisher は「トピック」にメッセージを送信し、Subscriber は「サブスクリプション」を通じてメッセージを受信します。
Fig 6.1 — 1トピックから複数の Subscriber へのファンアウト
6.2なぜ使うか
- Publisher と Subscriber が互いの稼働状況を意識せず疎結合で連携できる
- 1トピックに複数のサブスクリプションを紐づける「ファンアウト」で、同じイベントを複数システムに配信できる
- サービス障害時にもメッセージが保持され、リトライや再処理が可能
6.3具体例
Challenge Lab のシナリオでは、サムネイル生成完了を知らせるトピックを用意し、Cloud Function がそこにメッセージを発行します。この時点ではサブスクリプションを作らず「送信先の箱」だけを用意するのがポイントです(後続の消費者が必要になった時点で追加できます)。
6.4コード例(gcloud CLI)
# トピックを作成
gcloud pubsub topics create ${TOPIC_NAME}
# 動作確認用にサブスクリプションを作成
gcloud pubsub subscriptions create ${TOPIC_NAME}-sub \
--topic=${TOPIC_NAME}
# テストメッセージを発行
gcloud pubsub topics publish ${TOPIC_NAME} \
--message="thumbnail generated"
# サブスクリプションからメッセージを取得
gcloud pubsub subscriptions pull ${TOPIC_NAME}-sub --auto-ack --limit=56.5ベストプラクティス
| # | 項目 | ✅ 推奨 | ❌ 避けるべき |
|---|---|---|---|
| 1 | Publisher再利用 | クライアントを使い回して接続確立のオーバーヘッドを避ける | リクエストごとに新しいクライアントを生成する |
| 2 | メッセージ保持 | Publish前にサブスクリプションを用意するか保持を有効化する | サブスクリプション不在のままPublishし、メッセージを失う |
| 3 | 冪等な処理 | 「少なくとも1回配信」を前提に重複処理に耐える設計にする | メッセージが必ず1回だけ届く前提で実装する |
| 4 | デッドレターキュー | 失敗し続けるメッセージをデッドレタートピックへ退避させる | 失敗メッセージが際限なく再配信され続ける |
| 5 | 順序保証 | 順序が必要な場合のみ ordering key を設定する | 一律で順序保証を要求しスループットを落とす |
| 6 | バッチ処理 | クライアントのバッチ機能でスループットとコストを最適化する | 1メッセージ1リクエストで大量発行しコストを増大させる |
総合演習:Challenge Lab(GSP315)
7.1シナリオ概要
あなたは Jooli 社のジュニアクラウドエンジニアとして、写真管理アプリ「Memories」の開発チームから、アプリ開発環境の初期構築を依頼されます。ステップバイステップの手順書は与えられず、これまでの実習で得たスキルをもとに自力でタスクを完了させる、実務に近いシナリオです。
7.2統合アーキテクチャ図
Fig 7.1 — GSP315 の統合アーキテクチャ
7.3タスク一覧
| タスク | 内容 | 主な技術 |
|---|---|---|
| Task 1 | 写真保存用の Cloud Storage バケットを作成する | Cloud Storage |
| Task 2 | Cloud Run function が使用する Pub/Sub トピックを作成する | Pub/Sub |
| Task 3 | アップロードをトリガーにサムネイルを生成する関数(Gen2)を作成・デプロイ | Functions / Eventarc |
| Task 4 | 画像をアップロードしてインフラ全体の動作を検証する | Storage / Functions / Pub/Sub |
| Task 5 | 前任のクラウドエンジニアのプロジェクトアクセスを削除する | IAM |
7.4手順ごとの解説
Task 1: バケット作成 — ラボパネルに指定されたバケット名(例:qwiklabs-gcp-XX-xxxxxxxx-bucket)を使い、リージョンを選択してデフォルト設定で作成します。バケット名は採点システムが検証するため、指定された名前を正確に使用することが重要です。
Task 2: Pub/Sub トピック作成 — 関数が処理完了後にメッセージを発行するためのトピックを作成します。この段階ではサブスクリプションの作成は要求されていません(関数が Publisher として使うだけのため)。
Task 3: Cloud Run function(サムネイル生成)
- トリガー:対象バケットへの Cloud Storage
finalizedイベント - エントリポイントはコード内の関数名と完全に一致させる(不一致はデプロイ後の動作不良の典型的な原因)
- Eventarc がイベントを読み取れるよう、Cloud Storage サービスエージェントへ
roles/pubsub.publisherを付与するなど権限伝播が必要な場合がある(数分のタイムラグあり)
Task 4: 動作検証 — 指定の画像(例:map.jpg)をアップロードし、数十秒〜数分後にサムネイルが生成されることを確認します。生成されない場合は関数の「トリガー」タブで設定が正しく保存されているか確認し、必要ならトリガーを再作成します。
Task 5: IAM クリーンアップ — プロジェクトには「あなた(Owner)」と「前任エンジニア(Viewer)」の2プリンシパルが存在します。前任エンジニアの roles/viewer バインディングを削除し、最小権限の原則を実践して完了します。
7.5よくあるエラーと対処
| 症状 | 想定される原因 | 対処 |
|---|---|---|
| サムネイルが生成されない | Eventarc/Storage サービスエージェント権限が未伝播 | 数分待って再アップロード、または権限設定を再確認 |
| デプロイ成功だが関数がエラー終了 | エントリポイント名とコード内の関数名が不一致 | 「エントリポイント」欄を関数名と完全一致させる |
| サムネイルが無限に生成される | 生成物自身が再度トリガー対象になっている | ファイル名にサフィックスを付け既存サムネイルを除外 |
| Pub/Sub Publish でエラー | Storage サービスエージェントに roles/pubsub.publisher 未付与 | 該当サービスエージェントへ IAM ロールを追加 |
| 権限削除が完了と判定されない | 削除対象のメンバー/ロール指定が誤り | get-iam-policy で現状確認してから正確に削除 |
サービス横断ベストプラクティス早見表
| 観点 | Cloud Storage | IAM | Cloud Functions | Pub/Sub |
|---|---|---|---|---|
| 最小権限 | バケット単位でロールを付与 | リソース単位で付与 | 関数専用SAを用意 | トピック/サブ単位で絞る |
| スケール対策 | ランダムプレフィックスでホットスポット回避 | 該当なし | コールドスタート対策・依存最小化 | バッチ発行で最適化 |
| 信頼性 | ライフサイクル管理・再試行戦略 | 定期的な権限棚卸し | 冪等な処理設計 | デッドレターキュー・冪等Subscriber |
| 可観測性 | アクセスログ・監査ログ | Cloud Audit Logs | Cloud Logging でエラー監視 | 未処理メッセージ滞留を監視 |
よくあるエラーとトラブルシューティング
| カテゴリ | 症状 | チェックポイント |
|---|---|---|
| 権限伝播遅延 | 「Permission denied」が数分後に解消する | Eventarc/Storage サービスエージェントへの権限付与直後は数分の伝播待ちが必要 |
| バケット名の衝突 | バケット作成に失敗する | バケット名はグローバルで一意。プロジェクトID等を含めて一意性を担保する |
| 関数のタイムアウト | 大きな画像処理で関数がタイムアウトする | メモリ/タイムアウト設定を見直すか、ストリーム処理でメモリ使用量を削減 |
| メッセージ消失 | Publishしたのにメッセージが届かない | サブスクリプション未作成のままPublishしていないか確認(保持設定も検討) |
参考ソース一覧
10.1 提供されたコース URL(本ガイドの対象範囲)
10.2 Cloud Storage
- cloud.google.com/storage/docs/best-practices
- storage/docs/access-control/best-practices-access-control
- storage/docs/best-practices-media-workload
10.3 IAM
10.4 Cloud Functions / Cloud Run functions
- run/docs/tips/functions-best-practices
- run/docs/write-functions
- functions/docs/concepts/overview
- blog: least-privilege-for-cloud-functions-using-cloud-iam
10.5 Pub/Sub
10.6 Challenge Lab(GSP315)シナリオ確認に使用したソース
以下は公式ドキュメントではなく、GSP315 のシナリオ・タスク構成を裏付けるために参照したコミュニティ/サードパーティ記事です。コード例はいずれも本ガイド用に独自に書き直しており、これらからの転載ではありません。