DEV Community

jgngo
jgngo

Posted on • Updated on

CI/CD for .NET Core

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:

  1. Add files for building a docker image and pushing to the container registory
  2. Setup Code Pipeline
  3. 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"]
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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");
Enter fullscreen mode Exit fullscreen mode

Startup.cs

            app.UseEndpoints(endpoints =>
            {
                endpoints.MapControllers();
                endpoints.MapHealthChecks("/api/health");
            });
Enter fullscreen mode Exit fullscreen mode

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

  1. Add the Source stage
  2. Add the Build stage
  3. 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
Enter fullscreen mode Exit fullscreen mode

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

  1. Go to Clusters
  2. Create Service
  3. Select the Task Definition that you created in the step before
  4. 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)

Collapse
 
polterguy profile image
Thomas Hansen

Najs one, although I would prefer .Net 6, and a GitHub workflow file ... :)