From d5e52bddccbd5ee98b2dfa3c196e72d2eb115d19 Mon Sep 17 00:00:00 2001 From: CrazyMax <1951866+crazy-max@users.noreply.github.com> Date: Mon, 5 Feb 2024 13:02:27 +0100 Subject: [PATCH] bake: shm-size support Signed-off-by: CrazyMax <1951866+crazy-max@users.noreply.github.com> --- bake/bake.go | 14 ++++++++++++++ bake/bake_test.go | 8 ++++++++ bake/compose.go | 9 +++++++++ bake/compose_test.go | 2 ++ docs/bake-reference.md | 17 ++++++++++++++++- tests/bake.go | 33 +++++++++++++++++++++++++++++++++ 6 files changed, 82 insertions(+), 1 deletion(-) diff --git a/bake/bake.go b/bake/bake.go index 786ea9ed6bbb..f4d662ae9764 100644 --- a/bake/bake.go +++ b/bake/bake.go @@ -21,6 +21,7 @@ import ( "github.com/docker/buildx/util/platformutil" "github.com/docker/buildx/util/progress" "github.com/docker/cli/cli/config" + dockeropts "github.com/docker/cli/opts" hcl "github.com/hashicorp/hcl/v2" "github.com/moby/buildkit/client" "github.com/moby/buildkit/client/llb" @@ -699,6 +700,7 @@ type Target struct { NoCache *bool `json:"no-cache,omitempty" hcl:"no-cache,optional" cty:"no-cache"` NetworkMode *string `json:"-" hcl:"-" cty:"-"` NoCacheFilter []string `json:"no-cache-filter,omitempty" hcl:"no-cache-filter,optional" cty:"no-cache-filter"` + ShmSize *string `json:"shm-size,omitempty" hcl:"shm-size,optional"` // IMPORTANT: if you add more fields here, do not forget to update newOverrides and docs/bake-reference.md. // linked is a private field to mark a target used as a linked one @@ -809,6 +811,9 @@ func (t *Target) Merge(t2 *Target) { if t2.NoCacheFilter != nil { // merge t.NoCacheFilter = append(t.NoCacheFilter, t2.NoCacheFilter...) } + if t2.ShmSize != nil { // no merge + t.ShmSize = t2.ShmSize + } t.Inherits = append(t.Inherits, t2.Inherits...) } @@ -873,6 +878,8 @@ func (t *Target) AddOverrides(overrides map[string]Override) error { t.NoCache = &noCache case "no-cache-filter": t.NoCacheFilter = o.ArrValue + case "shm-size": + t.ShmSize = &value case "pull": pull, err := strconv.ParseBool(value) if err != nil { @@ -1233,6 +1240,12 @@ func toBuildOpt(t *Target, inp *Input) (*build.Options, error) { if t.NetworkMode != nil { networkMode = *t.NetworkMode } + shmSize := new(dockeropts.MemBytes) + if t.ShmSize != nil { + if err := shmSize.Set(*t.ShmSize); err != nil { + return nil, errors.Errorf("invalid value %s for membytes key shm-size", *t.ShmSize) + } + } bo := &build.Options{ Inputs: bi, @@ -1244,6 +1257,7 @@ func toBuildOpt(t *Target, inp *Input) (*build.Options, error) { Pull: pull, NetworkMode: networkMode, Linked: t.linked, + ShmSize: *shmSize, } platforms, err := platformutil.Parse(t.Platforms) diff --git a/bake/bake_test.go b/bake/bake_test.go index 7f92842bfa9b..8ecd5f2be5c1 100644 --- a/bake/bake_test.go +++ b/bake/bake_test.go @@ -22,6 +22,7 @@ target "webDEP" { VAR_BOTH = "webDEP" } no-cache = true + shm-size = "128m" } target "webapp" { @@ -45,6 +46,7 @@ target "webapp" { require.Equal(t, ".", *m["webapp"].Context) require.Equal(t, ptrstr("webDEP"), m["webapp"].Args["VAR_INHERITED"]) require.Equal(t, true, *m["webapp"].NoCache) + require.Equal(t, "128m", *m["webapp"].ShmSize) require.Nil(t, m["webapp"].Pull) require.Equal(t, 1, len(g)) @@ -129,6 +131,12 @@ target "webapp" { require.Equal(t, []string{"webapp"}, g["default"].Targets) }) + t.Run("ShmSizeOverride", func(t *testing.T) { + m, _, err := ReadTargets(ctx, []File{fp}, []string{"webapp"}, []string{"webapp.shm-size=256m"}, nil) + require.NoError(t, err) + require.Equal(t, "256m", *m["webapp"].ShmSize) + }) + t.Run("PullOverride", func(t *testing.T) { t.Parallel() m, g, err := ReadTargets(ctx, []File{fp}, []string{"webapp"}, []string{"webapp.pull=false"}, nil) diff --git a/bake/compose.go b/bake/compose.go index c9fd5ff122e3..2502f826885c 100644 --- a/bake/compose.go +++ b/bake/compose.go @@ -9,6 +9,7 @@ import ( "github.com/compose-spec/compose-go/v2/dotenv" "github.com/compose-spec/compose-go/v2/loader" composetypes "github.com/compose-spec/compose-go/v2/types" + dockeropts "github.com/docker/cli/opts" "github.com/pkg/errors" "gopkg.in/yaml.v3" ) @@ -86,6 +87,13 @@ func ParseCompose(cfgs []composetypes.ConfigFile, envs map[string]string) (*Conf } } + var shmSize *string + if s.Build.ShmSize > 0 { + shmSizeBytes := dockeropts.MemBytes(s.Build.ShmSize) + shmSizeStr := shmSizeBytes.String() + shmSize = &shmSizeStr + } + var secrets []string for _, bs := range s.Build.Secrets { secret, err := composeToBuildkitSecret(bs, cfg.Secrets[bs.Source]) @@ -122,6 +130,7 @@ func ParseCompose(cfgs []composetypes.ConfigFile, envs map[string]string) (*Conf CacheTo: s.Build.CacheTo, NetworkMode: &s.Build.Network, Secrets: secrets, + ShmSize: shmSize, } if err = t.composeExtTarget(s.Build.Extensions); err != nil { return nil, err diff --git a/bake/compose_test.go b/bake/compose_test.go index 4ef1019b12ac..cf1d097a4df6 100644 --- a/bake/compose_test.go +++ b/bake/compose_test.go @@ -303,6 +303,7 @@ services: args: CT_ECR: foo CT_TAG: bar + shm_size: 128m x-bake: secret: - id=mysecret,src=/local/secret @@ -332,6 +333,7 @@ services: require.Equal(t, []string{"linux/arm64"}, c.Targets[1].Platforms) require.Equal(t, []string{"type=docker"}, c.Targets[1].Outputs) require.Equal(t, newBool(true), c.Targets[1].NoCache) + require.Equal(t, ptrstr("128MiB"), c.Targets[1].ShmSize) } func TestComposeExtDedup(t *testing.T) { diff --git a/docs/bake-reference.md b/docs/bake-reference.md index afe87d4ba9fa..185778181ce6 100644 --- a/docs/bake-reference.md +++ b/docs/bake-reference.md @@ -213,7 +213,7 @@ target "webapp" { The following table shows the complete list of attributes that you can assign to a target: | Name | Type | Description | -| ----------------------------------------------- | ------- | -------------------------------------------------------------------- | +|-------------------------------------------------|---------|----------------------------------------------------------------------| | [`args`](#targetargs) | Map | Build arguments | | [`annotations`](#targetannotations) | List | Exporter annotations | | [`attest`](#targetattest) | List | Build attestations | @@ -233,6 +233,7 @@ The following table shows the complete list of attributes that you can assign to | [`platforms`](#targetplatforms) | List | Target platforms | | [`pull`](#targetpull) | Boolean | Always pull images | | [`secret`](#targetsecret) | List | Secrets to expose to the build | +| [`shm-size`](#targetshm-size) | List | Size of `/dev/shm` | | [`ssh`](#targetssh) | List | SSH agent sockets or keys to expose to the build | | [`tags`](#targettags) | List | Image names and tags | | [`target`](#targettarget) | String | Target build stage | @@ -832,6 +833,20 @@ RUN --mount=type=secret,id=KUBECONFIG \ KUBECONFIG=$(cat /run/secrets/KUBECONFIG) helm upgrade --install ``` +### `target.shm-size` + +The format is ``. `number` must be greater than `0`. Unit is +optional and can be `b` (bytes), `k` (kilobytes), `m` (megabytes), or `g` +(gigabytes). If you omit the unit, the system uses bytes. + +This is the same as the `--shm-size` flag for `docker build`. + +```hcl +target "default" { + shm-size = "128m" +} +``` + ### `target.ssh` Defines SSH agent sockets or keys to expose to the build. diff --git a/tests/bake.go b/tests/bake.go index caeb607a7016..9539d99017ad 100644 --- a/tests/bake.go +++ b/tests/bake.go @@ -32,6 +32,7 @@ var bakeTests = []func(t *testing.T, sb integration.Sandbox){ testBakeRemoteDockerfileCwd, testBakeRemoteLocalContextRemoteDockerfile, testBakeEmpty, + testBakeShmSize, } func testBakeLocal(t *testing.T, sb integration.Sandbox) { @@ -520,3 +521,35 @@ func testBakeEmpty(t *testing.T, sb integration.Sandbox) { require.Error(t, err, out) require.Contains(t, out, "couldn't find a bake definition") } + +func testBakeShmSize(t *testing.T, sb integration.Sandbox) { + dockerfile := []byte(` +FROM busybox AS build +RUN sh -c 'mount | grep /dev/shm > /out/shmsize && cat /out/shmsize +FROM scratch +COPY --from=build /out/shmsize / + `) + bakefile := []byte(` +target "default" { + shm-size = "128m" +} +`) + dir := tmpdir( + t, + fstest.CreateFile("docker-bake.hcl", bakefile, 0600), + fstest.CreateFile("Dockerfile", dockerfile, 0600), + ) + + dirDest := t.TempDir() + + out, err := bakeCmd( + sb, + withDir(dir), + withArgs("--set", "*.output=type=local,dest="+dirDest), + ) + require.NoError(t, err, out) + + dt, err := os.ReadFile(filepath.Join(dirDest, "shmsize")) + require.NoError(t, err) + require.Contains(t, string(dt), `size=131072k`) +}