概要
CDKを用いて,AWS Batchのコンピューティング環境(EC2起動タイプ)を,インターネットとの通信経路を持たないVPCで起動する方法をまとめました.
Batchのコンピューティング環境は,ECSクラスタとして作成されます.なので,ECSクラスタが展開できるVPC環境を準備してあげればOKです.
なぜそんなことをしたのか?
Batchで高負荷な計算処理(シミュレーション)を行う環境1を構築していたのですが,セキュリティ上の理由から,「インターネット経由の通信が存在しない環境でで」との要件があったためです.
検証環境
- CDK 1.59.0, Typesccript
- 東京リージョン (ap-northeast-1) 2
VPC Endpointを設置する
NAT GatewayやInternet Gateway等との通信経路が一切ないSubnetを選択しても,コンピューティング環境の作成自体は正常に終了します(してしまいます).
しかし,この状態では,ECSのコントロールプレーンやECRリポジトリとの通信もできず,コンピューティング環境を利用することができません.
そこで,必要なプライベート通信経路を確保するため,VPC Endpointを設置します.
必要なVPC Endpointは,下記のとおりです.
-
ECS コントロールプレーンとの通信経路
3つのInterface endpointが必要です(公式ドキュメントはこちら).
- com.amazonaws.ap-northeast-1.ecs-agent
- com.amazonaws.ap-northeast-1.ecs-telemetry
- com.amazonaws.ap-northeast-1.ecs
-
ECR リポジトリとの通信経路
2つのInterface endpointとS3 gateway endpointが必要です(公式ドキュメントはこちら).
- com.amazonaws.ap-northeast-1.ecr.dkr
- com.amazonaws.ap-northeast-1.ecr.api
- com.amazonaws.ap-northeast-1.s3
-
(用途によって) CloudWatch Logsとの通信経路
CloudWatch Logsへログを流したい場合には,追加で下記のInterface endpointも設置してください(公式ドキュメントはこちら).
- com.amazonaws.ap-northeast-1.logs
CDKで実装する
それでは,上述の環境をCDKで構築していきたいと思います.
Importするモジュール
import ec2 = require('@aws-cdk/aws-ec2');
import batch = require('@aws-cdk/aws-batch');
VPC
まずは,VPCを作成します.今回は,インターネットとの通信経路を持たないVPCを作成するので,
VPCコンストラクタに,下記のように引数を与えます.
const vpc = new ec2.Vpc(this, 'vpc', {
cidr: "10.0.0.0/16", // ここは環境に応じて変更してください
maxAzs: 3, // EC2を分散配置する際の,最大AZ数を指定する
subnetConfiguration: [{
cidrMask: 18, // ここは環境に応じて変更してください
name: 'for-batch-compute-env',
subnetType: ec2.SubnetType.ISOLATED, // ISOLATEDを指定する
}]
});
subnetTypeにISOLATED
を指定することがポイントです.こうすると,NAT Gatewayを設置しないVPCを構築できます.
(他にPRIVATE
やPUBLIC
を指定できますが,これらはNAT Gatewayを設置する構成となります.)
Security Group, Subnet Selection
次にEC2用のセキュリティグループを設定します.今回は,同一VPC内のみの通信を許可しました.
const securityGroup = new ec2.SecurityGroup(
this, 'batch-compute-env-sg',
{
vpc: vpc,
allowAllOutbound: true,
description: `For batch compute environment.`,
securityGroupName: `for-batch-compute-environment`
});
securityGroup.addIngressRule(
ec2.Peer.ipv4(vpc.vpcCidrBlock),
ec2.Port.allTraffic(),
`Allow inside security group`
);
後ほど用いる,サブネット選択の変数も定義しておきます.
const subnetSelection: ec2.SubnetSelection = {
subnetType: ec2.SubnetType.ISOLATED, onePerAz: true
};
VPC Endpoint
VPCを作成したら,必要なVPC endpointを設置していきます.CDKでは,専用のコンストラクタがあるので,VPC endpoint設置も簡単です.
S3向けのendpointのみgateway endpointでコンストラクタが違うので注意してください.
// Create VPC Endpoints for ECS
new ec2.InterfaceVpcEndpoint(
this, `vpce-ecs-agent`, {
service: ec2.InterfaceVpcEndpointAwsService.ECS_AGENT,
open: true,
privateDnsEnabled: true,
vpc: vpc,
subnets: { subnetType: ec2.SubnetType.ISOLATED },
securityGroups: [securityGroup]
});
new ec2.InterfaceVpcEndpoint(
this, `vpce-ecs-telemetry`, {
service: ec2.InterfaceVpcEndpointAwsService.ECS_TELEMETRY,
open: true,
privateDnsEnabled: true,
vpc: vpc,
subnets: { subnetType: ec2.SubnetType.ISOLATED },
securityGroups: [securityGroup]
});
new ec2.InterfaceVpcEndpoint(
this, `vpce-ecs`, {
service: ec2.InterfaceVpcEndpointAwsService.ECS,
open: true,
privateDnsEnabled: true,
vpc: vpc,
subnets: { subnetType: ec2.SubnetType.ISOLATED },
securityGroups: [securityGroup]
});
// Create VPC Endpoints for ECR
new ec2.InterfaceVpcEndpoint(
this, `vpce-ecr-docker`, {
service: ec2.InterfaceVpcEndpointAwsService.ECR_DOCKER,
open: true,
privateDnsEnabled: true,
vpc: vpc,
subnets: { subnetType: ec2.SubnetType.ISOLATED },
securityGroups: [securityGroup]
});
new ec2.InterfaceVpcEndpoint(
this, `vpce-ecr`, {
service: ec2.InterfaceVpcEndpointAwsService.ECR,
open: true,
privateDnsEnabled: true,
vpc: vpc,
subnets: { subnetType: ec2.SubnetType.ISOLATED },
securityGroups: [securityGroup]
});
new ec2.GatewayVpcEndpoint(
this, `vpce-s3`, {
service: ec2.GatewayVpcEndpointAwsService.S3,
vpc: vpc,
subnets: [subnetSelection],
});
Batch Computing環境
VPCの準備ができたらBatchコンピューティング環境を作成していきます.
const computeEnv = new batch.ComputeEnvironment(this, 'cluster', {
computeEnvironmentName: `my-batch-cluster`,
enabled: true,
managed: true,
computeResources: {
type: batch.ComputeResourceType.ON_DEMAND,
// spotインスタンスを使いたいときはSPOTを指定
// type: batch.ComputeResourceType.SPOT,
instanceTypes: [new ec2.InstanceType("t3small")], // インスタンスタイプ
vpc: vpc, // 先ほど作成したVPC
vpcSubnets: subnetSelection, // Isolated subnetを指定
securityGroups: [securityGroup], // インスタンスのセキュリティグループを指定
minvCpus: 0, // min VCPU数を指定
desiredvCpus: 0, // desired VCPU数を指定 (minとmaxの間の値)
maxvCpus: 4, // max VCPU数を指定
// 特定のAMIを指定したい場合はAMI IDの変数も与えます.
// image: new ec2.GenericLinuxImage({ 'ap-northeast-1': "AMI-ID" }),
}
});
注意点
- VPCエンドポイントは,利用状況に関わらず立てておくだけで料金が発生します.ECSクラスタ(EC2タイプ)では,最低6つのエンドポイントが必要で,そこそこの金額になります.お試しする際は,終わったら全てのリソースを削除することをお忘れなく!
- 本番で運用する際には,コストに見合うかの判断が大切ですね.状況によっては,セキュリティを担保する他の方法を検討したほうが良さそうです.
- EFSなど他のサービスも使用したい場合は,それぞれに対応したエンドポイント設置などの対応が必要です.
参考
Fargate起動タイプでは,必要なエンドポイントを減らせるようです.詳しくは,こちらのウェブサイトをご参照ください(分かりやすくまとまっており,私も助かりました).