Skip to content

Commit 8e16dc0

Browse files
committed
WIP add multi-arch support
1 parent e832f6b commit 8e16dc0

File tree

3 files changed

+68
-103
lines changed

3 files changed

+68
-103
lines changed

.github/workflows/container-image.yml

+4-4
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ jobs:
6161
steps:
6262
- uses: actions/checkout@v4
6363
- name: Build the server image
64-
run: make KIND=server PACKAGE_SOURCE=${{ matrix.package_source }} OS_NAME=${{ matrix.os}} BUILD_ARCH=${{ matrix.arch}} build-image
64+
run: make KIND=server PACKAGE_SOURCE=${{ matrix.package_source }} OS_NAME=${{ matrix.os}} build-image
6565
- name: Upload server image
6666
uses: ishworkh/[email protected]
6767
with:
@@ -89,7 +89,7 @@ jobs:
8989
steps:
9090
- uses: actions/checkout@v4
9191
- name: Build the ad server image
92-
run: make KIND=ad-server PACKAGE_SOURCE=${{ matrix.package_source }} OS_NAME=${{ matrix.os }} BUILD_ARCH=${{ matrix.arch }} build-image
92+
run: make KIND=ad-server PACKAGE_SOURCE=${{ matrix.package_source }} OS_NAME=${{ matrix.os }} build-image
9393
- name: Upload ad server image
9494
uses: ishworkh/[email protected]
9595
with:
@@ -109,7 +109,7 @@ jobs:
109109
steps:
110110
- uses: actions/checkout@v4
111111
- name: build the client image
112-
run: make KIND=client OS_NAME=${{ matrix.os }} BUILD_ARCH=${{ matrix.arch }} build-image
112+
run: make KIND=client OS_NAME=${{ matrix.os }} build-image
113113
# The client image is used as a base for the samba-toolbox build process.
114114
- name: Upload the client image
115115
uses: ishworkh/[email protected]
@@ -144,7 +144,7 @@ jobs:
144144
- name: Apply latest tag to image (for fedora)
145145
run: ${{ env.CONTAINER_CMD }} tag samba-client:${{ env.IMG_TAG }} quay.io/samba.org/samba-client:latest
146146
- name: Build the toolbox image
147-
run: make KIND=toolbox OS_NAME=${{ matrix.os }} BUILD_ARCH=${{ matrix.arch }} build-image
147+
run: make KIND=toolbox OS_NAME=${{ matrix.os }} build-image
148148
# Upload the toolbox image for reference and/or image push
149149
- name: Upload the toolbox image
150150
uses: ishworkh/[email protected]

Makefile

