Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix bake #12507

Merged
merged 1 commit into from
Jan 29, 2025
Merged

Fix bake #12507

Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 11 additions & 10 deletions cmd/compose/build.go
Original file line number Diff line number Diff line change
Expand Up @@ -68,16 +68,17 @@ func (opts buildOptions) toAPIBuildOptions(services []string) (api.BuildOptions,
uiMode = "rawjson"
}
return api.BuildOptions{
Pull: opts.pull,
Push: opts.push,
Progress: uiMode,
Args: types.NewMappingWithEquals(opts.args),
NoCache: opts.noCache,
Quiet: opts.quiet,
Services: services,
Deps: opts.deps,
SSHs: SSHKeys,
Builder: builderName,
Pull: opts.pull,
Push: opts.push,
Progress: uiMode,
Args: types.NewMappingWithEquals(opts.args),
NoCache: opts.noCache,
Quiet: opts.quiet,
Services: services,
Deps: opts.deps,
SSHs: SSHKeys,
Builder: builderName,
Compatibility: opts.Compatibility,
}, nil
}

Expand Down
8 changes: 6 additions & 2 deletions cmd/compose/create_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,9 @@ func TestRunCreate(t *testing.T) {
)

createOpts := createOptions{}
buildOpts := buildOptions{}
buildOpts := buildOptions{
ProjectOptions: &ProjectOptions{},
}
project := sampleProject()
err := runCreate(ctx, nil, backend, createOpts, buildOpts, project, nil)
require.NoError(t, err)
Expand All @@ -58,7 +60,9 @@ func TestRunCreate_Build(t *testing.T) {
createOpts := createOptions{
Build: true,
}
buildOpts := buildOptions{}
buildOpts := buildOptions{
ProjectOptions: &ProjectOptions{},
}
project := sampleProject()
err := runCreate(ctx, nil, backend, createOpts, buildOpts, project, nil)
require.NoError(t, err)
Expand Down
2 changes: 2 additions & 0 deletions pkg/api/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,8 @@ type BuildOptions struct {
Memory int64
// Builder name passed in the command line
Builder string
// Compatibility let compose run with best backward compatibility
Compatibility bool
}

// Apply mutates project according to build options
Expand Down
125 changes: 95 additions & 30 deletions pkg/compose/build_bake.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import (
"os"
"os/exec"
"path/filepath"
"slices"
"strconv"
"strings"

Expand All @@ -35,6 +36,7 @@ import (
"github.com/docker/cli/cli/command"
"github.com/docker/compose/v2/pkg/api"
"github.com/docker/compose/v2/pkg/progress"
"github.com/docker/docker/api/types/versions"
"github.com/docker/docker/builder/remotecontext/urlutil"
"github.com/moby/buildkit/client"
"github.com/moby/buildkit/util/progress/progressui"
Expand Down Expand Up @@ -93,19 +95,25 @@ type bakeGroup struct {
}

type bakeTarget struct {
Context string `json:"context,omitempty"`
Dockerfile string `json:"dockerfile,omitempty"`
Args map[string]string `json:"args,omitempty"`
Labels map[string]string `json:"labels,omitempty"`
Tags []string `json:"tags,omitempty"`
CacheFrom []string `json:"cache-from,omitempty"`
CacheTo []string `json:"cache-to,omitempty"`
Secrets []string `json:"secret,omitempty"`
SSH []string `json:"ssh,omitempty"`
Platforms []string `json:"platforms,omitempty"`
Target string `json:"target,omitempty"`
Pull bool `json:"pull,omitempty"`
NoCache bool `json:"no-cache,omitempty"`
Context string `json:"context,omitempty"`
Contexts map[string]string `json:"contexts,omitempty"`
Dockerfile string `json:"dockerfile,omitempty"`
DockerfileInline string `json:"dockerfile-inline,omitempty"`
Args map[string]string `json:"args,omitempty"`
Labels map[string]string `json:"labels,omitempty"`
Tags []string `json:"tags,omitempty"`
CacheFrom []string `json:"cache-from,omitempty"`
CacheTo []string `json:"cache-to,omitempty"`
Secrets []string `json:"secret,omitempty"`
SSH []string `json:"ssh,omitempty"`
Platforms []string `json:"platforms,omitempty"`
Target string `json:"target,omitempty"`
Pull bool `json:"pull,omitempty"`
NoCache bool `json:"no-cache,omitempty"`
ShmSize types.UnitBytes `json:"shm-size,omitempty"`
Ulimits []string `json:"ulimits,omitempty"`
Entitlements []string `json:"entitlements,omitempty"`
Outputs []string `json:"output,omitempty"`
}

type bakeMetadata map[string]buildStatus
Expand Down Expand Up @@ -136,8 +144,9 @@ func (s *composeService) doBuildBake(ctx context.Context, project *types.Project
Targets: map[string]bakeTarget{},
}
var group bakeGroup
var privileged bool

for _, service := range serviceToBeBuild {
for serviceName, service := range serviceToBeBuild {
if service.Build == nil {
continue
}
Expand All @@ -153,23 +162,43 @@ func (s *composeService) doBuildBake(ctx context.Context, project *types.Project

image := api.GetImageNameOrDefault(service, project.Name)

cfg.Targets[image] = bakeTarget{
Context: build.Context,
Dockerfile: dockerFilePath(build.Context, build.Dockerfile),
Args: args,
Labels: build.Labels,
Tags: append(build.Tags, image),
entitlements := build.Entitlements
if slices.Contains(build.Entitlements, "security.insecure") {
privileged = true
}
if build.Privileged {
entitlements = append(entitlements, "security.insecure")
privileged = true
}

outputs := []string{"type=docker"}
if options.Push && service.Image != "" {
outputs = append(outputs, "type=image,push=true")
}

cfg.Targets[serviceName] = bakeTarget{
Context: build.Context,
Contexts: additionalContexts(build.AdditionalContexts, service.DependsOn, options.Compatibility),
Dockerfile: dockerFilePath(build.Context, build.Dockerfile),
DockerfileInline: build.DockerfileInline,
Args: args,
Labels: build.Labels,
Tags: append(build.Tags, image),

CacheFrom: build.CacheFrom,
// CacheTo: TODO
Platforms: build.Platforms,
Target: build.Target,
Secrets: toBakeSecrets(project, build.Secrets),
SSH: toBakeSSH(build.SSH),
Pull: options.Pull,
NoCache: options.NoCache,
Platforms: build.Platforms,
Target: build.Target,
Secrets: toBakeSecrets(project, build.Secrets),
SSH: toBakeSSH(append(build.SSH, options.SSHs...)),
Pull: options.Pull,
NoCache: options.NoCache,
ShmSize: build.ShmSize,
Ulimits: toBakeUlimits(build.Ulimits),
Entitlements: entitlements,
Outputs: outputs,
}
group.Targets = append(group.Targets, image)
group.Targets = append(group.Targets, serviceName)
}

cfg.Groups["default"] = group
Expand All @@ -188,7 +217,14 @@ func (s *composeService) doBuildBake(ctx context.Context, project *types.Project
if err != nil {
return nil, err
}
cmd := exec.CommandContext(ctx, buildx.Path, "bake", "--file", "-", "--progress", "rawjson", "--metadata-file", metadata.Name())

args := []string{"bake", "--file", "-", "--progress", "rawjson", "--metadata-file", metadata.Name()}
mustAllow := buildx.Version != "" && versions.GreaterThanOrEqualTo(buildx.Version[1:], "0.17.0")
if privileged && mustAllow {
args = append(args, "--allow", "security.insecure")
}

cmd := exec.CommandContext(ctx, buildx.Path, args...)
// Remove DOCKER_CLI_PLUGIN... variable so buildx can detect it run standalone
cmd.Env = filter(os.Environ(), manager.ReexecEnvvar)

Expand Down Expand Up @@ -258,6 +294,31 @@ func (s *composeService) doBuildBake(ctx context.Context, project *types.Project
return results, nil
}

func additionalContexts(contexts types.Mapping, dependencies types.DependsOnConfig, compatibility bool) map[string]string {
ac := map[string]string{}
if compatibility {
for name := range dependencies {
ac[name] = "target:" + name
}
}
for k, v := range contexts {
ac[k] = v
}
return ac
}

func toBakeUlimits(ulimits map[string]*types.UlimitsConfig) []string {
s := []string{}
for u, l := range ulimits {
if l.Single > 0 {
s = append(s, fmt.Sprintf("%s=%d", u, l.Single))
} else {
s = append(s, fmt.Sprintf("%s=%d:%d", u, l.Soft, l.Hard))
}
}
return s
}

func toBakeSSH(ssh types.SSHConfig) []string {
var s []string
for _, key := range ssh {
Expand All @@ -270,11 +331,15 @@ func toBakeSecrets(project *types.Project, secrets []types.ServiceSecretConfig)
var s []string
for _, ref := range secrets {
def := project.Secrets[ref.Source]
target := ref.Target
if target == "" {
target = ref.Source
}
switch {
case def.Environment != "":
s = append(s, fmt.Sprintf("id=%s,type=env,env=%s", ref.Source, def.Environment))
s = append(s, fmt.Sprintf("id=%s,type=env,env=%s", target, def.Environment))
case def.File != "":
s = append(s, fmt.Sprintf("id=%s,type=file,src=%s", ref.Source, def.File))
s = append(s, fmt.Sprintf("id=%s,type=file,src=%s", target, def.File))
}
}
return s
Expand Down
Loading