构建多平台支持的 .NET 容器镜像
Intro
最近看到有朋友在尝试在 arm 上支持的 docker 镜像
刚好之前对 dotnet-exec 的镜像添加了多平台的支持,之前仅支持 x64 的平台,新增了对于 arm 的支持,于是想分享一下如何针对 Dockerfile
改造以支持多平台,之前有一篇官方博客介绍了多平台的容器支持,可以参考文末的参考链接,希望对大家有所帮助
Sample
多平台构建 Dockerfile 示例
FROM --platform=$BUILDPLATFORM mcr.microsoft.com/dotnet/sdk:9.0-preview-alpine AS build-env
ARG TARGETARCH
WORKDIR /app
COPY ./src/ ./src/
COPY ./build/ ./build/
COPY ./Directory.Build.props ./
COPY ./Directory.Build.targets ./
COPY ./Directory.Packages.props ./
WORKDIR /app/src/dotnet-exec/
ENV HUSKY=0
RUN dotnet publish -f net9.0 -a $TARGETARCH -o /app/out/
FROM mcr.microsoft.com/dotnet/runtime:9.0-preview-alpine AS final
LABEL Maintainer="WeihanLi"
LABEL Repository="https://github.com/WeihanLi/dotnet-exec"
WORKDIR /app
COPY --from=build-env /app/out/ ./
ENV PATH="/app:${PATH}"
RUN chmod +x /app/dotnet-exec
ENTRYPOINT [ "/app/dotnet-exec" ]
CMD [ "--help" ]
和之前的 Dockerfile相比,主要变化有两点:
指定 sdk 镜像时增加了
--platform=$BUILDPLATFORM
,这里 platform 指定的是要拉取镜像的架构,默认是本机的架构,比如 amd64 的架构默认 platform 是 linux/amd64, 我们也可以手动指定arm64
来构建arm64
架构的镜像dotnet publish 的时候指定了
-a $TARGETARCH
,对于 platform 是linux/amd64
的情况,TARGETARCH
会是amd64
BUILDPLATFORM
和TARGETARCH
均是 docker build 时的内置变量,详见 docker 文档 https://docs.docker.com/build/building/variables/#multi-platform-build-arguments
我们在使用 docker build 的时候可以指定 platform 参数
docker build -t multi-arch-sample --platform linux/arm64 .
也可以一次指定多个架构
docker buildx build --pull -t aspnetapp -f Dockerfile --platform linux/arm64,linux/arm,linux/amd64 .
Github Action Sample
接着看一个 github action yaml 的示例
name: docker
on:
workflow_dispatch:
# https://docs.github.com/en/actions/using-workflows/events-that-trigger-workflows#release
release:
types: [published]
push:
branches:
- "main"
paths:
- 'Dockerfile'
- 'Directory.*'
- 'src/**'
- 'build/**'
- '.github/workflows/docker.yml'
env:
DOCKER_HUB_USERNAME: "weihanli"
ContainerPlatforms: "linux/amd64,linux/arm64,linux/arm"
jobs:
docker-build:
if: github.repository == 'WeihanLi/dotnet-exec'
runs-on: ubuntu-latest
steps:
- name: Check Out
uses: actions/checkout@v4
- name: Set up QEMU
uses: docker/setup-qemu-action@v3
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Login to Docker Hub
uses: docker/login-action@v3
with:
username: ${{ env.DOCKER_HUB_USERNAME }}
password: ${{ secrets.DOCKER_HUB_ACCESS_TOKEN }}
- name: Build and push latest
id: docker_build_latest
uses: docker/build-push-action@v5
with:
# https://docs.github.com/en/actions/learn-github-actions/contexts#github-context
context: ./
file: ./Dockerfile
push: true
tags: ${{ env.DOCKER_HUB_USERNAME }}/dotnet-exec:latest
platforms: ${{ env.ContainerPlatforms }}
这里首先我们需要设置 qemu
以支持模拟多种架构,这样才能够实现支持本地之外的架构构建,其次我们需要设置 docker buildx 以比较方便地构建多平台架构支持镜像,最后在 build 的时候指定需要的 platform
References
https://docs.docker.com/build/building/multi-platform/
https://docs.docker.com/build/building/variables/#multi-platform-build-arguments
https://docs.docker.com/reference/dockerfile/#automatic-platform-args-in-the-global-scope
https://www.docker.com/blog/faster-multi-platform-builds-dockerfile-cross-compilation-guide/
https://devblogs.microsoft.com/dotnet/improving-multiplatform-container-support/
https://github.com/dotnet/dotnet-docker/blob/main/samples/aspnetapp/Dockerfile.alpine
https://github.com/WeihanLi/dotnet-exec/blob/0.18.1/Dockerfile
https://github.com/WeihanLi/dotnet-exec/blob/0.18.1/.github/workflows/docker.yml
https://github.com/WeihanLi/dotnet-exec/compare/0.17.0...0.18.0#diff-dd2c0eb6ea5cfc6c4bd4eac30934e2d5746747af48fef6da689e85b752f39557