经常有把自己的程序打包到ARM平台上去长期运行的需求,Docker Hub是最方便的选项。一个小trick可以让Docker Hub自动构建非amd64架构的Image。
现在对Docker Image来说,Docker Hub是最简单的CI构建平台了,只需要登陆上去给Github一个授权,CI就设置完成了。CI用的虚拟机限制是一次Build双核两小时(对大的Image是不太够的,还是Github Action比较靠谱,比如Build OpenWrt),对于自己的小项目是足够了。但是由于是用的虚拟机,运行在amd64下,默认只能生成自己架构的Image。我们需要自动的构建用于我们需要的架构的Image。
经过一番搜索发现这个需求有很久了,ARM架构下的直接构建现在也已经被写入了Docker的RoadMap。现在大家用的解决方案是用multiarch/qeum-static在user namespace下跑其他架构的VM。这个方案不仅能让你构建其他架构的Image,还能让你直接运行其他架构的Image(就是有些性能损失,这个没办法)。已经很好了。由于项目Readme里没有说明怎么在Dockerfile里直接用,这里备注一下。而且现在Dockerfile支持多阶段构建,可以把安装依赖、编译等部分扔到其他阶段中,使得最终生成的Image不包含这些中间过程的数据,让Image更加迷你。
设置build hook
需要在编译前运行multiarch/qemu-user-static:register
来准备环境。由于Docker Hub使用虚拟机,并且支持hook脚本,所以可以做到。
创建hooks/pre_build
,内容如下
#!/bin/sh
docker run --rm --privileged multiarch/qemu-user-static:register --reset
设置Dockerfile
这里直接给出最终Dockerfile例子,注释配有简单说明。每次FROM其他架构的Image都要把模拟器COPY过来COPY --from=qemu /usr/bin/qemu-aarch64-static /usr/bin
# Import armv8 parser runtime
FROM multiarch/qemu-user-static:x86_64-aarch64 as qemu
# Compile Stage
FROM arm64v8/python:3-slim AS compile-image
# Copy qemu
COPY --from=qemu /usr/bin/qemu-aarch64-static /usr/bin
RUN apt-get update
RUN apt-get install -y build-essential gcc libffi6 libffi-dev libssl-dev procps
# Install requirements
COPY requirements.txt .
RUN pip install --user --no-cache-dir -r requirements.txt
# Running Stage
FROM arm64v8/python:3-slim AS runtime-image
# Copy qemu
COPY --from=qemu /usr/bin/qemu-aarch64-static /usr/bin
# Copy requirements
COPY --from=compile-image /root/.local /root/.local
# Make sure scripts in .local are usable:
ENV PATH=/root/.local/bin:$PATH
# Copy application sources
WORKDIR /app
COPY . .
# Run the application, using /bin/sh -c for forward env variable
CMD [ "/bin/sh", "-c", "python ./main.py --token=${BOT_TOKEN} --chat_id=${BOT_CHAT_ID} --from_id=${BOT_FROM_ID}" ]