Pierrick Bouvier <[email protected]> writes:

> This new dockerfile allows to build a distroless image containing only
> qemu stripped release binaries, their lib dependencies, and installed
> artifacts (roms, keymap, ...). There is no shell, no python, nothing
> else. This is achieved thanks to a multi-stage build, where we add qemu
> binaries, artifacts and libraries in a new scratch image. Image has
> the minimal size possible.
>
> This is based on Ubuntu, which has the advantage to have working
> containers available up to 12.04. Debian old old stable have broken apt
> sources for instance. Ubuntu 10.04 binaries segfault due to missing
> vsyscall emulation on modern kernels, so 12.04 is the lowest possible.
>
> This unique dockerfile works for all qemu versions, with 0.12.0 being the
> oldest we can build today (based on ubuntu 12.04). Previous ones need an
> older compiler.
>
> To build the image, you need to provide a qemu and ubuntu version:
> $ podman build -f release.Dockerfile --build-arg QEMU_VERSION=v11.1.0 
> --build-arg UBUNTU_VERSION=24.04 -t qemu/v11.1.0
>
> To run it, as there is no shell, and no defined entrypoint, you need to
> choose the binary you want explicitely:
> $ podman run -it --rm qemu/v11.1.0 qemu-system-aarch64 --version
>
> Notes: We could optimize a bit further, by creating a base container for
> each ubuntu version, that is reused between all qemu versions built with
> it. Given that recent QEMU have around 800MB of binaries + artifacts,
> and only 100MB of library dependency, I don't think it's worth the extra
> complexity.
>
> Notes: Also, I considered create one image per binary. Problem is
> that qemu depends on other artifacts (rom, keymap, etc) and it's not
> easy to identify what is needed for one binary. Thus, I think it's
> better to stick to one container with all binaries per release.
>

Yeah, it's fine this way.

> Signed-off-by: Pierrick Bouvier <[email protected]>
> ---
>  tests/docker/dockerfiles/release.docker | 76 +++++++++++++++++++++++++
>  1 file changed, 76 insertions(+)
>  create mode 100644 tests/docker/dockerfiles/release.docker
>
> diff --git a/tests/docker/dockerfiles/release.docker 
> b/tests/docker/dockerfiles/release.docker
> new file mode 100644
> index 00000000000..611ecca9859
> --- /dev/null
> +++ b/tests/docker/dockerfiles/release.docker
> @@ -0,0 +1,76 @@
> +ARG UBUNTU_VERSION="UBUNTU_VERSION_build_arg_must_be_set"
> +FROM ubuntu:$UBUNTU_VERSION as build

I believe FROM should be capitalized the same as AS.

> +ARG UBUNTU_VERSION

Is this duplicated?

