A Simple Guide to .NET, AWS ECR, and GitHub Actions
Integrating .NET with AWS ECR for Seamless CI/CD Pipelines
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.
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.
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.
Steps to add permissions
- Permissions > Edit.
- Add statement.
- Specify a statement name, check the IAM user you created earlier, and set the Action values as shown in the image.
- Save and confirm the permission addition.
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.
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.
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.
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!