Skip to content

Commit 8c1d340

Browse files
committed
Allow custom worker images
This allows builders to provide their own worker image. This enables builders to install their own repos, as an example, or use pre-built workers. Adds `azlinux3/worker`, `mariner2/worker`, and `windowscross/worker/` build targets which outputs each worker image respectively. You can take the output of these, inject whatever is needed, and feed that as an input into another build. Signed-off-by: Brian Goff <[email protected]>
1 parent 3874b8b commit 8c1d340

File tree

15 files changed

+670
-107
lines changed

15 files changed

+670
-107
lines changed

frontend/azlinux/azlinux3.go

Lines changed: 40 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,11 @@ const (
1616
AzLinux3TargetKey = "azlinux3"
1717
tdnfCacheNameAzlinux3 = "azlinux3-tdnf-cache"
1818

19-
azlinux3Ref = "azurelinuxpreview.azurecr.io/public/azurelinux/base/core:3.0"
20-
azlinux3DistrolessRef = "azurelinuxpreview.azurecr.io/public/azurelinux/distroless/base:3.0"
19+
// Azlinux3Ref is the image ref used for the base worker image
20+
Azlinux3Ref = "azurelinuxpreview.azurecr.io/public/azurelinux/base/core:3.0"
21+
// Azlinux3WorkerContextName is the build context name that can be used to lookup
22+
Azlinux3WorkerContextName = "dalec-azlinux3-worker"
23+
azlinux3DistrolessRef = "azurelinuxpreview.azurecr.io/public/azurelinux/distroless/base:3.0"
2124
)
2225

