- Docker on Windows
- Elton Stoneman
- 554字
- 2021-07-02 19:53:19
Compiling the application during the build
There are two common approaches to packaging your own apps in Docker images. The first is to use a base image that contains the application platform and the build tools, so in your Dockerfile, you copy the source code into the image and compile the app as a step during the image building process.
This is a popular approach for public images because it means that anyone can build the image without having the application platform installed locally. It also means the tooling for the application is bundled with the image, so that can make it possible to debug and troubleshoot the application running in the container.
Here's an example with a simple .NET Core application. This Dockerfile is for the image dockeronwindows/ch02-dotnet-helloworld:
FROM microsoft/dotnet:1.1-sdk-nanoserver
WORKDIR /src
COPY src/ .
RUN dotnet restore; dotnet build
CMD ["dotnet", "run"]
The Dockerfile uses Microsoft's .NET Core image from Docker Hub as the base image. It's a specific variation of the image, one which is based on Nano Server and has the .NET Core 1.1 SDK installed. The build copies in the application source code from the context, and compiles the application as part of the container build process.
There are two new instructions in this Dockerfile which you haven't seen before:
- WORKDIR specifies the current working directory. Docker creates the directory in the intermediate container, if it doesn't already exist, and sets it to be the current directory. It remains the working directory for the subsequent instructions in the Dockerfile, and for containers when they run from the image.
- RUN executes a command inside an intermediate container and saves the state of the container after the command completes, creating a new image layer.
When I build this image, you'll see the dotnet command output, which is the application being compiled from the RUN instruction in the image build:
> docker image build --tag dockeronwindows/ch02-dotnet-helloworld .
Sending build context to Docker daemon 367.1kB
Step 1/5 : FROM microsoft/dotnet:1.1-sdk-nanoserver
---> 80950bc5c558
Step 2/5 : WORKDIR /src
---> 00352af1c40a
Removing intermediate container 1167582ec3ae
Step 3/5 : COPY src/ .
---> abd047ca95d7
Removing intermediate container 09d543e402c5
Step 4/5 : RUN dotnet restore; dotnet build
---> Running in 4ec42bb93ca1
Restoring packages for C:\src\HelloWorld.NetCore.csproj...
Generating MSBuild file C:\src\obj\HelloWorld.NetCore.csproj.nuget.g.props.
Writing lock file to disk. Path: C:\src\obj\project.assets.json
Restore completed in 10.36 sec for C:\src\HelloWorld.NetCore.csproj.
...
You'll see this approach a lot on Docker Cloud for applications built with platforms like .NET Core, Go, and Node.js, where the tooling is easy to add to a base image. It means that you can set up an automated build on Docker Cloud so Docker's servers build your image from the Dockerfile when you push code changes to GitHub. The servers can do that without having .NET Core, Go, or Node.js installed because all the build dependencies are inside the base image.
This option means that the final image will be a lot bigger than it needs to be for a production application. Platform tooling will probably use more disk than the app itself, and your end result is meant to be the application - all the build tools taking up space in your image will never be used when the container runs in production. An alternative is to build the application first and then package the compiled binaries into your container image.