Pluralsight Notes – Docker Images and Containers for ASP.NET Core

Docker Images and Containers for ASP.NET Core by Wes Higbee, is a great introductory course on everything you need to know to get your .net core application running in a container.  By the end of this course you will be able to build and run your application inside docker, as well as provide an optimized image for deployment.  All of this is done through the command line and the use of dockerfiles, with a final section on Visual Studio’s built-in docker support.  Learning all of the commands necessary to build and run an application in a container, gives you a better appreciation for what the built-in support is doing and how to troubleshoot and future problems.

Running an ASP.NET Core App in a Container

    • dotnet commands
      • new / restore / build
      • Web/App Projects – run / publish
      • Library Projects – pack / nugetpush
      • Test Projects – test
    • Container is an isolated process – own resource stack
    • Container image contains the filesystem to run the application
    • Docker Commands
      • docker version
      • docker run --rm -it microsoft/dotnet:2-runtime dotnet
    • Docker for windows – Switch to windows containers or linux containers
    • Windows container mounting volume
      • docker run --rm -it  -v ${PWD}:C:\apisource microsoft/dotnet:2-runtime dotnet
    • Need to use aspnetcore image
    • Get container ipaddress
      • docker inspect {container}
    • Map port from a container to host port
      • -p {hostport}:{containerport}
      • docker run --rm -it  -v ${PWD}:C:\apisource -p 8080:80 microsoft/aspnetcore

Picking a Base Image

    • Docker engine smart enough to determine which image you need – windows or linux arch
    • manifest-tool
      • inspect microsoft/dotnet:2-runtime – shows both available arch
      • inspect microsoft/dotnet:{linux tag} – will only show the linux digest available
    • What app model am I using?
      • Console application/windows type service
      • Asp dot net core website/web api
    • OS base image
      • windows or linux
    • What components are needed?
      • Runtime vs Sdk
      • Prod vs dev
      • What you need inside the image besides the OS
    • Version
      • Runtime version
      • OS version
      • Nightly builds of images to test out the latest and greatest versions
    • Keep up with changes by following the GitHub repositories

Distributing a Pre-published App in an Image

    • Copy published application files into container layer and build image
    • Create dockerfile to copy the published app and build the image
      • FROM microsoft/aspnetcore-build:2
        WORKDIR /app
        COPY {src:published app} . ##(copy files into container working directory /app folder)
        ENTRYPOINT ["dotnet", "/app/api.dll"]
    • docker build -t {tagname} .
    • Output will be an image with your published app
    • docker image ls (to see the images)
    • docker run --rm -it -p 8080:80 {tagname}
    • Push image to an image registry
    • .dockerignore file to minimize build context
      • * (ignore everything)
      • !{publishfolder} (don’t ignore published app)

Building the App in a Container

    • --entrypoint bash – enter bash shell of the resulting container to navigate the filesystem
    • docker diff {container id}
      • show changes made to image
    • docker inspect {image tag}
    • Configuration is defined with the image
    • docker run --rm -it -v ${PWD}:/api  microsoft/dotnet:2-sdk
      • Need to use the SDK image not the runtime image for building/publishing
    • aspnetcore-build image optimized for core
    • When starting and stopping containers for dev make sure you run dotnet restore to repopulate package cache

Automate Building with a Dockerfile

      • docker events -h (get realtime events from the docker engine)
      • Each instruction creates a container modifies then commits to create new image – this repeats until the final image is ready
      • Rocker alternative build tool
      • Example Docker File For Building
        • FROM microsoft/aspnetcore-build:2
          WORKDIR /api
          COPY . .
          RUN dotnet restore
          RUN dotnet publish -o /publish
          WORKDIR /publish
          ENTRYPOINT ["dotnet", "/publish/api.dll"
      • Default content root is the working directory – need to make sure that is set to the publish folder as we likely will not have the source in the final runtime image

Using a Multi-stage Build to Create a Runtime Optimized Image

    • Use container to build then pull out published app and create image with only runtime in one dockerfile
    • Container per instruction is what allows the flexibility to do multi stage docker files
    • In order to switch to the new image you add another FROM instruction
    • Multi Stage Docker File
      • Build Stage
        • FROM microsoft/aspnetcore-build:2 as build-env #(this will name the stage for reference in other stages)
          WORKDIR /api
          COPY . .
          RUN dotnet restore
          RUN dotnet publish -o /publish
      • Runtime Stage
        • FROM microsoft/aspnetcore:2
          WORKDIR /publish
          COPY --from=build-env /publish .  #(stages are also numbered --from=0 means the same as --from=build-env)
          ENTRYPOINT ["dotnet", "api.dll"]
    • Optimizing build stage
      • Do not copy in all of the source at once, just copy proj file which changes infrequently thus limiting the number of times package restore is run
        • COPY api.csproj .
          RUN dotnet restore
          COPY . .
          RUN dotnet publish -o /publish
      • You can utilize the composability of csproj file to split up into multiple pieces to optimize build/restore times

Composing an ASP.NET Core App

    • Docker compose automates setup and deployment of container
    • docker-compose.yml
      • version: ‘3.1’
      • services:
        • generator:
          • image: aspnetcore/generator:multi
          • ports:
            • – “8080:80”
    • Default file used “docker-compose.yml”
    • docker-compose up
    • docker-compose up -d (detach from shell, start in background)
    • docker-compose logs
    • docker-compose logs -f (attach again)
    • Making changes to the yaml service will remove old container and create a new one with the new configuration
    • docker-compose.yml
      • version: ‘3.1’
      • services:
        • generator:
          • build:
            • context: .
          • image: aspnetcore/generator:multi
          • ports:
            • – “8080:80”
    • After first compose, changes to dockerfile or source need to use docker-compose build or docker-compose up –build to rebuild the image
    • Compose allows you to spin up multiple services or dependencies your app might need (ie mail server or database)
      • docker-compose.yml
        • version: ‘3.1’
        • services:
          • generator:
            • build:
              • context: .
            • image: aspnetcore/generator:multi
            • ports:
              • – “8080:80”
          • mail:
            • image: mailhog/mailhog
            • ports:
              • – “8025:8025”
              • – “1025:1025”
    • Service name defined in compose file can be used as hostname (mail:1025)
    • docker-compose down (stop and remove all containers)

Dissecting Visual Studio’s Docker Support

    • Right click project file – “Docker Support”
    • Docker file setup to copy in published application (build on machine then copy published app into container)
    • docker-compose.override.yml – allows you to override values for development
    • Set startup project as the “Docker” project to run in docker
    • When debugging visual studio mounts the source code as a volume
    • Running “tail” command which allows the container to continue to run so visual studio does not have to start and stop the container for debugging purposes (long running environment)
    • docker exec -it {containerid} bash (get into the running container)
    • docker-compose.vs.debug.g.yml and docker-compose.vs.release.g.yml – auto generated by visual studio
    • Switch to release and build – this will create a release image – this will copy the published output into the image