Skip to main content

Dockerized App Using ECS, ECR, and Fargate

A minimal "Hello, World" container in Fargate.

This example lives in the pulumi/examples repository. Check out just this directory to use it:

Get started with this example
git clone --filter=blob:none --sparse https://github.com/pulumi/examples pulumi-examples
git -C pulumi-examples sparse-checkout set aws-ts-hello-fargate
cd pulumi-examples/aws-ts-hello-fargate

This example, inspired by the Docker Getting Started Tutorial, builds, deploys, and runs a simple containerized application to a private container registry, and scales out five load balanced replicas, all in just a handful of lines of Node.js code, and leveraging modern and best-in-class AWS features.

To do this, we use Pulumi infrastructure as code to provision an Elastic Container Service (ECS) cluster, build our Dockerfile and deploy the resulting image to a private Elastic Container Registry (ECR) repository, and then create a scaled-out Fargate service behind an Elastic Application Load Balancer that allows traffic from the Internet on port 80. Because this example using AWS services directly, you can mix in other resources, like S3 buckets, RDS databases, and so on.

Prerequisites#

Running the Example#

After cloning this repo, cd into it and run these commands:

  1. Create a new stack, which is an isolated deployment target for this example:

    Terminal window
    pulumi stack init dev
  2. Set your desired AWS region:

    Terminal window
    pulumi config set aws:region us-east-1 # any valid AWS region will work
  3. Deploy everything with a single pulumi up command. This will show you a preview of changes first, which includes all of the required AWS resources (clusters, services, and the like). Don’t worry if it’s more than you expected — this is one of the benefits of Pulumi, it configures everything so that so you don’t need to!

    Terminal window
    pulumi up

    After being prompted and selecting “yes”, your deployment will begin. It’ll complete in a few minutes:

    Updating (dev):
    Type Name Status
    + pulumi:pulumi:Stack aws-ts-hello-fargate-dev created
    + ├─ awsx:x:ecs:Cluster cluster created
    + │ ├─ awsx:x:ec2:SecurityGroup cluster created
    + │ │ ├─ awsx:x:ec2:EgressSecurityGroupRule cluster-egress created
    + │ │ │ └─ aws:ec2:SecurityGroupRule cluster-egress created
    + │ │ ├─ awsx:x:ec2:IngressSecurityGroupRule cluster-ssh created
    + │ │ │ └─ aws:ec2:SecurityGroupRule cluster-ssh created
    + │ │ ├─ awsx:x:ec2:IngressSecurityGroupRule cluster-containers created
    + │ │ │ └─ aws:ec2:SecurityGroupRule cluster-containers created
    + │ │ └─ aws:ec2:SecurityGroup cluster created
    + │ └─ aws:ecs:Cluster cluster created
    + ├─ awsx:x:elasticloadbalancingv2:ApplicationLoadBalancer net-lb created
    + │ ├─ awsx:x:elasticloadbalancingv2:ApplicationTargetGroup web created
    + │ │ └─ aws:elasticloadbalancingv2:TargetGroup ca84d134 created
    + │ ├─ awsx:x:elasticloadbalancingv2:ApplicationListener web created
    + │ │ ├─ awsx:x:ec2:IngressSecurityGroupRule web-external-0-ingress created
    + │ │ │ └─ aws:ec2:SecurityGroupRule web-external-0-ingress created
    + │ │ └─ aws:elasticloadbalancingv2:Listener web created
    + │ └─ aws:elasticloadbalancingv2:LoadBalancer 218ffe37 created
    + ├─ awsx:x:ec2:Vpc default-vpc created
    + │ ├─ awsx:x:ec2:Subnet default-vpc-public-0 created
    + │ ├─ awsx:x:ec2:Subnet default-vpc-public-1 created
    > │ ├─ aws:ec2:Subnet default-vpc-public-0 read
    > │ └─ aws:ec2:Subnet default-vpc-public-1 read
    + ├─ awsx:x:ecs:FargateTaskDefinition app-svc created
    + │ ├─ aws:ecr:Repository app-img created
    + │ ├─ aws:cloudwatch:LogGroup app-svc created
    + │ ├─ aws:iam:Role app-svc-task created
    + │ ├─ aws:iam:Role app-svc-execution created
    + │ ├─ aws:ecr:LifecyclePolicy app-img created
    + │ ├─ aws:iam:RolePolicyAttachment app-svc-task-32be53a2 created
    + │ ├─ aws:iam:RolePolicyAttachment app-svc-task-fd1a00e5 created
    + │ ├─ aws:iam:RolePolicyAttachment app-svc-execution-9a42f520 created
    + │ └─ aws:ecs:TaskDefinition app-svc created
    + ├─ awsx:x:ecs:FargateService app-svc created
    + │ └─ aws:ecs:Service app-svc created
    > └─ aws:ec2:Vpc default-vpc read
    Outputs:
    url: "218ffe37-e8023b7-1429118690.us-east-1.elb.amazonaws.com"
    Resources:
    + 34 created
    Duration: 3m30s
    Permalink: https://app.pulumi.com/acmecorp/aws-ts-hello-fargate/dev/updates/1
  4. At this point, your app is running! The URL was published so it’s easy to interact with:

    Terminal window
    curl http://$(pulumi stack output url)
    <h3>Hello World!</h3>
    <b>Hostname:</b> ip-172-31-39-18.ec2.internal<br/>
    <b>Visits:</b> <i>cannot connect to Redis, counter disabled</i>
  5. To view the container’s runtime logs, use the pulumi logs command. The single pulumi up above built your Dockerfile, pushed the image to ECR, and rolled it out to Fargate for you — so all that’s left is to watch it serve traffic:

    Terminal window
    pulumi logs --follow
    Collecting logs for stack dev since 2021-03-26T10:49:57.000-07:00.
    2021-03-26T11:45:02.624-07:00[nginx-185c47c] 172.31.38.69 - - [26/Mar/2021:18:45:02 +0000] "GET / HTTP/1.1" 200 205 "-" "curl/7.64.1" "-"
  6. Once you are done, you can destroy all of the resources, and the stack:

    Terminal window
    pulumi destroy
    pulumi stack rm

Related

The infrastructure as code platform for any cloud.