DEV Community

Cover image for Getting Started with Amazon ECS Express Mode

Getting Started with Amazon ECS Express Mode

AWS App Runner End of Support

Did you know that AWS App Runner has been deprecated?

AWS App Runner

I've been using AWS App Runner for my simple services. It's a bit sad that I'm no longer able to create a new service, even though I can still maintain AWS App Runner services.

Quick Learning of Amazon ECS Express Mode

Amazon ECS Express Mode is an alternative to AWS App Runner. I've tried to use Amazon ECS directly, but the setup is quite a lot. Let's delegate these tasks to Amazon ECS Express Mode.

Preparing the Service

This is a kind of exploration, especially if you are a new learner of AWS. I think this is a good way to learn it.

You can choose your preferred language. However, in this article, I will use C# and .NET. You may skip this step if you have a web application that is already using a container.

Prepare the project

  1. Download and install .NET SDK (if you haven't). I'm using .NET 10.
  2. Run dotnet new sln to create a new solution.
  3. Run dotnet new gitignore to create the .gitignore
  4. Run dotnet new webapi -o ApiSample to create the Project.
  5. Run dotnet sln add ApiSample to connect the project to the solution.
  6. Test building the project with dotnet build.
  7. You may need to add some lines to the ApiSample/Program.cs file to add a health check API.

    // Add this line before builder.Build()
    builder.Services.AddHealthChecks();
    
    var app = builder.Build();
    
    // ... truncated   
    
    // Add this line before app.Run() 
    app.MapHealthChecks("/health").WithName("HealthCheck");
    
    app.Run();
    
  8. Try to run the app by using dotnet run --project ApiSample. Open the API, for example, localhost:5007/health; it should show "Healthy".

Health API Result

Preparing the Container Image

I will use GitHub Container Registry to host the container image. So, let's build the CI/CD in GitHub Actions. Here is a sample to publish the container image. I saved the file in .github/workflows/deploy.yml.

name: Deploy

on:
  push:
    branches:
      - main
  workflow_dispatch:

env:
  REGISTRY: ghcr.io
  IMAGE_NAME: ${{ github.repository }}/apisample

jobs:

  publish:
    name: Publish ApiSample image
    runs-on: ubuntu-latest
    permissions:
      contents: read
      packages: write
    steps:
      - name: Check out source
        uses: actions/checkout@v4

      - name: Log in to GitHub Container Registry
        uses: docker/login-action@v3
        with:
          registry: ${{ env.REGISTRY }}
          username: ${{ github.actor }}
          password: ${{ secrets.GITHUB_TOKEN }}

      - name: Build and push ApiSample
        run: >-
          dotnet publish ./ApiSample/ApiSample.csproj
          --configuration Release
          /t:PublishContainer
          -p:ContainerRegistry=${{ env.REGISTRY }}
          -p:ContainerRepository=${{ env.IMAGE_NAME }}
          -p:ContainerImageTags='"${{ github.sha }};latest"'
Enter fullscreen mode Exit fullscreen mode
  • Code explanation:
    1. It will check out the code.
    2. It will authenticate to GitHub Container Registry.
    3. It will publish to GitHub Container Registry using dotnet publish.

Let's push the code to test if the CD codes are works.

If it's successful. Your repository will have the Container Repository (Packages) like this. Ensure the repository is Public.

Container Repository

I hosted my code here.

Preparing Infrastructure

We will prepare the infrastructure by using Terraform. If you are not familiar with it, you may use another tool or manually create it; however, I'm not recommended to do it manually.

Please ensure you've installed AWS CLI and configured the credentials to access AWS.

  1. Download and install Terraform CLI.
  2. Create a new folder infra in the previous project.
  3. Create a new file main.tf. You may choose another region as you prefer.

    terraform {
      required_providers {
        aws = {
          source  = "hashicorp/aws"
          version = "~> 6.0"
        }
      }
    }
    
    # Configure the AWS Provider
    provider "aws" {
      region = "us-east-1"
    }
    
  4. Ensure your terminal has been changed to infra. Run terraform init. It will initialize and prepare the provider.

  5. We need two things before deployment. The first is hosted container images, and the second is ECS Express service mode. In this case, I have hosted the container image using GitHub Container Registry.

  6. Add these lines to main.tf.

    # 1. Create IAM roles for ECS Express Gateway
    resource "aws_iam_role" "execution" {
      name = "ecs-express-gateway-execution-role"
    
      assume_role_policy = jsonencode({
        Version = "2012-10-17"
        Statement = [
          {
            Action = "sts:AssumeRole"
            Effect = "Allow"
            Principal = {
              Service = "ecs-tasks.amazonaws.com"
            }
          },
        ]
      })
    }
    
    resource "aws_iam_role_policy_attachment" "execution" {
      role       = aws_iam_role.execution.name
      policy_arn = "arn:aws:iam::aws:policy/service-role/AmazonECSTaskExecutionRolePolicy"
    }
    
    resource "aws_iam_role" "infrastructure" {
      name = "ecs-express-gateway-infrastructure-role"
    
      assume_role_policy = jsonencode({
        Version = "2012-10-17"
        Statement = [
          {
            Action = "sts:AssumeRole"
            Effect = "Allow"
            Principal = {
              Service = "ecs.amazonaws.com"
            }
          },
        ]
      })
    }
    
    resource "aws_iam_role_policy_attachment" "infrastructure" {
      role       = aws_iam_role.infrastructure.name
      policy_arn = "arn:aws:iam::aws:policy/service-role/AmazonECSInfrastructureRoleforExpressGatewayServices"
    }
    
    # 2. Create ECS Express Gateway Service
    
    resource "aws_ecs_express_gateway_service" "apisample" {
      execution_role_arn      = aws_iam_role.execution.arn
      infrastructure_role_arn = aws_iam_role.infrastructure.arn
      health_check_path       = "/health"
    
      primary_container {
        container_port = 8080
        image = "ghcr.io/berviantoleo/aws-express-mode/apisample:latest"
      }
    
      depends_on = [
        aws_iam_role.execution,
        aws_iam_role.infrastructure,
      ]
    }
    
    # 3. Output the URL of the ECS Express Gateway Service
    
    output "apisample_url" {
      value = aws_ecs_express_gateway_service.apisample.ingress_paths
    }
    
  7. Let's try to run terraform apply to deploy the AWS ECS Express Mode. If it's successful, it will return the URL of the service. However, please note that the service may need a while to be fully deployed.

URL Service

If it's successful, when I open the health URL, it will return Healthy.

Clean Up

Clean Up

Don't forget to clean up the AWS Resources if you are not using them. You can use terraform destroy to remove the ECS Express Mode. As in the documentation, I've added depends_on to ensure that, while destroying the ECS Express Mode, we don't remove the IAM Role first, as it will leave the ECS Express Service stuck while draining.

Thank you

Thank you for reading. If you have any feedback, please let me know.

Thank You GIF

Top comments (0)