> +
> +# add deb-src for apt build-dep
> +RUN sed -e 's/Types: deb/Types: deb deb-src/' -i /etc/apt/sources.list.d/* 
> || true
> +RUN sed -e 's/# deb-src/deb-src/' -i /etc/apt/sources.list
> +# archive.canonical.com is not reachable anymore, and cause a long timeout
> +RUN sed -e '/archive.canonical.com/d' -i /etc/apt/sources.list
> +# LTS < 14.04 are hosted on https://old-releases.ubuntu.com/releases/
> +RUN if [ $(echo $UBUNTU_VERSION | cut -f 1 -d '.') -lt 14 ]; then \
> +    sed -e 's/archive/old-releases/g' -i /etc/apt/sources.list; \
> +fi

Hm, so I imagine these containers have reached end-of-life? I wonder
whether we should cap how further back we go based on this. It's one
thing to workaround a few installation bugs we list/install our
dependencies, another thing is the distro image poiting to dead URLs.

> +
> +# use apt-get since apt was missing -y option in some ancient distro

Ok, this is a reasonable issue to encounter and fix in the dockerfile. I
pointed at this on the cover letter, but we don't gain much in knowing
exactly which apt version has -y or not.

> +RUN apt-get update && \
> +env DEBIAN_FRONTEND=noninteractive apt-get install -y git build-essential
> +RUN apt-get update && \
> +env DEBIAN_FRONTEND=noninteractive apt-get build-dep -y --arch-only qemu
> +# additional dependencies that are missing at some point in history
> +RUN apt-get update && \
> +env DEBIAN_FRONTEND=noninteractive apt-get install -y ninja-build flex bison 
> libpixman-1-dev

So a discrepancy on which QEMU version and how the distro packaged it at
the time vs. which dependencies we had. Is this something that would
have been solved by lcitool? (Hm, did we even use it back then?)

> +# python3-venv didn't exist in ancient ubuntu distro
> +RUN apt-get update && \
> +if apt-cache show python3-venv; then \
> +    env DEBIAN_FRONTEND=noninteractive apt-get install -y python3-venv; \
> +fi

Maybe good to know which version so we know when to drop this block?

I see some of these check the ubuntu version, some not, I wonder how
easy it will be to break an older image's build when trying to fix a new
one. I find it a bit confusing.

> +
> +# patch cc and c++ to inject warning suppression options
> +RUN mv /usr/bin/cc /usr/bin/cc.real
> +RUN echo "#!/usr/bin/env bash" > /usr/bin/cc && \
> +echo "exec /usr/bin/cc.real \"\$@\" -Wno-error -Wno-int-conversion" >> 
> /usr/bin/cc && \
> +chmod +x /usr/bin/cc
> +RUN mv /usr/bin/c++ /usr/bin/c++.real
> +RUN echo "#!/usr/bin/env bash" > /usr/bin/c++ && \
> +echo "exec /usr/bin/c++.real \"\$@\" -Wno-error -Wno-int-conversion" >> 
> /usr/bin/c++ && \
> +chmod +x /usr/bin/c++
> +

This assumes this dockerfile will not be used to test a current
build. Probably ok.

> +# 2.9.0 => 3.1.0: clone git submodules from expired url, replace them with 
> gitlab.
> +# 2.9.0 => 2.11.0: issue with libfdt version, solved with dtc submodule, 
> which
> +#                  was removed later.
> +# Ubuntu < 14.04: git has no --single-branch, so perform manual fetch after 
> clone.

See how unstructured this has become? A comment here, the code down
there, nothing actually checks the version, the sed happens for all
versions, etc. Dockerfiles are bad at this kind of thing.

> +ARG QEMU_VERSION
> +RUN echo "QEMU_VERSION=${QEMU_VERSION:?QEMU_VERSION build arg must be set}"

In order to build local trees I added at this point:

RUN --mount=type=bind,from=qemu-src,target=/tmp/qemu-src,rw \
cd /tmp && \
if echo "${QEMU_VERSION}" | grep -q "\."; then \
    git clone https://gitlab.com/qemu-project/qemu.git --depth 1 && cd qemu && \
    git fetch origin "${QEMU_VERSION}" --depth 1 && \
    git checkout FETCH_HEAD; \
else \
    git clone qemu-src qemu && cd qemu && \
    git checkout "${QEMU_VERSION}"; \
fi && \


> +RUN cd /tmp && \
> +git clone https://gitlab.com/qemu-project/qemu.git --depth 1 && cd qemu && \
> +git fetch origin "${QEMU_VERSION}" --depth 1 && \
> +git checkout FETCH_HEAD && \
> +sed -e 's#git://git.qemu.org#https://gitlab.com/qemu-project/#' -i 
> .gitmodules && \
> +sed -e 's#git://git.qemu-project.org#https://gitlab.com/qemu-project/#' -i 
> .gitmodules && \
> +sed -e 's#https://git.qemu.org/git/#https://gitlab.com/qemu-project/#' -i 
> .gitmodules && \
> +sed -e 's#git://github.com#https://github.com#' -i .gitmodules && \
> +if grep -q dtc .gitmodules; then git submodule update --init dtc; fi && \
> +./configure --prefix=/opt/qemu --disable-docs && \
> +make install -j $(nproc) && \
> +strip /opt/qemu/bin/* && \
> +rm -rf /tmp/*
> +
> +# retrieve runtime dependencies (libs + loader)
> +RUN ldd /opt/qemu/bin/* | grep '=>' | sed -e 's/.*=>//' -e 's/(.*//' | sort 
> -u > /opt/qemu/libs.links
> +RUN find /lib*/ld-linux* >> /opt/qemu/libs.links
> +RUN cat /opt/qemu/libs.links | xargs -n1 readlink -f > 
> /opt/qemu/libs.realpath
> +# store them in /deps
> +RUN mkdir /deps && cp --parents $(cat /opt/qemu/libs.*) /deps/
> +
> +################################################################################
> +FROM scratch
> +
> +# copy qemu and all associated artifacts (roms, ...)
> +COPY --from=build /opt/qemu /usr
> +COPY --from=build /deps /
> +
> +# build with:
> +# podman build -f release.docker --build-arg QEMU_VERSION=v11.1.0 
> --build-arg UBUNTU_VERSION=24.04 -t qemu/v11.1.0
> +# run with:
> +# podman run -it --rm qemu/v11.1.0 qemu-system-aarch64 --version

Reply via email to