AWS Batch on EC2: a Deployment Checklist

Table of Contents

This post is for teams running compute-heavy workloads on AWS Batch with EC2—genomics pipelines, media processing, ETL, simulations—not for “hello world” Fargate tutorials. It assumes you already have a container image, a VPC, and a reason to use Batch instead of ECS or Lambda.

If you have debugged a job that sat in RUNNABLE for twenty minutes or failed with AccessDenied on an S3 object encrypted with KMS, most of this will feel familiar. The goal is a checklist you can hand to a teammate before the next pipeline go-live.

Prerequisites

Before applying Terraform or submitting jobs, confirm these exist:

ItemWhy it matters
ECR repositoryImmutable image tags per build; Batch job definitions reference image URIs
VPC + subnetsBatch EC2 instances need subnets with routes to ECR, S3, CloudWatch Logs, and your data sources
Security groupsInstance SG egress; downstream resources (RDS, NFS) must allow traffic from the Batch SG or instance SG
IAM: service, instance, execution, job rolesFour distinct roles—mixing them up is the fastest way to a 2 a.m. incident
CloudWatch log groupContainer logs land here; without it you are guessing from job status alone
S3 / EFS / FSx pathsKnow where input and reference data live before sizing storage

Checklist before terraform apply

Walk through these in order every time you stand up or change a Batch environment.

1. Network placement

  • Subnets have outbound path to ECR, S3, and CloudWatch (NAT gateway, VPC endpoints, or hybrid routing—pick one deliberately).
  • Application subnets vs database subnets: Batch compute does not belong in DB-only subnets unless you have verified routing and SG rules.
  • Security group egress is explicit enough for your compliance model (open 0.0.0.0/0 egress is common but not always acceptable).

2. Compute environment

  • Instance types are available in the target AZ/region (Batch will fail CE creation if types are invalid or capacity is restricted).
  • min_vcpus / max_vcpus / desired_vcpus match workload burst patterns—desired_vcpus > 0 keeps warm capacity; 0 scales to zero but adds cold-start latency.
  • Root EBS volume size fits container image layers plus scratch data; 100 GiB is a default, not a law.
  • EBS encryption enabled; KMS key policy allows the instance role if using a customer-managed key.

3. Job definition

  • Image URI pins a specific tag or digest—not only latest in production.
  • CPU and memory match what the container actually needs (Batch schedules on vCPU/memory; OOM kills look like mysterious retries).
  • Environment variables documented; secrets from SSM or Secrets Manager, not baked into the image.
  • command override behavior understood—empty command uses the image CMD; pipeline wrappers should fail non-zero on application errors.

4. IAM: job role vs execution role

  • Execution role — pull image, write logs, read secrets for container startup.
  • Job role — runtime S3, KMS decrypt, RDS, or other AWS API calls inside the container.
  • S3 GetObject on the bucket is not enough when objects use SSE-KMS—you need kms:Decrypt on the key and key policy trust for the job role.
  • Optional additional_job_policy_arns for workload-specific least privilege instead of one giant policy.

5. Storage mounts

  • EFS — file system ID, mount path, transit encryption if required; security groups allow NFS from Batch instances.
  • FSx / Lustre — DNS name and mount path tested from a representative instance.
  • Reference genomes or static datasets: confirm paths exist in the image or are mounted before the job starts—not “we will copy later.”

6. Observability and alerts

  • Log group name matches job definition awslogs configuration.
  • SNS (or equivalent) on Batch job state change for FAILED—not only on exit code 0 with errors buried in logs.
  • Consider a CloudWatch Logs metric filter on "ERROR" if application code can succeed with a zero exit code while logging failures.

Checklist before submitting a test job

  • Job name / queue name / job definition name triple-checked in CLI or console.
  • Test job uses the same subnets, SGs, and roles as production—not a one-off admin role that hides IAM gaps.
  • Input data path exists and is readable with the job role (test with aws s3 ls or a minimal container that only lists paths).
  • Someone is watching CloudWatch Logs and Batch job status—not just waiting for an email.

Debugging quick reference

SymptomLikely causeFirst check
Job stuck RUNNABLECE at capacity, insufficient instance types, or subnet/IP exhaustionCE status, describe-compute-environments, EC2 limits
AccessDenied on S3Job role policy or KMS key policyCloudWatch log line, IAM policy simulator, key policy
CE INVALIDBad instance type, subnet, or IAM instance profileBatch event messages on CE
Job SUCCEEDED but wrong outputApp logged error but exited 0Log stream; fix container exit codes
Slow first runCold start, desired_vcpus = 0, large image pullCE scaling, ECR pull time, instance launch

Terraform layout that scales

Patterns that survive more than one region:

  1. Reusable module — compute environment, queue, job definition, IAM, SG, logging in one place.
  2. deployment/<region>/<env>.tfvars — VPC ID, subnets, image tag, and sizing per location; keep the module generic.
  3. Remote state — one backend bucket with per-workspace or per-key separation; document the naming convention.
  4. Tags — cost center, owner, provisioning tool, and environment on every resource; future-you will need them for chargeback and audits.

Relationship to ECS

Use ECS when you have long-running services behind a load balancer. Use Batch when work is job-shaped: finite input, batch output, scale-to-zero between runs, and instance sizing driven by peak compute rather than steady HTTP traffic. Many platform teams run both.

What’s next

This series started with ECS deploy pipelines, moved through Terraform layout and Logs Insights for day-two operations. Batch is where those habits meet scientific and regulated workloads—the subject of a longer essay on how LAMP-era ops thinking still applies.


If you only do one thing: pin production job definitions to an immutable image tag, put the job role through an S3 + KMS read test before the first real run, and make CloudWatch Logs the default answer to “what happened?”—not the Batch console status alone.

Share :

Related Posts

From Varnish and Drupal Tuning to Platform Engineering

In 2013 I wrote about Varnish in front of Drupal and where Drupal sites actually lose performance. The stack was Apache, PHP, MySQL, SSH, and a lot of hand-tuning. Today I work on AWS Batch, multi-region Terraform, and hybrid lab-to-cloud integrations in life sciences. The logos changed; the job did not.

Read More

Terraform Module Layout I Use for Multi-Environment AWS

This post is for teams already running Terraform in AWS who have felt the pain of three “similar but not quite the same” environment folders. It is not a Terraform 101 tutorial, and it assumes you know what a module, variable, and remote state backend are.

Read More

GitHub Actions to ECR to ECS: a Deployment Checklist

This post is for teams already running workloads on Amazon ECS who want a reliable GitHub Actions pipeline without reinventing the wheel each release. It is not a greenfield Kubernetes guide, and it assumes you have a working cluster, service, and task definition—not a blank AWS account.

Read More