2326
func NewAzlinux3Handler() gwclient.BuildFunc {
@@ -26,11 +29,29 @@ func NewAzlinux3Handler() gwclient.BuildFunc {
2629

2730
type azlinux3 struct{}
2831

29-
func (w azlinux3) Base(resolver llb.ImageMetaResolver, opts ...llb.ConstraintsOpt) llb.State {
30-
return llb.Image(azlinux3Ref, llb.WithMetaResolver(resolver), dalec.WithConstraints(opts...)).Run(
32+
func (w azlinux3) Base(sOpt dalec.SourceOpts, opts ...llb.ConstraintsOpt) (llb.State, error) {
33+
base, err := sOpt.GetContext(Azlinux3Ref, dalec.WithConstraints(opts...))
34+
if err != nil {
35+
return llb.Scratch(), err
36+
}
37+
38+
if base != nil {
39+
return *base, nil
40+
}
41+
42+
base, err = sOpt.GetContext(Azlinux3WorkerContextName, dalec.WithConstraints(opts...))
43+
if err != nil {
44+
return llb.Scratch(), nil
45+
}
46+
if base != nil {
47+
return *base, nil
48+
}
49+
50+
img := llb.Image(Azlinux3Ref, llb.WithMetaResolver(sOpt.Resolver), dalec.WithConstraints(opts...))
51+
return img.Run(
3152
w.Install([]string{"rpm-build", "mariner-rpm-macros", "build-essential", "ca-certificates"}, installWithConstraints(opts)),
3253
dalec.WithConstraints(opts...),
33-
).Root()
54+
).Root(), nil
3455
}
3556

3657
func (w azlinux3) Install(pkgs []string, opts ...installOpt) llb.RunOption {
@@ -53,6 +74,20 @@ func (azlinux3) DefaultImageConfig(ctx context.Context, resolver llb.ImageMetaRe
5374
return &cfg, nil
5475
}
5576

77+
func (azlinux3) WorkerImageConfig(ctx context.Context, resolver llb.ImageMetaResolver, platform *ocispecs.Platform) (*dalec.DockerImageSpec, error) {
78+
_, _, dt, err := resolver.ResolveImageConfig(ctx, Azlinux3Ref, sourceresolver.Opt{Platform: platform})
79+
if err != nil {
80+
return nil, err
81+
}
82+
83+
var cfg dalec.DockerImageSpec
84+
if err := json.Unmarshal(dt, &cfg); err != nil {
85+
return nil, err
86+
}
87+
88+
return &cfg, nil
89+
}
90+
5691
func (azlinux3) tdnfCacheMount(root string) llb.RunOption {
5792
return llb.AddMount(filepath.Join(root, tdnfCacheDir), llb.Scratch(), llb.AsPersistentCacheDir(tdnfCacheNameAzlinux3, llb.CacheMountLocked))
5893
}

frontend/azlinux/handle_container.go

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ func handleContainer(w worker) gwclient.BuildFunc {
3535
return nil, nil, err
3636
}
3737

38-
st, err := specToContainerLLB(w, client, spec, targetKey, rpmDir, rpms, sOpt, pg)
38+
st, err := specToContainerLLB(w, spec, targetKey, rpmDir, rpms, sOpt, pg)
3939
if err != nil {
4040
return nil, nil, err
4141
}
@@ -62,12 +62,17 @@ func handleContainer(w worker) gwclient.BuildFunc {
6262
return nil, nil, err
6363
}
6464

65+
base, err := w.Base(sOpt, pg)
66+
if err != nil {
67+
return nil, nil, err
68+
}
69+
6570
withTestDeps := func(in llb.State) llb.State {
6671
deps := spec.GetTestDeps(targetKey)
6772
if len(deps) == 0 {
6873
return in
6974
}
70-
return w.Base(client, pg).Run(
75+
return base.Run(
7176
w.Install(spec.GetTestDeps(targetKey), atRoot("/tmp/rootfs")),
7277
pg,
7378
dalec.ProgressGroup("Install test dependencies"),
@@ -130,11 +135,14 @@ func readRPMs(ctx context.Context, client gwclient.Client, st llb.State) ([]stri
130135
return out, nil
131136
}
132137

133-
func specToContainerLLB(w worker, client gwclient.Client, spec *dalec.Spec, targetKey string, rpmDir llb.State, files []string, sOpt dalec.SourceOpts, opts ...llb.ConstraintsOpt) (llb.State, error) {
138+
func specToContainerLLB(w worker, spec *dalec.Spec, targetKey string, rpmDir llb.State, files []string, sOpt dalec.SourceOpts, opts ...llb.ConstraintsOpt) (llb.State, error) {
134139
opts = append(opts, dalec.ProgressGroup("Install RPMs"))
135140
const workPath = "/tmp/rootfs"
136141

137-
builderImg := w.Base(client, opts...)
142+
builderImg, err := w.Base(sOpt, opts...)
143+
if err != nil {
144+
return llb.Scratch(), err
145+
}
138146

139147
rootfs := llb.Scratch()
140148
if ref := dalec.GetBaseOutputImage(spec, targetKey); ref != "" {

frontend/azlinux/handle_depsonly.go

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,16 @@ func handleDepsOnly(w worker) gwclient.BuildFunc {
1515
return func(ctx context.Context, client gwclient.Client) (*gwclient.Result, error) {
1616
return frontend.BuildWithPlatform(ctx, client, func(ctx context.Context, client gwclient.Client, platform *ocispecs.Platform, spec *dalec.Spec, targetKey string) (gwclient.Reference, *dalec.DockerImageSpec, error) {
1717
pg := dalec.ProgressGroup("Build mariner2 deps-only container: " + spec.Name)
18-
baseImg := w.Base(client, pg)
18+
19+
sOpt, err := frontend.SourceOptFromClient(ctx, client)
20+
if err != nil {
21+
return nil, nil, err
22+
}
23+
24+
baseImg, err := w.Base(sOpt, pg)
25+
if err != nil {
26+
return nil, nil, err
27+
}
1928
rpmDir := baseImg.Run(
2029
dalec.ShArgs(`set -ex; dir="/tmp/rpms/RPMS/$(uname -m)"; mkdir -p "${dir}"; tdnf install -y --releasever=2.0 --downloadonly --alldeps --downloaddir "${dir}" `+strings.Join(spec.GetRuntimeDeps(targetKey), " ")),
2130
pg,
@@ -27,11 +36,7 @@ func handleDepsOnly(w worker) gwclient.BuildFunc {
2736
return nil, nil, err
2837
}
2938

30-
sOpt, err := frontend.SourceOptFromClient(ctx, client)
31-
if err != nil {
32-
return nil, nil, err
33-
}
34-
st, err := specToContainerLLB(w, client, spec, targetKey, rpmDir, files, sOpt, pg)
39+
st, err := specToContainerLLB(w, spec, targetKey, rpmDir, files, sOpt, pg)
3540
if err != nil {
3641
return nil, nil, err
3742
}

frontend/azlinux/handle_rpm.go

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,12 @@ func installBuildDeps(w worker, spec *dalec.Spec, targetKey string, opts ...llb.
6565
}
6666

6767
func specToRpmLLB(ctx context.Context, w worker, client gwclient.Client, spec *dalec.Spec, sOpt dalec.SourceOpts, targetKey string, opts ...llb.ConstraintsOpt) (llb.State, error) {
68-
base := w.Base(client, opts...).With(installBuildDeps(w, spec, targetKey, opts...))
68+
base, err := w.Base(sOpt, opts...)
69+
base = base.With(installBuildDeps(w, spec, targetKey, opts...))
70+
if err != nil {
71+
return llb.Scratch(), err
72+
}
73+
6974
br, err := rpm.SpecToBuildrootLLB(base, spec, sOpt, targetKey, opts...)
7075
if err != nil {
7176
return llb.Scratch(), err

frontend/azlinux/handler.go

Lines changed: 60 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,10 @@ const (
1919
)
2020

2121
type worker interface {
22-
Base(resolver llb.ImageMetaResolver, opts ...llb.ConstraintsOpt) llb.State
22+
Base(sOpt dalec.SourceOpts, opts ...llb.ConstraintsOpt) (llb.State, error)
2323
Install(pkgs []string, opts ...installOpt) llb.RunOption
2424
DefaultImageConfig(context.Context, llb.ImageMetaResolver, *ocispecs.Platform) (*dalec.DockerImageSpec, error)
25+
WorkerImageConfig(context.Context, llb.ImageMetaResolver, *ocispecs.Platform) (*dalec.DockerImageSpec, error)
2526
}
2627

2728
func newHandler(w worker) gwclient.BuildFunc {
@@ -44,18 +45,30 @@ func newHandler(w worker) gwclient.BuildFunc {
4445
Description: "Builds a container image with only the runtime dependencies installed.",
4546
})
4647

48+
mux.Add("worker", handleBaseImg(w), &targets.Target{
49+
Name: "worker",
50+
Description: "Builds the base worker image responsible for building the rpm",
51+
})
52+
4753
return mux.Handle
4854
}
4955

5056
func handleDebug(w worker) gwclient.BuildFunc {
5157
return func(ctx context.Context, client gwclient.Client) (*gwclient.Result, error) {
52-
return rpm.HandleDebug(getSpecWorker(w))(ctx, client)
58+
sOpt, err := frontend.SourceOptFromClient(ctx, client)
59+
if err != nil {
60+
return nil, err
61+
}
62+
return rpm.HandleDebug(getSpecWorker(w, sOpt))(ctx, client)
5363
}
5464
}
5565

56-
func getSpecWorker(w worker) rpm.WorkerFunc {
66+
func getSpecWorker(w worker, sOpt dalec.SourceOpts) rpm.WorkerFunc {
5767
return func(resolver llb.ImageMetaResolver, spec *dalec.Spec, targetKey string, opts ...llb.ConstraintsOpt) (llb.State, error) {
58-
st := w.Base(resolver, opts...)
68+
st, err := w.Base(sOpt, opts...)
69+
if err != nil {
70+
return llb.Scratch(), err
71+
}
5972
if spec.HasGomods() {
6073
deps := spec.GetBuildDeps(targetKey)
6174
hasGolang := func(s string) bool {
@@ -70,3 +83,46 @@ func getSpecWorker(w worker) rpm.WorkerFunc {
7083
return st, nil
7184
}
7285
}
86+
87+
func handleBaseImg(w worker) gwclient.BuildFunc {
88+
return func(ctx context.Context, client gwclient.Client) (*gwclient.Result, error) {
89+
return frontend.BuildWithPlatform(ctx, client, func(ctx context.Context, client gwclient.Client, platform *ocispecs.Platform, spec *dalec.Spec, targetKey string) (gwclient.Reference, *dalec.DockerImageSpec, error) {
90+
91+
sOpt, err := frontend.SourceOptFromClient(ctx, client)
92+
if err != nil {
93+
return nil, nil, err
94+
}
95+
96+
st, err := w.Base(sOpt)
97+
if err != nil {
98+
return nil, nil, err
99+
}
100+
101+
def, err := st.Marshal(ctx)
102+
if err != nil {
103+
return nil, nil, err
104+
}
105+
106+
req := gwclient.SolveRequest{
107+
Definition: def.ToPB(),
108+
}
109+
110+
res, err := client.Solve(ctx, req)
111+
if err != nil {
112+
return nil, nil, err
113+
}
114+
115+
ref, err := res.SingleRef()
116+
if err != nil {
117+
return nil, nil, err
118+
}
119+
120+
cfg, err := w.DefaultImageConfig(ctx, client, platform)
121+
if err != nil {
122+
return nil, nil, err
123+
}
124+
125+
return ref, cfg, nil
126+
})
127+
}
128+
}

frontend/azlinux/mariner2.go

Lines changed: 38 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,9 @@ const (
1616
Mariner2TargetKey = "mariner2"
1717
tdnfCacheNameMariner2 = "mariner2-tdnf-cache"
1818

19-
mariner2Ref = "mcr.microsoft.com/cbl-mariner/base/core:2.0"
20-
mariner2DistrolessRef = "mcr.microsoft.com/cbl-mariner/distroless/base:2.0"
19+
Mariner2Ref = "mcr.microsoft.com/cbl-mariner/base/core:2.0"
20+
Mariner2WorkerContextName = "dalec-mariner2-worker"
21+
mariner2DistrolessRef = "mcr.microsoft.com/cbl-mariner/distroless/base:2.0"
2122
)
2223

2324
func NewMariner2Handler() gwclient.BuildFunc {
@@ -26,11 +27,28 @@ func NewMariner2Handler() gwclient.BuildFunc {
2627

2728
type mariner2 struct{}
2829

29-
func (w mariner2) Base(resolver llb.ImageMetaResolver, opts ...llb.ConstraintsOpt) llb.State {
30-
return llb.Image(mariner2Ref, llb.WithMetaResolver(resolver), dalec.WithConstraints(opts...)).Run(
31-
w.Install([]string{"rpm-build", "mariner-rpm-macros", "systemd-rpm-macros", "build-essential", "ca-certificates"}, installWithConstraints(opts)),
30+
func (w mariner2) Base(sOpt dalec.SourceOpts, opts ...llb.ConstraintsOpt) (llb.State, error) {
31+
base, err := sOpt.GetContext(Mariner2Ref, dalec.WithConstraints(opts...))
32+
if err != nil {
33+
return llb.Scratch(), err
34+
}
35+
36+
if base == nil {
37+
base, err = sOpt.GetContext(Mariner2WorkerContextName, dalec.WithConstraints(opts...))
38+
if err != nil {
39+
return llb.Scratch(), nil
40+
}
41+
}
42+
43+
if base == nil {
44+
st := llb.Image(Mariner2Ref, llb.WithMetaResolver(sOpt.Resolver), dalec.WithConstraints(opts...))
45+
base = &st
46+
}
47+
48+
return base.Run(
49+
w.Install([]string{"rpm-build", "mariner-rpm-macros", "build-essential", "ca-certificates"}, installWithConstraints(opts)),
3250
dalec.WithConstraints(opts...),
33-
).Root()
51+
).Root(), nil
3452
}
3553

3654
func (w mariner2) Install(pkgs []string, opts ...installOpt) llb.RunOption {
@@ -55,6 +73,20 @@ func (mariner2) DefaultImageConfig(ctx context.Context, resolver llb.ImageMetaRe
5573
return &cfg, nil
5674
}
5775

76+
func (mariner2) WorkerImageConfig(ctx context.Context, resolver llb.ImageMetaResolver, platform *ocispecs.Platform) (*dalec.DockerImageSpec, error) {
77+
_, _, dt, err := resolver.ResolveImageConfig(ctx, Mariner2Ref, sourceresolver.Opt{Platform: platform})
78+
if err != nil {
79+
return nil, err
80+
}
81+
82+
var cfg dalec.DockerImageSpec
83+
if err := json.Unmarshal(dt, &cfg); err != nil {
84+
return nil, err
85+
}
86+
87+
return &cfg, nil
88+
}
89+
5890
func (mariner2) tdnfCacheMount(root string) llb.RunOption {
5991
return llb.AddMount(filepath.Join(root, tdnfCacheDir), llb.Scratch(), llb.AsPersistentCacheDir(tdnfCacheNameMariner2, llb.CacheMountLocked))
6092
}

frontend/windows/handle_container.go

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,10 @@ func handleContainer(ctx context.Context, client gwclient.Client) (*gwclient.Res
5454
}
5555

5656
pg := dalec.ProgressGroup("Build windows container: " + spec.Name)
57-
worker := workerImg(sOpt, pg)
57+
worker, err := workerImg(sOpt, pg)
58+
if err != nil {
59+
return nil, nil, err
60+
}
5861

5962
bin, err := buildBinaries(ctx, spec, worker, client, sOpt, targetKey)
6063
if err != nil {

frontend/windows/handle_zip.go

Lines changed: 28 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -18,10 +18,11 @@ import (
1818
)
1919

2020
const (
21-
workerImgRef = "mcr.microsoft.com/mirror/docker/library/ubuntu:jammy"
22-
outputDir = "/tmp/output"
23-
buildScriptName = "_build.sh"
24-
aptCachePrefix = "jammy-windowscross"
21+
workerImgRef = "mcr.microsoft.com/mirror/docker/library/ubuntu:jammy"
22+
WindowscrossWorkerContextName = "dalec-windowscross-worker"
23+
outputDir = "/tmp/output"
24+
buildScriptName = "_build.sh"
25+
aptCachePrefix = "jammy-windowscross"
2526
)
2627

2728
func handleZip(ctx context.Context, client gwclient.Client) (*gwclient.Result, error) {
@@ -32,7 +33,10 @@ func handleZip(ctx context.Context, client gwclient.Client) (*gwclient.Result, e
3233
}
3334

3435
pg := dalec.ProgressGroup("Build windows container: " + spec.Name)
35-
worker := workerImg(sOpt, pg)
36+
worker, err := workerImg(sOpt, pg)
37+
if err != nil {
38+
return nil, nil, err
39+
}
3640

3741
bin, err := buildBinaries(ctx, spec, worker, client, sOpt, targetKey)
3842
if err != nil {
@@ -168,13 +172,29 @@ func generateInvocationScript(binaries []string) *strings.Builder {
168172
return script
169173
}
170174

171-
func workerImg(sOpt dalec.SourceOpts, opts ...llb.ConstraintsOpt) llb.State {
172-
// TODO: support named context override... also this should possibly be its own image, maybe?
175+
func workerImg(sOpt dalec.SourceOpts, opts ...llb.ConstraintsOpt) (llb.State, error) {
176+
base, err := sOpt.GetContext(workerImgRef, dalec.WithConstraints(opts...))
177+
if err != nil {
178+
return llb.Scratch(), err
179+
}
180+
181+
if base != nil {
182+
return *base, nil
183+
}
184+
185+
base, err = sOpt.GetContext(WindowscrossWorkerContextName, dalec.WithConstraints(opts...))
186+
if err != nil {
187+
return llb.Scratch(), nil
188+
}
189+
if base != nil {
190+
return *base, nil
191+
}
192+
173193
return llb.Image(workerImgRef, llb.WithMetaResolver(sOpt.Resolver), dalec.WithConstraints(opts...)).
174194
Run(
175195
dalec.ShArgs("apt-get update && apt-get install -y build-essential binutils-mingw-w64 g++-mingw-w64-x86-64 gcc git make pkg-config quilt zip"),
176196
dalec.WithMountedAptCache(aptCachePrefix),
177-
).Root()
197+
).Root(), nil
178198
}
179199

180200
func createBuildScript(spec *dalec.Spec) llb.State {

0 commit comments

Comments
 (0)