This is a guide for setting up CI/CD for a .NET API in the AWS environment using AWS Code Pipeline and AWS ECS.
Here are the steps:
- Add files for building a docker image and pushing to the container registory
- Setup Code Pipeline
- Setup ECS
Two files Dockerfile
and buildspec.yml
need to be added to the project.
The TLS 1.0 option is needed if your SQL Server database does not support TLS 1.2. The recommended option is to update your database to the secure protocol.
You may also change sdk and aspnet version to 5.0 if you haven't updated to 6.0 yet.
This Dockerfile uses a multi-stage build to get an optimal image size.
Dockerfile
FROM mcr.microsoft.com/dotnet/sdk:6.0 AS build-env
WORKDIR /app
# Copy csproj and restore as distinct layers
COPY *.csproj ./
RUN dotnet restore
# Copy everything else and build
COPY . ./
RUN dotnet publish -c Release -o out
# Build runtime image
FROM mcr.microsoft.com/dotnet/aspnet:6.0
WORKDIR /app
# Enable TLS 1.0
RUN sed -i 's/DEFAULT@SECLEVEL=2/DEFAULT@SECLEVEL=1/g' /etc/ssl/openssl.cnf
RUN sed -i 's/MinProtocol = TLSv1.2/MinProtocol = TLSv1/g' /etc/ssl/openssl.cnf
RUN sed -i 's/DEFAULT@SECLEVEL=2/DEFAULT@SECLEVEL=1/g' /usr/lib/ssl/openssl.cnf
RUN sed -i 's/MinProtocol = TLSv1.2/MinProtocol = TLSv1/g' /usr/lib/ssl/openssl.cnf
COPY --from=build-env /app/out .
ENTRYPOINT ["dotnet", "myapp-whatever.dll"]
buildspec.yml
version: 0.2
phases:
pre_build:
commands:
- echo Logging in to Amazon ECR...
- aws --version
- aws ecr get-login-password --region $AWS_DEFAULT_REGION | docker login --username AWS --password-stdin $AWS_ACCOUNT_ID.dkr.ecr.$AWS_DEFAULT_REGION.amazonaws.com
- REPOSITORY_URI=$AWS_ACCOUNT_ID.dkr.ecr.$AWS_DEFAULT_REGION.amazonaws.com/$IMAGE_REPO_NAME
- COMMIT_HASH=$(echo $CODEBUILD_RESOLVED_SOURCE_VERSION | cut -c 1-7)
- IMAGE_TAG=${COMMIT_HASH:=latest}
build:
commands:
- echo Build started on `date`
- echo Building the Docker image...
- docker build -t $REPOSITORY_URI:latest .
- docker tag $REPOSITORY_URI:latest $REPOSITORY_URI:$IMAGE_TAG
post_build:
commands:
- echo Build completed on `date`
- echo Pushing the Docker images...
- docker push $REPOSITORY_URI:latest
- docker push $REPOSITORY_URI:$IMAGE_TAG
- echo Writing image definitions file...
- printf '[{"name":"%s","imageUri":"%s"}]' $IMAGE_REPO_NAME $REPOSITORY_URI:$IMAGE_TAG > imagedefinitions.json
artifacts:
files: imagedefinitions.json
If you don't have a health check endpoint, this is important for containers for the orchestrator to know if your container is ready or if needs to be restarted.
Program.cs
builder.Services.AddHealthChecks();
var app = builder.Build();
app.MapHealthChecks("/api/health");
Startup.cs
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
endpoints.MapHealthChecks("/api/health");
});
You will need to do this in sequence.
Create the Elastic Container Repository (ECR)
Take note of your image repo name and URL.
Create CodePipeline
- Add the Source stage
- Add the Build stage
- Skip the Deployment stage for now.
When you first create the CodePipeline, skip the deployment stage because you will add it only after your first image has been created.
You will need to go to IAM -> Roles -> codebuild-name-service-role and add the AmazonEC2ContainerRegistryFullAccess policy to that service role.
After a successful build, then you may proceed to create the ECS Service.
Create CodeBuild
Choose the following:
Environment Image: Managed Image
Operating System: Ubuntu
Runtime: Standard
Image: aws/codebuild/standard:5.0
Environment Type: Linux
Privileged: True
You will need to configure the following environment variables:
AWS_DEFAULT_REGION
AWS_ACCOUNT_ID
IMAGE_REPO_NAME
Create ECS Task Definition
Image URI: Copy the repository URL and append :latest
to it
Task CPU: .25 vCPU
Task memory: .5 GB
Create ECS Service
- Go to Clusters
- Create Service
- Select the Task Definition that you created in the step before
- Select VPC, Subnets and Security Group
It will take a while for the service to be created and it will fail because there is no image in the repository yet.
Add Deploy
Stage Name: Deploy
Action Name: Deploy
Action Provider: Amazon ECS
Input Artifact: BuildArtifact
Top comments (1)
Najs one, although I would prefer .Net 6, and a GitHub workflow file ... :)