+1-6
Original file line numberDiff line numberDiff line change
@@ -41,14 +41,9 @@ DYN_BUILDFILE=$(shell $(call _BUILD_KP,$(KIND),$(if $(PACKAGE_SOURCE),$(PACKAGE_
4141

4242
REPO_BASE=quay.io/samba.org/
4343

44-
_BUILD_KP=$(BUILD_IMAGE) $(if $(CONTAINER_CMD),--container-engine=$(CONTAINER_CMD)) $(BI_PREFIX_ARGS) --kind=$1 --package-source=$2 --distro-base=$(SRC_OS_NAME) --repo-base=$(REPO_BASE) $(if $(BUILD_ARCH),--arch=$(BUILD_ARCH)) $3
44+
_BUILD_KP=$(BUILD_IMAGE) $(if $(CONTAINER_CMD),--container-engine=$(CONTAINER_CMD)) $(BI_PREFIX_ARGS) --kind=$1 --package-source=$2 --distro-base=$(SRC_OS_NAME) --repo-base=$(REPO_BASE) $3
4545

4646

47-
arch_flag=$(strip $(if $(filter docker,$(CONTAINER_CMD)),\
48-
$(if $(filter-out $(HOST_ARCH),$(BUILD_ARCH)),\
49-
$(error Setting BUILD_ARCH != $(HOST_ARCH) not supported on docker)),\
50-
$(if $(BUILD_ARCH),--arch $(BUILD_ARCH))))
51-
5247
build: build-server build-nightly-server build-ad-server build-client \
5348
build-toolbox
5449
.PHONY: build

hack/build-image

+63-93
Original file line numberDiff line numberDiff line change
@@ -14,23 +14,22 @@ and list build status files (aka buildfiles).
1414
1515
Usage:
1616
# build an image
17-
./hack/build-image --kind server --distro-base fedora --arch amd64
17+
./hack/build-image --kind server --distro-base fedora
1818
1919
# print out the FQIN
2020
./hack/build-image --kind samba-server --distro-base fedora \\
21-
--arch amd64 --print
21+
--print
2222
2323
# print out the FQIN and additional tags
2424
./hack/build-image --kind samba-server --distro-base fedora \\
25-
--arch amd64 --print-tags
25+
--print-tags
2626
2727
# print out the FQIN and additional tags for multiple images, with
2828
# and without a repository base
2929
./hack/build-image --kind samba-server \\
3030
--distro-base fedora \\
3131
--distro-base centos \\
3232
--distro-base opensuse \\
33-
--arch amd64 \\
3433
--repo-base quay.io/foobar --without-repo-bases --print-tags
3534
3635
"""
@@ -48,12 +47,6 @@ import sys
4847

4948
logger = logging.getLogger("build-image")
5049

51-
# Set FORCE_ARCH_FLAG if you want to test passing the --arch flag to podman all
52-
# the time. This was the previous behavior but we found it to have some issues.
53-
# When this is false the --arch flag is passed to podman ONLY when the target
54-
# arch != the host system arch.
55-
FORCE_ARCH_FLAG = False
56-
5750
# IMAGE_KINDS - map aliases/names to canonical names for the kinds
5851
# of images we can build
5952
IMG_SERVER = "samba-server"
@@ -73,17 +66,11 @@ IMAGE_KINDS = {
7366
"samba-toolbox": IMG_TOOLBOX,
7467
}
7568

76-
# ARCHITECTURES - map supported arch names/alias to canonical names
77-
AMD64 = "amd64"
78-
ARM64 = "arm64"
79-
ARCHITECTURES = {
80-
# alternate names
81-
"x86_64": AMD64,
82-
"aarch64": ARM64,
83-
# canonical names
84-
"amd64": AMD64,
85-
"arm64": ARM64,
86-
}
69+
# PLATFORMS - list of supported platforms
70+
PLATFORMS = [
71+
"linux/amd64",
72+
"linux/arm64"
73+
]
8774

8875
# DISTROS - list of supported distro bases
8976
FEDORA = "fedora"
@@ -134,15 +121,6 @@ def check_kind(kind):
134121
except KeyError:
135122
raise ValueError(f"invalid kind: {kind}")
136123

137-
138-
def check_arch(arch):
139-
"""Return the canonical name for the arch or raise a ValueError."""
140-
try:
141-
return ARCHITECTURES[arch]
142-
except KeyError:
143-
raise ValueError(f"invalid arch: {arch}")
144-
145-
146124
def check_distro(distro):
147125
"""Return the canonical name for a distro base or raise a ValueError."""
148126
if distro in DISTROS:
@@ -203,37 +181,51 @@ def container_engine(cli):
203181

204182
def container_build(cli, target):
205183
"""Construct and execute a command to build the target container image."""
206-
args = [container_engine(cli), "build"]
184+
engine = container_engine(cli)
185+
build_args = [engine]
186+
builder_rm_args = [engine]
187+
builder_create_args = [engine]
188+
builder_name = "samba-in-kubernetes"
189+
190+
if "docker" in engine:
191+
build_args += ["buildx", "build", f"--builder={builder_name}"]
192+
builder_rm_args += ["buildx", "rm", builder_name]
193+
builder_create_args += ["buildx", "create", f"--name={builder_name}"]
194+
elif "podman" in engine:
195+
build_args += ["build", f"--manifest={builder_name}"]
196+
builder_rm_args += ["manifest", "rm", builder_name]
197+
builder_create_args += ["manifest", "create", builder_name]
198+
else:
199+
raise ValueError(f"invalid container engine: {engine}")
200+
207201
pkgs_from = PACKAGES_FROM[target.pkg_source]
208202
if pkgs_from:
209-
args.append(f"--build-arg=INSTALL_PACKAGES_FROM={pkgs_from}")
210-
# docker doesn't currently support alt. architectures
211-
if "docker" in args[0]:
212-
if target.arch != host_arch():
213-
raise RuntimeError("Docker does not support --arch")
214-
elif target.arch != host_arch() or FORCE_ARCH_FLAG:
215-
# We've noticed a few small quirks when using podman with the --arch
216-
# option. The main issue is that building the client image works
217-
# but then the toolbox image fails because it somehow doesn't see
218-
# the image we just built as usable. This doesn't happen when
219-
# --arch is not provided. So if the target arch and the host_arch
220-
# are the same, skip passing the extra argument.
221-
args.append(f"--arch={target.arch}")
203+
build_args.append(f"--build-arg=INSTALL_PACKAGES_FROM={pkgs_from}")
222204
if cli.extra_build_arg:
223-
args.extend(cli.extra_build_arg)
205+
build_args.extend(cli.extra_build_arg)
224206
for tname in target.all_names(baseless=cli.without_repo_bases):
225-
args.append("-t")
226-
args.append(tname)
227-
args.append("-f")
228-
args.append(target_containerfile(target))
229-
args.append(kind_source_dir(target.name))
230-
args = [str(a) for a in args]
231-
run(cli, args, check=True)
207+
build_args.append("-t")
208+
build_args.append(tname)
209+
build_args.append("-f")
210+
build_args.append(target_containerfile(target))
211+
build_args.append(kind_source_dir(target.name))
212+
build_args = [str(a) for a in build_args]
213+
build_args.append(f"--platform={','.join(PLATFORMS)}")
214+
215+
# Make sure that no builder exists, so that we have a clean environment.
216+
run(cli, builder_rm_args)
217+
# Create builder
218+
run(cli, builder_create_args, check=True)
219+
# Build image
220+
run(cli, build_args, check=True)
232221

233222

234223
def container_push(cli, push_name):
235224
"""Construct and execute a command to push a container image."""
236-
args = [container_engine(cli), "push", push_name]
225+
args = [container_engine(cli)]
226+
if "podman" in args[0]:
227+
args.append("manifest")
228+
args = args + ["push", push_name]
237229
run(cli, args, check=True)
238230

239231

@@ -281,17 +273,6 @@ def target_containerfile(target):
281273
"""Return the path to a containerfile given an image target."""
282274
return str(kind_source_dir(target.name) / f"Containerfile.{target.distro}")
283275

284-
285-
def host_arch():
286-
"""Return the name of the host's native architecture."""
287-
return check_arch(platform.machine().lower())
288-
289-
290-
def default_arches():
291-
"""Return a list of the default architectures to use for building."""
292-
return [host_arch()]
293-
294-
295276
class RepoConfig:
296277
def __init__(self, default_repo_base, distro_repo=None):
297278
self.default = default_repo_base
@@ -303,18 +284,17 @@ class RepoConfig:
303284

304285
class TargetImage:
305286
def __init__(
306-
self, name, pkg_source, distro, arch, extra_tag="", *, repo_base=""
287+
self, name, pkg_source, distro, extra_tag="", *, repo_base=""
307288
):
308289
self.name = name
309290
self.pkg_source = pkg_source
310291
self.distro = distro
311-
self.arch = arch
312292
self.extra_tag = extra_tag
313293
self.repo_base = repo_base
314294
self.additional_tags = []
315295

316296
def tag_name(self):
317-
tag_parts = [self.pkg_source, self.distro, self.arch]
297+
tag_parts = [self.pkg_source, self.distro]
318298
if self.extra_tag:
319299
tag_parts.append(self.extra_tag)
320300
tag = "-".join(tag_parts)
@@ -355,21 +335,20 @@ class TargetImage:
355335
base = ""
356336
rest = image_name
357337
iname, tag = rest.split(":", 1)
358-
tparts = tag.split("-", 3)
359-
if len(tparts) < 3:
338+
tparts = tag.split("-", 2)
339+
if len(tparts) < 2:
360340
raise ValueError(f"too few tag components: {tag!r}")
361341
return cls(
362342
iname,
363343
check_pkg_source(tparts[0]),
364344
check_distro(tparts[1]),
365-
check_arch(tparts[2]),
366-
extra_tag=(tparts[3] if len(tparts) > 3 else ""),
345+
extra_tag=(tparts[2] if len(tparts) > 3 else ""),
367346
repo_base=base,
368347
)
369348

370349

371350
def generate_images(cli):
372-
"""Given full image names or a matrix of kind/pkg_source/distro_base/arch
351+
"""Given full image names or a matrix of kind/pkg_source/distro_base
373352
values generate a list of target images to build/process.
374353
"""
375354
images = {}
@@ -379,16 +358,14 @@ def generate_images(cli):
379358
for kind in cli.kind or []:
380359
for pkg_source in cli.package_source or DEFAULT_PKG_SOURCES:
381360
for distro_base in cli.distro_base or DEFAULT_DISTRO_BASES:
382-
for arch in cli.arch or default_arches():
383-
timg = TargetImage(
384-
kind,
385-
pkg_source,
386-
distro_base,
387-
arch,
388-
extra_tag=(cli.extra_tag or ""),
389-
repo_base=rc.find_base(distro_base),
390-
)
391-
images[str(timg)] = timg
361+
timg = TargetImage(
362+
kind,
363+
pkg_source,
364+
distro_base,
365+
extra_tag=(cli.extra_tag or ""),
366+
repo_base=rc.find_base(distro_base),
367+
)
368+
images[str(timg)] = timg
392369
return list(images.values())
393370

394371

@@ -401,15 +378,15 @@ def add_special_tags(img, distro_qualified=True):
401378
# to keep us compatible with older tagging schemes from earlier versions of
402379
# the project.
403380
if img.distro in [FEDORA, OPENSUSE]:
404-
if img.arch == host_arch() and img.pkg_source == DEFAULT:
381+
if img.pkg_source == DEFAULT:
405382
img.additional_tags.append((LATEST, QUAL_NONE))
406-
if img.arch == host_arch() and img.pkg_source == NIGHTLY:
383+
if img.pkg_source == NIGHTLY:
407384
img.additional_tags.append((NIGHTLY, QUAL_NONE))
408385
if not distro_qualified:
409386
return # skip creating "distro qualified" tags
410-
if img.arch == host_arch() and img.pkg_source == "default":
387+
if img.pkg_source == "default":
411388
img.additional_tags.append((f"{img.distro}-{LATEST}", QUAL_DISTRO))
412-
if img.arch == host_arch() and img.pkg_source == "nightly":
389+
if img.pkg_source == "nightly":
413390
img.additional_tags.append((f"{img.distro}-{NIGHTLY}", QUAL_DISTRO))
414391

415392

@@ -592,13 +569,6 @@ def main():
592569
"(like: --repo-base-for=centos=wonky.io/smb)"
593570
),
594571
)
595-
parser.add_argument(
596-
"--arch",
597-
"-a",
598-
type=check_arch,
599-
action="append",
600-
help="The name of the CPU architecture to build for",
601-
)
602572
parser.add_argument(
603573
"--package-source",
604574
"-p",

0 commit comments

Comments
 (0)