- Cloud Run Functions第2世代はCloud Runベースに刷新され処理時間60分・メモリ32GBに大幅拡張
- 第1世代からの移行手順とコード変更のポイントを詳細に解説
- Eventarc統合・トラフィック分割・最小インスタンスで本番運用品質を実現
Google Cloudのサーバーレス関数サービスが**Cloud Functions(第1世代)からCloud Run Functions(第2世代)**へと大きく進化しました。基盤がCloud Runに統合されたことで、処理時間・メモリ・同時実行の制限が大幅に緩和され、より幅広いユースケースに対応できるようになっています。
本記事では、第2世代の新機能と改善点、第1世代からの移行手順、SES現場での実践的な活用法を詳しく解説します。
- Cloud Run Functions第2世代のアーキテクチャと新機能
- 第1世代との詳細な比較と移行手順
- Eventarc・Cloud Run統合による高度なイベント処理
- パフォーマンス最適化とコスト削減テクニック
Cloud Run Functions第2世代とは
アーキテクチャの変化
第2世代では、内部基盤がCloud Runに統合されました。これにより、Cloud Runの持つ強力なインフラ機能をサーバーレス関数から利用できるようになりました。
【第1世代アーキテクチャ】
ユーザー → Cloud Functions独自基盤 → 関数実行
【第2世代アーキテクチャ】
ユーザー → Cloud Run基盤 → Cloud Run Functions → 関数実行
↑
Eventarc(イベント駆動)
Cloud Build(ビルド)
Artifact Registry(コンテナ保存)
第1世代 vs 第2世代 比較表
| 機能 | 第1世代 | 第2世代 |
|---|---|---|
| 処理時間上限 | 9分(540秒) | 60分(3,600秒) |
| メモリ上限 | 8 GB | 32 GB |
| vCPU | 最大2 | 最大8 |
| 同時実行数/インスタンス | 1 | 最大1,000 |
| 最小インスタンス | なし | 対応 |
| トラフィック分割 | なし | 対応 |
| イベントトリガー | 独自 | Eventarc |
| VPCコネクタ | 必須 | Direct VPC egress |
| リビジョン管理 | なし | 対応 |
| Cloud Run統合 | なし | ネイティブ |

