概要
CDKを使ってAWS環境を作成するときの方法についてまとめていこうと思います。
前回の続きです。
定義にはS3,DynamoDB,RDSの部分もありますがそのあたりは次回以降に・・・
準備
- 前回の転記部分もあります。詳細は前回を参照
- AWS SummitのCDKハンズオンを見て準備をしましょう。
- こちらでも簡単に準備手順を
- AWS CLIのインストール
- AWS Configureの設定
- アカウントはCDKで作成するリソースにアクセスできる権限を付与しましょう。(お試しでやる場合はAdministrator権限の方がいいかもしれません)
- node.jsのインストール
-
npm install -g aws-cdk
のコマンドでcdkをインストール
プロジェクトの準備
- TypeScriptでの例となります。
- 空のディレクトリを用意する。
- ディレクトリに移動して以下のコマンドを実行する
cdk init sample-app --language typescript
- 初期ディレクトリなどが作成されるのを待ちます。
ライブラリのインストール
- 必要に応じて npm コマンドでライブラリをインストールします。以下のようなコマンドです。
npm install @aws-cdk/aws-ecs
npm install @aws-cdk/aws-batch
npm install @aws-cdk/aws-ec2
npm install @aws-cdk/aws-iam
npm install @aws-cdk/aws-ecr
-
注意点
- ライブラリのバージョンが一致していないとコンパイルエラーやdeploy時にエラーになるので
package.json
のバージョンを合わせて、package-lock.json
とnode_modules
配下を削除してnpm install
を実施しましょう。
- ライブラリのバージョンが一致していないとコンパイルエラーやdeploy時にエラーになるので
コンパイルの準備
- ライブラリインストール後にプロジェクトを作成したディレクトリに移動して以下のコマンドを実行します。windowsの場合はライブラリのインストール時には停止する必要があるので注意を
npm run watch
各ソースの説明
- ./lib/cdk-stack.ts
- 各定義を作成する場所です。基本的にこのファイルを修正します
CDKの定義
-
VPCなどを指定する部分はIDを指定します。
-
ソース全体
長いので折りたたんでます
import * as cdk from '@aws-cdk/core';
import * as batch from '@aws-cdk/aws-batch';
import * as dynamodb from '@aws-cdk/aws-dynamodb';
import * as rds from '@aws-cdk/aws-rds';
import * as s3 from '@aws-cdk/aws-s3';
import * as ec2 from '@aws-cdk/aws-ec2';
import * as iam from '@aws-cdk/aws-iam';
import * as ecs from '@aws-cdk/aws-ecs';
import * as ssm from '@aws-cdk/aws-ssm';
import * as ecr from '@aws-cdk/aws-ecr';
import { ContainerImage, EcrImage } from '@aws-cdk/aws-ecs';
import { Repository } from '@aws-cdk/aws-ecr';
import { ServerlessCluster, SubnetGroup } from '@aws-cdk/aws-rds';
import { Effect } from '@aws-cdk/aws-iam';
export class CdkStack extends cdk.Stack {
constructor(scope: cdk.App, id: string, props?: cdk.StackProps) {
super(scope, id, props);
const vpc: ec2.IVpc = ec2.Vpc.fromLookup(this, 'VPC', {
vpcId: 'vpc-0890be0a4389aa3b3',
});
const selectSubnets: ec2.SelectedSubnets = vpc.selectSubnets({
subnets: [
ec2.Subnet.fromSubnetAttributes(this, 'Subnet', {
subnetId: 'subnet-0f3d599ff3a439e8b',
availabilityZone: 'ap-northeast-1a',
routeTableId: 'rtb-0b3f9acea163735d2',
}),
]
});
// 既存のセキュリティーグループを取得
const securityGroup: ec2.ISecurityGroup = ec2.SecurityGroup.fromSecurityGroupId(
this, 'SecurityGroup', 'sg-011b45aab947a7b11',
);
// バッチのロール
const batchRole: iam.IRole = new iam.Role(this, 'BatchRole', {
roleName: 'TestBatchRole',
assumedBy: new iam.CompositePrincipal(
new iam.ServicePrincipal('batch.amazonaws.com'),
),
path:'/service-role/',
managedPolicies: [
iam.ManagedPolicy.fromManagedPolicyArn(
this,
'AWSBatchServiceRole',
'arn:aws:iam::aws:policy/service-role/AWSBatchServiceRole',
),
],
});
// インスタンスのロール S3とDynamoDBへのアクセスを追加
const instanceRole: iam.IRole = new iam.Role(this, 'InstanceRole', {
roleName: 'TestInstanceRole',
assumedBy: new iam.CompositePrincipal(
new iam.ServicePrincipal('ec2.amazonaws.com'),
),
managedPolicies: [
iam.ManagedPolicy.fromManagedPolicyArn(
this,
'AmazonEC2ContainerServiceforEC2Role',
'arn:aws:iam::aws:policy/service-role/AmazonEC2ContainerServiceforEC2Role',
),
iam.ManagedPolicy.fromManagedPolicyArn(this,'AwsS3FullAccess','arn:aws:iam::aws:policy/AmazonS3FullAccess'),
iam.ManagedPolicy.fromManagedPolicyArn(this,'AwsDynamoFullAccess','arn:aws:iam::aws:policy/AmazonDynamoDBFullAccess')
],
});
// Job用ロールを作成
const jobRole: iam.IRole = new iam.Role(this, 'JobRole', {
roleName: 'TestJobRole',
assumedBy: new iam.CompositePrincipal(
new iam.ServicePrincipal('ecs-tasks.amazonaws.com'),
),
managedPolicies: [
iam.ManagedPolicy.fromManagedPolicyArn(
this,
'AmazonECSTaskExecutionRolePolicy',
'arn:aws:iam::aws:policy/service-role/AmazonECSTaskExecutionRolePolicy',
),
],
});
// インスタンスプロフィールを作成
const instanceProfile: iam.CfnInstanceProfile = new iam.CfnInstanceProfile(this, 'InstanceProfile', {
instanceProfileName: 'Testprofile',
roles: [instanceRole.roleName],
path:'/'
});
// コンピューティング環境を作成
const computeEnvironment: batch.ComputeEnvironment = new batch.ComputeEnvironment(this, 'BatchCompute', {
computeEnvironmentName: 'TestComputeEnvironment',
computeResources: {
type: batch.ComputeResourceType.ON_DEMAND,
instanceRole: instanceProfile.attrArn,
vpc: vpc,
vpcSubnets: selectSubnets,
securityGroups: [securityGroup],
},
serviceRole:batchRole
});
const repository = Repository.fromRepositoryName(this,'pandastestRepo','pandastest2')
const ecscontainerImage = ecs.ContainerImage.fromEcrRepository( repository,'latest')
// jobのQueを作成
new batch.JobQueue(this, 'JobQueue', {
jobQueueName: 'jobQueque',
computeEnvironments: [{
computeEnvironment: computeEnvironment,
order: 1,
}],
});
const jobDefinec = new batch.JobDefinition(this, 'JobDefinition', {
jobDefinitionName: 'pandasTest',
container: {
command: ['1','3','A'], // コンテナ内で実行されるコマンド
environment: {'RDS_PASS': 'password','TEST':'ABC'},
image: ecscontainerImage,
jobRole: jobRole,
vcpus: 1,
memoryLimitMiB: 32,
},
});
// RDS周り
const selectRdsSubnets: ec2.SelectedSubnets = vpc.selectSubnets({
subnets: [
ec2.Subnet.fromSubnetAttributes(this, 'Subnet1', {
subnetId: 'subnet-0f3d599ff3a439e8b',
availabilityZone: 'ap-northeast-1a',
routeTableId: 'rtb-0b3f9acea163735d2',
}),
ec2.Subnet.fromSubnetAttributes(this, 'Subnet2', {
subnetId: 'subnet-08a1d1ea639bb8876',
availabilityZone: 'ap-northeast-1a',
routeTableId: 'rtb-0b3f9acea163735d2',
}),
]
});
const subnetGroup=new rds.SubnetGroup(this,'subnetgroup',{
vpc:vpc,
description:'for rds subnetGroup',
subnetGroupName:'sdfsubnetgroup',
vpcSubnets:selectRdsSubnets
})
const dbname='testdb';
const masterUsername='root';
const masterPassword='password';
const rdsCluster = new rds.CfnDBCluster(this, 'DBCluster', {
engine: 'aurora-mysql',
dbClusterIdentifier: `main-cluster`,
engineMode: 'serverless',
engineVersion: '5.7.mysql_aurora.2.07.1',
enableHttpEndpoint: false,
databaseName: dbname,
masterUsername: masterUsername,
masterUserPassword: masterPassword,
backupRetentionPeriod: 1 ,
dbSubnetGroupName:subnetGroup.subnetGroupName,
scalingConfiguration: {
autoPause: true,
maxCapacity: 2 ,
minCapacity: 1,
secondsUntilAutoPause: 600 ,
},
deletionProtection: false ,
});
// S3
const dataBucket = new s3.Bucket(this, 'pf-bucket-data', {
bucketName: `bucket-data-${this.region}-${this.account}`,
blockPublicAccess:s3.BlockPublicAccess.BLOCK_ALL
});
// S3 BucketPolicy
const dataBucketPolicy = new s3.BucketPolicy(this, 'pf-bucket-data-policy', {
bucket : dataBucket,
});
const s3dataStatement = new iam.PolicyStatement({
effect: Effect.ALLOW,
actions:['s3:ListBucket','s3:PutObject','s3:ListBucket'],
resources:[
"arn:aws:s3:::" + dataBucket.bucketName,
"arn:aws:s3:::" + dataBucket.bucketName + "/*"
],
principals:[new iam.AccountPrincipal(this.account)]
})
const s3Statement = new iam.PolicyStatement({
effect: Effect.ALLOW,
actions:['s3:ListBucket','s3:PutObject','s3:ListBucket'],
resources:[
"arn:aws:s3:::" + dataBucket.bucketName,
"arn:aws:s3:::" + dataBucket.bucketName + "/*"
]
})
const s3Statementssm = new iam.PolicyStatement({
effect: Effect.ALLOW,
actions:['ssm:DescribeParameters','ssm:GetParameter'],
resources:['*']
})
dataBucketPolicy.document.addStatements(s3dataStatement)
const sdfDynamoDB=new dynamodb.Table(this,'sdfCountTable',{
partitionKey: {
name: "sequence_key",
type: dynamodb.AttributeType.STRING,
},
tableName:'sequence_table_cdk',
billingMode:dynamodb.BillingMode.PROVISIONED,
removalPolicy: cdk.RemovalPolicy.DESTROY,
readCapacity:2,
writeCapacity:2,
})
const dynamoDbStatement = new iam.PolicyStatement({
effect: Effect.ALLOW,
actions:[
"dynamodb:BatchGetItem",
"dynamodb:BatchWriteItem",
"dynamodb:PutItem",
"dynamodb:ListTables",
"dynamodb:GetItem",
"dynamodb:Scan",
"dynamodb:Query",
"dynamodb:UpdateItem",
"dynamodb:UpdateTable",
"dynamodb:GetRecords"
],resources:[sdfDynamoDB.tableArn]
})
const s3DynamoDBPolicy= new iam.ManagedPolicy(this,'s3Dynamo',{
managedPolicyName:'s3dynamodbpolicy',
statements:[s3Statement,dynamoDbStatement],
description:'for s3Dynamo',
})
}
}
AWS Batchの部分
- AWS Batchの部分だけピックアップします
- job定義に設定するロールの設定、コンピューティング環境に設定するインスタンスプロフィールは以下のように作成します。
- 必要に応じて権限を追加したりしてください。
// バッチのロール
const batchRole: iam.IRole = new iam.Role(this, 'BatchRole', {
roleName: 'TestBatchRole',
assumedBy: new iam.CompositePrincipal(
new iam.ServicePrincipal('batch.amazonaws.com'),
),
path:'/service-role/',
managedPolicies: [
iam.ManagedPolicy.fromManagedPolicyArn(
this,
'AWSBatchServiceRole',
'arn:aws:iam::aws:policy/service-role/AWSBatchServiceRole',
),
],
});
// インスタンスのロール S3とDynamoDBへのアクセスを追加
const instanceRole: iam.IRole = new iam.Role(this, 'InstanceRole', {
roleName: 'TestInstanceRole',
assumedBy: new iam.CompositePrincipal(
new iam.ServicePrincipal('ec2.amazonaws.com'),
),
managedPolicies: [
iam.ManagedPolicy.fromManagedPolicyArn(
this,
'AmazonEC2ContainerServiceforEC2Role',
'arn:aws:iam::aws:policy/service-role/AmazonEC2ContainerServiceforEC2Role',
),
iam.ManagedPolicy.fromManagedPolicyArn(this,'AwsS3FullAccess','arn:aws:iam::aws:policy/AmazonS3FullAccess'),
iam.ManagedPolicy.fromManagedPolicyArn(this,'AwsDynamoFullAccess','arn:aws:iam::aws:policy/AmazonDynamoDBFullAccess')
],
});
// Job用ロールを作成
const jobRole: iam.IRole = new iam.Role(this, 'JobRole', {
roleName: 'TestJobRole',
assumedBy: new iam.CompositePrincipal(
new iam.ServicePrincipal('ecs-tasks.amazonaws.com'),
),
managedPolicies: [
iam.ManagedPolicy.fromManagedPolicyArn(
this,
'AmazonECSTaskExecutionRolePolicy',
'arn:aws:iam::aws:policy/service-role/AmazonECSTaskExecutionRolePolicy',
),
],
});
// インスタンスプロフィールを作成
const instanceProfile: iam.CfnInstanceProfile = new iam.CfnInstanceProfile(this, 'InstanceProfile', {
instanceProfileName: 'Testprofile',
roles: [instanceRole.roleName],
path:'/'
});
- コンピューティング環境の設定
- インスタンスのロールやサブネットなどをこちらで設定します。
// コンピューティング環境を作成
const computeEnvironment: batch.ComputeEnvironment = new batch.ComputeEnvironment(this, 'BatchCompute', {
computeEnvironmentName: 'TestComputeEnvironment',
computeResources: {
type: batch.ComputeResourceType.ON_DEMAND,
instanceRole: instanceProfile.attrArn,
vpc: vpc,
vpcSubnets: selectSubnets,
securityGroups: [securityGroup],
},
serviceRole:batchRole
});
- リポジトリの指定
- 新規でリポジトリを作るところも行う場合は new で作成します。今回はすでにあるリポジトリを使います。
const repository = Repository.fromRepositoryName(this,'pandastestRepo','pandastest2')
const ecscontainerImage = ecs.ContainerImage.fromEcrRepository( repository,'latest')
- JobのキューとJob定義
- ジョブ定義の時に使用するCPUやメモリなどを指定します、
// jobのQueを作成
new batch.JobQueue(this, 'JobQueue', {
jobQueueName: 'jobQueque',
computeEnvironments: [{
computeEnvironment: computeEnvironment,
order: 1,
}],
});
const jobDefinec = new batch.JobDefinition(this, 'JobDefinition', {
jobDefinitionName: 'pandasTest',
container: {
command: ['1','3','A'], // コンテナ内で実行されるコマンド
environment: {'RDS_PASS': 'password','TEST':'ABC'},
image: ecscontainerImage,
jobRole: jobRole,
vcpus: 1,
memoryLimitMiB: 32,
},
});