OpenMCF logoOpenMCF

Loading...

AWS ECS Service

Deploys a Fargate-based ECS service with a task definition, optional ALB integration (path-based or hostname-based routing), CloudWatch logging, and target-tracking autoscaling. The component creates the task definition, ECS service, target group, listener rules, and scaling policies from a single manifest.

What Gets Created

When you deploy an AwsEcsService resource, OpenMCF provisions:

  • CloudWatch Log Group — a cloudwatch.LogGroup named /ecs/<serviceName> with 30-day retention (created when logging is enabled, which is the default)
  • ECS Task Definition — an ecs.TaskDefinition configured for Fargate with awsvpc networking, the specified CPU/memory, container image, environment variables, secrets, S3 environment files, and optional IAM roles
  • ECS Service — an ecs.Service running the task definition on the specified cluster with the desired replica count and network configuration
  • ALB Target Group — an lb.TargetGroup of type ip (created only when alb.enabled is true) with configurable health check settings
  • ALB Listener Rule — an lb.ListenerRule for path-based or hostname-based routing (created only when alb.enabled is true and a routing type is specified)
  • Auto Scaling Target — an appautoscaling.Target for the ECS service (created only when autoscaling.enabled is true)
  • CPU Scaling Policy — an appautoscaling.Policy using ECSServiceAverageCPUUtilization target tracking (created when autoscaling.targetCpuPercent is set)
  • Memory Scaling Policy — an appautoscaling.Policy using ECSServiceAverageMemoryUtilization target tracking (created when autoscaling.targetMemoryPercent is set)

Prerequisites

  • AWS credentials configured via environment variables or OpenMCF provider config
  • An existing ECS cluster (deploy with AwsEcsCluster or provide an ARN)
  • At least one VPC subnet for Fargate task placement
  • A security group allowing traffic to the container port
  • An existing ALB with a listener on the target port if enabling ALB integration (deploy with AwsAlb)
  • IAM roles for task execution (image pull, log writes) and optional task role (AWS API access)

Quick Start

Create a file ecs-service.yaml:

apiVersion: aws.openmcf.org/v1
kind: AwsEcsService
metadata:
  name: my-api
  labels:
    openmcf.org/provisioner: pulumi
    pulumi.openmcf.org/organization: my-org
    pulumi.openmcf.org/project: my-project
    pulumi.openmcf.org/stack.name: dev.AwsEcsService.my-api
spec:
  clusterArn: arn:aws:ecs:us-east-1:123456789012:cluster/my-cluster
  container:
    image:
      repo: nginx
      tag: latest
    cpu: 256
    memory: 512
    port: 80
  network:
    subnets:
      - subnet-0a1b2c3d4e5f00001
      - subnet-0a1b2c3d4e5f00002

Deploy:

openmcf apply -f ecs-service.yaml

This creates a single-replica Fargate service running nginx with CloudWatch logging enabled by default.

Configuration Reference

Required Fields

FieldTypeDescriptionValidation
clusterArnStringValueOrRefARN of the ECS cluster where this service runs. Can reference an AwsEcsCluster resource via valueFrom.Required
clusterArn.valuestringDirect cluster ARN value—
clusterArn.valueFromobjectForeign key referenceDefault kind: AwsEcsCluster, field: status.outputs.cluster_arn
container.cpuint32vCPU units for the task. Valid Fargate values: 256, 512, 1024, 2048, 4096.Required
container.memoryint32Memory in MiB for the task. Valid values depend on CPU (e.g., 256 CPU supports 512-2048 MiB).Required
network.subnetsStringValueOrRef[]VPC subnet IDs for Fargate task placement. Can reference AwsVpc resources via valueFrom.Required, at least 1 item

Optional Fields

