In my previous post, I talked about my learnings of getting started with Docker in Visual studio and a brief intro into the Docker ecosystem.
Visual Studio can get you up and running very fast with Docker, without having to create Docker files and using the Docker command lines. However, I am going to try and explain what a Docker file is, Docker build, Docker run and also Docker Compose and how it all comes together.
Tl;dr:
- Docker files describe how to build a Docker image.
- The Docker build command builds images based on Docker files
- The Docker run command starts a Docker image
- Docker compose files combine docker building and running in a single file.
So…What is a Docker file?
A Docker file is in the form of a YAML file that contains a set of instructions that describes what the application needs in order to build it. If you are new to YAML, here’s a nice intro.
Taking the sample docker file from this sample which was generated by Visual Studio, it can be broken into 4 stages.
Let’s try and break it down.
Stage 1: Specify the runtime
FROM microsoft/dotnet:2.1-aspnetcore-runtime AS base
WORKDIR /app
EXPOSE 80
The first line uses the FROM syntax to define what base docker image to use. In this case, it specifies the dotnet 2.1 runtime.
The next line uses the WORKDIR
command which sets the working directory.
The final line of the first step uses the EXPOSE
feature which exposes port 80.
Stage 2: Building
The next stage is more involved.
FROM microsoft/dotnet:2.1-sdk AS build
WORKDIR /src
COPY DockerAspNetCoreDemo/DockerAspNetCoreDemo.csproj DockerAspNetCoreDemo/
RUN dotnet restore DockerAspNetCoreDemo/DockerAspNetCoreDemo.csproj
COPY . .
WORKDIR /src/DockerAspNetCoreDemo
RUN dotnet build DockerAspNetCoreDemo.csproj -c Release -o /app
Similar to the first stage, it again uses the FROM
syntax to define an image. Notice this time it specifies the dotnet 2.1 sdk rather than the runtime. This is so that it can build the app.
The next line sets the working directory to src
. It then uses the copy syntax to copy the csproj file into a new folder within docker called DockerAspNetCoreDemo
.
It runs dotnet restore
using the copied proj file. It then copies everything and from the current source folder to the docker folder of src
. Finally, it runs dotnet build
with the release parameter and outputs the files into the app
directory which was created in stage 1.
Stage 3: Publishing
The penultimate step below executes the dotnet publish
command and has a parameter that specifies the output to the app
folder.
FROM build AS publish
RUN dotnet publish DockerAspNetCoreDemo.csproj -c Release -o /app
Stage 4: Setting the entry point
Finally, these steps instruct Docker where the entry point of how to start the application. I suppose it’s equivalent to the dotnet-run
command.
FROM base AS final
WORKDIR /app
COPY --from=publish /app .
ENTRYPOINT ["dotnet", "DockerAspNetCoreDemo.dll"]
Docker build
Now that we have a Docker file, one can run the docker build
command to build a docker image.
Now, if navigate to the root directory of the demo application and run:
docker build DockerAspNetCoreDemo -f DockerAspNetCoreDemo/Dockerfile -t aspnetdemo
You may get an error like this:
C:\Users\chlee\Documents\Github\DockerAspNetCoreDemo>docker build DockerAspNetCoreDemo -f DockerAspNetCoreDemo/Dockerfile -t aspnetdemo
Sending build context to Docker daemon 4.209MB
Step 1/16 : FROM microsoft/dotnet:2.1-aspnetcore-runtime AS base
---> f8297fe48f0c
Step 2/16 : WORKDIR /app
---> Using cache
---> c16c3d21ce14
Step 3/16 : EXPOSE 80
---> Using cache
---> 6fd93b472bcc
Step 4/16 : FROM microsoft/dotnet:2.1-sdk AS build
---> f4bc69f831aa
Step 5/16 : WORKDIR /src
---> Using cache
---> 782546a1fbc5
Step 6/16 : COPY DockerAspNetCoreDemo/DockerAspNetCoreDemo.csproj DockerAspNetCoreDemo/
COPY failed: GetFileAttributesEx \\?\C:\WINDOWS\TEMP\docker-builder185318480\DockerAspNetCoreDemo\DockerAspNetCoreDemo.csproj: The system cannot find the path specified.
Not great. Why? Well after some research and discovering this git issue comment it turns out that its the way Visual Studio generates the docker file. However, running this in Visual Studio will have no issues.
A Simpler Docker file
With the above docker file specific to Visual Studio, below is a simpler version. This was taken and modified from the docker site
FROM microsoft/dotnet:2.1-sdk AS build-env
WORKDIR /app
EXPOSE 80
# 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 microsoft/dotnet:2.1-aspnetcore-runtime
WORKDIR /app
COPY --from=build-env /app/out .
ENTRYPOINT ["dotnet", "DockerAspNetCoreDemo.dll"]
Now if you run:
docker build DockerAspNetCoreDemo -f DockerAspNetCoreDemo/Dockerfile-alternative -t aspnetdemo
-f
is the filename of the new simpler docker file.-t
specifies a tag for the image, in our case itsaspnetdemo
.
Then the output will be:
C:\Users\chlee\Documents\Github\DockerAspNetCoreDemo>docker build DockerAspNetCoreDemo -f DockerAspNetCoreDemo/Dockerfile-alternative -t aspnetdemo
Sending build context to Docker daemon 4.209MB
Step 1/11 : FROM microsoft/dotnet:2.1-sdk AS build-env
---> f4bc69f831aa
Step 2/11 : WORKDIR /app
---> Using cache
---> 9025461ed217
Step 3/11 : EXPOSE 80
---> Using cache
---> 0e3c072cc161
Step 4/11 : COPY *.csproj ./
---> Using cache
---> 3eadd1126142
Step 5/11 : RUN dotnet restore
---> Using cache
---> 481f505ae094
Step 6/11 : COPY . ./
---> Using cache
---> 570fb6690fb4
Step 7/11 : RUN dotnet publish -c Release -o out
---> Using cache
---> 382bad5ea05e
Step 8/11 : FROM microsoft/dotnet:2.1-aspnetcore-runtime
---> f8297fe48f0c
Step 9/11 : WORKDIR /app
---> Using cache
---> c16c3d21ce14
Step 10/11 : COPY --from=build-env /app/out .
---> Using cache
---> 07c15508103a
Step 11/11 : ENTRYPOINT dotnet DockerAspNetCoreDemo.dll
---> Using cache
---> 0eeff78b4f71
Successfully built 0eeff78b4f71
Successfully tagged aspnetdemo:latest
This should have created a docker image, and to confirm this, you can run docker images
to list all the images.
You should get something like this:
REPOSITORY TAG IMAGE ID CREATED SIZE
aspnetdemo latest 0eeff78b4f71 18 minutes ago 506MB
microsoft/dotnet 2.1-aspnetcore-runtime f8297fe48f0c 45 hours ago 503MB
Docker run
Now that we have an image, we can run the docker run
command to start the image and load it into a container.
docker run -d -p 8080:80 --name aspnetapp aspnetdemo
The docker run parameters used can be described below:
-d
specifies it’s in detach mode, which means it will run in the background.-p
specifies the external port 8080 and the internal port of the image which is 80--name
specifies the name of the container- last parameter,
aspnetdemo
is the image name that we want to run.
Run the command docker ps
to verify it is running. You should see something like this:
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
5a04e20efb39 aspnetdemo "dotnet DockerAspN..." 38 seconds ago Up 34 seconds 0.0.0.0:8080->80/tcp aspnetapp
Finally, if you load in a browser https://localhost:8080
you should see something like this:
What is Docker Compose?
Docker compose is another command where it can be used in conjunction with Docker files. A Docker compose file will tend to have instructions on how to start the application. In general, it will just refer to the Docker file or an existing docker image and also include any app-specific parameters. For instance, in a web app, we can specify ports and any environment variables.
Here is an example of a docker-compose file:
version: '3.4'
services:
dockeraspnetcoredemo:
build:
context: .
dockerfile: DockerAspNetCoreDemo/Dockerfile
ports:
- "8080:80"
Notice that it specifies the docker file DockerAspNetCoreDemo/Dockerfile
. If we wanted to specify an image, the compose file will look something like this:
version: '3.4'
services:
dockeraspnetcoredemo:
image: aspnetdemo
ports:
- "8080:80"
Now, if we run:
docker-compose -f docker-compose.yml up -d
-f
specifies the filenameup
is the command to “start” the image-d
is the detach mode which runs it in the background
You should see the demo site again if you navigate to https://localhost:8080
Summary
I talked about what is a Docker file is, how to build a docker image from a docker file. Then I walked through how to start a docker image either via the docker run command or via a docker compose file.
I hope this has been helpful and some insight into the Docker world.
You can grab the code from https://github.com/ch-lee/DockerAspNetCoreDemo