AWS App Runner End of Support
Did you know that AWS App Runner has been deprecated?
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
- Download and install .NET SDK (if you haven't). I'm using .NET 10.
- Run
dotnet new slnto create a new solution. - Run
dotnet new gitignoreto create the.gitignore - Run
dotnet new webapi -o ApiSampleto create the Project. - Run
dotnet sln add ApiSampleto connect the project to the solution. - Test building the project with
dotnet build. -
You may need to add some lines to the
ApiSample/Program.csfile 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(); Try to run the app by using
dotnet run --project ApiSample. Open the API, for example,localhost:5007/health; it should show "Healthy".
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"'
- Code explanation:
- It will check out the code.
- It will authenticate to GitHub Container Registry.
- 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.
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.
- Download and install Terraform CLI.
- Create a new folder
infrain the previous project. -
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" } Ensure your terminal has been changed to
infra. Runterraform init. It will initialize and prepare the provider.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.
-
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 } Let's try to run
terraform applyto 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.
If it's successful, when I open the health URL, it will return Healthy.
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.






Top comments (0)