Platform-specific RUN statements in Dockerfile

Hi :wave:t2:

I have an ASP.NET Core application running in Docker on my Raspberry Pi (arm64). This is the Dockerfile:

ARG BASE_IMAGE=mcr.microsoft.com/dotnet/aspnet:7.0-bullseye-slim-arm64v8
FROM ${BASE_IMAGE} AS base
WORKDIR /app

FROM mcr.microsoft.com/dotnet/sdk:7.0 AS build
WORKDIR /src
COPY ["src/ScreenshotCreator.Api/ScreenshotCreator.Api.csproj", "src/ScreenshotCreator.Api/"]
COPY ["src/ScreenshotCreator.Logic/ScreenshotCreator.Logic.csproj", "src/ScreenshotCreator.Logic/"]
RUN dotnet restore "src/ScreenshotCreator.Api/ScreenshotCreator.Api.csproj"
COPY . .
WORKDIR "/src/src/ScreenshotCreator.Api"
RUN dotnet build "ScreenshotCreator.Api.csproj" -c Release -o /app/build

FROM build AS publish
RUN dotnet publish "ScreenshotCreator.Api.csproj" -c Release -o /app/publish /p:UseAppHost=false

FROM base AS final
WORKDIR /app
COPY --from=publish /app/publish .
RUN apt-get update
RUN apt-get install -y wget libssl1.1 libunwind8
RUN mkdir -p /opt/microsoft/powershell/7
RUN wget -O /tmp/powershell.tar.gz https://github.com/PowerShell/PowerShell/releases/download/v7.2.6/powershell-7.2.6-linux-arm64.tar.gz
RUN tar zxf /tmp/powershell.tar.gz -C /opt/microsoft/powershell/7
RUN chmod +x /opt/microsoft/powershell/7/pwsh
RUN ln -s /opt/microsoft/powershell/7/pwsh /usr/bin/pwsh
RUN rm /tmp/powershell.tar.gz
RUN ["pwsh", "playwright.ps1", "install", "chromium"]
RUN ["pwsh", "playwright.ps1", "install-deps", "chromium"]
ENTRYPOINT ["dotnet", "ScreenshotCreator.Api.dll"]

When trying to build and run this Docker container on my Windows machine (amd64, Docker via WSL2 (Ubuntu)), it fails because a) the base image is not correct and b) the bunch of RUN statements for installing PowerShell at the end have to look different depending on the platform:

# Install PWSH on Raspberry
# https://learn.microsoft.com/en-us/powershell/scripting/install/install-raspbian?view=powershell-7.3#install-on-raspberry-pi-os
sudo apt-get update
sudo apt-get install '^libssl1.0.[0-9]$' libunwind8 -y
wget https://github.com/PowerShell/PowerShell/releases/download/v7.3.4/powershell-7.3.4-linux-arm64.tar.gz
mkdir ~/powershell
tar -xvf ./powershell-7.3.4-linux-arm32.tar.gz -C ~/powershell
~/powershell/pwsh


# Install PWSH on Ubuntu (WSL2/Docker)
# https://learn.microsoft.com/en-us/powershell/scripting/install/install-ubuntu?view=powershell-7.3#installation-via-package-repository
sudo apt-get update
sudo apt-get install -y wget apt-transport-https software-properties-common
wget -q "https://packages.microsoft.com/config/ubuntu/$(lsb_release -rs)/packages-microsoft-prod.deb"
sudo dpkg -i packages-microsoft-prod.deb
rm packages-microsoft-prod.deb
sudo apt-get update
sudo apt-get install -y powershell
pwsh

I solved problem a with the variable BASE_IMAGE that I set override locally, but I’m not sure how to handle b. What’s the recommended pattern for this using Docker?

  1. Maintain two different Dockerfiles (arm64/Raspi and amd64/Ubuntu/WSL) and swallow the bitter pill of duplicating the first half of the Dockerfile.
  2. Using some sort of conditional RUN statement so that there is only only Dockerfile, looking like this:
ARG BASE_IMAGE=mcr.microsoft.com/dotnet/aspnet:7.0-bullseye-slim-arm64v8
FROM ${BASE_IMAGE} AS base
WORKDIR /app

FROM mcr.microsoft.com/dotnet/sdk:7.0 AS build
WORKDIR /src
COPY ["src/ScreenshotCreator.Api/ScreenshotCreator.Api.csproj", "src/ScreenshotCreator.Api/"]
COPY ["src/ScreenshotCreator.Logic/ScreenshotCreator.Logic.csproj", "src/ScreenshotCreator.Logic/"]
RUN dotnet restore "src/ScreenshotCreator.Api/ScreenshotCreator.Api.csproj"
COPY . .
WORKDIR "/src/src/ScreenshotCreator.Api"
RUN dotnet build "ScreenshotCreator.Api.csproj" -c Release -o /app/build

FROM build AS publish
RUN dotnet publish "ScreenshotCreator.Api.csproj" -c Release -o /app/publish /p:UseAppHost=false

FROM base AS final
WORKDIR /app
COPY --from=publish /app/publish .

if ${PLATFORM}=="arm":
    RUN apt-get update
    RUN apt-get install -y wget libssl1.1 libunwind8
    RUN mkdir -p /opt/microsoft/powershell/7
    RUN wget -O /tmp/powershell.tar.gz https://github.com/PowerShell/PowerShell/releases/download/v7.2.6/powershell-7.2.6-linux-arm64.tar.gz
    RUN tar zxf /tmp/powershell.tar.gz -C /opt/microsoft/powershell/7
    RUN chmod +x /opt/microsoft/powershell/7/pwsh
    RUN ln -s /opt/microsoft/powershell/7/pwsh /usr/bin/pwsh
    RUN rm /tmp/powershell.tar.gz
    RUN ["pwsh", "playwright.ps1", "install", "chromium"]
    RUN ["pwsh", "playwright.ps1", "install-deps", "chromium"]
else 
    RUN apt-get update
    RUN apt-get install -y wget apt-transport-https software-properties-common
    RUN wget -q https://packages.microsoft.com/config/ubuntu/20.04/packages-microsoft-prod.deb
    RUN dpkg -i packages-microsoft-prod.deb
    RUN apt-get update
    RUN apt-get install -y powershell
    RUN ["pwsh", "playwright.ps1" ,"install", "chromium"]
    RUN ["pwsh", "playwright.ps1" ,"install-deps", "chromium"]

ENTRYPOINT ["dotnet", "ScreenshotCreator.Api.dll"]

Thank you for your help!

Multi-arch images can be built using the built-in variables of buildkit

https://docs.docker.com/engine/reference/builder/#automatic-platform-args-in-the-global-scope

  • TARGETPLATFORM - platform of the build result. Eg linux/amd64, linux/arm/v7, windows/amd64.
  • TARGETOS - OS component of TARGETPLATFORM
  • TARGETARCH - architecture component of TARGETPLATFORM
  • TARGETVARIANT - variant component of TARGETPLATFORM
  • BUILDPLATFORM - platform of the node performing the build.
  • BUILDOS - OS component of BUILDPLATFORM
  • BUILDARCH - architecture component of BUILDPLATFORM
  • BUILDVARIANT - variant component of BUILDPLATFORM

You can’t compose the Dockerfile dynamically unless you are using a template system and generate the file, but you don’t need that. Use the variables in a shell script and write the conditions there or just create multiple scripts containing the architecture in the name like install-arm64.sh and install-amd64.sh and execute the script like install-${TARGETARCH}.sh.

1 Like

That’s pretty smart and works like a charm, thank you!