in lib/batch-resources.ts [29:235]
constructor(scope: cdk.Construct, id: string, props: BatchResourcesProps) {
super(scope, id, props);
// =====================================================================================
// Building IAM Resources for Batch inference image and pushing to ECR
// =====================================================================================
const batchJobRole = new iam.Role(this, "mlBlogBatchJobRole", {
assumedBy: new iam.CompositePrincipal(
new iam.ServicePrincipal("ecs-tasks.amazonaws.com"),
new iam.ServicePrincipal("ec2.amazonaws.com")
),
managedPolicies: [
iam.ManagedPolicy.fromAwsManagedPolicyName(
"service-role/AmazonECSTaskExecutionRolePolicy"
),
iam.ManagedPolicy.fromAwsManagedPolicyName(
"service-role/AmazonEC2ContainerServiceforEC2Role"
),
],
});
const batchJobExecRole = new iam.Role(this, "mlBlogBatchExecRole", {
assumedBy: new iam.ServicePrincipal("ecs-tasks.amazonaws.com"),
managedPolicies: [
iam.ManagedPolicy.fromAwsManagedPolicyName(
"service-role/AmazonECSTaskExecutionRolePolicy"
),
],
});
const compEnvSvcRole = iam.Role.fromRoleArn(
this,
`${prefix}-compute-role`,
`arn:aws:iam::${cdk.Aws.ACCOUNT_ID}:role/aws-service-role/batch.amazonaws.com/AWSServiceRoleForBatch`,
{ mutable: false }
);
const ecrCleanUpRole = new iam.Role(this, "EcrCleanUpRole", {
assumedBy: new iam.ServicePrincipal("lambda.amazonaws.com"),
});
// =====================================================================================
// Building our Batch inference image and pushing to ECR
// =====================================================================================
const batchImageRepo = new ecr.Repository(
this,
`${prefix}-${batchImageRepoName}`,
{
removalPolicy: cdk.RemovalPolicy.DESTROY, // <==FOR DEMO ONLY ===
repositoryName: `${batchImageRepoName}`,
}
);
const batchInfImage = new DockerImageAsset(this, `${prefix}-image`, {
directory: path.join(__dirname, "../container_images/batch_image"),
});
const batchImagepush = new ecrdeploy.ECRDeployment(
this,
`${prefix}-image-deploy`,
{
src: new ecrdeploy.DockerImageName(batchInfImage.imageUri),
dest: new ecrdeploy.DockerImageName(
`${batchImageRepo.repositoryUri}:latest`
),
}
);
// =====================================================================================
// Configuring AWS Batch
// =====================================================================================
const batchComputeEnv = new batch.CfnComputeEnvironment(
this,
`${prefix}-compute-env`,
{
computeEnvironmentName: `${prefix}-compute-env`,
type: "MANAGED",
state: "ENABLED",
computeResources: {
maxvCpus: 256,
type: "FARGATE",
subnets: [
props.vpc.publicSubnets[0].subnetId,
props.vpc.publicSubnets[1].subnetId,
],
securityGroupIds: [props.batchSg.securityGroupId],
},
serviceRole: compEnvSvcRole.roleArn,
}
);
const batchJobDef = new batch.CfnJobDefinition(this, `${prefix}-JobDef`, {
jobDefinitionName: `${prefix}-JobDef`,
retryStrategy: { attempts: 1 },
type: "container",
platformCapabilities: ["FARGATE"],
containerProperties: {
image: `${batchImageRepo.repositoryUri}:latest`,
networkConfiguration: { assignPublicIp: "ENABLED" },
resourceRequirements: [
{ type: "VCPU", value: "4" },
{ type: "MEMORY", value: "16384" },
],
jobRoleArn: batchJobRole.roleArn,
executionRoleArn: batchJobExecRole.roleArn,
command: ["python", "batch_processor.py"],
},
});
let s3Actions = ["s3:ListBucket", "s3:GetObject", "s3:PutObject"];
batchJobRole.addToPolicy(
new iam.PolicyStatement({
resources: [inputBucketArn, `${inputBucketArn}/*`],
actions: s3Actions,
effect: iam.Effect.ALLOW,
})
);
batchJobExecRole.addToPolicy(
new iam.PolicyStatement({
resources: [inputBucketArn, `${inputBucketArn}/*`],
actions: s3Actions,
effect: iam.Effect.ALLOW,
})
);
batchJobDef.node.addDependency(batchImagepush);
const batchJobQ = new batch.CfnJobQueue(
this,
`${prefix}-${batchJobQueueName}`,
{
computeEnvironmentOrder: [
{
order: 1,
computeEnvironment: batchComputeEnv.ref,
},
],
priority: 1,
state: "ENABLED",
jobQueueName: batchJobQueueName,
}
);
this.batchJobSubmitterPolicy = new iam.PolicyStatement({
effect: iam.Effect.ALLOW,
actions: [
"batch:DescribeJobQueues",
"batch:DescribeJobs",
"batch:DescribeJobDefinitions",
"batch:ListJobs",
"batch:DescribeComputeEnvironments",
"batch:UntagResource",
"batch:DeregisterJobDefinition",
"batch:TerminateJob",
"batch:CancelJob",
"batch:ListTagsForResource",
"batch:SubmitJob",
"batch:RegisterJobDefinition",
"batch:TagResource",
"batch:UpdateJobQueue",
],
resources: [
`arn:aws:batch:${cdk.Aws.REGION}:${cdk.Aws.ACCOUNT_ID}:job/*`,
`arn:aws:batch:${cdk.Aws.REGION}:${cdk.Aws.ACCOUNT_ID}:job-definition/${batchJobDef.jobDefinitionName}:*`,
`arn:aws:batch:${cdk.Aws.REGION}:${cdk.Aws.ACCOUNT_ID}:job-queue/${batchJobQ.jobQueueName}`,
`arn:aws:batch:${cdk.Aws.REGION}:${cdk.Aws.ACCOUNT_ID}:compute-environment/${batchComputeEnv.computeEnvironmentName}`,
],
});
this.ecrPolicy = new iam.PolicyStatement({
resources: [batchImageRepo.repositoryArn],
effect: iam.Effect.ALLOW,
actions: [
"ecr:DescribeRepositories",
"ecr:BatchDeleteImage",
"ecr:DeleteRegistryPolicy",
"ecr:ListImages",
"ecr:DeleteRepositoryPolicy",
"ecr:DeleteLifecyclePolicy",
"ecr:DeleteRepository",
],
});
ecrCleanUpRole.addToPrincipalPolicy(this.ecrPolicy);
this.batchLambdaParam = new ssm.StringListParameter(
this,
`${prefix}-LambdaParam`,
{
parameterName: "treeLambdaEnv",
stringListValue: [batchJobDef.ref, batchJobQ.ref, batchComputeEnv.ref],
tier: ssm.ParameterTier.STANDARD,
simpleName: true,
}
);
this.batchEcrCleanupParam = new ssm.StringParameter(
this,
"batch-ecr-cleanup-ssm-param",
{
parameterName: "batchEcrClean",
stringValue: batchImageRepo.repositoryName,
tier: ssm.ParameterTier.STANDARD,
simpleName: true,
}
);
}