第2世代のセットアップ
プロジェクト初期化
# 必要なAPIの有効化
gcloud services enable \
cloudfunctions.googleapis.com \
run.googleapis.com \
eventarc.googleapis.com \
cloudbuild.googleapis.com \
artifactregistry.googleapis.com
# プロジェクト設定
gcloud config set project my-project-id
gcloud config set run/region asia-northeast1
HTTP関数の作成
// index.ts - HTTP関数(第2世代)
import { HttpFunction } from '@google-cloud/functions-framework';
export const helloWorld: HttpFunction = (req, res) => {
const name = req.query.name || req.body?.name || 'World';
res.json({
message: `Hello, ${name}!`,
version: '2nd-gen',
timestamp: new Date().toISOString(),
region: process.env.FUNCTION_REGION || 'unknown',
});
};
// package.json
{
"name": "cloud-run-functions-demo",
"version": "1.0.0",
"main": "dist/index.js",
"scripts": {
"build": "tsc",
"start": "functions-framework --target=helloWorld",
"deploy": "gcloud functions deploy hello-world --gen2 --runtime=nodejs22 --trigger-http --allow-unauthenticated --region=asia-northeast1 --entry-point=helloWorld"
},
"dependencies": {
"@google-cloud/functions-framework": "^3.4.0"
},
"devDependencies": {
"typescript": "^5.4.0",
"@types/node": "^22.0.0"
}
}
デプロイ
# HTTP関数のデプロイ
gcloud functions deploy hello-world \
--gen2 \
--runtime=nodejs22 \
--trigger-http \
--allow-unauthenticated \
--region=asia-northeast1 \
--memory=256Mi \
--cpu=1 \
--timeout=60s \
--min-instances=0 \
--max-instances=100 \
--entry-point=helloWorld
# デプロイ確認
gcloud functions describe hello-world \
--gen2 \
--region=asia-northeast1
Eventarc統合によるイベント駆動
Eventarcの概要
第2世代ではEventarcがイベントトリガーの標準となりました。Cloud Storageのアップロード、Pub/Subメッセージ、Firestoreの変更など、90以上のGCPサービスからのイベントを受信できます。
Cloud Storage トリガー
// storage-trigger.ts
import { CloudEvent } from '@google-cloud/functions-framework';
import { Storage } from '@google-cloud/storage';
import sharp from 'sharp';
interface StorageObjectData {
bucket: string;
name: string;
contentType: string;
size: string;
}
const storage = new Storage();
export const processUploadedImage = async (
event: CloudEvent<StorageObjectData>
) => {
const { bucket, name, contentType } = event.data!;
if (!contentType?.startsWith('image/')) {
console.log(`Skipping non-image file: ${name}`);
return;
}
console.log(`Processing image: gs://${bucket}/${name}`);
// 画像のリサイズ処理
const file = storage.bucket(bucket).file(name);
const [buffer] = await file.download();
const resized = await sharp(buffer)
.resize(800, 600, { fit: 'inside' })
.webp({ quality: 85 })
.toBuffer();
const thumbnailName = `thumbnails/${name.replace(/\.[^.]+$/, '.webp')}`;
await storage.bucket(bucket).file(thumbnailName).save(resized, {
metadata: { contentType: 'image/webp' },
});
console.log(`Thumbnail created: ${thumbnailName}`);
};
# Cloud Storage トリガーでデプロイ
gcloud functions deploy process-uploaded-image \
--gen2 \
--runtime=nodejs22 \
--trigger-event-filters="type=google.cloud.storage.object.v1.finalized" \
--trigger-event-filters="bucket=my-upload-bucket" \
--region=asia-northeast1 \
--memory=1Gi \
--cpu=2 \
--timeout=300s \
--entry-point=processUploadedImage
Firestore トリガー
// firestore-trigger.ts
import { CloudEvent } from '@google-cloud/functions-framework';
import { Firestore } from '@google-cloud/firestore';
interface FirestoreEventData {
value: {
name: string;
fields: Record<string, any>;
};
oldValue?: {
name: string;
fields: Record<string, any>;
};
}
const db = new Firestore();
export const onOrderCreated = async (
event: CloudEvent<FirestoreEventData>
) => {
const { value } = event.data!;
const orderId = value.name.split('/').pop();
console.log(`New order created: ${orderId}`);
// 注文処理のワークフロー
// 1. 在庫チェック
// 2. 決済処理
// 3. 確認メール送信
// 4. 配送手配
await db.collection('order-logs').add({
orderId,
status: 'processing',
timestamp: new Date(),
});
};
Pub/Sub トリガー
// pubsub-trigger.ts
import { CloudEvent } from '@google-cloud/functions-framework';
interface PubSubData {
message: {
data: string; // base64エンコード
attributes: Record<string, string>;
};
}
export const processMessage = async (
event: CloudEvent<PubSubData>
) => {
const data = JSON.parse(
Buffer.from(event.data!.message.data, 'base64').toString()
);
console.log('Received message:', data);
// メッセージ処理
switch (data.type) {
case 'user.created':
await handleUserCreated(data.payload);
break;
case 'order.completed':
await handleOrderCompleted(data.payload);
break;
default:
console.warn(`Unknown event type: ${data.type}`);
}
};
async function handleUserCreated(payload: any) {
// ウェルカムメール送信、初期設定など
}
async function handleOrderCompleted(payload: any) {
// レポート更新、通知送信など
}
第2世代の強力な新機能
同時実行(Concurrency)
第2世代の最大の改善点の1つが、1インスタンスで複数リクエストを同時処理できるようになったことです。
# 同時実行数を設定してデプロイ
gcloud functions deploy api-handler \
--gen2 \
--runtime=nodejs22 \
--trigger-http \
--region=asia-northeast1 \
--concurrency=80 \
--cpu=2 \
--memory=1Gi \
--min-instances=1 \
--max-instances=50
【同時実行の効果】
第1世代: 100リクエスト/秒 → 100インスタンス必要
第2世代: 100リクエスト/秒 → 2-5インスタンスで処理可能
↓
コスト75%削減!
最小インスタンス(Min Instances)
コールドスタートを回避するために、最小インスタンス数を設定できます。
# 最小インスタンスを設定
gcloud functions deploy critical-api \
--gen2 \
--min-instances=2 \
--max-instances=100
| ユースケース | min-instances推奨値 |
|---|---|
| API(レイテンシ重視) | 1-3 |
| バッチ処理 | 0 |
| Webhook受信 | 1 |
| 社内ツール | 0 |
| 本番API(高トラフィック) | 3-10 |
トラフィック分割
カナリアデプロイやA/Bテストを実現するトラフィック分割機能です。
# 新しいリビジョンをデプロイ(トラフィック0%)
gcloud functions deploy my-function \
--gen2 \
--no-traffic
# 10%のトラフィックを新リビジョンに振り分け
gcloud run services update-traffic my-function \
--region=asia-northeast1 \
--to-revisions=my-function-00002-abc=10
# 問題なければ100%に切り替え
gcloud run services update-traffic my-function \
--region=asia-northeast1 \
--to-latest
Direct VPC Egress
VPCコネクタを使わずに直接VPCにアクセスできるようになりました。
# Direct VPC egressでデプロイ
gcloud functions deploy internal-api \
--gen2 \
--network=my-vpc \
--subnet=my-subnet \
--egress-settings=private-ranges-only \
--region=asia-northeast1
第1世代からの移行
移行チェックリスト
□ ランタイムバージョンの確認(Node.js 22推奨)
□ --gen2 フラグの追加
□ イベントトリガーのEventarc形式への変更
□ 環境変数の移行
□ IAM権限の更新
□ VPC接続設定の見直し
□ テストの実行と動作確認
□ モニタリング・アラートの再設定
コード変更のポイント
// 第1世代(変更前)
import { Request, Response } from '@google-cloud/functions-framework';
export const myFunction = (req: Request, res: Response) => {
// Cloud Functions独自のシグネチャ
res.send('Hello');
};
// 第2世代(変更後) - 同じシグネチャが使用可能!
import { HttpFunction } from '@google-cloud/functions-framework';
export const myFunction: HttpFunction = (req, res) => {
// 基本的にはコード変更不要
res.send('Hello');
};
イベントトリガーの変更:
// 第1世代のCloud Storageトリガー
export const processFile = (data: any, context: any) => {
const file = data;
console.log(`Processing: ${file.name}`);
};
// 第2世代のCloud Storageトリガー
import { CloudEvent } from '@google-cloud/functions-framework';
export const processFile = (event: CloudEvent<StorageObjectData>) => {
const file = event.data!;
console.log(`Processing: ${file.name}`);
};
デプロイコマンドの変更
# 第1世代
gcloud functions deploy my-function \
--runtime=nodejs20 \
--trigger-bucket=my-bucket
# 第2世代
gcloud functions deploy my-function \
--gen2 \
--runtime=nodejs22 \
--trigger-event-filters="type=google.cloud.storage.object.v1.finalized" \
--trigger-event-filters="bucket=my-bucket" \
--region=asia-northeast1
パフォーマンス最適化
コールドスタート対策
// グローバルスコープで初期化(インスタンス再利用時に効く)
import { Firestore } from '@google-cloud/firestore';
import { SecretManagerServiceClient } from '@google-cloud/secret-manager';
// これらはコールドスタート時のみ初期化される
const db = new Firestore();
const secretManager = new SecretManagerServiceClient();
let cachedApiKey: string | null = null;
export const myFunction: HttpFunction = async (req, res) => {
// APIキーのキャッシュ
if (!cachedApiKey) {
const [secret] = await secretManager.accessSecretVersion({
name: 'projects/my-project/secrets/api-key/versions/latest',
});
cachedApiKey = secret.payload?.data?.toString() || '';
}
// 処理実行
const result = await processRequest(req.body, cachedApiKey);
res.json(result);
};
メモリ・CPU最適化
【ユースケース別推奨設定】
┌───────────────────────┬───────┬────────┬───────────┐
│ ユースケース │ CPU │ メモリ │ タイムアウト │
├───────────────────────┼───────┼────────┼───────────┤
│ 軽量API │ 0.083 │ 128Mi │ 10s │
│ 標準API │ 1 │ 512Mi │ 30s │
│ 画像処理 │ 2 │ 2Gi │ 120s │
│ データ処理 │ 4 │ 8Gi │ 540s │
│ ML推論 │ 8 │ 32Gi │ 3600s │
│ バッチ処理 │ 4 │ 4Gi │ 3600s │
└───────────────────────┴───────┴────────┴───────────┘
コスト最適化
【コスト計算例: 月間100万リクエスト】
第1世代(concurrency=1):
- CPU: 100万 × 0.5秒 × $0.000016/vCPU-秒 = $8.00
- メモリ: 100万 × 0.5秒 × 256MB × $0.0000025/GB-秒 = $0.32
- リクエスト: 100万 × $0.40/100万 = $0.40
- 合計: 約$8.72/月
第2世代(concurrency=80):
- CPU: 12,500インスタンス秒 × $0.000024/vCPU-秒 = $0.30
- メモリ: 12,500 × 256MB × $0.0000025/GB-秒 = $0.008
- リクエスト: 100万 × $0.40/100万 = $0.40
- 合計: 約$0.71/月
→ 第2世代で約92%のコスト削減!
SES現場での活用シナリオ
Webhook処理サーバー
// Stripe Webhook処理
export const stripeWebhook: HttpFunction = async (req, res) => {
const sig = req.headers['stripe-signature'] as string;
try {
const event = stripe.webhooks.constructEvent(
req.rawBody!,
sig,
process.env.STRIPE_WEBHOOK_SECRET!
);
switch (event.type) {
case 'payment_intent.succeeded':
await handlePaymentSuccess(event.data.object);
break;
case 'customer.subscription.deleted':
await handleSubscriptionCancelled(event.data.object);
break;
}
res.json({ received: true });
} catch (err) {
console.error('Webhook error:', err);
res.status(400).send(`Webhook Error: ${err}`);
}
};
スケジュール実行(Cloud Scheduler連携)
# 日次レポート生成ジョブ
gcloud scheduler jobs create http daily-report \
--schedule="0 9 * * *" \
--time-zone="Asia/Tokyo" \
--uri="https://asia-northeast1-my-project.cloudfunctions.net/daily-report" \
--http-method=POST \
--oidc-service-account-email=scheduler@my-project.iam.gserviceaccount.com
マイクロサービスのエンドポイント
// マイクロサービス: ユーザーサービス
export const userService: HttpFunction = async (req, res) => {
const { method, path } = req;
try {
switch (`${method} ${path}`) {
case 'GET /users':
return res.json(await listUsers(req.query));
case 'GET /users/:id':
return res.json(await getUser(req.params.id));
case 'POST /users':
return res.status(201).json(await createUser(req.body));
case 'PUT /users/:id':
return res.json(await updateUser(req.params.id, req.body));
default:
return res.status(404).json({ error: 'Not Found' });
}
} catch (error) {
console.error('User service error:', error);
res.status(500).json({ error: 'Internal Server Error' });
}
};
まとめ
Cloud Run Functions第2世代は、Cloud Runベースへの刷新により大幅な性能向上とコスト削減を実現しました。
| 改善ポイント | 効果 |
|---|---|
| 処理時間上限 | 9分 → 60分(6.7倍) |
| メモリ上限 | 8GB → 32GB(4倍) |
| 同時実行 | 1 → 最大1,000 |
| コスト | 最大92%削減(高トラフィック時) |
| コールドスタート | 最小インスタンスで回避 |
SES案件では、第2世代への移行支援やEventarc統合の設計・実装が求められる機会が増えています。Google Cloud Functions入門から基礎を固め、本記事の内容で第2世代の実践力を身につけましょう。