Skip to content

Commit e351289

Browse files
committed
feat: Add API in Shipwright for multi-arch build
Shipwright had no API-level mechanism for users to define the required OS/ARCH combinations for multi-arch container image builds. Add ImagePlatform and MultiArch types to the Build CRD, embedded as spec.output.multiArch.platforms. Users can now declare a list of os/arch combinations that images should be built for. The same API is available on BuildRun through the embedded BuildSpec. Static validation rejects empty platforms, missing os/arch fields, and nodeSelector conflicts with kubernetes.io/os or kubernetes.io/arch labels that would interfere with per-platform scheduling. Users can now define the required OS/ARCH for multi-arch builds declaratively on Build and BuildRun resources. Invalid configurations are caught at Build creation time with clear error reasons. This lays the API foundation for the orchestration layer in a follow-up PR. Signed-off-by: Anchita Borah <anborah@redhat.com>
1 parent 69dc308 commit e351289

File tree

6 files changed

+379
-0
lines changed

6 files changed

+379
-0
lines changed

deploy/crds/shipwright.io_buildruns.yaml

Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7734,6 +7734,39 @@ spec:
77347734
description: Labels references the additional labels to
77357735
be applied on the image
77367736
type: object
7737+
multiArch:
7738+
description: |-
7739+
MultiArch configures building container images for multiple OS and CPU
7740+
architecture combinations. When set, the build controller will orchestrate
7741+
parallel builds for each specified platform and assemble the results into
7742+
an OCI image index.
7743+
properties:
7744+
platforms:
7745+
description: Platforms is the list of os/architecture
7746+
combinations to build for.
7747+
items:
7748+
description: |-
7749+
ImagePlatform describes the operating system and CPU architecture
7750+
of a container image, following the OCI image index specification.
7751+
properties:
7752+
arch:
7753+
description: Arch is the CPU architecture of
7754+
the image platform (e.g. "amd64", "arm64",
7755+
"s390x", "ppc64le").
7756+
type: string
7757+
os:
7758+
description: OS is the operating system of the
7759+
image platform (e.g. "linux").
7760+
type: string
7761+
required:
7762+
- arch
7763+
- os
7764+
type: object
7765+
minItems: 1
7766+
type: array
7767+
required:
7768+
- platforms
7769+
type: object
77377770
pushSecret:
77387771
description: Describes the secret name for pushing a container
77397772
image.
@@ -10332,6 +10365,38 @@ spec:
1033210365
description: Labels references the additional labels to be applied
1033310366
on the image
1033410367
type: object
10368+
multiArch:
10369+
description: |-
10370+
MultiArch configures building container images for multiple OS and CPU
10371+
architecture combinations. When set, the build controller will orchestrate
10372+
parallel builds for each specified platform and assemble the results into
10373+
an OCI image index.
10374+
properties:
10375+
platforms:
10376+
description: Platforms is the list of os/architecture combinations
10377+
to build for.
10378+
items:
10379+
description: |-
10380+
ImagePlatform describes the operating system and CPU architecture
10381+
of a container image, following the OCI image index specification.
10382+
properties:
10383+
arch:
10384+
description: Arch is the CPU architecture of the image
10385+
platform (e.g. "amd64", "arm64", "s390x", "ppc64le").
10386+
type: string
10387+
os:
10388+
description: OS is the operating system of the image
10389+
platform (e.g. "linux").
10390+
type: string
10391+
required:
10392+
- arch
10393+
- os
10394+
type: object
10395+
minItems: 1
10396+
type: array
10397+
required:
10398+
- platforms
10399+
type: object
1033510400
pushSecret:
1033610401
description: Describes the secret name for pushing a container
1033710402
image.
@@ -12756,6 +12821,39 @@ spec:
1275612821
description: Labels references the additional labels to be
1275712822
applied on the image
1275812823
type: object
12824+
multiArch:
12825+
description: |-
12826+
MultiArch configures building container images for multiple OS and CPU
12827+
architecture combinations. When set, the build controller will orchestrate
12828+
parallel builds for each specified platform and assemble the results into
12829+
an OCI image index.
12830+
properties:
12831+
platforms:
12832+
description: Platforms is the list of os/architecture
12833+
combinations to build for.
12834+
items:
12835+
description: |-
12836+
ImagePlatform describes the operating system and CPU architecture
12837+
of a container image, following the OCI image index specification.
12838+
properties:
12839+
arch:
12840+
description: Arch is the CPU architecture of the
12841+
image platform (e.g. "amd64", "arm64", "s390x",
12842+
"ppc64le").
12843+
type: string
12844+
os:
12845+
description: OS is the operating system of the image
12846+
platform (e.g. "linux").
12847+
type: string
12848+
required:
12849+
- arch
12850+
- os
12851+
type: object
12852+
minItems: 1
12853+
type: array
12854+
required:
12855+
- platforms
12856+
type: object
1275912857
pushSecret:
1276012858
description: Describes the secret name for pushing a container
1276112859
image.

