use. NET 6 to develop TodoList application (30) -- Realizing Docker packaging and deployment

Posted by Maknis on Sun, 16 Jan 2022 11:39:33 +0100

Series navigation and source code

demand

The most used scenario of. NET 6 Web API application is as a back-end microservice application. In actual projects, we generally publish the application by packaging it into a docker image for better deployment, including the microservice project deployment based on Kubernetes platform.

Generally speaking, applications deployed as microservices are located under a virtual subnet, that is, they are not directly exposed to external users, and the requests go through the internal network, so there are few HTTPS requirements. However, as a demonstration, we will introduce how to implement HTTPS to access applications in docker in this article.

target

Implement the packaging and operation of docker image of application, including HTTPS based access.

Principles and ideas

The implementation idea of application docker image packaging is very simple. Prepare a correct dockerfile, configure HTTPS as needed, and finally build the image correctly.

realization

Implement Docker image packaging

When creating a dockerfile file in the Api project, we generally build the application in two steps: the first step is to compile and publish, and the second step is to copy the published file to the runtime environment, which can reduce the size of the image.

If you are developing a project using Visual Studio or Rider, you can select whether to use Docker support when creating the project. You can select the container environment as Linux, and the project template will automatically generate the correct Dockerfile for us. Or we can right-click the project and select Add Docker support.

The following is the content of our handwritten dockerfile. For the little partners who have little experience in writing dockerfile, the most error prone place is the path problem. Because we have generated the dockefile in the Api project, there is a problem only from the path in the file content, but it doesn't matter. When packaging the image, we can specify the execution context of the dockefile. As long as we execute docker build in the solution directory, there is no problem.

ARG NET_IMAGE=6.0-bullseye-slim
FROM mcr.microsoft.com/dotnet/aspnet:${NET_IMAGE} AS base
WORKDIR /app
EXPOSE 80
EXPOSE 443
ENV ASPNETCORE_ENVIRONMENT=Development

FROM mcr.microsoft.com/dotnet/sdk:${NET_IMAGE} AS build
WORKDIR /src
COPY ["src/TodoList.Api/TodoList.Api.csproj", "TodoList.Api/"]
COPY ["src/TodoList.Application/TodoList.Application.csproj", "TodoList.Application/"]
COPY ["src/TodoList.Domain/TodoList.Domain.csproj", "TodoList.Domain/"]
COPY ["src/TodoList.Infrastructure/TodoList.Infrastructure.csproj", "TodoList.Infrastructure/"]
RUN dotnet restore "TodoList.Api/TodoList.Api.csproj"
COPY ./src .
WORKDIR "/src/TodoList.Api"
RUN dotnet build "TodoList.Api.csproj" -c Release -o /app/build

FROM build AS publish
RUN dotnet publish --no-restore "TodoList.Api.csproj" -c Release -o /app/publish

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

Before constructing the image, there are several small pits to note:

  • Temporarily delete the usehttpsreduction Middleware in the Program because we have not configured the HTTPS certificate;
  • In the csproj file of the API project, todolist Api. The configuration of the XML file in Debug mode is copied to the Release. Otherwise, an error will be reported: could not find file '/ APP / todolist Api. xml;
  • Modify the corresponding Appsettings {env}. For the database connection string in JSON, use the docker network model to obtain other containers. Change localhost to mssql. This name is the name of the container running sql server docker locally. We will use the docker network to allow applications to connect to the database docker container.

Now let's build this image, make sure it is in the solution directory, and pay attention to the last one Indicates the execution context path of the currently selected dockerfile file, i.e. solution directory:

$ docker build -t todo-list -f src/TodoList.Api/Dockerfile .

Generated image:

Run, expose port 80, use the -- link parameter to indicate that the current application container needs to be connected to the network where the database container is located, and use the API client to verify the login request:

$ docker run -p 80:80 --name=todo_list_in_docker --link=mssql -d todo-list
4733f35c2c9558b78e3c7b9281536d8891f19bf87b18fa0ad953e94f7b984184

