Go+node.js/claudeをどう動かすかを考えた話
はじめに
初めまして!
皆様どうもこんにちわ、こんばんわ、おはようございます。
エンジニアの enomoto です。
最近、あるアプリケーションで Go + Docker(Node.js)を本番環境やステージング環境でどのように動かすかを検討していました。その際の考えたことを備忘録として記録しておきます。
検討時に重視した観点は以下の通りです:
- デプロイの簡単さ(PoC 段階のため)
- 環境構築の簡単さ(PoC 段階のため)
- ローカル環境との差分の少なさ
システム概要
この構成は Go サーバーでリクエストを受け取り、事前にビルドしておいた Docker コンテナ(Node.js + Claude)を起動し、コンテナ上の Claude Code にファイルへの書き込みを実行させます。その結果を Go 側で読み取り、データベースに保存するシステムです。
※Volume マウントを使用することで、Go 側でもコンテナから書き込まれたファイルを参照できるようにする必要があります。
検討した構成
以下の 4 つの構成を検討しました:
- Lambda(Go)+ Lambda(Node.js コンテナイメージ)
- Lambda 単体(Go + Node.js コンテナイメージ)
- EC2 上で Go + Docker(Node.js)
- EC2 上で Go と Node.js のコンテナを Docker Compose で動かす
※AWS Fargate はファイルへの書き込みができないため、この時点で選択肢から除外しました。
これらの構成が最適なのかどうかはさておき、こういう構成も選択肢としてあるんだぐらいで眺めてもらえると幸いです。
それぞれの構成について詳しく説明します。
1. Lambda(Go)+ Lambda(Node.js)
必要なリソース
構築するもの:
- Lambda × 2
- API Gateway
- IAM ロール(Lambda 実行用、ECR アクセス用)
- CloudWatch Logs(ログ管理)
デプロイ自動化のために必要なもの:
- Node.js のビルド済みイメージを push する ECR
- ビルドして ECR に push するための GitHub Actions
動作フロー
- API Gateway を通じて Go の Lambda にリクエストが送信される
- Go Lambda から別の Node.js Lambda を呼び出す
- Node.js Lambda で Claude Code が tmp ディレクトリ内にファイルを書き込む
- 書き込み結果を Go Lambda にレスポンスとして返す
- Go Lambda でデータベースに保存する
メリット
- サーバーレスの恩恵を最大限受けられる(自動スケーリング、従量課金、インフラ管理不要など)
デメリット
- Lambda を 2 つ用意し、それぞれでデプロイが必要
- Lambda 用の Node.js イメージを ECR で管理する必要がある
- ローカル環境と全く同じようには動作しない(サーバーレス環境のため)
- Go の Lambda が本当に必要か疑問(この疑問から次のパターンが生まれました)
2. Lambda 単体(Go + Node.js)
必要なリソース
構築するもの:
- Lambda × 1
- API Gateway
- IAM ロール(Lambda 実行用、ECR アクセス用)
- CloudWatch Logs(ログ管理)
デプロイ自動化のために必要なもの:
- Node.js + Go のシングルバイナリをビルドしたイメージを push する ECR
- ビルドして ECR に push するための GitHub Actions
前の構成との違い
前の構成では Go と Node.js を別々の Lambda 関数として分けていましたが、今回は単一の Lambda 関数内で両方を動作させています。
Go はビルドするとシングルバイナリになるため、Node.js ベースのコンテナイメージ内に Go のバイナリを含めることで、一つのコンテナで両方の処理を実行できます。この特性を活かし、以下の要素を含む Dockerfile を一つ用意します:
- Go をビルドした成果物のシングルバイナリ
- Node.js のイメージ
- Claude Code のインストール
動作フロー
- API Gateway を通じて Go + Node.js の Lambda にリクエストが送信される
- Lambda 内で Claude Code が tmp ディレクトリ内にファイルを書き込む
- Go がそのファイルを読み取り、データベースに保存する
メリット
- Lambda が 1 つだけでデプロイ先が少なくなった
- 管理するリソースが減った
デメリット
- Lambda 用の Node.js イメージを ECR で管理する必要がある
- ローカル環境と全く同じようには動作しない(サーバーレス環境のため)
- ビルドのパターンがやや複雑
サーバーレスからの方向転換
当初は lambrollを使った Lambda デプロイが良いと考えていましたが、次第に課題が見えてきました。サーバーレス環境はローカルでの動作と使い勝手が異なり、様々な制約があります。Lambda 用にイメージを push する作業も煩雑で、PoCの段階ではかなり多くの時間を食うのでは?結果的に EC2 の方が運用しやすいのではないか?という結論に至りました。
3. EC2 上で Go + Docker(Node.js)
この構成はローカル環境と全く同じように動作します。
デプロイパターン 1:ECR を使用
必要なリソース:
- EC2
- VPC やその他ネットワーク系(サブネット、インターネットゲートウェイ、ルートテーブル)
- セキュリティグループ(HTTP/HTTPS、SSH アクセス用)
- キーペア(SSH 接続用)
- Elastic IP(固定 IP が必要な場合)
- IAM ロール(EC2 が ECR にアクセスするため)
- ECR
デプロイ自動化のために必要なもの:
- Node.js のイメージをビルドして ECR に push し、そのイメージを EC2 で pull する GitHub Actions
デプロイパターン 2:EC2 上でビルド
必要なリソース:
- EC2
- VPC やその他ネットワーク系(サブネット、インターネットゲートウェイ、ルートテーブル)
- セキュリティグループ(HTTP/HTTPS、SSH アクセス用)
- キーペア(SSH 接続用)
- Elastic IP(固定 IP が必要な場合)
EC2 上に事前インストールが必要なもの:
- Docker
- Git
- その他必要なツール
デプロイ自動化のために必要なもの:
- 構築済みの EC2 に SSH で接続し、git pull でソースコードを取得、EC2上でdocker build を実行する GitHub Actions
メリット
- ローカル環境とほぼ同じように動作する
- EC2 なので、一度セットアップ~自動デプロイまで構築すれば楽に運用できる
デメリット
- VPC などのネットワーク構成を自分で構築する必要がある
- EC2 インスタンスの管理が必要
- サーバーレスと比較してコストがかかる場合がある(EC2が常時起動なので)
4. EC2 上で Go と Node.js のコンテナを Docker Compose で動かす
この構成では nodejsコンテナ呼び出しをするときに2 つのアプローチが考えられます。
パターン A:Docker Compose ネットワークを使用
Docker Compose のネットワーク機能を使い、コンテナ間通信を行うパターンです。
パターン B:Docker API を使用
通常、コンテナ内からは Docker コマンドを実行できませんが、UNIX ソケット(/var/run/docker.sock
)をマウントすることで、Go 側のコンテナから Docker API を操作し、Node.js 側のコンテナを動的に起動するパターンです。
※この構成では Docker socket への強力な権限(root 相当)が必要となるため、セキュリティ上の考慮が重要です。
デプロイ方法
どちらのパターンでも、以下の 2 つのデプロイ方法が選択できます:
方法 1:ECR を使用
必要なリソース:
- EC2
- VPC やその他ネットワーク系(サブネット、インターネットゲートウェイ、ルートテーブル)
- セキュリティグループ(HTTP/HTTPS、SSH アクセス用)
- キーペア(SSH 接続用)
- Elastic IP(固定 IP が必要な場合)
- IAM ロール(EC2 が ECR にアクセスするため)
- ECR
EC2 上に事前インストールが必要なもの:
- Docker
- Docker Compose
デプロイ自動化のために必要なもの:
- ECR にイメージを push し、それを EC2 上で pull する Github Actions
方法 2:EC2 上でビルド
必要なリソース:
- EC2
- VPC やその他ネットワーク系(サブネット、インターネットゲートウェイ、ルートテーブル)
- セキュリティグループ(HTTP/HTTPS、SSH アクセス用)
- キーペア(SSH 接続用)
- Elastic IP(固定 IP が必要な場合)
EC2 上に事前インストールが必要なもの:
- Docker
- Docker Compose
- Git
- その他必要なツール
デプロイ自動化のために必要なもの:
- EC2 上で git pull でソースコードを取得し、docker build を実行するGithub Actions
メリット
- オールコンテナ化により、可搬性がある
- Docker Compose により、複数コンテナの管理が簡単
- 開発環境との一貫性が保たれる(開発環境もdocker compose運用した場合)
デメリット
- コンテナ間通信やコンテナからのDocker呼び出しの設定が必要でやや複雑
※3番のパターンのメリットデメリットに加えて上記のメリットデメリットがある
終わりに
結局何やかんやとゴニョゴニョと書きましたが、以下のような理由で 3 番のパターンで構築することにしました。
・ローカルと全く同じような状況で動作する
・環境構築や CD の構築も割と楽にできる
一つのアプリケーションでもクラウド環境での動かした方はたくさんあります。
それぞれのメリットデメリットを比較し、今の状況に最適な環境を用意しましょう。
Discussion