Skip to content

Commit 6f1d33f

Browse files
authored
fix: Implement buildx fixes for general buildkit support and platform handling (#734)
* fix: Implement buildx fixes for general buildkit support and platform handling * chore: Revert to having buildkit for non-buildx build attribute
1 parent da2a796 commit 6f1d33f

File tree

7 files changed

+78
-13
lines changed

7 files changed

+78
-13
lines changed

docs/resources/image.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ resource "docker_image" "ubuntu" {
4343

4444
### Build
4545

46-
You can also use the resource to build an image. By default the build block is using the old legacy docker build. In order to use a buildx builder, please read the section below
46+
You can also use the resource to build an image. If you want to use a buildx builder with all of its features, please read the section below.
4747

4848
-> **Note**: The default timeout for the building is 20 minutes. If you need to increase this, you can use [operation timeouts](https://developer.hashicorp.com/terraform/language/resources/syntax#operation-timeouts).
4949

@@ -85,7 +85,7 @@ resource "docker_image" "zoo" {
8585

8686
-> **Note**: The buildx feature is currently in preview and may have some quirks. Known issues: Setting `ulimits` will not work.
8787

88-
The `build` argument uses the legacy docker builder. If you want to use a buildx builder, you need to set the `builder` argument. For the default buildx builder, you can set the `builder` argument to `default`. For a custom buildx builder, you can set the `builder` argument to the name of the builder. You can find the name of the builder by running `docker buildx ls`.
88+
If you want to use a buildx builder, you need to set the `builder` argument. For the default buildx builder, you can set the `builder` argument to `default`. For a custom buildx builder, you can set the `builder` argument to the name of the builder. You can find the name of the builder by running `docker buildx ls`.
8989

9090
The single platform build result is automatically loaded to `docker images`.
9191

@@ -125,7 +125,7 @@ Optional:
125125
- `build_args` (Map of String) Pairs for build-time variables in the form of `ENDPOINT : "https://example.com"`
126126
- `build_id` (String) BuildID is an optional identifier that can be passed together with the build request. The same identifier can be used to gracefully cancel the build with the cancel request.
127127
- `build_log_file` (String) Path to a file where the buildx log are written to. Only available when `builder` is set. If not set, no logs are available. The path is taken as is, so make sure to use a path that is available.
128-
- `builder` (String) Set the name of the buildx builder to use. If not set or empty, the legacy builder will be used.
128+
- `builder` (String) Set the name of the buildx builder to use. If not set, the legacy builder is used.
129129
- `cache_from` (List of String) Images to consider as cache sources
130130
- `cgroup_parent` (String) Optional parent cgroup for the container
131131
- `cpu_period` (Number) The length of a CPU period in microseconds
@@ -143,7 +143,7 @@ Optional:
143143
- `memory_swap` (Number) Total memory (memory + swap), -1 to enable unlimited swap
144144
- `network_mode` (String) Set the networking mode for the RUN instructions during build
145145
- `no_cache` (Boolean) Do not use the cache when building the image
146-
- `platform` (String) Set platform if server is multi-platform capable
146+
- `platform` (String) Set the target platform for the build. Defaults to `GOOS/GOARCH`. For more information see the [docker documentation](https://github.com/docker/buildx/blob/master/docs/reference/buildx.md#-set-the-target-platforms-for-the-build---platform)
147147
- `pull_parent` (Boolean) Attempt to pull the image even if an older image exists locally
148148
- `remote_context` (String) A Git repository URI or HTTP/HTTPS context URI. Will be ignored if `builder` is set.
149149
- `remove` (Boolean) Remove intermediate containers after a successful build. Defaults to `true`.

internal/provider/docker_buildx_build.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -353,7 +353,7 @@ func mapBuildAttributesToBuildOptions(buildAttributes map[string]interface{}, im
353353
options.target = target
354354
}
355355

356-
if platform, ok := buildAttributes["platform"].(string); ok {
356+
if platform, ok := buildAttributes["platform"].(string); ok && len(platform) > 0 {
357357
options.platforms = append(options.platforms, platform)
358358
}
359359

internal/provider/resource_docker_image.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -388,7 +388,7 @@ func resourceDockerImage() *schema.Resource {
388388
},
389389
"platform": {
390390
Type: schema.TypeString,
391-
Description: "Set platform if server is multi-platform capable",
391+
Description: "Set the target platform for the build. Defaults to `GOOS/GOARCH`. For more information see the [docker documentation](https://github.com/docker/buildx/blob/master/docs/reference/buildx.md#-set-the-target-platforms-for-the-build---platform)",
392392
Optional: true,
393393
ForceNew: true,
394394
},
@@ -406,7 +406,7 @@ func resourceDockerImage() *schema.Resource {
406406
},
407407
"builder": {
408408
Type: schema.TypeString,
409-
Description: "Set the name of the buildx builder to use. If not set or empty, the legacy builder will be used.",
409+
Description: "Set the name of the buildx builder to use. If not set, the legacy builder is used.",
410410
Optional: true,
411411
ForceNew: true,
412412
},

internal/provider/resource_docker_image_funcs.go

Lines changed: 69 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import (
88
"fmt"
99
"io"
1010
"log"
11+
"net"
1112
"os"
1213
"path/filepath"
1314
"strings"
@@ -16,12 +17,15 @@ import (
1617
"github.com/docker/docker/api/types"
1718
"github.com/docker/docker/api/types/image"
1819
"github.com/docker/docker/api/types/registry"
20+
"github.com/docker/docker/api/types/versions"
1921
"github.com/docker/docker/client"
2022
"github.com/docker/docker/errdefs"
2123
"github.com/docker/docker/pkg/jsonmessage"
2224
"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
2325
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
2426
"github.com/mitchellh/go-homedir"
27+
"github.com/moby/buildkit/session"
28+
"github.com/moby/buildkit/session/secrets/secretsprovider"
2529
"github.com/moby/go-archive"
2630
"github.com/pkg/errors"
2731
)
@@ -56,15 +60,17 @@ func resourceDockerImageCreate(ctx context.Context, d *schema.ResourceData, meta
5660
}
5761
buildLogFile := rawBuild["build_log_file"].(string)
5862

63+
log.Printf("[DEBUG] build options %#v", options)
64+
5965
err = runBuild(ctx, dockerCli, options, buildLogFile)
6066
if err != nil {
61-
return diag.FromErr(err)
67+
return diag.Errorf("Error running buildx build: %v", err)
6268
}
6369
} else {
6470

6571
err := buildDockerImage(ctx, rawBuild, imageName, client)
6672
if err != nil {
67-
return diag.FromErr(err)
73+
return diag.Errorf("Error running legacy build: %v", err)
6874
}
6975
}
7076
}
@@ -356,6 +362,23 @@ func buildDockerImage(ctx context.Context, rawBuild map[string]interface{}, imag
356362

357363
buildContext := rawBuild["context"].(string)
358364

365+
buildKitSession := enableBuildKitIfSupported(ctx, client, &buildOptions)
366+
367+
// If Buildkit is enabled, try to parse and use secrets if present.
368+
if buildKitSession != nil {
369+
if secretsRaw, secretsDefined := rawBuild["secrets"]; secretsDefined {
370+
parsedSecrets := parseBuildSecrets(secretsRaw)
371+
372+
store, err := secretsprovider.NewStore(parsedSecrets)
373+
if err != nil {
374+
return err
375+
}
376+
377+
provider := secretsprovider.NewSecretProvider(store)
378+
buildKitSession.Allow(provider)
379+
}
380+
}
381+
359382
buildCtx, relDockerfile, err := prepareBuildContext(buildContext, buildOptions.Dockerfile)
360383
if err != nil {
361384
return err
@@ -377,6 +400,33 @@ func buildDockerImage(ctx context.Context, rawBuild map[string]interface{}, imag
377400
return nil
378401
}
379402

403+
const minBuildkitDockerVersion = "1.39"
404+
405+
func enableBuildKitIfSupported(
406+
ctx context.Context,
407+
client *client.Client,
408+
buildOptions *types.ImageBuildOptions,
409+
) *session.Session {
410+
dockerClientVersion := client.ClientVersion()
411+
log.Printf("[DEBUG] DockerClientVersion: %v, minBuildKitDockerVersion: %v\n", dockerClientVersion, minBuildkitDockerVersion)
412+
if versions.GreaterThanOrEqualTo(dockerClientVersion, minBuildkitDockerVersion) {
413+
log.Printf("[DEBUG] Enabling BuildKit")
414+
s, _ := session.NewSession(ctx, "docker-provider")
415+
dialSession := func(ctx context.Context, proto string, meta map[string][]string) (net.Conn, error) {
416+
return client.DialHijack(ctx, "/session", proto, meta)
417+
}
418+
//nolint
419+
go s.Run(ctx, dialSession)
420+
defer s.Close() //nolint:errcheck
421+
buildOptions.SessionID = s.ID()
422+
buildOptions.Version = types.BuilderBuildKit
423+
return s
424+
} else {
425+
buildOptions.Version = types.BuilderV1
426+
return nil
427+
}
428+
}
429+
380430
func prepareBuildContext(specifiedContext string, specifiedDockerfile string) (io.ReadCloser, string, error) {
381431
var (
382432
dockerfileCtx io.ReadCloser
@@ -465,3 +515,20 @@ func decodeBuildMessages(response types.ImageBuildResponse) (string, error) {
465515

466516
return buf.String(), buildErr
467517
}
518+
519+
func parseBuildSecrets(secretsRaw interface{}) []secretsprovider.Source {
520+
options := secretsRaw.([]interface{})
521+
522+
secrets := make([]secretsprovider.Source, len(options))
523+
for i, option := range options {
524+
secretRaw := option.(map[string]interface{})
525+
source := secretsprovider.Source{
526+
ID: secretRaw["id"].(string),
527+
FilePath: secretRaw["src"].(string),
528+
Env: secretRaw["env"].(string),
529+
}
530+
secrets[i] = source
531+
}
532+
533+
return secrets
534+
}

templates/resources/image.md.tmpl

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ you need to use it in combination with `docker_registry_image` as follows:
2828

2929
### Build
3030

31-
You can also use the resource to build an image. By default the build block is using the old legacy docker build. In order to use a buildx builder, please read the section below
31+
You can also use the resource to build an image. If you want to use a buildx builder with all of its features, please read the section below.
3232

3333
-> **Note**: The default timeout for the building is 20 minutes. If you need to increase this, you can use [operation timeouts](https://developer.hashicorp.com/terraform/language/resources/syntax#operation-timeouts).
3434

@@ -46,7 +46,7 @@ You can use the `triggers` argument to specify when the image should be rebuild.
4646

4747
-> **Note**: The buildx feature is currently in preview and may have some quirks. Known issues: Setting `ulimits` will not work.
4848

49-
The `build` argument uses the legacy docker builder. If you want to use a buildx builder, you need to set the `builder` argument. For the default buildx builder, you can set the `builder` argument to `default`. For a custom buildx builder, you can set the `builder` argument to the name of the builder. You can find the name of the builder by running `docker buildx ls`.
49+
If you want to use a buildx builder, you need to set the `builder` argument. For the default buildx builder, you can set the `builder` argument to `default`. For a custom buildx builder, you can set the `builder` argument to the name of the builder. You can find the name of the builder by running `docker buildx ls`.
5050

5151
The single platform build result is automatically loaded to `docker images`.
5252

testdata/resources/docker_image/testDockerImageBuildSecrets.tf

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ resource "docker_image" "test" {
55
dockerfile = "Dockerfile"
66
force_remove = true
77
builder = "default"
8-
platform = "linux/amd64"
98

109
secrets {
1110
id = "TEST_SECRET_SRC"

testdata/resources/docker_image/testDockerImageBuildxBuildLog.tf

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ resource "docker_image" "test" {
55
dockerfile = "Dockerfile"
66
force_remove = true
77
builder = "default"
8-
platform = "linux/amd64"
98

109
build_log_file = "%s"
1110
}

0 commit comments

Comments
 (0)