dotnet-docker/documentation/azurelinux.md

7.3 KiB

Azure Linux

Azure Linux (previously known as CBL-Mariner) is an MIT-licensed, RPM-based Linux distribution published by Microsoft. Azure Linux .NET images are publicly supported by Microsoft.

  • 8.0-cbl-mariner2.0
    • docker pull mcr.microsoft.com/dotnet/sdk:8.0-cbl-mariner2.0
    • docker pull mcr.microsoft.com/dotnet/aspnet:8.0-cbl-mariner2.0
    • docker pull mcr.microsoft.com/dotnet/runtime:8.0-cbl-mariner2.0
    • docker pull mcr.microsoft.com/dotnet/runtime-deps:8.0-cbl-mariner2.0

Azure Linux Distroless

Azure Linux distroless .NET images contain only the minimal set of packages .NET needs, with everything else removed. General distroless .NET containers documentation is available here.

Azure Linux distroless .NET images are available for all supported .NET versions in the following image repos:

You can use the following image tags:

  • 8.0-cbl-mariner2.0-distroless
  • 6.0-cbl-mariner2.0-distroless

Installing Additional Packages

If your app requires additional packages besides icu and tzdata, you can follow the same pattern that .NET uses to install the .NET runtime dependencies.

Azure Linux 3.0 (Preview)

FROM mcr.microsoft.com/dotnet/nightly/aspnet:8.0-azurelinux3.0-distroless AS base

FROM azurelinuxpreview.azurecr.io/public/azurelinux/base/core:3.0 AS installer

RUN tdnf install -y fdupes \
    && tdnf clean all

COPY --from=base / /staging1
COPY --from=base / /staging2

RUN tdnf install -y --releasever=3.0 --installroot /staging2 tzdata \
    && tdnf clean all --releasever=3.0 --installroot /staging2

# Prepare the staging2 directory to be copied to the final stage by removing unnecessary files
# that will only cause extra image bloat.
RUN \
    # Remove duplicates from staging2 that exist in staging1
    fdupes /staging1 /staging2 -rdpN \
    \
    # Delete duplicate symlinks
    # Function to find and format symlinks w/o including root dir (format: /path/to/symlink /path/to/target)
    && getsymlinks() { find $1 -type l -printf '%p %l\n' | sed -n "s/^\\$1\\(.*\\)/\\1/p"; } \
    # Combine set of symlinks between staging1 and staging2
    && (getsymlinks "/staging1"; getsymlinks "/staging2") \
        # Sort them
        | sort \
        # Find the duplicates
        | uniq -d \
        # Extract just the path to the symlink
        | cut -d' ' -f1 \
        # Prepend the staging2 directory to the paths
        | sed -e 's/^/\/staging2/' \
        # Delete the files
        | xargs rm \
    \
    # General cleanup
    && rm -rf /staging2/etc/tdnf \
    && rm -rf /staging2/run/* \
    && rm -rf /staging2/var/cache/tdnf \
    && rm -rf /staging2/var/lib/rpm \
    && rm -rf /staging2/usr/share/doc \
    && rm -rf /staging2/usr/share/man \
    && find /staging2 -type d -empty -delete

FROM base
COPY --from=installer /staging2/ /

Azure Linux 2.0

FROM mcr.microsoft.com/dotnet/aspnet:6.0-cbl-mariner2.0-distroless AS base

FROM mcr.microsoft.com/cbl-mariner/base/core:2.0 AS installer

RUN tdnf install -y fdupes \
    && tdnf clean all

COPY --from=base / /staging1
COPY --from=base / /staging2

RUN tdnf install -y --releasever=2.0 --installroot /staging2 <package-name> \
    && tdnf clean all --releasever=2.0 --installroot /staging2

# Prepare the staging2 directory to be copied to the final stage by removing unnecessary files
# that will only cause extra image bloat.
RUN \
    # Remove duplicates from staging2 that exist in staging1
    fdupes /staging1 /staging2 -rdpN \
    \
    # Delete duplicate symlinks
    # Function to find and format symlinks w/o including root dir (format: /path/to/symlink /path/to/target)
    && getsymlinks() { find $1 -type l -printf '%p %l\n' | sed -n "s/^\\$1\\(.*\\)/\\1/p"; } \
    # Combine set of symlinks between staging1 and staging2
    && (getsymlinks "/staging1"; getsymlinks "/staging2") \
        # Sort them
        | sort \
        # Find the duplicates
        | uniq -d \
        # Extract just the path to the symlink
        | cut -d' ' -f1 \
        # Prepend the staging2 directory to the paths
        | sed -e 's/^/\/staging2/' \
        # Delete the files
        | xargs rm \
    \
    # General cleanup
    && rm -rf /staging2/etc/tdnf \
    && rm -rf /staging2/run/* \
    && rm -rf /staging2/var/cache/tdnf \
    && rm -rf /staging2/var/lib/rpm \
    && rm -rf /staging2/usr/share/doc \
    && rm -rf /staging2/usr/share/man \
    && find /staging2/var/log -type f -size +0 -delete \
    && find /staging2 -type d -empty -delete

FROM base
COPY --from=installer /staging2/ /

Debugging with Container Fast Mode

In order to reduce image size and attack surface, Azure Linux .NET Runtime images do not contain the tools required to debug .NET apps using Visual Studio. The easiest way to enable local Visual Studio debugging while not modifying the production image is to use Container Fast Mode.

To enable Container Fast Mode debugging without affecting your app's production image, you can create a new stage based off the base stage (called debug in the example) that contains the debugging tools, and then point the VS Fast Mode tools to that debug stage.

Here's an example chart showing the inheritance of the build stages:

flowchart TD
    base --> debug
    base --> final
    build --> publish

Here's an example configuration based off of a simple ASP.NET Core app:

*.csproj

<PropertyGroup>
  ...
+ <DockerfileFastModeStage>debug</DockerfileFastModeStage>
  ...
</PropertyGroup>

Dockerfile

# Learn about building .NET container images:
# https://github.com/dotnet/dotnet-docker/blob/main/samples/README.md
FROM mcr.microsoft.com/dotnet/aspnet:8.0-cbl-mariner2.0 AS base
- USER $APP_UID
WORKDIR /app
EXPOSE 8080
EXPOSE 8081

+ # this stage is used by VS for fast local debugging; it does not appear in the final image
+ FROM base AS debug
+ RUN tdnf install -y procps-ng # <-- Install tools needed for debugging (e.g. the `pidof` command)

FROM mcr.microsoft.com/dotnet/sdk:8.0-cbl-mariner2.0 AS build
ARG BUILD_CONFIGURATION=Release
WORKDIR /src
COPY ["aspnetapp/aspnetapp.csproj", "aspnetapp/"]
RUN dotnet restore "./aspnetapp/aspnetapp.csproj"
COPY . .
WORKDIR "/src/aspnetapp"
RUN dotnet build "./aspnetapp.csproj" -c $BUILD_CONFIGURATION -o /app/build

FROM build AS publish
ARG BUILD_CONFIGURATION=Release
RUN dotnet publish "./aspnetapp.csproj" -c $BUILD_CONFIGURATION -o /app/publish /p:UseAppHost=false

FROM base AS final
WORKDIR /app
COPY --from=publish /app/publish .
+ # Make sure non-root user is enabled after the debug stage so that we have permission to install the debug dependencies
+ USER $APP_UID
ENTRYPOINT ["dotnet", "aspnetapp.dll"]

If this example doesn't work for your scenario, see Container Tools build properties for more information on customizing the Fast Mode stage, or setting a custom DockerDebuggeeKillProgram.