FieldTypeDefaultDescription
container.image.repostring""Container image repository (e.g., nginx, 123456789012.dkr.ecr.us-east-1.amazonaws.com/my-app).
container.image.tagstring""Container image tag (e.g., latest, v1.2.3).
container.portint320Container port to expose. Omit for background workers that do not receive inbound traffic.
container.replicasint321Number of task replicas. Higher values improve availability at increased cost.
container.env.variablesmap<string,string>{}Environment variables injected into the container as key-value pairs.
container.env.secretsmap<string,string>{}Secret values injected as environment variables. Values can be plaintext or ARN references to Secrets Manager / SSM Parameter Store.
container.env.s3Filesstring[][]S3 URIs loaded as environment files via the ECS environmentFiles feature. Must be unique.
container.logging.enabledbooltrueAuto-creates a CloudWatch Log Group at /ecs/<serviceName> with 30-day retention and configures the awslogs driver.
network.securityGroupsStringValueOrRef[][]Security group IDs for task ENIs. Can reference AwsSecurityGroup resources via valueFrom.
iam.taskExecutionRoleArnStringValueOrRef—IAM role for ECS to pull images and write logs. Can reference an AwsIamRole resource via valueFrom.
iam.taskRoleArnStringValueOrRef—IAM role the container assumes for AWS API calls. Can reference an AwsIamRole resource via valueFrom.
alb.enabledboolfalseAttaches the service to an ALB via a target group and listener rule.
alb.arnStringValueOrRef—ARN of the ALB. Required when alb.enabled is true. Can reference an AwsAlb resource via valueFrom.
alb.routingTypestring—Routing mode. Valid values: path, hostname.
alb.pathstring""URL path pattern for routing (e.g., /api/*). Required when routingType is path.
alb.hostnamestring""Hostname for routing (e.g., api.example.com). Required when routingType is hostname.
alb.listenerPortint3280Port on the ALB listener to attach the rule to.
alb.listenerPriorityint32100Priority of the listener rule. Lower numbers have higher priority. Must be unique per ALB.
alb.healthCheck.protocolstringHTTPHealth check protocol. Valid values: HTTP, HTTPS, TCP.
alb.healthCheck.pathstring/Health check path (HTTP/HTTPS only).
alb.healthCheck.portstringtraffic-portHealth check port. Use traffic-port or an explicit port number as a string.
alb.healthCheck.intervalint3230Seconds between health checks.
alb.healthCheck.timeoutint325Seconds before a health check times out.
alb.healthCheck.healthyThresholdint325Consecutive successes before a target is considered healthy.
alb.healthCheck.unhealthyThresholdint322Consecutive failures before a target is considered unhealthy.
healthCheckGracePeriodSecondsint3260Seconds ECS ignores ALB health check failures during container startup. Only applies when alb.enabled is true.
autoscaling.enabledboolfalseEnables target-tracking autoscaling for the service.
autoscaling.minTasksint32—Minimum number of tasks. Must be >= 1. Required when autoscaling is enabled.
autoscaling.maxTasksint32—Maximum number of tasks. Must be >= 1 and >= minTasks. Required when autoscaling is enabled.
autoscaling.targetCpuPercentint3275Target average CPU utilization percentage (1-100). Scaling out occurs when CPU exceeds this threshold.
autoscaling.targetMemoryPercentint32—Target average memory utilization percentage (1-100). Optional; most services scale on CPU alone.

Examples

Background Worker (No Ingress)

A background processing service with no exposed port and no ALB:

apiVersion: aws.openmcf.org/v1
kind: AwsEcsService
metadata:
  name: queue-worker
  labels:
    openmcf.org/provisioner: pulumi
    pulumi.openmcf.org/organization: my-org
    pulumi.openmcf.org/project: my-project
    pulumi.openmcf.org/stack.name: dev.AwsEcsService.queue-worker
spec:
  clusterArn: arn:aws:ecs:us-east-1:123456789012:cluster/my-cluster
  container:
    image:
      repo: 123456789012.dkr.ecr.us-east-1.amazonaws.com/worker
      tag: v1.0.0
    cpu: 512
    memory: 1024
    replicas: 2
    env:
      variables:
        QUEUE_URL: https://sqs.us-east-1.amazonaws.com/123456789012/my-queue
        WORKER_CONCURRENCY: "10"
  network:
    subnets:
      - subnet-private-az1
      - subnet-private-az2
    securityGroups:
      - sg-worker
  iam:
    taskExecutionRoleArn: arn:aws:iam::123456789012:role/ecsTaskExecutionRole
    taskRoleArn: arn:aws:iam::123456789012:role/workerTaskRole

Service with Path-Based ALB Routing

An API service fronted by an ALB using path-based routing:

apiVersion: aws.openmcf.org/v1
kind: AwsEcsService
metadata:
  name: api-service
  labels:
    openmcf.org/provisioner: pulumi
    pulumi.openmcf.org/organization: my-org
    pulumi.openmcf.org/project: my-project
    pulumi.openmcf.org/stack.name: prod.AwsEcsService.api-service
spec:
  clusterArn: arn:aws:ecs:us-east-1:123456789012:cluster/prod-cluster
  container:
    image:
      repo: 123456789012.dkr.ecr.us-east-1.amazonaws.com/api
      tag: v2.1.0
    cpu: 1024
    memory: 2048
    port: 8080
    replicas: 3
  network:
    subnets:
      - subnet-private-az1
      - subnet-private-az2
    securityGroups:
      - sg-api
  iam:
    taskExecutionRoleArn: arn:aws:iam::123456789012:role/ecsTaskExecutionRole
  alb:
    enabled: true
    arn: arn:aws:elasticloadbalancing:us-east-1:123456789012:loadbalancer/app/prod-alb/1234567890
    routingType: path
    path: /api/*
    listenerPort: 80
    listenerPriority: 10
    healthCheck:
      protocol: HTTP
      path: /health
      interval: 15
      timeout: 5
      healthyThreshold: 3
      unhealthyThreshold: 2
  healthCheckGracePeriodSeconds: 90

Service with Hostname-Based ALB Routing

A web application routed by hostname through an ALB:

apiVersion: aws.openmcf.org/v1
kind: AwsEcsService
metadata:
  name: web-app
  labels:
    openmcf.org/provisioner: pulumi
    pulumi.openmcf.org/organization: my-org
    pulumi.openmcf.org/project: my-project
    pulumi.openmcf.org/stack.name: prod.AwsEcsService.web-app
spec:
  clusterArn: arn:aws:ecs:us-east-1:123456789012:cluster/prod-cluster
  container:
    image:
      repo: 123456789012.dkr.ecr.us-east-1.amazonaws.com/web
      tag: v3.0.0
    cpu: 512
    memory: 1024
    port: 3000
    replicas: 2
  network:
    subnets:
      - subnet-private-az1
      - subnet-private-az2
    securityGroups:
      - sg-web
  alb:
    enabled: true
    arn: arn:aws:elasticloadbalancing:us-east-1:123456789012:loadbalancer/app/prod-alb/1234567890
    routingType: hostname
    hostname: app.example.com
    listenerPort: 80

Service with Autoscaling

A service that scales between 2 and 10 replicas based on CPU utilization:

apiVersion: aws.openmcf.org/v1
kind: AwsEcsService
metadata:
  name: scalable-api
  labels:
    openmcf.org/provisioner: pulumi
    pulumi.openmcf.org/organization: my-org
    pulumi.openmcf.org/project: my-project
    pulumi.openmcf.org/stack.name: prod.AwsEcsService.scalable-api
spec:
  clusterArn: arn:aws:ecs:us-east-1:123456789012:cluster/prod-cluster
  container:
    image:
      repo: 123456789012.dkr.ecr.us-east-1.amazonaws.com/api
      tag: v2.5.0
    cpu: 1024
    memory: 2048
    port: 8080
    replicas: 2
  network:
    subnets:
      - subnet-private-az1
      - subnet-private-az2
    securityGroups:
      - sg-api
  iam:
    taskExecutionRoleArn: arn:aws:iam::123456789012:role/ecsTaskExecutionRole
  alb:
    enabled: true
    arn: arn:aws:elasticloadbalancing:us-east-1:123456789012:loadbalancer/app/prod-alb/1234567890
    routingType: hostname
    hostname: api.example.com
    listenerPort: 80
    healthCheck:
      protocol: HTTP
      path: /health
  autoscaling:
    enabled: true
    minTasks: 2
    maxTasks: 10
    targetCpuPercent: 70
    targetMemoryPercent: 80

Using Foreign Key References

Reference other OpenMCF-managed resources instead of hardcoding ARNs and IDs:

apiVersion: aws.openmcf.org/v1
kind: AwsEcsService
metadata:
  name: ref-service
  labels:
    openmcf.org/provisioner: pulumi
    pulumi.openmcf.org/organization: my-org
    pulumi.openmcf.org/project: my-project
    pulumi.openmcf.org/stack.name: prod.AwsEcsService.ref-service
spec:
  clusterArn:
    valueFrom:
      kind: AwsEcsCluster
      name: prod-cluster
      field: status.outputs.cluster_arn
  container:
    image:
      repo: 123456789012.dkr.ecr.us-east-1.amazonaws.com/app
      tag: v1.0.0
    cpu: 512
    memory: 1024
    port: 8080
  network:
    subnets:
      - valueFrom:
          kind: AwsVpc
          name: prod-vpc
          field: status.outputs.private_subnets[0].id
      - valueFrom:
          kind: AwsVpc
          name: prod-vpc
          field: status.outputs.private_subnets[1].id
    securityGroups:
      - valueFrom:
          kind: AwsSecurityGroup
          name: app-sg
          field: status.outputs.security_group_id
  iam:
    taskExecutionRoleArn:
      valueFrom:
        kind: AwsIamRole
        name: ecs-exec-role
        field: status.outputs.role_arn
    taskRoleArn:
      valueFrom:
        kind: AwsIamRole
        name: app-task-role
        field: status.outputs.role_arn
  alb:
    enabled: true
    arn:
      valueFrom:
        kind: AwsAlb
        name: prod-alb
        field: status.outputs.load_balancer_arn
    routingType: hostname
    hostname: app.example.com
    listenerPort: 80

Stack Outputs

After deployment, the following outputs are available in status.outputs:

OutputTypeDescription
aws_ecs_service_namestringName of the created ECS service
ecs_cluster_namestringCluster ARN/name the service is deployed in
load_balancer_dns_namestringDNS name of the ALB (empty if ALB is not enabled)
service_urlstringExternal URL constructed from alb.hostname when hostname routing is used (empty otherwise)
service_discovery_namestringInternal DNS name if service discovery is configured
cloudwatch_log_group_namestringName of the CloudWatch log group (e.g., /ecs/my-api)
cloudwatch_log_group_arnstringARN of the CloudWatch log group
service_arnstringARN of the ECS service
target_group_arnstringARN of the ALB target group (empty if ALB is not enabled)

Related Components

  • AwsEcsCluster — provides the cluster where this service runs
  • AwsAlb — provides the Application Load Balancer for ingress traffic
  • AwsVpc — provides subnets for Fargate task placement
  • AwsSecurityGroup — controls network access to task ENIs
  • AwsIamRole — provides task execution and task roles
  • AwsEcrRepo — hosts container images deployed by this service

Next article

AWS EKS Cluster

AWS EKS Cluster Deploys an AWS EKS cluster control plane with configurable public/private API endpoint access, optional envelope encryption of Kubernetes secrets via KMS, and optional control plane logging to CloudWatch. The component requires at least two subnets in distinct Availability Zones for high availability. What Gets Created When you deploy an AwsEksCluster resource, OpenMCF provisions: EKS Cluster — an aws:eks:Cluster control plane placed in the specified subnets, using the provided...
Read next article
Presets
3 ready-to-deploy configurationsView presets →