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.
- 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.
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.
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.
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
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.
The penultimate step below executes the
dotnet publish command and has a parameter that specifies the output to the
FROM build AS publish RUN dotnet publish DockerAspNetCoreDemo.csproj -c Release -o /app
Finally, these steps instruct Docker where the entry point of how to start the application. I suppose it's equivalent to the
FROM base AS final WORKDIR /app COPY --from=publish /app . ENTRYPOINT ["dotnet", "DockerAspNetCoreDemo.dll"]
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.
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
-fis the filename of the new simpler docker file.
-tspecifies a tag for the image, in our case its
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
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:
-dspecifies it's in detach mode, which means it will run in the background.
-pspecifies the external port 8080 and the internal port of the image which is 80
--namespecifies the name of the container
- last parameter,
aspnetdemois 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:
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
-fspecifies the filename
upis the command to "start" the image
-dis the detach mode which runs it in the background
You should see the demo site again if you navigate to
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