Batch Jobs

Create a Batch Job with EventBridge Trigger

# get default vpc
data "aws_vpc" "default" {
  default = true
}

# get all the subnets
data "aws_subnets" "all" {
  filter {
    name   = "vpc-id"
    values = [data.aws_vpc.default.id]
  }
}

# role that the instance could assume
resource "aws_iam_role" "ecs_instance_role" {
  name               = "ecs_instance_role"
  assume_role_policy = <<EOF
{
    "Version": "2012-10-17",
    "Statement": [
    {
        "Action": "sts:AssumeRole",
        "Effect": "Allow",
        "Principal": {
            "Service": "ec2.amazonaws.com"
        }
    }
    ]
}
EOF
}

# attach a managed policy to the role
resource "aws_iam_role_policy_attachment" "ecs_instance_role" {
  role       = aws_iam_role.ecs_instance_role.name
  policy_arn = "arn:aws:iam::aws:policy/service-role/AmazonEC2ContainerServiceforEC2Role"
}

# create an instance profile from the role
resource "aws_iam_instance_profile" "ecs_instance_role" {
  name = "ecs_instance_role"
  role = aws_iam_role.ecs_instance_role.name
}

# create role for the batch service to assume
resource "aws_iam_role" "aws_batch_service_role" {
  name = "aws_batch_service_role"

  assume_role_policy = <<EOF
{
    "Version": "2012-10-17",
    "Statement": [
    {
        "Action": "sts:AssumeRole",
        "Effect": "Allow",
        "Principal": {
        "Service": "batch.amazonaws.com"
        }
    }
    ]
}
EOF
}

# attach a managed policy to the batch role
resource "aws_iam_role_policy_attachment" "aws_batch_service_role" {
  role       = aws_iam_role.aws_batch_service_role.name
  policy_arn = "arn:aws:iam::aws:policy/service-role/AWSBatchServiceRole"
}

# ec2 instances need to have a security group
resource "aws_security_group" "sg" {
  name = "aws_batch_compute_environment_security_group"

  #   open up egress
  egress {
    from_port   = 0
    to_port     = 0
    protocol    = "-1"
    cidr_blocks = ["0.0.0.0/0"]
  }
}

# create batch compute environment
resource "aws_batch_compute_environment" "ce" {
  compute_environment_name = "batch-ce"

  compute_resources {
    instance_role  = aws_iam_instance_profile.ecs_instance_role.arn
    subnets        = data.aws_subnets.all.ids
    instance_type  = ["optimal"]
    max_vcpus      = 3
    min_vcpus      = 0
    bid_percentage = 100

    security_group_ids = [
      aws_security_group.sg.id,
    ]

    type                = "SPOT"
    allocation_strategy = "BEST_FIT"
    # needs to be created first
    # check out https://docs.aws.amazon.com/batch/latest/userguide/spot_fleet_IAM_role.html
    spot_iam_fleet_role = "arn:aws:iam::690521436457:role/AmazonEC2SpotFleetTaggingRole"
  }


  type         = "MANAGED"
  service_role = aws_iam_role.aws_batch_service_role.arn
  depends_on   = [aws_iam_role_policy_attachment.aws_batch_service_role]
}

# create batch job definition
resource "aws_batch_job_definition" "jd" {
  name = "batch-jd"
  type = "container"

  container_properties = <<CONTAINER_PROPERTIES
{
    "image": "${aws_ecr_repository.my_awesome_repo.repository_url}:latest",
    "resourceRequirements": [
    {"type": "VCPU", "value": "1"},
    {"type": "MEMORY", "value": "1024"}
  ]
}
CONTAINER_PROPERTIES
}

# create ecr repo to push docker image too
resource "aws_ecr_repository" "repo" {
  name = "my-awesome-repo"
}

# create batch job queue
resource "aws_batch_job_queue" "queue" {
  name     = "job-queue"
  state    = "ENABLED"
  priority = 1
  compute_environments = [
    aws_batch_compute_environment.ce.arn,
  ]
}

# create event rule to run the batch job
resource "aws_cloudwatch_event_rule" "sample" {
  name                = "sample"
  description         = "Sample Batch Job"
  schedule_expression = "rate(10 minutes)"
}

# create target for the event rule
resource "aws_cloudwatch_event_target" "target" {
  rule      = aws_cloudwatch_event_rule.sample.name
  target_id = "to-batch"
  arn       = aws_batch_job_queue.queue.arn
  role_arn  = aws_iam_role.eb_role.arn
  batch_target {
    job_definition = aws_batch_job_definition.jd.arn
    job_name       = "schedule"
    job_attempts   = 1
  }

  depends_on = [
    aws_iam_role_policy_attachment.eb_attachment
  ]
}

# create role for eventbridge to assume
resource "aws_iam_role" "eb_role" {
  name = "eb_role"

  assume_role_policy = <<EOF
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "",
      "Effect": "Allow",
      "Principal": {
        "Service": "events.amazonaws.com"
      },
      "Action": "sts:AssumeRole"
    }
  ]
}
EOF
}

# create policy for event eventbridge role
resource "aws_iam_policy" "policy" {
  name        = "eb_policy"
  description = "eb_policy"

  policy = jsonencode({
    Version = "2012-10-17"
    Statement = [
      {
        Action = [
          "batch:SubmitJob",
        ]
        Effect   = "Allow"
        Resource = "*"
      },
    ]
  })
}

# attach policy to role
resource "aws_iam_role_policy_attachment" "eb_attachment" {
  role       = aws_iam_role.eb_role.name
  policy_arn = aws_iam_policy.policy.arn
}