1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

30日間で理解する GCP for AWSエンジニア - 実践ブログシリーズ - 12日目: Cloud Run:サーバーレスでコンテナを動かすGCPの独自サービスを試してみよう

Last updated at Posted at 2025-08-26

【AWS経験者向け】Cloud Run:サーバーレスでコンテナを動かすGCPの独自サービスを試してみよう


はじめに:サーバーレスとコンテナの新しいカタチ

皆さん、こんにちは!「30日間でGCPをマスターするAWSエンジニアの挑戦」シリーズ、12日目へようこそ。

AWSでのコンテナ運用は、EC2のような仮想サーバーを使うか、ECSやEKSといったコンテナオーケストレーションサービスを使うのが一般的です。さらに、サーバー管理の煩雑さから解放されるAWS Fargateは、「サーバーレスでコンテナを動かす」という新しい選択肢を提供しました。

GCPにも、これらとは一線を画す独自のサービス、Cloud Runがあります。Cloud Runは、コンテナをサーバーレス環境で実行するという点でAWS Fargateに似ていますが、そのシンプルさと柔軟性は驚くほどです。Lambdaのようにリクエストがなければインスタンス数がゼロになり、リソースコストを最小限に抑えられます。

この記事では、AWSのコンテナサービスの知識を前提に、GCPのCloud RunがなぜGCPの独自サービスと言えるのか、以下のポイントを徹底的に比較し、その強みを体感していきます:

  • Cloud Runの核心:FaaSでもCaaSでもない、新しい概念
  • AWS FargateとLambdaとの違い:それぞれの強みと使い分け
  • 実践ハンズオン:コンテナをサーバーレスにデプロイする

この記事を読めば、Cloud RunがWebサービスやAPIの構築にどれほど強力なツールであるかが明確に理解できます。


Cloud Runの核心:サーバーレスとコンテナの融合

Cloud Runの最も重要な特徴は、「リクエスト駆動でコンテナがスケールする」 という点です。これは、Cloud Functions(FaaS)とコンテナ(CaaS) の利点を融合した、GCP独自の設計思想です。

Cloud Runの核心機能

  1. リクエストに応じて自動スケーリング: リクエスト数が急増すると、インスタンスを自動で増やします
  2. ゼロへのスケーリング: リクエストがなくなると、インスタンスを自動で0にスケールダウンします。これにより、課金が完全に停止し、コストを最小限に抑えることができます
  3. 任意のコンテナイメージを実行可能: Lambdaのように特定のランタイムに縛られることなく、任意の言語、フレームワーク、ライブラリを含むコンテナイメージをデプロイできます

Knativeベースのアーキテクチャ

Cloud Runは、Kubernetes上で動作するオープンソースプロジェクト「Knative」をベースにしています。これにより、標準化されたサーバーレス環境を提供しながら、ポータビリティも確保されています。

このシンプルさが、Cloud Runの最大の魅力です。開発者は、アプリケーションのコンテナイメージを用意するだけで、インフラ管理から完全に解放されます。


AWSのサービスと徹底比較

Cloud Runの立ち位置を理解するために、AWSの類似サービスと詳しく比べてみましょう。

項目 AWS Lambda AWS Fargate GCP Cloud Run
実行単位 関数 (Function) タスク (Task) リビジョン (Revision)
基盤技術 ランタイム環境 ECS/EKS Knative (Kubernetes)
スケール範囲 0 to N 最小タスク数を維持 0 to N
運用モデル 関数コードをアップロード タスク定義とクラスタ管理 コンテナイメージをデプロイ
料金モデル 実行回数+実行時間 CPU+メモリの使用時間 CPU+メモリ+リクエスト数
コールドスタート 100ms~数秒 30秒~1分 1~3秒
最大実行時間 15分 制限なし 60分

AWS Lambdaとの違い

Lambdaが「関数」単位で実行されるのに対し、Cloud Runは 「コンテナ」 で実行されます。これにより、以下のようなメリットがあります:

開発の一貫性

  • ローカル環境との一貫性:ローカルで動くコンテナイメージをそのままデプロイできるため、開発と本番環境の差異が少なくなります
  • デバッグの容易さ:コンテナ内でのログ確認やトラブルシューティングが簡単

