Guide · AWS Batch · Container Configuration
AWS Batch Container Properties — resourceRequirements, Fargate, logConfiguration
The containerProperties object in RegisterJobDefinitionCommand controls everything about how your container runs. From an MCP server you specify the Docker image, vCPU and memory requirements, environment variables, IAM role for the job, volume mounts, and log configuration. The four decisions with the most gotchas are: vcpus/memory vs resourceRequirements (the top-level fields are deprecated for Fargate — always use resourceRequirements), jobRoleArn vs executionRoleArn (the job role controls what your code can call in AWS; the execution role controls Fargate infrastructure — ECR image pull and CloudWatch log delivery), Fargate-specific requirements (networkConfiguration with subnets in the compute environment, fargatePlatformConfiguration, and executionRoleArn are all mandatory), and secrets in environment variables (never put secrets directly in environment — use secrets to inject from Secrets Manager or Parameter Store at job start).
TL;DR
Use resourceRequirements: [{type:'VCPU', value:'2'}, {type:'MEMORY', value:'4096'}] (not deprecated vcpus/memory). Set jobRoleArn for your application's AWS API calls. For Fargate also set executionRoleArn (needs ecr:*, logs:*), fargatePlatformConfiguration:{platformVersion:'LATEST'}, and networkConfiguration:{assignPublicIp:'ENABLED'} for public subnets. Use secrets array to inject Secrets Manager / Parameter Store values — not environment. Add logConfiguration with logDriver:'awslogs' pointing at a CloudWatch log group.
Resource requirements
The resourceRequirements array replaces the deprecated top-level vcpus and memory fields. It is required for Fargate and strongly recommended for EC2 jobs. Each entry has a type (VCPU, MEMORY, or GPU) and a string value.
Fargate vCPU and memory combinations are constrained — not all pairs are valid. The table below shows the supported combinations:
| vCPU | Valid memory values (MiB) |
|---|---|
| 0.25 | 512, 1024, 2048 |
| 0.5 | 1024–4096 (1024 increments) |
| 1 | 2048–8192 (1024 increments) |
| 2 | 4096–16384 (1024 increments) |
| 4 | 8192–30720 (1024 increments) |
| 8 | 16384–61440 (4096 increments) |
| 16 | 32768–122880 (8192 increments) |
import {
RegisterJobDefinitionCommand,
type ContainerProperties,
} from '@aws-sdk/client-batch';
// EC2 job: vCPU and memory are flexible (integers only)
const ec2Container: ContainerProperties = {
image: '123456789012.dkr.ecr.us-east-1.amazonaws.com/my-job:latest',
resourceRequirements: [
{ type: 'VCPU', value: '4' },
{ type: 'MEMORY', value: '8192' }, // MiB
],
jobRoleArn: 'arn:aws:iam::123456789012:role/batch-job-role',
};
// Fargate job: vCPU must be string decimal, e.g. '0.25', '0.5', '1', '2', '4', '8', '16'
const fargateContainer: ContainerProperties = {
image: '123456789012.dkr.ecr.us-east-1.amazonaws.com/my-job:latest',
resourceRequirements: [
{ type: 'VCPU', value: '2' },
{ type: 'MEMORY', value: '4096' },
],
jobRoleArn: 'arn:aws:iam::123456789012:role/batch-job-role',
executionRoleArn: 'arn:aws:iam::123456789012:role/batch-execution-role',
fargatePlatformConfiguration: { platformVersion: 'LATEST' },
networkConfiguration: { assignPublicIp: 'ENABLED' },
};
// GPU job on EC2 (p3/g4dn/g5 instance types required in compute env)
const gpuContainer: ContainerProperties = {
image: '763104351884.dkr.ecr.us-east-1.amazonaws.com/pytorch-training:2.2.0-gpu-py310',
resourceRequirements: [
{ type: 'VCPU', value: '8' },
{ type: 'MEMORY', value: '32768' },
{ type: 'GPU', value: '1' }, // number of GPUs; not supported on Fargate
],
jobRoleArn: 'arn:aws:iam::123456789012:role/batch-ml-job-role',
};
Environment variables and secrets
The environment array passes non-sensitive configuration to the container. Each entry is a {name, value} object. These values are visible in DescribeJobsCommand output and in AWS console — do not put secrets here.
Use the secrets array to inject values from AWS Secrets Manager or Parameter Store. Batch fetches the secret at job startup and injects it as an environment variable before the container process starts.
const containerWithSecrets: ContainerProperties = {
image: '123456789012.dkr.ecr.us-east-1.amazonaws.com/my-job:latest',
resourceRequirements: [
{ type: 'VCPU', value: '1' },
{ type: 'MEMORY', value: '2048' },
],
// Non-sensitive config: safe to log and inspect
environment: [
{ name: 'ENVIRONMENT', value: 'production' },
{ name: 'LOG_LEVEL', value: 'INFO' },
{ name: 'OUTPUT_BUCKET',value: 'my-results-bucket' },
],
// Sensitive values: injected at runtime from Secrets Manager / SSM Parameter Store
secrets: [
{
// Secrets Manager: inject a specific key from a JSON secret
name: 'DB_PASSWORD',
valueFrom: 'arn:aws:secretsmanager:us-east-1:123456789012:secret:prod/db-AbCdEf:password::',
},
{
// SSM Parameter Store (SecureString)
name: 'API_KEY',
valueFrom: 'arn:aws:ssm:us-east-1:123456789012:parameter/prod/api-key',
},
],
jobRoleArn: 'arn:aws:iam::123456789012:role/batch-job-role',
executionRoleArn: 'arn:aws:iam::123456789012:role/batch-execution-role',
};
The executionRoleArn must include permissions to fetch the secrets. Add these to the execution role policy:
{
"Effect": "Allow",
"Action": [
"secretsmanager:GetSecretValue",
"ssm:GetParameters"
],
"Resource": [
"arn:aws:secretsmanager:us-east-1:123456789012:secret:prod/*",
"arn:aws:ssm:us-east-1:123456789012:parameter/prod/*"
]
}
IAM roles: jobRoleArn vs executionRoleArn
These two roles serve completely different purposes and are attached to different identities:
| Field | Assumed by | Grants access to | Required on |
|---|---|---|---|
jobRoleArn | Your container process | AWS APIs your code calls (S3, DynamoDB, SQS, etc.) | EC2 and Fargate |
executionRoleArn | ECS Fargate agent | ECR image pull, CloudWatch Logs, Secrets Manager, SSM | Fargate only (but required) |
The execution role trust policy must allow ecs-tasks.amazonaws.com to assume it. The managed policy arn:aws:iam::aws:policy/service-role/AmazonECSTaskExecutionRolePolicy covers ECR and CloudWatch Logs; add secretsmanager:GetSecretValue and ssm:GetParameters manually if you use the secrets array.
// Execution role trust policy
{
"Version": "2012-10-17",
"Statement": [{
"Effect": "Allow",
"Principal": { "Service": "ecs-tasks.amazonaws.com" },
"Action": "sts:AssumeRole"
}]
}
// Job role trust policy (same principal)
{
"Version": "2012-10-17",
"Statement": [{
"Effect": "Allow",
"Principal": { "Service": "ecs-tasks.amazonaws.com" },
"Action": "sts:AssumeRole"
}]
}
EFS and host volumes
AWS Batch supports two volume types: host-path volumes (EC2 only; maps a path on the EC2 host into the container) and EFS volumes (available on both EC2 and Fargate). EFS is the standard choice for shared persistent storage in batch pipelines.
import { type Volume, type MountPoint } from '@aws-sdk/client-batch';
const volumes: Volume[] = [
{
name: 'efs-data',
efsVolumeConfiguration: {
fileSystemId: 'fs-0abc1234def5678',
rootDirectory: '/batch-data', // mount this path from EFS as the root
transitEncryption: 'ENABLED', // encrypt in transit (recommended)
authorizationConfig: {
accessPointId: 'fsap-0abc1234def5678', // optional EFS Access Point
iam: 'ENABLED', // use jobRoleArn to authorize EFS access
},
},
},
];
const mountPoints: MountPoint[] = [
{
containerPath: '/data', // path inside the container
sourceVolume: 'efs-data',
readOnly: false,
},
];
const containerWithEfs: ContainerProperties = {
image: '123456789012.dkr.ecr.us-east-1.amazonaws.com/my-job:latest',
resourceRequirements: [
{ type: 'VCPU', value: '2' },
{ type: 'MEMORY', value: '4096' },
],
volumes,
mountPoints,
jobRoleArn: 'arn:aws:iam::123456789012:role/batch-job-role',
executionRoleArn: 'arn:aws:iam::123456789012:role/batch-execution-role',
fargatePlatformConfiguration: { platformVersion: 'LATEST' },
networkConfiguration: { assignPublicIp: 'DISABLED' }, // private subnet + NAT Gateway
};
When iam: 'ENABLED' in authorizationConfig, the EFS file system uses IAM authorization in addition to POSIX permissions. Add elasticfilesystem:ClientMount and elasticfilesystem:ClientWrite to the job role for the specific file system ARN.
CloudWatch log configuration
The logConfiguration field controls how stdout/stderr from your container is forwarded. The awslogs driver is the standard choice for CloudWatch Logs integration. Each job run creates a log stream named {streamPrefix}/{jobName}/{jobId}.
import { type LogConfiguration } from '@aws-sdk/client-batch';
const logConfiguration: LogConfiguration = {
logDriver: 'awslogs',
options: {
// Log group must exist — Batch does not create it automatically
'awslogs-group': '/aws/batch/my-pipeline',
'awslogs-region': 'us-east-1',
// Stream prefix: final stream name = {prefix}/{jobName}/{jobId}
'awslogs-stream-prefix': 'my-pipeline',
// Optional: create the log group if it doesn't exist (requires logs:CreateLogGroup)
'awslogs-create-group': 'true',
},
};
After a job completes, retrieve the log stream name from DescribeJobsCommand response: job.container.logStreamName. This is the fully qualified stream name you pass to GetLogEventsCommand. If the job failed during container startup (image pull error, secrets fetch error), the log stream may not exist — check job.statusReason first.
Fargate-specific note: the execution role must have logs:CreateLogStream and logs:PutLogEvents for the log group ARN. The managed AmazonECSTaskExecutionRolePolicy grants logs:CreateLogStream and logs:PutLogEvents for all log groups, but scope it down in production:
{
"Effect": "Allow",
"Action": [
"logs:CreateLogStream",
"logs:PutLogEvents"
],
"Resource": "arn:aws:logs:us-east-1:123456789012:log-group:/aws/batch/my-pipeline:*"
}
Fargate-only restrictions
When platformCapabilities: ['FARGATE'], certain containerProperties fields are not supported and will cause ClientException: Fargate does not support X:
| Unsupported field | EC2 alternative |
|---|---|
privileged: true | Use EC2 compute environment |
ulimits | Not configurable on Fargate |
devices | Not configurable on Fargate |
instanceType override | Fargate manages instance selection |
| Host-path volumes | Use EFS volumes instead |
resourceRequirements[GPU] | Use EC2 p3/g4 instance types |
Fargate also requires both executionRoleArn (for ECR image pull) and networkConfiguration (for the ENI attached to the Fargate task). If you omit either, RegisterJobDefinitionCommand returns ClientException: Fargate requires executionRoleArn at job registration time, not at submission time — which makes it hard to debug if you register definitions separately from job queues.
Related pages
- AWS Batch overview — CreateComputeEnvironment, CreateJobQueue, RegisterJobDefinition — set up the infrastructure
- AWS Batch job lifecycle — SubmitJob, DescribeJobs, retryStrategy — polling job state and handling failures
- AWS Batch array jobs and job dependencies — arrayProperties, dependsOn — fan-out patterns
- AWS IAM for MCP servers — job role and execution role design
- AWS CloudWatch for MCP servers — query Batch job logs