deploy/crds/shipwright.io_builds.yaml

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2813,6 +2813,38 @@ spec:
28132813
description: Labels references the additional labels to be applied
28142814
on the image
28152815
type: object
2816+
multiArch:
2817+
description: |-
2818+
MultiArch configures building container images for multiple OS and CPU
2819+
architecture combinations. When set, the build controller will orchestrate
2820+
parallel builds for each specified platform and assemble the results into
2821+
an OCI image index.
2822+
properties:
2823+
platforms:
2824+
description: Platforms is the list of os/architecture combinations
2825+
to build for.
2826+
items:
2827+
description: |-
2828+
ImagePlatform describes the operating system and CPU architecture
2829+
of a container image, following the OCI image index specification.
2830+
properties:
2831+
arch:
2832+
description: Arch is the CPU architecture of the image
2833+
platform (e.g. "amd64", "arm64", "s390x", "ppc64le").
2834+
type: string
2835+
os:
2836+
description: OS is the operating system of the image
2837+
platform (e.g. "linux").
2838+
type: string
2839+
required:
2840+
- arch
2841+
- os
2842+
type: object
2843+
minItems: 1
2844+
type: array
2845+
required:
2846+
- platforms
2847+
type: object
28162848
pushSecret:
28172849
description: Describes the secret name for pushing a container
28182850
image.

pkg/apis/build/v1beta1/build_types.go

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,11 @@ const (
8787
SchedulerNameNotValid BuildReason = "SchedulerNameNotValid"
8888
// RuntimeClassNameNotValid indicates that the RuntimeClassName is not valid
8989
RuntimeClassNameNotValid BuildReason = "RuntimeClassNameNotValid"
90+
// MultiArchNodeSelectorConflict indicates that nodeSelector contains kubernetes.io/os or
91+
// kubernetes.io/arch which conflicts with multi-arch platform scheduling
92+
MultiArchNodeSelectorConflict BuildReason = "MultiArchNodeSelectorConflict"
93+
// MultiArchInvalidPlatform indicates that a multi-arch platform entry has invalid or empty fields
94+
MultiArchInvalidPlatform BuildReason = "MultiArchInvalidPlatform"
9095
// AllValidationsSucceeded indicates a Build was successfully validated
9196
AllValidationsSucceeded = "all validations succeeded"
9297
)
@@ -271,6 +276,28 @@ type VulnerabilityScanOptions struct {
271276
Ignore *VulnerabilityIgnoreOptions `json:"ignore,omitempty"`
272277
}
273278

