Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update build-in-sdk-container documentation for .NET 9 and add section on Docker buildx outputs #5923

Merged
merged 6 commits into from
Sep 30, 2024
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
89 changes: 73 additions & 16 deletions samples/build-in-sdk-container.md
Original file line number Diff line number Diff line change
@@ -1,27 +1,84 @@
# Build in a .NET SDK container

You can use Docker to run your build in an isolated environment using the [.NET SDK Docker image](../README.sdk.md). This is useful to either avoid the need to install .NET on the build machine or ensure that your environment is correctly configured (dev, staging, or production).
You can use Docker to run your build in an isolated environment using the [.NET SDK Docker image](../README.sdk.md).
This is useful to avoid the need to install .NET on the build machine and helps ensure that your build environment is correctly configured (dev, staging, or production).

The instructions assume that you have cloned the repository locally, and that you are in the `samples/dotnetapp` directory (due to the volume mounting syntax), as demonstrated by the examples.
## Build using a Dockerfile (Requires buildx)

## Requirements
Docker [buildx](https://docs.docker.com/reference/cli/docker/buildx/) has built-in support for [exporting files from the docker build command](https://docs.docker.com/build/building/export/).
Using a Dockerfile to build .NET apps is advantageous because it allows you to specify all of the apps required dependencies and build instructions in one place.

The `dotnetapp` sample contains a sample [Dockerfile](./dotnetapp/Dockerfile.sdk-build) that supports this functionality.
This sample uses a multi-stage Dockerfile with a `FROM scratch` stage.
The Dockerfile copies the build outputs into that stage using the `COPY` instruction.
Then, when you provide the `--output/-o <directory>` argument to the Docker build command, Docker will copy the entire filesystem of the final stage of the image to the specified directory.
Since the sample Dockerfile's final stage is a `FROM scratch` stage, the result is that the build outputs are placed in the specified directory on the host machine's disk.

### Build single-platform binary

From the `samples/dotnetapp` directory:

```pwsh
docker build --pull -f Dockerfile.sdk-build --output ./out .
```

You can also give it a try without cloning this repository:

```pwsh
docker build --pull -f Dockerfile.sdk-build --output ./out 'https://github.com/dotnet/dotnet-docker.git#:samples/dotnetapp'
```

### Build binaries for multiple platforms at once

Taking advantage of Docker buildx, you can cross-build binaries for multiple platforms at once, all without using emulation.
For more info about how this works, see our documentation on [building images for a specific platform](./build-for-a-platform.md).

```pwsh
docker buildx build --pull --platform linux/amd64,linux/arm64 -f ./samples/dotnetapp/Dockerfile.sdk-build --output out ./samples/dotnetapp/
```

Docker buildx will create a separate sub-directory for each target platform:

```pwsh
PS> tree /F out
C:\...\dotnetapp\out
├───linux_amd64
│ dotnetapp
│ dotnetapp.deps.json
│ dotnetapp.dll
│ dotnetapp.pdb
│ dotnetapp.runtimeconfig.json
└───linux_arm64
dotnetapp
dotnetapp.deps.json
dotnetapp.dll
dotnetapp.pdb
dotnetapp.runtimeconfig.json
```

## Build by running Docker container directly

If you can't use Docker buildx or don't want to use a Dockerfile, you can build your app by running the SDK image directly and volume mounting your app's source code into the container.
These instructions assume that you have cloned the repository locally, and that you are in the `samples/dotnetapp` directory (due to the volume mounting syntax), as demonstrated by the examples.

### Requirements

This scenario relies on [volume mounting](https://docs.docker.com/engine/admin/volumes/volumes/) (that's the `-v` argument) to make source available within the container (to build it). You may need to enable [shared drives (Windows)](https://docs.docker.com/docker-for-windows/#shared-drives) or [file sharing (macOS)](https://docs.docker.com/docker-for-mac/#file-sharing) first.

`dotnet publish` (and `build`) produces native executables for applications. If you use a Linux container, you will build a Linux executable that will not run on Windows or macOS. You can use a [runtime argument](https://docs.microsoft.com/en-us/dotnet/core/rid-catalog) (`-r`) to specify the type of assets that you want to publish (if they don't match the SDK container). The following examples assume you want assets that match your host operating system, and use runtime arguments to ensure that.

## Pull SDK image
### Pull SDK image

It is recommended to pull the SDK image before running the appropriate command. This ensures that you get the latest patch version of the SDK. Use the following command:

```console
docker pull mcr.microsoft.com/dotnet/sdk:8.0
docker pull mcr.microsoft.com/dotnet/sdk:9.0
```

## Linux
### Linux

```console
docker run --rm -v $(pwd):/app -w /app mcr.microsoft.com/dotnet/sdk:8.0 dotnet publish -c Release -o out
docker run --rm -v $(pwd):/app -w /app mcr.microsoft.com/dotnet/sdk:9.0 dotnet publish -c Release -o out
```

You can see the built binaries with the following command:
Expand All @@ -31,10 +88,10 @@ $ ls out
dotnetapp dotnetapp.deps.json dotnetapp.dll dotnetapp.pdb dotnetapp.runtimeconfig.json
```

## macOS
### macOS

```console
docker run --rm -v $(pwd):/app -w /app mcr.microsoft.com/dotnet/sdk:8.0 dotnet publish -c Release -o out -r osx-x64 --self-contained false
docker run --rm -v $(pwd):/app -w /app mcr.microsoft.com/dotnet/sdk:9.0 dotnet publish -c Release -o out -r osx-x64 --self-contained false
```

You can see the built binaries with the following command:
Expand All @@ -46,12 +103,12 @@ dotnetapp.deps.json dotnetapp.runtimeconfig.json
dotnetapp.dll
```

## Windows using Linux containers
### Windows using Linux containers

The following example uses PowerShell.

```console
docker run --rm -v ${pwd}:/app -w /app mcr.microsoft.com/dotnet/sdk:8.0 dotnet publish -c Release -o out -r win-x64 --self-contained false
docker run --rm -v ${pwd}:/app -w /app mcr.microsoft.com/dotnet/sdk:9.0 dotnet publish -c Release -o out -r win-x64 --self-contained false
```

You can see the built binaries with the following command:
Expand All @@ -71,12 +128,12 @@ Mode LastWriteTime Length Name
-a---- 11/2/2020 10:46 AM 152 dotnetapp.runtimeconfig.json
```

## Windows using Windows containers
### Windows using Windows containers

The following example uses PowerShell.

```console
docker run --rm -v ${pwd}:c:\app -w c:\app mcr.microsoft.com/dotnet/sdk:8.0-nanoserver-ltsc2022 dotnet publish -c Release -o out
docker run --rm -v ${pwd}:c:\app -w c:\app mcr.microsoft.com/dotnet/sdk:9.0-nanoserver-ltsc2022 dotnet publish -c Release -o out
```

> [!WARNING]
Expand All @@ -100,14 +157,14 @@ Mode LastWriteTime Length Name
-a---- 11/2/2020 10:49 AM 160 dotnetapp.runtimeconfig.json
```

## Building to a separate location
### Building to a separate location

You may want the build output to be written to a separate location than the source directory. That's easy to do with a second volume mount.

The following example demonstrates doing that on macOS:

```console
docker run --rm -v ~/dotnetapp:/out -v $(pwd):/app -w /app mcr.microsoft.com/dotnet/sdk:8.0 dotnet publish -c Release -o /out -r osx-x64 --self-contained false
docker run --rm -v ~/dotnetapp:/out -v $(pwd):/app -w /app mcr.microsoft.com/dotnet/sdk:9.0 dotnet publish -c Release -o /out -r osx-x64 --self-contained false
```

You can see the built binaries with the following command:
Expand All @@ -123,7 +180,7 @@ The following PowerShell example demonstrates doing that on Windows (using Linux

```console
mkdir C:\dotnetapp
docker run --rm -v C:\dotnetapp:c:\app\out -v ${pwd}:c:\app -w /app mcr.microsoft.com/dotnet/sdk:8.0 dotnet publish -c Release -o out -r win-x64 --self-contained false
docker run --rm -v C:\dotnetapp:c:\app\out -v ${pwd}:c:\app -w /app mcr.microsoft.com/dotnet/sdk:9.0 dotnet publish -c Release -o out -r win-x64 --self-contained false
```

You can see the built binaries with the following command:
Expand Down
18 changes: 18 additions & 0 deletions samples/dotnetapp/Dockerfile.sdk-build
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# Learn about building .NET container images:
# https://github.com/dotnet/dotnet-docker/blob/main/samples/README.md
FROM --platform=$BUILDPLATFORM mcr.microsoft.com/dotnet/sdk:9.0 AS build
ARG TARGETARCH
WORKDIR /source

# Copy project file and restore as distinct layers
COPY --link *.csproj .
RUN dotnet restore -a $TARGETARCH

# Copy source code and publish app
COPY --link . .
RUN dotnet publish -a $TARGETARCH --no-restore -o /out

# Output stage
# Learn more about exporting binaries with Docker: https://docs.docker.com/build/building/export/
FROM scratch
COPY --link --from=build /out .