
Claude Code ハンズオン環境をClaude Codeで構築してみた
【2026-05-28 追記】 100名規模のオンライン開催を視野に入れた構成変更について、本記事末尾に追記しています。詳細は「追記(2026-05-28):オンライン100名規模開催に向けた構成変更」セクションをご参照ください。
ハンズオン環境の全体構成
まず、完成した環境の全体像をご覧ください。
参加者がブラウザでURLにアクセスしてから、Claude Codeが使えるようになるまでの流れは以下のとおりです。なお、構成図上では1つの図にまとめていますが、ブログ上では性質が異なる2つのフローに分けて説明します。
ユーザーアクセスフロー(ステップ1〜7・11)
参加者がブラウザからアクセスし、Claude Codeを実行するまでの流れです。
| ステップ | 内容 |
|---|---|
| 1. ユーザーアクセス | 参加者がブラウザからHTTPSでIDEのURLにアクセス(Route 53のカスタムドメイン経由) |
| 2. DNS解決 | Route 53がカスタムドメインをCloudFrontに解決 |
| 3. CDN+TLS終端 | CloudFrontがACM証明書でTLSを終端。シークレットヘッダーを付与してFrontend ALBへ転送 |
| 4. Frontend ALBルーティング | Frontend ALBがシークレットヘッダーを検証し、auth-gatewayコンテナへ転送 |
| 5. OIDC認証 | nginx+oauth2-proxyが未認証リクエストをCognito Hosted UIへリダイレクト。ログイン後にトークンを発行 |
| 6. auth-gateway → Shard ALB(動的振り分け) | auth-gatewayが /userN/* から所属シャードを計算し、対応するシャードALB(internal)へ X-Internal-Secret ヘッダー付きでプロキシ |
| 7. Shard ALB → code-server | シャードALBがパスベースルーティング(/userN/*)で参加者専用のcode-serverタスクへ転送(1 user = 1 task = 1 TG) |
| 11. AI推論(Amazon Bedrock) | code-server上のClaude CodeがAmazon Bedrockを経由してClaude Sonnet 4.5を呼び出し |
環境構築フロー(ステップ8〜10、参加者アクセス前に実行)
受講者が触る前に、コンテナイメージのビルドとデプロイを行うパイプラインです。
| ステップ | 内容 |
|---|---|
| 8. Dockerビルド | S3からDockerfileと教材を取得し、CodeBuildがClaude Code CLIインストール済みイメージをビルド |
| 9. イメージPUSH | ビルド済みイメージをAmazon ECRにプッシュ |
| 10. イメージPULL・起動 | ECS FargateタスクがECRから最新イメージをプルし、code-serverを起動 |
この構成を作るにあたり、大きく3つの課題がありました。以降では、課題ごとに検討したアプローチと採用した理由を説明します。
課題1:受講者ごとの環境をどう用意するか(ステップ8〜10)
AWS上にVS Code(code-server)とClaude CLIが入った環境を人数分用意する必要があります。最初に直面したのが「どういう構成でその環境を準備するか」というコスト・運用両面での検討です。
検討したアプローチ
A案:1台のEC2で複数受講者に対応する
最初に思い浮かんだのは、1台のEC2インスタンス上に受講者全員分の環境をまとめて構築するアプローチです。シンプルで管理もしやすい反面、受講者間の環境が分離されないため、ファイル操作やプロセスが干渉するリスクがあります。
B案:コンテナで受講者ごとに環境を分離する(採用)
受講者1人につき1つのコンテナを起動する構成です。環境が完全に分離されるため、他の受講者の操作が影響を及ぼしません。
採用理由
コンテナ化を選んだ決め手は再利用性です。コンテナイメージとして管理しておけば、他のハンズオンテーマでも同じ仕組みを流用できます。人数の増減も、起動するコンテナ数を変更するだけで対応できる点も運用上のメリットでした。
ステップ8でCodeBuildを使ってDockerイメージをビルドし(S3から教材ファイルも同時に取り込み)、ステップ9でECRにプッシュ、ステップ10でECS Fargateが人数分のコンテナを起動する流れになっています。
課題2:アクセスURLを1つに統一したい(ステップ1〜4・6〜7)
受講者ごとにコンテナを分けると、次の問題が生じます。「受講者ごとに異なるURLを案内する」ことになり、ハンズオン進行の妨げになります。セミナー中に「あなたは3番のURLを使ってください」という案内は、混乱のもとです。
やりたいこと: 全員が同一のURLにアクセスし、認証後に自分のコンテナへ自動で振り分けられる。
採用したアプローチ:ALBによるパスベースルーティング
ALB(Application Load Balancer)を活用して、ステップ1〜4の流れでリクエストをauth-gatewayまで届け、ステップ6〜7でユーザーごとのコンテナへ振り分けます。
認証後、ユーザーのニックネーム(user1、user2 ...)をもとに /user{N}/ へリダイレクトし、そのパスに対応するコンテナへ転送します。自分以外のパスにはアクセスできない制御も加えています。
なお、ステップ3でCloudFrontをFrontend ALBの前段に置いているのは、code-serverのWebSocket通信に必要なHTTPS終端と、ALBへの直接アクセス防止(シークレットヘッダー検証)のためです。
また、Frontend ALB/Shard ALBの2層構成にしている理由については、後述の「追記(2026-05-28):オンライン100名規模開催に向けた構成変更」をご参照ください。
課題3:code-serverへの認証をどう組み込むか(ステップ5)
ALBで1つのURLに集約できたとして、次の問題が出てきました。
code-server自体には、外部IDPとの連携機能がありません。
code-serverにはパスワード認証の仕組みはあるものの、CognitoのようなIDPと連携してOIDC認証を行う機能が標準では用意されていません。受講者全員に個別のパスワードを発行・管理する運用も、規模が増えると現実的ではありません。
採用したアプローチ:OAuth2-Proxy + Cognito
auth-gatewayというコンテナを別途用意し、その中でnginx + OAuth2-Proxyを動かす構成を採用しました(ステップ5)。
- OAuth2-ProxyがCognito(OIDC)と連携し、ログイン・セッション管理を担当
- nginxがOAuth2-Proxyと連携し、認証済みリクエストのみをcode-serverへ転送
code-server自体には手を加えず、認証の仕組みを前段に追加する形で解決しています。
実際にやった作業
TerraformによるIaC化
上述の構成全体をTerraformで実装しました。Route 53・CloudFront・ALB・ECS Fargate・Cognito・IAMなど、必要なリソースを1つのモジュールとしてまとめています。terraform apply 一発で環境が立ち上がる状態を目標に設計しています。
この実装作業はClaude Codeとの対話を通じて進めました。インフラ構成の設計から、Terraformコードの記述・修正まで、AIとやりとりしながら構築を進めています。
コンテナイメージの構成
code-serverコンテナはUbuntu 24.04をベースに、以下を組み込んでいます。
- code-server(ブラウザ版VS Code)
- Claude Code CLI
- AWS CLI(ECS TaskロールでAmazon Bedrockにアクセス)
- ハンズオン用教材ファイル
Claude CodeはAmazon Bedrockを経由してClaude Sonnet 4.5を呼び出す設定にしており(ステップ11)、受講者側でAPIキーを準備する必要はありません。
auth-gatewayコンテナはnginx公式イメージをベースに、OAuth2-Proxyを組み込んでいます。
ハンズオン進行の改善:受講者フィードバックをもとに操作方法を変更
環境の整備と並行して、ハンズオンの進め方自体も回を重ねるごとに改善しています。
初回は、Claude CLIとコマンドラインを使って操作してもらう形式でした。しかし実施後、受講者の方からいくつかのご意見をいただきました。
- 「コマンド操作が多く、ハンズオンのテンポが落ちてしまう」
- 「チャット画面だけで完結できると、より直感的に使えそう」
- 「プログラミングの経験がないので、コマンドラインの操作に戸惑ってしまった」
これらのフィードバックを受け、3回目の開催からはcode-serverにClaude CodeのVS Code拡張機能(プラグイン)を組み込み、チャット画面のみで操作してもらう構成に変更しました。コマンドラインを使わず、チャットでの指示だけでハンズオンが完結するため、プログラミング経験のない受講者の方にも参加しやすくなっています。
このような進行方法の変更もコンテナイメージに反映できるため、環境をコンテナ化しておいた利点が活きています。
Cognitoユーザー登録スクリプトの工夫
受講者アカウントの登録にはCognitoを使用しますが、Cognitoのデフォルト設定では1日あたりのメール送信数に上限があります。招待メールを送ると1ユーザー1通消費されるため、参加者が多い場合に制限に引っかかる可能性があります。
この点を考慮し、登録スクリプトを2つのモードで切り替えられるようにしました。
| モード | 用途 | 動作 |
|---|---|---|
--invite |
少人数向け | Cognitoから招待メールを送付。受講者がメールの一時パスワードでログイン |
--admin |
大人数向け | 管理者がパスワードをCSVで指定し、メール送信なしで登録 |
CSVにメールアドレス・パスワード・ニックネームを記載してスクリプトを実行するだけで、受講者アカウントをまとめて登録できます。
まとめ
Claude Codeハンズオンの環境構築は、「1つのURLで全員がアクセスできる、個人ごとに分離されたブラウザ完結の開発環境」という要件を満たすために、いくつかの技術的な組み合わせが必要でした。
- ECS Fargate(ステップ8〜10):受講者ごとのコンテナ分離と再利用性
- ALB(Frontend / Shard)+ OAuth2-Proxy + Cognito(ステップ4〜7):1URLでのアクセス集約と認証
- CloudFront(ステップ3):HTTPS終端とセキュリティ
構成はTerraformで管理しているため、次回以降の開催でも同じ仕組みを再利用できます。
追記(2026-05-28):オンライン100名規模開催に向けた構成変更
これまでClaude Codeハンズオンセミナーは対面で開催してきました。会場のキャパシティや、講師から受講者へのサポートを行き届かせやすくする観点から、1回あたり30名程度を上限としていました。
今回、より多くの方にご参加いただける形を検討するなかで、100名規模のオンライン開催を視野に入れた構成見直しを行いました。その過程でAWS Application Load Balancer(ALB)のクォータに起因する新たな課題に直面したので、検討の経緯と最終的に採用したアプローチを追記します。
課題4:ALBのTarget GroupsのQuota上限
これまでの構成では、受講者1人につき1つのTarget Group(TG)を作成し、すべてを1台のALBに集約していました。しかし、ALBには以下のクォータがあります。
| 項目 | 上限値 |
|---|---|
| Target Groups per Application Load Balancer | 100(ハードリミット・緩和申請不可) |
つまり、1台のALBに登録できるTGは100個までで、緩和申請による引き上げもできません。auth-gateway用に1つTGを使うと、受講者用に確保できるのは最大99人分となり、100名規模の開催では構成が成立しません。
検討した5つのアプローチ
クォータを回避する方法として、以下の5案を比較検討しました。
| 案 | 内容 | 採否と理由 |
|---|---|---|
| A. クォータ緩和申請 | AWSサポートを通じてTarget Groupsの上限引き上げを依頼 | 不採用:ハードリミットのため緩和申請が受け付けられない |
| B. ALBを複数台に分割(シャーディング) | 一定人数ごとにALBを分け、前段で振り分ける | 採用:クォータを根本回避でき、コンテナ側の構成は変更不要 |
| C. auth-gatewayがcode-serverへ直接プロキシ | ALBの内部リスナーやユーザー別TGを廃止し、Cloud Map(Service Discovery)で各タスクを名前解決して直接転送 | 不採用:TG/Ruleのクォータは完全に外せるが、auth-gateway側のコード変更、Cloud Map登録、ALB相当のヘルスチェック処理の自前実装が必要で変更範囲が大きい |
| D. 単一TG+パスリライトで集約 | 全code-serverを1つのTGに登録し、パスごとの振り分けはauth-gatewayが担う | 不採用:ALBのTG内振り分けは負荷分散アルゴリズム(ラウンドロビン等)で決まるため、ユーザーと特定タスクの紐付けをALB層では維持できず、セッション断が起きる |
| E. 単一TG+スティッキーセッションで固定 | D案にALBのスティッキーセッション(Cookieベース)を組み合わせ、一度振られたコンテナにユーザーを固定する | 不採用:初回振り分けは負荷分散アルゴリズム任せのため「user1のニックネームを持つ受講者を必ずcode-server-user1のコンテナに届ける」という事前マッピングは作れない。タスク置換時にも別コンテナへ振り直されるリスクが残る |
採用構成:フロントエンドALB + シャードALBの2層化(B案)
採用したB案では、ALBを役割で2層に分けています。
| ALBの役割 | 用途 |
|---|---|
| フロントエンドALB(1台、インターネット公開) | CloudFrontからの受け口。auth-gateway用のTGのみを持つ |
| シャードALB(複数台、internal) | code-server用のTGを収容。一定人数(users_per_shard)ずつに分散して登録 |
リクエストの流れは以下のとおりです。
- CloudFrontがHTTPSを終端し、シークレットヘッダーを付与してフロントエンドALBへ転送
- フロントエンドALBがauth-gatewayへ転送し、Cognito連携でOIDC認証を実施
- auth-gatewayが認証情報(ニックネーム)から所属シャードを判定
- 該当するシャードALB(internal)へ転送
- シャードALBがパスベースルーティング(
/userN/)で対象のcode-serverコンテナへ届ける
シャード数は受講者数と1シャードあたりの収容数から自動算出する形にしており、Terraform変数 users_per_shard を変えるだけで人数の増減に追従できる作りにしています。例えば50人ずつに分けて100名を収容する場合、シャードALBは2台になります。
設計上の前提:1 TG = 1 コンテナ
シャードALB内のターゲットグループ(TG)は、受講者1人につき1つを割り当てています。これは「TGを選ぶ=特定のコンテナを選ぶ」状態を維持するための設計です。
ALBのルーティングは「リスナールール→TG」までは決定論的に決まりますが、TG内のターゲット選択は負荷分散アルゴリズムに委ねられます。1つのTGに複数のコンテナを入れてしまうと、ユーザーと特定タスクの紐付けをALB層では保てなくなる(D案を採用しなかった理由でもあります)ため、シャーディング後もこの「1 TG = 1 コンテナ」の前提は維持しています。
この前提があることで、auth-gatewayの責務は「Cognitoによる認証」と「パスとニックネームの一致確認」の2つに絞ることができ、ルーティング自体はALBに委ねられます。auth-gatewayは認証と認可だけを担当すればよく、ユーザーごとの振り分け先を管理する必要がないため、運用・改修がしやすくなっています。
内部ALBへの直接アクセス防止
シャードALBはinternalで配置していますが、auth-gateway以外からのアクセスを受け付けないよう、auth-gateway→シャードALB間にもシークレットヘッダー(X-Internal-Secret)の検証を入れています。CloudFront→フロントエンドALB間と同じ思想を、内部経路にも適用した形です。
変更の影響範囲
採用したB案の良い点は、変更範囲がインフラ層(ALB構成)とauth-gatewayの振り分けロジックに閉じることでした。
- CloudFront:オリジンはフロントエンドALB1つのままで変更なし
- code-serverコンテナ:変更なし
- Cognito連携:変更なし
- Terraform:ALB定義の構造化(フロント/シャード)とシャード数の自動算出を追加
今回の構成変更は、すべてTerraformコードに反映済みです。次回以降の規模変更にも、変数の調整だけで対応できる状態になっています。
環境構築の詳細について興味のある方は、クラスメソッド 人材ソリューション部までお気軽にお問い合わせください。
また、Claude Codeハンズオンセミナーは5月も開催予定です。ご興味のある方はぜひお申し込みください。