279+
// ImagePlatform describes the operating system and CPU architecture
280+
// of a container image, following the OCI image index specification.
281+
type ImagePlatform struct {
282+
// OS is the operating system of the image platform (e.g. "linux").
283+
// +required
284+
OS string `json:"os"`
285+
286+
// Arch is the CPU architecture of the image platform (e.g. "amd64", "arm64", "s390x", "ppc64le").
287+
// +required
288+
Arch string `json:"arch"`
289+
}
290+
291+
// MultiArch configures multi-architecture image builds. When specified,
292+
// the build controller will orchestrate parallel builds for each platform
293+
// and assemble the results into an OCI image index (manifest list).
294+
type MultiArch struct {
295+
// Platforms is the list of os/architecture combinations to build for.
296+
// +required
297+
// +kubebuilder:validation:MinItems=1
298+
Platforms []ImagePlatform `json:"platforms"`
299+
}
300+
274301
// Image refers to an container image with credentials
275302
type Image struct {
276303
// Image is the reference of the image.
@@ -310,6 +337,14 @@ type Image struct {
310337
//
311338
// +optional
312339
Timestamp *string `json:"timestamp,omitempty"`
340+
341+
// MultiArch configures building container images for multiple OS and CPU
342+
// architecture combinations. When set, the build controller will orchestrate
343+
// parallel builds for each specified platform and assemble the results into
344+
// an OCI image index.
345+
//
346+
// +optional
347+
MultiArch *MultiArch `json:"multiArch,omitempty"`
313348
}
314349

315350
// BuildStatus defines the observed state of Build

pkg/apis/build/v1beta1/zz_generated.deepcopy.go

Lines changed: 40 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

pkg/validate/output.go

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,11 @@ package validate
66

77
import (
88
"context"
9+
"fmt"
910
"strconv"
1011

1112
build "github.com/shipwright-io/build/pkg/apis/build/v1beta1"
13+
corev1 "k8s.io/api/core/v1"
1214
"k8s.io/utils/ptr"
1315
)
1416

@@ -47,10 +49,53 @@ func (b *BuildSpecOutputValidator) ValidatePath(_ context.Context) error {
4749
}
4850
}
4951

52+
if b.Build.Spec.Output.MultiArch != nil {
53+
b.validateMultiArch()
54+
}
55+
5056
return nil
5157
}
5258

59+
func (b *BuildSpecOutputValidator) validateMultiArch() {
60+
if valid, reason, msg := ValidateMultiArchPlatforms(b.Build.Spec.Output.MultiArch.Platforms); !valid {
61+
b.Build.Status.Reason = ptr.To[build.BuildReason](reason)
62+
b.Build.Status.Message = ptr.To(msg)
63+
return
64+
}
65+
if valid, reason, msg := ValidateMultiArchNodeSelector(b.Build.Spec.NodeSelector); !valid {
66+
b.Build.Status.Reason = ptr.To[build.BuildReason](reason)
67+
b.Build.Status.Message = ptr.To(msg)
68+
return
69+
}
70+
}
71+
5372
func (b *BuildSpecOutputValidator) isEmptySource() bool {
5473
return b.Build.Spec.Source == nil ||
5574
b.Build.Spec.Source.Git == nil && b.Build.Spec.Source.OCIArtifact == nil && b.Build.Spec.Source.Local == nil
5675
}
76+
77+
// ValidateMultiArchPlatforms validates the platforms in a multiArch configuration.
78+
// This is used by BuildRun validation which doesn't go through the Build validator.
79+
func ValidateMultiArchPlatforms(platforms []build.ImagePlatform) (bool, build.BuildReason, string) {
80+
if len(platforms) == 0 {
81+
return false, build.MultiArchInvalidPlatform, "multiArch.platforms must contain at least one platform entry"
82+
}
83+
for i, p := range platforms {
84+
if p.OS == "" || p.Arch == "" {
85+
return false, build.MultiArchInvalidPlatform, fmt.Sprintf("multiArch.platforms[%d] must specify both os and arch", i)
86+
}
87+
}
88+
return true, "", ""
89+
}
90+
91+
// ValidateMultiArchNodeSelector checks that nodeSelector does not conflict with multi-arch scheduling.
92+
func ValidateMultiArchNodeSelector(nodeSelector map[string]string) (bool, build.BuildReason, string) {
93+
if _, ok := nodeSelector[corev1.LabelOSStable]; ok {
94+
return false, build.MultiArchNodeSelectorConflict, fmt.Sprintf("nodeSelector must not contain %q when multiArch is configured; the build controller manages os/arch scheduling", corev1.LabelOSStable)
95+
}
96+
if _, ok := nodeSelector[corev1.LabelArchStable]; ok {
97+
return false, build.MultiArchNodeSelectorConflict, fmt.Sprintf("nodeSelector must not contain %q when multiArch is configured; the build controller manages os/arch scheduling", corev1.LabelArchStable)
98+
}
99+
return true, "", ""
100+
}
101+

0 commit comments

Comments
 (0)