技術選択の自由度

  • PythonのFlask、RubyのRails、JavaのSpringなど、Webサーバーを含むフルスタックアプリケーションもデプロイ可能
  • Lambdaでは特定のランタイムに合わせたコードを書く必要がありますが、Cloud Runは制約がありません

AWS Fargateとの違い

項目 AWS Fargate GCP Cloud Run
概念モデル ECS/EKSの起動タイプ スタンドアロンサービス
設定の複雑さ タスク定義、サービス、クラスタ 単一のコマンドでデプロイ
最小インスタンス 1以上を維持 0まで縮小可能
ネットワーク設定 VPC、セキュリティグループ等の詳細設定 自動で最適化
デプロイ方法 タスク定義の更新 新しいリビジョンの作成

Fargateは強力ですが、ECSやEKSの概念を理解する必要があります。一方、Cloud Runはgcloud run deployという一つのコマンドで、コンテナをデプロイできる手軽さが最大の特徴です。


Cloud Runの料金体系

Cloud Runの料金は非常にシンプルで予測しやすい構造になっています。

課金要素

  1. CPU使用時間: $0.00002400/vCPU秒
  2. メモリ使用時間: $0.00000250/GB秒
  3. リクエスト数: $0.40/100万リクエスト

無料利用枠(毎月)

  • CPU時間:240,000 vCPU秒
  • メモリ時間:450,000 GB秒
  • リクエスト数:200万リクエスト

実際のコスト例

小規模API(月間100万リクエスト、1vCPU、512MB、平均応答時間100ms)の場合:

CPU時間: 1,000,000 × 0.1秒 = 100,000 vCPU秒 → 無料枠内
メモリ時間: 1,000,000 × 0.1秒 × 0.5GB = 50,000 GB秒 → 無料枠内
リクエスト数: 1,000,000リクエスト → 無料枠内

合計: $0

実践ハンズオン:Cloud Runにコンテナをデプロイする

簡単なWebアプリケーションをコンテナ化し、Cloud Runにデプロイしてみましょう。

事前準備

# 必要なAPIを有効化
gcloud services enable run.googleapis.com
gcloud services enable cloudbuild.googleapis.com

# プロジェクトIDを設定
export PROJECT_ID=$(gcloud config get-value project)

1. サンプルアプリケーションの作成

より実用的なFlaskアプリケーションを作成します。

# app.py
import os
from flask import Flask, jsonify, request
import datetime

app = Flask(__name__)

@app.route('/')
def hello():
    return jsonify({
        'message': 'Hello, Cloud Run!',
        'timestamp': datetime.datetime.now().isoformat(),
        'version': '1.0'
    })

@app.route('/health')
def health():
    return jsonify({'status': 'healthy'}), 200

@app.route('/env')
def env():
    return jsonify({
        'port': os.environ.get('PORT', '8080'),
        'service': os.environ.get('K_SERVICE', 'local'),
        'revision': os.environ.get('K_REVISION', 'local'),
    })

@app.route('/echo', methods=['POST'])
def echo():
    data = request.get_json()
    return jsonify({
        'echo': data,
        'received_at': datetime.datetime.now().isoformat()
    })

if __name__ == '__main__':
    port = int(os.environ.get('PORT', 8080))
    app.run(host='0.0.0.0', port=port)

2. 依存関係ファイル作成

# requirements.txt
Flask==2.3.3
gunicorn==21.2.0

3. Dockerfileの作成

プロダクション対応のDockerfileを作成します。

# Dockerfile
FROM python:3.11-slim

# セキュリティとパフォーマンスの設定
RUN useradd --create-home --shell /bin/bash app
WORKDIR /home/app

# 依存関係のインストール
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt

# アプリケーションファイルのコピー
COPY --chown=app:app . .

# 非rootユーザーに切り替え
USER app

# ヘルスチェック
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
    CMD curl -f http://localhost:$PORT/health || exit 1

# Gunicornでアプリケーションを起動
CMD exec gunicorn --bind :$PORT --workers 1 --threads 8 --timeout 0 app:app

