はじめに
業務では主にkiro-cliを使用していますが、ローカルの WSL 環境がメモリ不足で頻繁に落ちるようになり、開発体験が著しく悪化していました。そのため、脱WSLを目指して「リモートに開発環境を持っていこう」と思い立ち、AWS 上に EC2 ベースのリモート開発環境を構築しました。
リモート開発環境の記事は世の中に多くありますが、本記事では以下の点にフォーカスします。
- SSM Session Manager によるセキュアな接続
- Spot Instance + ASG によるコスト削減
- AWS CDK による IaC 管理で再現性を担保
概要構成図
アーキテクチャは以下の通りです。
開発者はローカルのVS CodeからSSHでSSMを経由してEC2にアクセスします。
ソースコード
cdkのソースコードはGitHubで公開しています。
デプロイ〜接続方法
-
cdk deployでスタック一式をデプロイ - EventBridge Scheduler が平日 9:00 に ASG の desired を 1 に変更 → EC2 起動
- UserData がデータ EBS をアタッチし、Docker / 開発ツールをセットアップ
- ローカル PC から
ssh remote-devで接続(ProxyCommand 内で SSM セッションを確立) - VS Code Remote-SSH がリモートの VS Code Server に接続し、ローカルと同じ体験で開発開始
前提条件
本構成を構築・利用するために、あらかじめ以下の準備・インストールが必要です。
1. AWS 関連
- AWS アカウント: 管理者権限(AdministratorAccess)を推奨
-
AWS CLI: ローカル PC で認証設定(
aws configure)が完了していること -
Session Manager Plugin:
- ブラウザではなくターミナルから SSM を経由するために必須です
- インストール手順(公式)
-
SSH 鍵ペア:
- 接続に使用する公開鍵・秘密鍵(例:
~/.ssh/id_ed25519)
- 接続に使用する公開鍵・秘密鍵(例:
2. 開発・構築環境
- Node.js: CDK を実行するために必要(LTS 推奨)
-
AWS CDK CLI:
-
npm install -g aws-cdkでインストール済みであること
-
- TypeScript: CDK のコード記述・コンパイルに使用
3. VS Code
- VS Code 本体: 最新版を推奨
- Remote - SSH (拡張機能): Microsoft 公式。これがないとリモート開発が始まりません
4. ネットワーク環境
-
ローカル PC:
awsコマンドが実行でき、HTTPS (Port 443) で AWS エンドポイントにアクセスできること
接続方式
Remote - SSHとは
VS Code の Remote-SSH 拡張機能は、SSH 接続先のマシンに VS Code Server を自動インストールし、ローカルの VS Code からリモートのファイルシステム・ターミナル・拡張機能をシームレスに操作できる仕組みです。体感はローカル開発とほぼ変わりません。
~/.ssh/config の ProxyCommand をサポートしているため、SSM Session Manager 経由の接続をそのまま VS Code に統合できます。
AWS Systems Manager Session Managerとは
AWS Systems Manager Session Manager は、EC2 インスタンスへのシェルアクセスを インバウンドポートを開けずに 実現するサービスです。EC2 上の SSM Agent がアウトバウンド HTTPS で SSM エンドポイントに接続し、そのチャネルを通じてセッションが確立されます。
本構成では SSH over SSM を利用しています。ProxyCommand で aws ssm start-session を呼び出し、SSM のトンネル上で SSH プロトコルを通します。
Host remote-dev
HostName placeholder
User ubuntu
ProxyCommand powershell -Command "$id = (aws autoscaling describe-auto-scaling-groups ...); aws ssm start-session --target $id --document-name AWS-StartSSHSession --parameters portNumber=%p ..."
IdentityFile ~/.ssh/id_ed25519
ProxyCommand 内で ASG から現在稼働中のインスタンス ID を動的に取得するため、Spot 中断で ID が変わっても手動更新は不要です。
他の接続方式との比較
| 方式 | セキュリティ | コスト | 備考 |
|---|---|---|---|
| SSH over SSM(本構成) | ◎ SG全閉、IAM認証 | ◎ 追加費用なし | ProxyCommand で透過的に利用可能 |
| SSH 直接 (ポート22開放) | △ IP制限必須 | ◎ | SG設定ミスのリスクあり |
| Private Subnet + NAT GW | ◎ | × 月$45〜 | 個人利用にはオーバースペック |
本構成は Public Subnet に配置しつつ SG インバウンドを全閉にすることで、Private Subnet 構成と実質同等のセキュリティを追加コストゼロで実現しています。
コスト削減
Spot Instance
Spot Instance は AWS の余剰キャパシティを最大 70% 割引で利用できる仕組みです。開発環境は「中断されても致命的ではない」ワークロードなので、Spot との相性が抜群です。
本構成では Auto Scaling Group の Mixed Instances Policy を使い、4 つのインスタンスタイプを候補にしています。
mixedInstancesPolicy: {
instancesDistribution: {
onDemandPercentageAboveBaseCapacity: 0, // 100% Spot
spotAllocationStrategy: SpotAllocationStrategy.PRICE_CAPACITY_OPTIMIZED,
},
launchTemplateOverrides: [
{ instanceType: new ec2.InstanceType('t3.large') }, // Intel
{ instanceType: new ec2.InstanceType('t3a.large') }, // AMD
{ instanceType: new ec2.InstanceType('m5.large') }, // Intel
{ instanceType: new ec2.InstanceType('m5a.large') }, // AMD
],
}
中断への備え
Spot の最大の懸念は「突然インスタンスが消える」ことですが、以下の設計で対処しています。
- ルート EBS は使い捨て ― 環境構築は UserData で毎回自動化(Docker, Node.js, Kiro CLI 等)
-
データ EBS は永続 ― ソースコード・SSH 鍵・設定ファイルは別 EBS (50GB) に保存し、
RemovalPolicy.RETAINで保護 - ASG が自動復旧 ― Spot 中断 → ASG が新インスタンスを起動 → UserData がタグでデータ EBS を検索・再アタッチ
- Mixed Instances Policy ― 4 タイプ候補化でプール枯渇リスクを分散
- DLM 日次スナップショット ― データ EBS を 7 世代バックアップ
コスト内訳
| 項目 | 月額 |
|---|---|
| EC2 Spot (t3.large 相当, 平日200h) | ~$7 |
| EBS gp3 65GB (ルート15 + データ50) | ~$5 |
| EventBridge Scheduler | ~$0 |
| CloudWatch / その他 | ~$2 |
| 合計 | ~$14 |
Public Subnet + SSM + Spot でかなりコストを抑えることができています。
運用の工夫
CDKで定義
環境全体を AWS CDK (TypeScript) の単一スタックで管理しています。
lib/
├── remote-dev-stack.ts # スタック本体(各 Construct を組み立て)
└── constructs/
├── network.ts # VPC, Public Subnet, SG (インバウンド全閉)
├── iam.ts # EC2 Instance Role (SSM + EBS attach)
├── data-volume.ts # 永続 EBS 50GB + DLM 日次スナップショット
├── compute.ts # Launch Template + ASG (Mixed Instances + Spot)
└── scheduler.ts # EventBridge Scheduler (平日 09:00-19:00)
cdk deploy 一発で環境が再現できるため、万が一スタックを壊しても再構築が容易です。データ EBS だけは RemovalPolicy.RETAIN で保護されているので、スタック削除でも消えません。
自動起動停止
EventBridge Scheduler で平日 09:00 に ASG の desired を 1 に、19:00 に 0 に設定しています。
new scheduler.CfnSchedule(this, 'Start', {
scheduleExpression: 'cron(0 9 ? * MON-FRI *)',
scheduleExpressionTimezone: 'Asia/Tokyo',
target: {
arn: 'arn:aws:scheduler:::aws-sdk:autoscaling:updateAutoScalingGroup',
input: JSON.stringify({
AutoScalingGroupName: asg.autoScalingGroupName,
DesiredCapacity: 1,
}),
},
});
週末や夜間は自動で停止するため、課金が止まります。スケジュール外に作業したいときはヘルパースクリプトで即座に起動できます。
./scripts/connect.sh start # 手動起動
./scripts/connect.sh status # 状態確認
./scripts/connect.sh ssh # SSM 接続
実際の開発体験
良い点
- メモリ不足から解放 ― 8GB RAM を丸ごと開発に使える。WSL のメモリ競合がなくなった
- 環境がクリーン ― Dev Container で案件ごとに完全分離。ホスト汚染なし
- どこからでも同じ環境 ― PC が変わっても SSM 認証さえ通れば即接続
- セキュリティの安心感 ― SG インバウンド全閉なので設定ミスの心配がない
注意点
- こまめな git push が必須 ― Spot 中断に備えて作業中は頻繁にコミット・プッシュする習慣が必要
- 朝一の起動待ち ― インスタンス起動 + UserData 実行に 2〜3 分かかる
- ネットワーク依存 ― オフライン環境では当然使えない
最後に
ここまでセキュアかつ安価かつ使い捨てができるリモート開発環境について紹介しました。
リモートに開発環境を移すことでローカルPCの制約に縛られず、自由で快適な開発ライフが送れます。
cdkでデプロイできるようにコードにしていますのでぜひお試しください。

