openziti / ziti-builder

Cross-compile builder container image for ziti-tunnel-sdk-c
Apache License 2.0
2 stars 0 forks source link

publish a multi-platform container image #4

Closed qrkourier closed 3 months ago

qrkourier commented 1 year ago

Support macOS M1 and other arm64 users better by accelerating local builds with a multi-platform container image.

Expand the ziti-cmake image's Dockerfile to take advantage of BuildKit multi-platform features.

The Dockerfile should continue to configure Debian multi-arch in the image, but should switch to install the correct cross-compile tools for each target architecture. Presently, the image treats amd64 as native and arm, arm64 as cross-builds. The new image will treat the target architecture as native, and also install the cross-compile tools for the others.

scareything commented 1 year ago

here's one way to do this:

# setting an arg to itself is weird, but apparently automatic build args are not initialized in time for FROM directives?
ARG TARGETARCH=$TARGETARCH
ARG TARGETOS=$TARGETOS

# "/" cannot be used in stage names, so map the platform to a valid stage name
FROM --platform=linux/amd64 ubuntu:bionic AS linux-amd64
RUN touch /i_am_an_amd64_build_host.txt

FROM --platform=linux/arm64 ubuntu:bionic AS linux-arm64
RUN touch /i_am_an_arm64_build_host.txt

FROM $TARGETOS-$TARGETARCH

# nothing needed here, except perhaps ENV, USER directives etc that are common to all
# target architectures. the image contents are "inherited" the stage for the target arch
qrkourier commented 1 year ago

Taking that a step further @scareything, I see two approaches with different implications for the consumer projects' build scripts.

  1. The current approach: publish a cross-builder image for each platform: amd64, arm64 with the necessary utilities and libraries for cross-compiling with CMake. The build script always runs the same container image and the container runtime selects the best cross-builder image from the manifest.
  2. an alternative approach: publish single-target (not cross-builder) images for each target architecture: amd64, arm64, arm with the necessary utilities and libraries for building only the target architecture. The build script runs the appropriate container image depending on the build preset's target architecture. In this alternative, builds that happen to target the host's CPU architecture are vastly more performant.

These have the same outcome: fast builds when the target arch matches the host arch. The main differences are whether script complexity is offloaded to Ziti projects' respective build scripts (run the image for the target arch) or offloaded to the Dockerfile that must have switching logic to install the right cross-compile utilities and libraries for each cross-builder variant.

I'm leaning toward a simpler Dockerfile, one for each target architecture, and a pattern of build scripts in each Ziti project that runs the appropriate image based on the CMake preset's target architecture, e.g., ./cmake.sh -p ci-linux-arm64 would invoke docker run --platform linux/arm64 openziti/ziti-cmake, and the container image would have native-architecture utilities and libraries only, not use Debian multi-arch at all.

scareything commented 1 year ago

We rely on (slow) emulation if we use --platform when invoking docker run, no?

qrkourier commented 1 year ago

I'm assuming the container runtime will not emulate when the --platform target happens to match the host architecture, so those would be fast builds.

qrkourier commented 3 months ago

This builder image seems to be serving its purpose for CI. I may have overestimated its potential value as a local/offline tool. I'm not actively working on making the cross-compiling work in all directions. It's x64 native and cross-compile to the others for now. Please re-open if diversifying this image to be able to build natively (without emulating or cross-compiling) on arm64, and specify whether the goal would be only building natively or also cross-compiling to x64 or armhf (v7) or both.