4. Cloud Buildを使用したビルドとデプロイ

Cloud Buildを使用して、よりスケーラブルな方法でデプロイします。

# cloudbuild.yaml
steps:
  # コンテナイメージをビルド
  - name: 'gcr.io/cloud-builders/docker'
    args: ['build', '-t', 'gcr.io/$PROJECT_ID/hello-cloud-run:$BUILD_ID', '.']
  
  # イメージをContainer Registryにプッシュ
  - name: 'gcr.io/cloud-builders/docker'
    args: ['push', 'gcr.io/$PROJECT_ID/hello-cloud-run:$BUILD_ID']
  
  # Cloud Runにデプロイ
  - name: 'gcr.io/cloud-builders/gcloud'
    args:
      - 'run'
      - 'deploy'
      - 'hello-cloud-run'
      - '--image'
      - 'gcr.io/$PROJECT_ID/hello-cloud-run:$BUILD_ID'
      - '--region'
      - 'asia-northeast1'
      - '--platform'
      - 'managed'
      - '--allow-unauthenticated'
      - '--memory'
      - '512Mi'
      - '--cpu'
      - '1'
      - '--max-instances'
      - '10'
      - '--concurrency'
      - '80'

images:
  - 'gcr.io/$PROJECT_ID/hello-cloud-run:$BUILD_ID'

5. デプロイの実行

# Cloud Buildを使用してデプロイ
gcloud builds submit --config cloudbuild.yaml

# または直接gcloudコマンドでデプロイ
gcloud run deploy hello-cloud-run \
    --source . \
    --region asia-northeast1 \
    --platform managed \
    --allow-unauthenticated \
    --memory 512Mi \
    --cpu 1 \
    --max-instances 10 \
    --concurrency 80 \
    --set-env-vars "ENV=production"

6. デプロイ結果の確認

# サービス一覧を確認
gcloud run services list

# サービスの詳細情報を取得
gcloud run services describe hello-cloud-run --region=asia-northeast1

# ログの確認
gcloud logs read "resource.type=cloud_run_revision" --limit=10

本番運用のベストプラクティス

パフォーマンス最適化

CPU割り当て設定

# Always allocated(常時CPU割り当て)
gcloud run services update hello-cloud-run \
    --cpu-throttling \
    --region=asia-northeast1

# CPU throttling(リクエスト処理中のみCPU割り当て)
gcloud run services update hello-cloud-run \
    --no-cpu-throttling \
    --region=asia-northeast1

同時並行性の調整

# 1インスタンスあたりの同時リクエスト数を調整
gcloud run services update hello-cloud-run \
    --concurrency=100 \
    --region=asia-northeast1

セキュリティ設定

IAM設定

# 特定のサービスアカウントのみアクセス許可
gcloud run services add-iam-policy-binding hello-cloud-run \
    --member="serviceAccount:your-service@your-project.iam.gserviceaccount.com" \
    --role="roles/run.invoker" \
    --region=asia-northeast1

VPCコネクタの設定

# VPCリソースへのアクセスが必要な場合
gcloud run services update hello-cloud-run \
    --vpc-connector=projects/$PROJECT_ID/locations/asia-northeast1/connectors/my-connector \
    --region=asia-northeast1

監視とロギング

カスタムメトリクス

# app.py内にメトリクス追加
from google.cloud import monitoring_v3
import time

client = monitoring_v3.MetricServiceClient()
project_name = f"projects/{PROJECT_ID}"

def create_custom_metric():
    series = monitoring_v3.TimeSeries()
    series.metric.type = "custom.googleapis.com/request_count"
    series.resource.type = "cloud_run_revision"
    # メトリクス実装...

構造化ログ

import logging
import json

# 構造化ログの設定
logging.basicConfig(
    level=logging.INFO,
    format='%(message)s'
)

def log_request(request_id, endpoint, duration):
    log_entry = {
        'timestamp': datetime.datetime.now().isoformat(),
        'request_id': request_id,
        'endpoint': endpoint,
        'duration_ms': duration,
        'severity': 'INFO'
    }
    logging.info(json.dumps(log_entry))

