A Simple Guide to .NET, AWS ECR, and GitHub Actions

Integrating .NET with AWS ECR for Seamless CI/CD Pipelines

BCAL
.Net Programming
5 min readSep 18, 2024

--

.NET, AWS ECR and GitHub Actions

AWS ECR (Amazon Elastic Container Registry) is an AWS service for storing and managing Docker images. It allows for secure image storage and deployment, and it integrates easily with CI/CD pipelines.

It offers features like private repositories, image lifecycle management, and image scanning, making it easy to manage images, including the automatic deletion of unused ones.

Using ECR is straightforward, involving steps like creating a repository, pushing Docker images, and pulling them. Additionally, it can be integrated with CI/CD tools like Jenkins or GitHub Actions for automated deployment.

The cost depends on storage and data transfer, so it’s important to optimize the images you’re using and implement lifecycle policies.

Based on all this, I’ll walk you through how to create an ECR image using GitHub Actions in a .NET project.

.NET Project

Below is a basic API project created with .NET 8. Since it’s a default project, I’ll skip any additional explanations.

.NET 8 API

The Dockerfile is configured as shown below, and it’s set to expose the default .NET 8 port, 8080.

FROM mcr.microsoft.com/dotnet/aspnet:8.0 AS base
USER app
WORKDIR /app
EXPOSE 8080

FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build
ARG BUILD_CONFIGURATION=Release
WORKDIR /src
COPY ["SampleApi.csproj", "."]
RUN dotnet restore "./././SampleApi.csproj"
COPY . .
WORKDIR "/src/."
RUN dotnet build "./SampleApi.csproj" -c $BUILD_CONFIGURATION -o /app/build

FROM build AS publish
ARG BUILD_CONFIGURATION=Release
RUN dotnet publish "./SampleApi.csproj" -c $BUILD_CONFIGURATION -o /app/publish /p:UseAppHost=false

FROM base AS final
WORKDIR /app
COPY --from=publish /app/publish .
ENTRYPOINT ["dotnet", "SampleApi.dll"]

AWS

IAM

Before creating ECR, I’ll create a USER for preparation.
The policy is as follows:

  • AmazonEC2ContainerRegistryPowerUser

When deploying ECR later, you will also need the AmazonEC2ContainerRegistryFullAccess policy.

ECR

You can choose between public and private repositories, I created a private repository. Assign a repository name and leave the rest as default.

Create private repository

Once the creation is complete, you will see an empty repository without any images, as shown. Now, the next step is to grant access to the repository. Select “Permissions” on the left.

Empty Repository

Steps to add permissions

  1. Permissions > Edit.
  2. Add statement.
  3. Specify a statement name, check the IAM user you created earlier, and set the Action values as shown in the image.
  4. Save and confirm the permission addition.
Permission > Edit
Steps to add Permissions

This is the json of policy.

{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "cicd",
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::***************:user/cicd"
},
"Action": [
"ecr:BatchCheckLayerAvailability",
"ecr:BatchGetImage",
"ecr:CompleteLayerUpload",
"ecr:GetDownloadUrlForLayer",
"ecr:InitiateLayerUpload",
"ecr:PutImage",
"ecr:UploadLayerPart"
]
}
]
}

GitHub Actions

I have set up the workflows for GitHub Actions as follows:

  • It triggers only on-tag events.
  • Docker tags are set to the version and latest.
  • Secret variables are configured as:
    REGION: AWS ECR region
    ACCESS_KEY: IAM access key for AWS ECR permissions
    SECRET_KEY: IAM secret key for AWS ECR permissions
    ECR_URI: URI of the ECR repository
name: ECR Build

on:
push:
tags:
- 'v*.*.*'

jobs:
build:
name: ECR Build
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4

- name: Configure AWS credentials
uses: aws-actions/configure-aws-credentials@v1
with:
aws-region: ${{ secrets.REGION }}
aws-access-key-id: ${{ secrets.ACCESS_KEY }}
aws-secret-access-key: ${{ secrets.SECRET_KEY }}

- name: AWS ECR Login
run: aws ecr get-login-password --region ${{ secrets.REGION }} | docker login --username AWS --password-stdin ${{ secrets.ECR_URI }}

- name: Docker Build
run: docker build --no-cache -t ${{ secrets.ECR_URI }}/sample-api:$(git describe --tags | sed s/[v]//g) .

- name: ADD Commit Tag For Docker Images
run: docker tag ${{ secrets.ECR_URI }}/sample-api:$(git describe --tags | sed s/[v]//g) ${{ secrets.ECR_URI }}/sample-api:latest

- name: Commit Tag Based Docker Image Push
run: |
docker push ${{ secrets.ECR_URI }}/sample-api:$(git describe --tags | sed s/[v]//g)
docker push ${{ secrets.ECR_URI }}/sample-api:latest

It was successfully released after executing Actions with the v1.0.0 tag using the created workflows.

GitHub Actions

Result

After the GitHub Action is completed, if you go back to ECR, you can see that two tags, latest and 1.0.0, have been created as releases.

Repository after creating image tag 1.0.0

What happens if you deploy with version 1.1.0? In the following image, you can see that the 1.1.0 image has been added, and the latest tag has been updated to match 1.1.0.

Repository after creating image tag 1.1.0

Conclusion

In this blog post we walk through how to create an image from a .NET API project build on ECR and automate it with the help of GitHub Actions. By combining GitHub Actions with AWS IAM, we could have had an ideal pipeline that automatically builds and deploys images whenever changes in codes happen, thereby making the deployment process more efficient for the project.

This design can be scaled even further to support larger deployment environments and features may be added. So, feel free to experiment and start automating your projects with the help of AWS ECR and GitHub Actions!

--

--