Request authentication:

Enable HTTPS access

Next, we add HTTPS support to the container. In order to achieve this, of course, we still need to continue to use the usehttpsredirect middleware, and then we need to add a certificate and add this certificate when starting the container.

dotnet dev-certs https -ep ${HOME}/.aspnet/https/aspnetapp.pfx -p Test@Password
dotnet dev-certs https --trust

Re build and run the container. This time, we use port 5001 of HTTPS to access the API in the container. We need to expose port 443 in the HTTPS container to the port on the host (I choose port 5001), formulate relevant HTTPS environment variables, specify the certificate, and mount the path to save the certificate on the host into the container for access.

docker run \
    -p 80:80 \
    -p 5001:443 \
    --name=todo_list_in_docker \
    --link=mssql \
    -e ASPNETCORE_URLS="https://+;http://+" \
    -e ASPNETCORE_HTTPS_PORT=5001 \
    -e ASPNETCORE_Kestrel__Certificates__Default__Password="Test@Password" \
    -e ASPNETCORE_Kestrel__Certificates__Default__Path=/https/aspnetapp.pfx \
    -v ${HOME}/.aspnet/https:/https/ \
    -d \
    todo-list

Add docker compose function

Here, we found a troublesome problem that we need to remember these configurations, and we need to manually start the database container and application container respectively each time. We can complete it through docker compose, so we first stop and delete the application container and database container, and start creating a docker compose file in the solution directory:

version: '3.4'

services:
  todo-list:
    image: todo-list
    # Configure port forwarding
    ports:
      - "80:80"
      - "5001:443"
    # Configure container environment variables
    environment:
      - ASPNETCORE_ENVIRONMENT=Development
      - ASPNETCORE_URLS=https://+;http://+
      - ASPNETCORE_HTTPS_PORT=5001
      - ASPNETCORE_Kestrel__Certificates__Default__Password=Test@Password
      - ASPNETCORE_Kestrel__Certificates__Default__Path=/https/aspnetapp.pfx
    # Mount certificate path
    volumes:
      - ~/.aspnet/https:/https:ro
    # You need to start the database container first
    depends_on:
      - mssql
    # Todo list responds to the request through the public network and connects to the database container through the private network
    networks:
      - private
      - public

  mssql:
    image: mcr.microsoft.com/mssql/server:2019-latest
    # Port forwarding is configured to directly access the database from the host. If there is no need to directly access the database from the host, you only need to declare that container port 1433 does not forward
    ports:
      - "1433:1433"
    environment:
      - SA_PASSWORD=StrongPwd123
      - ACCEPT_EULA=Y
    # Mount data directory for persistence
    volumes:
      - mssqldata:/var/opt/mssql
    networks:
      - private
      - public

# Because the mssqldata path has been created before, you need to declare to use the existing path here
volumes:
  mssqldata:

networks:
  private:
  public:

Continue to request authentication after running:

$ docker-compose up --build
Creating network "todolist_private" with the default driver
Creating network "todolist_public" with the default driver
Recreating todolist_mssql_1 ... done
Recreating todolist_todo-list_1 ... done
Attaching to todolist_mssql_1, todolist_todo-list_1
// Omit the following log

Request result:

So far, the demonstration of how to use containers for application packaging and deployment is over. How to apply these steps in Kubernetes and CI/CD will be covered again in the series of microservices later.

summary

The error prone part of docker packaging application lies in the dockerfile path. In addition, if there are other operations in the container, such as installing some third-party agents (such as splunk agent), you also need to operate carefully. For how to Debug Docker Build, you can refer to articles written by others, such as this: Debugging Docker builds.

reference material

  1. Hosting ASP.NET Core images with Docker over HTTPS
  2. Hosting ASP.NET Core images with Docker Compose over HTTPS
  3. Debugging Docker builds

Topics: webapi