実際の使用ケースとパフォーマンス

コールドスタートの検証

Cloud Runの実際のパフォーマンスを測定してみましょう:

# 複数回リクエストを送信してコールドスタートを測定
for i in {1..5}; do
  echo "Request $i:"
  time curl -s https://hello-cloud-run-abc.a.run.app/ > /dev/null
  echo "Waiting 10 minutes for scale-to-zero..."
  sleep 600
done

典型的な結果

  • 初回リクエスト(コールドスタート): 2-4秒
  • 2回目以降(ウォームインスタンス): 100-300ms

適用ケース別の評価

ユースケース 適用度 理由
Web API ⭐⭐⭐⭐⭐ ゼロスケール、简単デプロイ、コスト効率
Webアプリケーション ⭐⭐⭐⭐ セッション管理に注意が必要
バッチ処理 ⭐⭐⭐⭐ 時間制限(60分)内なら最適
リアルタイム処理 ⭐⭐ コールドスタートが課題
常時稼働サービス ⭐⭐ 最小インスタンス設定が必要

まとめ:Cloud Runは「究極のサーバーレス」か?

今回は、GCPの独自サービスであるCloud Runを、AWSのFargateとLambdaと比較しました。

サービス AWS Fargate AWS Lambda GCP Cloud Run
主な用途 コンテナオーケストレーション イベント駆動型の関数実行 リクエスト駆動のコンテナ実行
メリット サーバー管理不要、柔軟性 サーバー管理不要、軽量 ゼロスケール、任意のコンテナ、シンプル
デメリット 最小タスク数維持でコスト発生 ランタイム制限、コールドスタート 実行時間制限(60分)
学習コスト 高(ECS/EKSの理解必要) 中(特定ランタイム対応) 低(コンテナの知識のみ)

Cloud Runを選ぶべき場面

◎ 強く推奨

  • API開発(REST、GraphQL)
  • 軽量なWebアプリケーション
  • 不定期なバッチ処理
  • プロトタイプ開発

△ 注意して検討

  • 常時高負荷のサービス
  • リアルタイム性が重要なサービス
  • 長時間実行されるバッチ処理(60分超)

Cloud Runは、そのシンプルさとコスト効率の高さから、 「コンテナベースのサーバーレス」 という新しい選択肢として、多くの開発者に受け入れられています。特に、ローカル開発環境との一貫性を保ちながら、運用負荷を最小限に抑えたい場合には理想的なソリューションです。


次回は、AWS FargateとCloud Runの比較をより深く掘り下げます。「コンテナ運用モデルの根本的な違い」 をテーマに、それぞれの設計思想の違いから最適な選択肢を見つける方法を解説します。お楽しみに!

この記事が役に立ったという方は、ぜひ「いいね」や「ストック」をお願いします!

シリーズ記事一覧

  • [【1日目】はじめの一歩!AWSエンジニアがGCPで最初にやるべきこと]
  • [【2日目】GCPのIAMはAWSとどう違う?「プリンシパル」と「ロール」の理解]
  • [【3日目】VPCとVPCネットワーク:GCPのネットワーク設計思想を理解する]
  • [【4日目】S3とCloud Storage:オブジェクトストレージを徹底比較]
  • [【5日目】RDSとCloud SQL:マネージドデータベースの運用管理の違い]
  • [【6日目】EC2とCompute Engine:インスタンスの起動から課金モデルまで]
  • [【7日目】1週間のまとめ:AWSとGCP、それぞれの得意なことと設計思想]
  • [【8日目】EKSとGKE:Kubernetesのマネージドサービスを比較体験!]
  • [【9日目】Dockerイメージをどこに置く?ECRとArtifact Registryを比較]
  • [【10日目】LambdaとCloud Functions:イベント駆動型サーバーレスの実装]
  • [【11日目】API GatewayとCloud Endpoints:API公開のベストプラクティス]
  • [【12日目】Cloud Run:サーバーレスでコンテナを動かすGCPの独自サービスを試してみよう](この記事)
  • [【13日目】AWS FargateとCloud Run:コンテナ運用モデルの根本的な違い]
1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?