post-cover

本記事で紹介するプログラムは以下の GitHub リポジトリで公開しています

GitHub - isec-promotion/ptz-controller-gcp

本記事は連載形式でお届けしています。各回の内容は以下のリンクからご覧いただけます。

はじめに

前回の記事では、Node.js と React を使ってローカルネットワーク内の PTZ カメラを Web ブラウザから制御するシステムをご紹介しました。

今回はその続編として、このシステムを Google Cloud Platform (GCP) にデプロイし、インターネット経由でどこからでも安全に遠隔操作できるようにしたアーキテクチャと、その導入手順について詳しく解説します。

ローカル環境のシステムをクラウド化する際に直面する「どうやって安全に社内ネットワークのカメラと通信するか?」という課題を、Raspberry Pi を中継器とすることで解決しました。この記事が、同じような構成を検討している方の助けになれば幸いです。


システム構成:クラウドとローカルのハイブリッドアーキテクチャ

本システムは、操作用のフロントエンドとバックエンドを GCP 上に配置し、カメラ設置環境には Raspberry Pi を設置して両者をつなぎます。


┌─────────────────┐     ┌─────────────────┐     ┌─────────────────┐
│ Frontend        │     │ Backend         │     │ Raspberry Pi    │
│ (Cloud Run)     │◄───►│ (App Engine)    │◄───►│ (Local)         │
│                 │     │                 │     │                 │
│ - React UI      │     │ - PTZ API       │     │ - Camera Stream │
│ - PTZ Controls  │     │ - Stream Proxy  │     │ - PTZ Control   │
│ - Video Player  │     │ - Auth & CORS   │     │ - Heartbeat     │
└─────────────────┘     └─────────────────┘     └─────────────────┘
  • フロントエンド (Cloud Run): React 製の Web アプリをコンテナ化し、Cloud Run でスケーラブルに提供。
  • バックエンド (App Engine): PTZ 操作用 API、映像中継、Raspberry Pi 管理を担当。
  • Raspberry Pi (ローカル): カメラと同一ネットワークに設置。GCP からの指示で PTZ 操作や映像変換 (FFmpeg) を実行。

ポイントは、Raspberry Pi から GCP へ WebSocket 接続を開始する仕組み。これにより、ポート開放なしで安全な通信が可能になります。

ディレクトリ構成

プロジェクト全体のディレクトリ構成は以下のようになっています。


cloud/
├── cloud-backend/ \# GCP バックエンド (App Engine)
│ ├── src/
│ ├── app.yaml \# App Engine 設定
│ └── deploy.sh \# デプロイスクリプト
│
├── cloud-frontend/ \# GCP フロントエンド (Cloud Run)
│ ├── src/
│ ├── Dockerfile
│ └── deploy.sh
│
└── raspberry/ \# Raspberry Pi アプリケーション
├── src/
├── setup.sh \# セットアップスクリプト
└── package.json

デプロイとセットアップの手順

実際にこのシステムを構築する手順を見ていきましょう。

前提条件

  • GCP アカウント
  • Google Cloud CLI (gcloud)
  • Node.js 18 以上
  • Docker(フロントエンド用)

Step 1: バックエンド (App Engine)

まず API サーバーを App Engine にデプロイします。

# cloud/cloud-backend/ ディレクトリに移動
cd cloud-backend

# 環境変数にあなたのGCPプロジェクトIDを設定
export GOOGLE_CLOUD_PROJECT=your-project-id

# デプロイスクリプトを実行
./deploy.sh

機密情報はコードに書かず Secret Manager に保存します。

以下のコマンドで 'YOUR_..._VALUE' を実際の値に置き換えてください。

# カメラの接続情報を設定
echo 'YOUR_CAMERA_IP' | gcloud secrets versions add camera-ip --data-file=-
echo 'YOUR_CAMERA_USERNAME' | gcloud secrets versions add camera-username --data-file=-
echo 'YOUR_CAMERA_PASSWORD' | gcloud secrets versions add camera-password --data-file=-

# Raspberry Pi とバックエンド間の認証キーを設定
echo 'YOUR_STRONG_RANDOM_KEY' | gcloud secrets versions add raspberry-pi-auth-key --data-file=-

# ユーザー認証用のJWT秘密鍵を設定
echo 'YOUR_JWT_SECRET_KEY' | gcloud secrets versions add jwt-secret --data-file=-

