From 2a9c198ec4e46940773b63db043dac56c2258984 Mon Sep 17 00:00:00 2001 From: Mykhailo Kremniov Date: Mon, 25 Aug 2025 16:14:11 +0300 Subject: [PATCH 1/3] Fix release Dockerfile's base builder image - use the same distro as in the runner image --- build-tools/docker/Dockerfile.builder | 12 ++++++++++-- build-tools/docker/Dockerfile.runner-base | 2 ++ 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/build-tools/docker/Dockerfile.builder b/build-tools/docker/Dockerfile.builder index 1cffd0eb7..61c09b3f2 100644 --- a/build-tools/docker/Dockerfile.builder +++ b/build-tools/docker/Dockerfile.builder @@ -8,11 +8,19 @@ # TODO: dockerfile 1.7 syntax allows specifying --exclude for COPY, so the same can be done # without an additional stage. But at the moment of writing this it's still experimental. # Switch to using it when it becomes stable. -FROM rust as source + +# Note: the base image here doesn't really matter, we just use the same one as in the "builder" +# stage below. +FROM rust:bookworm as source COPY . /src RUN rm -r /src/build-tools -FROM rust AS builder +# Note: the builder image should use the same or an older distro compared to the runner images, +# so that its GLIBC version is also the same or older. Otherwise the built executables have +# a chance to get a dependency on a newer version of some GLIBC symbol that is not present +# in the runner's GLIBC, and the executables won't work. +# TODO: consider producing musl-based executables instead. +FROM rust:bookworm AS builder WORKDIR /usr/src/ diff --git a/build-tools/docker/Dockerfile.runner-base b/build-tools/docker/Dockerfile.runner-base index 2512b9ba2..d2101cbd4 100644 --- a/build-tools/docker/Dockerfile.runner-base +++ b/build-tools/docker/Dockerfile.runner-base @@ -1,3 +1,5 @@ +# Note: this must be consistent with the builder image's base image, see the corresponding comment +# in Dockerfile.builder. FROM debian:bookworm-slim RUN apt-get update && apt-get install -y gosu && rm -rf /var/lib/apt/lists/* From a45ebc6f5ec375c373a3c61d2acb56ac2b7f4cb7 Mon Sep 17 00:00:00 2001 From: Mykhailo Kremniov Date: Wed, 27 Aug 2025 15:32:12 +0300 Subject: [PATCH 2/3] Specify "--platform linux/amd64" in build-tools/docker/build.py, so that it doesn't try building arm64 on arm-based macs. Make sure the resulting version tags always start with "v". --- build-tools/docker/build.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/build-tools/docker/build.py b/build-tools/docker/build.py index 4f17feb1a..99cd7141a 100644 --- a/build-tools/docker/build.py +++ b/build-tools/docker/build.py @@ -34,6 +34,9 @@ def build_docker_image(dockerfile_path, image_name, tags, num_jobs=None): if num_jobs: command += f" --build-arg NUM_JOBS={num_jobs}" + # Force the amd64 platform in case we're building on an arm-based one. + command += " --platform linux/amd64" + # Note: "plain" output is more verbose, but it makes it easier to understand what went wrong # when a problem occurs. command += " --progress=plain" @@ -127,6 +130,10 @@ def main(): args = parser.parse_args() version = args.version if args.version else get_cargo_version("Cargo.toml") + # Note: the CI currently takes the version from the release tag, so it always starts with "v", + # but the version from Cargo.toml doesn't have this prefix. + version = version if version.startswith('v') else f"v{version}" + tags = [version, *args.local_tags] if args.build: From 7f339e68219956bc46f5db7dff6cf845dee1bc7b Mon Sep 17 00:00:00 2001 From: Mykhailo Kremniov Date: Thu, 28 Aug 2025 12:31:31 +0300 Subject: [PATCH 3/3] build-tools/docker/build.py: tag the images both as "X.Y.Z" and "vX.Y.Z" and push both tags --- build-tools/docker/build.py | 67 ++++++++++++++++++------------------- 1 file changed, 32 insertions(+), 35 deletions(-) diff --git a/build-tools/docker/build.py b/build-tools/docker/build.py index 99cd7141a..04324cf3a 100644 --- a/build-tools/docker/build.py +++ b/build-tools/docker/build.py @@ -46,31 +46,22 @@ def build_docker_image(dockerfile_path, image_name, tags, num_jobs=None): # Run the command subprocess.check_call(command, shell=True) print(f"Built {image_name} successfully (the tags are: {full_tags}).") - except Exception as error: - print(f"Error occurred: {error}") + except subprocess.CalledProcessError as error: + print(f"Failed to build {image_name}: {error}") exit(1) # stop the build -def push_docker_image(image_name, version, latest=False): - # Docker tag command - full_image_name = f"{image_name}:{version}" - if latest: - latest_image_name = f"{image_name}:latest" - tag_command = f"docker tag {full_image_name} {latest_image_name}" - subprocess.check_call(tag_command, shell=True) - - # Docker push command - push_command = f"docker push {full_image_name}" - subprocess.check_call(push_command, shell=True) +def push_docker_image(image_name, tags): + for tag in tags: + full_image_name = f"{image_name}:{tag}" + push_command = f"docker push {full_image_name}" - # if latest flag is true, push the image with 'latest' tag - if latest: - push_command_latest = f"docker push {latest_image_name}" - subprocess.check_call(push_command_latest, shell=True) - - print(f"Pushed {full_image_name} successfully.") - if latest: - print(f"Pushed {latest_image_name} successfully.") + try: + subprocess.check_call(push_command, shell=True) + print(f"Pushed {full_image_name} successfully.") + except subprocess.CalledProcessError as error: + print(f"Failed to push {full_image_name}: {error}") + exit(1) # stop the build def delete_docker_image(image_name, version): @@ -84,8 +75,9 @@ def delete_docker_image(image_name, version): try: subprocess.check_call(command, shell=True) print(f"Deleted {full_image_name} successfully.") - except subprocess.CalledProcessError: - print(f"Failed to delete {full_image_name}.") + except subprocess.CalledProcessError as error: + print(f"Failed to delete {full_image_name}: {error}") + # No need to fail the build here def build_instances(tags, docker_hub_user, num_jobs): @@ -109,20 +101,20 @@ def build_instances(tags, docker_hub_user, num_jobs): # delete_docker_image("mintlayer-builder", "latest") -def push_instances(docker_hub_user, version, latest): - push_docker_image(f"{docker_hub_user}/node-daemon", version, latest) - push_docker_image(f"{docker_hub_user}/api-blockchain-scanner-daemon", version, latest) - push_docker_image(f"{docker_hub_user}/api-web-server", version, latest) - push_docker_image(f"{docker_hub_user}/wallet-cli", version, latest) - push_docker_image(f"{docker_hub_user}/wallet-rpc-daemon", version, latest) - push_docker_image(f"{docker_hub_user}/dns-server", version, latest) +def push_instances(docker_hub_user, tags): + push_docker_image(f"{docker_hub_user}/node-daemon", tags) + push_docker_image(f"{docker_hub_user}/api-blockchain-scanner-daemon", tags) + push_docker_image(f"{docker_hub_user}/api-web-server", tags) + push_docker_image(f"{docker_hub_user}/wallet-cli", tags) + push_docker_image(f"{docker_hub_user}/wallet-rpc-daemon", tags) + push_docker_image(f"{docker_hub_user}/dns-server", tags) def main(): parser = argparse.ArgumentParser(formatter_class=argparse.ArgumentDefaultsHelpFormatter) parser.add_argument('--push', action='store_true', help='Push the Docker image to Docker Hub') parser.add_argument('--docker-hub-user', help='Docker Hub username', default='mintlayer') - parser.add_argument('--latest', action='store_true', help='Tag the Docker image as latest while pushing') + parser.add_argument('--latest', action='store_true', help='Tag the Docker image as latest') parser.add_argument('--build', type=lambda x: (str(x).lower() == 'true'), default=True, help="Set to false avoid the build") parser.add_argument('--version', help='Override version number', default=None) parser.add_argument('--num_jobs', help='Number of parallel jobs', default=(os.cpu_count() or 1)) @@ -132,16 +124,21 @@ def main(): version = args.version if args.version else get_cargo_version("Cargo.toml") # Note: the CI currently takes the version from the release tag, so it always starts with "v", # but the version from Cargo.toml doesn't have this prefix. - version = version if version.startswith('v') else f"v{version}" + version = version.removeprefix("v") + + # We want to push both "X.Y.Z" and "vX.Y.Z". + tags_to_push = [version, f"v{version}"] + if args.latest: + tags_to_push.append("latest") - tags = [version, *args.local_tags] + all_tags = args.local_tags + tags_to_push if args.build: - build_instances(tags, args.docker_hub_user, args.num_jobs) + build_instances(all_tags, args.docker_hub_user, args.num_jobs) # Only push the image if the --push flag is provided if args.push: - push_instances(args.docker_hub_user, version, args.latest) + push_instances(args.docker_hub_user, tags_to_push) if __name__ == "__main__":