Skip to content

Commit

Permalink
hack: use buildx to cross-build images with docker
Browse files Browse the repository at this point in the history
When Docker is used and the target architecture differs from the host
architecture, buildx is used for cross-building.

Depending on the container engine and the target architecture,
multiple commands need to be executed to prepare the environment,
build the image, and clean up artifacts afterward.

To streamline this process, a tasks array (an array of lambdas) has
been introduced, its elements are executed sequencally at the end
of the container_build function.

Signed-off-by: Alexander Bachmann <[email protected]>
  • Loading branch information
abachmann committed Nov 11, 2024
1 parent 7a16e9f commit aaa3765
Showing 1 changed file with 36 additions and 17 deletions.
53 changes: 36 additions & 17 deletions hack/build-image
Original file line number Diff line number Diff line change
Expand Up @@ -203,23 +203,42 @@ def container_engine(cli):

def container_build(cli, target):
"""Construct and execute a command to build the target container image."""
args = [container_engine(cli), "build"]
pkgs_from = PACKAGES_FROM[target.pkg_source]
if pkgs_from:
args.append(f"--build-arg=INSTALL_PACKAGES_FROM={pkgs_from}")
# docker doesn't currently support alt. architectures
if "docker" in args[0]:
if target.arch != host_arch():
raise RuntimeError("Docker does not support --arch")
elif target.arch != host_arch() or FORCE_ARCH_FLAG:
# We've noticed a few small quirks when using podman with the --arch
# option. The main issue is that building the client image works
# but then the toolbox image fails because it somehow doesn't see
# the image we just built as usable. This doesn't happen when
# --arch is not provided. So if the target arch and the host_arch
# are the same, skip passing the extra argument.
args.append(f"--arch={target.arch}")
run(cli, args + create_common_container_engine_args(cli, target), check=True)
eng = container_engine(cli)
tasks = []

# For docker cross-builds we need to use buildx
if "docker" in eng and target.arch != host_arch():
args = [eng, "buildx"]

# Docker's default builder only supports the host architecture.
# Therefore, we need to create a new builder to support other
# architectures, and we must ensure we start with a fresh builder
# that does not contain any images from previous builds.
tasks.append(lambda : run(cli, args + ["rm", target.flat_name()], check=False))
tasks.append(lambda : run(cli, args + ["create", f"--name={target.flat_name()}"], check=True))

tasks.append(lambda : run(cli, args + [
"build",
f"--builder={target.flat_name()}",
f"--platform=linux/{target.arch}",
"--load"] + create_common_container_engine_args(cli, target), check=True))

tasks.append(lambda : run(cli, args + ["rm", target.flat_name()], check=True))
else:
args = [eng, "build"]
if target.arch != host_arch() or FORCE_ARCH_FLAG:
# We've noticed a few small quirks when using podman with the --arch
# option. The main issue is that building the client image works
# but then the toolbox image fails because it somehow doesn't see
# the image we just built as usable. This doesn't happen when
# --arch is not provided. So if the target arch and the host_arch
# are the same, skip passing the extra argument.
args += [f"--arch={target.arch}"]

tasks.append(lambda : run(cli, args + create_common_container_engine_args(cli, target), check=True))

for task in tasks:
task()

def create_common_container_engine_args(cli, target):
args = []
Expand Down

0 comments on commit aaa3765

Please sign in to comment.