Step 2: フロントエンド (Cloud Run)

次に React 製の UI を Cloud Run にデプロイします。

# cloud/cloud-frontend/ ディレクトリに移動
cd cloud-frontend

# 環境変数にGCPプロジェクトIDと、先ほどデプロイしたバックエンドのURLを設定
export GOOGLE_CLOUD_PROJECT=your-project-id
export APP_URL=your-project-id.an.r.appspot.com # バックエンドのURL

# デプロイスクリプトを実行
./deploy.sh

Step 3: Raspberry Pi セットアップ

ローカルに置く Raspberry Pi を設定します。

# cloud/raspberry/ ディレクトリに移動
cd raspberry

# .env.exampleをコピーして環境変数ファイルを作成
cp .env.example .env

# セットアップスクリプトを実行(依存関係のインストールなど)
./setup.sh

# nanoなどのエディタで .env ファイルを編集
nano .env

.env に環境値を入力してください。

# バックエンドの完全なURL
GCP_BACKEND_URL=[https://your-project-id.an.r.appspot.com](https://your-project-id.an.r.appspot.com)

# このデバイスを識別するためのユニークなID
DEVICE_ID=raspberry-pi-001

# バックエンドのSecret Managerで設定した値と同じ認証キー
AUTH_KEY=YOUR_STRONG_RANDOM_KEY

# PTZカメラのIPアドレスと認証情報
CAMERA_IP=192.168.1.108
CAMERA_USERNAME=admin
CAMERA_PASSWORD=your_camera_password

設定後に Raspberry Pi 上でアプリを起動すれば、システム全体が稼働します。

セキュリティに関する注意(重要)

注意: 本システムの現在の実装は、あくまで技術的なコンセプトを実証するためのものです。このまま本番環境で利用するにはセキュリティが不十分です。

現状の実装では、フロントエンドの URL を知っていれば誰でもカメラの映像を閲覧し、操作できてしまいます。本格的に運用する際は、必ず追加のセキュリティ対策を実装してください。

ここでは、本構成で採用している基本的なセキュリティの仕組みと、本番運用へ向けた課題について解説します。

採用している基本的な仕組み

  • 機密情報の隔離: パスワード等は GCP Secret Manager で管理(コードへ埋め込まない)。
  • デバイス認証: Raspberry Pi は共有 認証キー で接続検証。
  • 通信暗号化: すべて HTTPS/WSS で暗号化。

本番環境で利用するための課題

上記の対策は重要ですが、これだけでは不十分です。セキュアなシステムとして利用するためには、少なくとも以下の機能追加が必要です。

  1. フロントエンドの認証機能: ユーザー ID とパスワードによるログイン機能を実装し、許可されたユーザーのみがカメラを操作できるようにする必要があります。(例: Firebase Authentication, Auth0 等の認証サービスの導入)
  2. 認可(権限管理): ユーザーごとに「映像の閲覧のみ」「PTZ 操作も可能」といった権限を管理する仕組みを導入することが望ましいです。
  3. より強固なネットワーク設定: 必要に応じてファイアウォールルールでアクセス元 IP アドレスを制限するなど、ネットワークレベルでのセキュリティ強化も検討してください。

監視とトラブルシューティング

クラウドでシステムを運用する上で、監視は不可欠です。

  • ログ管理: Cloud Run(フロントエンド)と App Engine(バックエンド)のログは自動で Google Cloud Logging に集約されます。リアルタイム確認は以下のコマンドで行えます。
# バックエンドのログ
gcloud app logs tail -s default

# フロントエンドのログ
gcloud run logs tail --service=ptz-control-frontend --region=asia-northeast1
  • 死活監視: Raspberry Pi は定期的にバックエンドへ ハートビート を送信し、オンライン状態を常に確認できます。

エラー発生時は、まず各サービスのログを確認し、Secret Manager や .env の設定値を再確認してください。

まとめ

本記事では、ローカルの PTZ カメラ制御を GCP + Raspberry Pi でクラウド化し、遠隔操作を可能にする仕組みを紹介しました。

クラウドとデバイスを組み合わせることで、利用シーンは大きく広がります。
今回の構成はあくまで コンセプト実証 であり、本番運用には認証や権限管理などのセキュリティ強化が必須です。

IoT やリモートワーク向けシステム構築の一助になれば幸いです。

SNSでシェアしよう

この記事が役に立ったら、ぜひシェアしてください