From 9743352c9b2125eb36fb855766b0de00a2e2a49d Mon Sep 17 00:00:00 2001 From: Bryce Lampe Date: Fri, 15 Mar 2024 14:01:32 -0700 Subject: [PATCH] delete remote tags --- examples/aws-container-registry/ts/index.ts | 36 ------- examples/examples_nodejs_test.go | 26 +++++ examples/go.mod | 5 +- examples/go.sum | 12 ++- examples/test-buildx/ecr/ts/.gitignore | 2 + examples/test-buildx/ecr/ts/Pulumi.yaml | 3 + examples/test-buildx/ecr/ts/app/Dockerfile | 3 + examples/test-buildx/ecr/ts/index.ts | 53 ++++++++++ examples/test-buildx/ecr/ts/package.json | 11 +++ examples/test-buildx/ecr/ts/tsconfig.json | 18 ++++ .../cmd/pulumi-resource-docker/schema.json | 4 +- provider/internal/cache.go | 7 +- provider/internal/client.go | 47 +++++++-- provider/internal/doc/migration.md | 3 +- provider/internal/image.go | 99 ++++++++++--------- provider/internal/image_test.go | 11 +-- provider/internal/index.go | 6 +- provider/internal/mockclient_test.go | 16 ++- sdk/dotnet/Buildx/Image.cs | 3 +- .../Buildx/Inputs/CacheToRegistryArgs.cs | 7 +- sdk/dotnet/Buildx/Outputs/CacheToRegistry.cs | 7 +- sdk/go/docker/buildx/image.go | 3 +- sdk/go/docker/buildx/pulumiTypes.go | 28 ++++-- .../java/com/pulumi/docker/buildx/Image.java | 3 +- .../buildx/inputs/CacheToRegistryArgs.java | 28 ++++-- .../buildx/outputs/CacheToRegistry.java | 14 ++- sdk/nodejs/buildx/image.ts | 3 +- sdk/nodejs/types/input.ts | 7 +- sdk/nodejs/types/output.ts | 7 +- sdk/python/pulumi_docker/buildx/_inputs.py | 14 ++- sdk/python/pulumi_docker/buildx/image.py | 6 +- sdk/python/pulumi_docker/buildx/outputs.py | 14 ++- 32 files changed, 350 insertions(+), 156 deletions(-) create mode 100644 examples/test-buildx/ecr/ts/.gitignore create mode 100644 examples/test-buildx/ecr/ts/Pulumi.yaml create mode 100644 examples/test-buildx/ecr/ts/app/Dockerfile create mode 100644 examples/test-buildx/ecr/ts/index.ts create mode 100644 examples/test-buildx/ecr/ts/package.json create mode 100644 examples/test-buildx/ecr/ts/tsconfig.json diff --git a/examples/aws-container-registry/ts/index.ts b/examples/aws-container-registry/ts/index.ts index 2008911d..e0802a1b 100644 --- a/examples/aws-container-registry/ts/index.ts +++ b/examples/aws-container-registry/ts/index.ts @@ -1,6 +1,5 @@ import * as aws from "@pulumi/aws"; import * as docker from "@pulumi/docker"; -import * as pulumi from "@pulumi/pulumi"; import * as random from "@pulumi/random"; // Create a private ECR registry. @@ -43,38 +42,3 @@ const image = new docker.Image("my-image", { // Export the resulting image name export const imageName = image.baseImageName; export const repoDigest = image.repoDigest; - -// buildx - -const buildxImage = new docker.buildx.Image("buildx", { - tags: [pulumi.interpolate`${repo.repositoryUrl}:buildx`], - platforms: ["linux/arm64", "linux/amd64"], - push: true, - cacheTo: [ - { - registry: { - mode: "max", - imageManifest: true, - ociMediaTypes: true, - ref: pulumi.interpolate`${repo.repositoryUrl}:cache`, - }, - }, - ], - cacheFrom: [ - { - registry: { - ref: pulumi.interpolate`${repo.repositoryUrl}:cache`, - }, - }, - ], - context: { - location: "app", - }, - registries: [ - { - address: registryInfo.server, - username: registryInfo.username, - password: registryInfo.password, - }, - ], -}); diff --git a/examples/examples_nodejs_test.go b/examples/examples_nodejs_test.go index 615124f9..956ab563 100644 --- a/examples/examples_nodejs_test.go +++ b/examples/examples_nodejs_test.go @@ -30,7 +30,9 @@ import ( "github.com/aws/aws-sdk-go/aws/session" "github.com/aws/aws-sdk-go/service/ecr" "github.com/pulumi/pulumi/pkg/v3/testing/integration" + "github.com/regclient/regclient/types/ref" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" ) func TestBuildxTs(t *testing.T) { @@ -108,6 +110,30 @@ func TestAwsContainerRegistryNode(t *testing.T) { integration.ProgramTest(t, &test) } +func TestAwsContainerRegistryBuildxNode(t *testing.T) { + region := os.Getenv("AWS_REGION") + if region == "" { + t.Skipf("Skipping test due to missing AWS_REGION environment variable") + } + test := getJsOptions(t). + With(integration.ProgramTestOptions{ + Dir: path.Join(getCwd(t), "test-buildx/ecr/ts"), + Config: map[string]string{ + "aws:region": region, + }, + ExtraRuntimeValidation: func(t *testing.T, stack integration.RuntimeValidationStackInfo) { + r, ok := stack.Outputs["ref"].(string) + require.True(t, ok) + assert.NotEmpty(t, r) + ref, err := ref.New(r) + require.NoError(t, err) + assert.NotEmpty(t, ref.Digest) + }, + }) + + integration.ProgramTest(t, &test) +} + func TestDigitaloceanContainerRegistry(t *testing.T) { t.Skipf("Skipping test due to known storageUsageBytes issue https://github.com/pulumi/pulumi-docker/issues/718") diff --git a/examples/go.mod b/examples/go.mod index e6d62662..4290c8c8 100644 --- a/examples/go.mod +++ b/examples/go.mod @@ -6,6 +6,7 @@ require ( github.com/aws/aws-sdk-go v1.49.0 github.com/docker/docker v24.0.7+incompatible github.com/pulumi/pulumi/pkg/v3 v3.107.0 + github.com/regclient/regclient v0.5.7 github.com/stretchr/testify v1.8.4 ) @@ -80,7 +81,7 @@ require ( github.com/golang/snappy v0.0.4 // indirect github.com/google/go-querystring v1.1.0 // indirect github.com/google/s2a-go v0.1.7 // indirect - github.com/google/uuid v1.4.0 // indirect + github.com/google/uuid v1.6.0 // indirect github.com/google/wire v0.5.0 // indirect github.com/googleapis/enterprise-certificate-proxy v0.3.2 // indirect github.com/googleapis/gax-go/v2 v2.12.0 // indirect @@ -156,7 +157,7 @@ require ( github.com/segmentio/encoding v0.3.5 // indirect github.com/sergi/go-diff v1.3.1 // indirect github.com/skeema/knownhosts v1.2.1 // indirect - github.com/spf13/cobra v1.7.0 // indirect + github.com/spf13/cobra v1.8.0 // indirect github.com/spf13/pflag v1.0.5 // indirect github.com/texttheater/golang-levenshtein v1.0.1 // indirect github.com/tweekmonster/luser v0.0.0-20161003172636-3fa38070dbd7 // indirect diff --git a/examples/go.sum b/examples/go.sum index 89b451e5..b14fcaac 100644 --- a/examples/go.sum +++ b/examples/go.sum @@ -832,7 +832,7 @@ github.com/coreos/pkg v0.0.0-20160727233714-3ac0863d7acf/go.mod h1:E3G3o1h8I7cfc github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= -github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= +github.com/cpuguy83/go-md2man/v2 v2.0.3/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/creack/pty v1.1.11/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= @@ -1207,8 +1207,8 @@ github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+ github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.2.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/google/uuid v1.4.0 h1:MtMxsa51/r9yyhkyLsVeVt0B+BGQZzpQiTQ4eHZ8bc4= -github.com/google/uuid v1.4.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= +github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/wire v0.5.0 h1:I7ELFeVBr3yfPIcc8+MWvrjk+3VjbcSzoXm3JVa+jD8= github.com/google/wire v0.5.0/go.mod h1:ngWDr9Qvq3yZA10YrxfyGELY/AFWGVpy9c1LTRi1EoU= github.com/googleapis/enterprise-certificate-proxy v0.0.0-20220520183353-fd19c99a87aa/go.mod h1:17drOmN3MwGY7t0e+Ei9b45FFGA3fBs3x36SsCg1hq8= @@ -1838,6 +1838,8 @@ github.com/pulumi/pulumi/sdk/v3 v3.107.0 h1:bef+ayh9+4KkAqXih4EjlHfQXRY24NWPwWBI github.com/pulumi/pulumi/sdk/v3 v3.107.0/go.mod h1:Ml3rpGfyZlI4zQCG7LN2XDSmH4XUNYdyBwJ3yEr/OpI= github.com/rakyll/embedmd v0.0.0-20171029212350-c8060a0752a2/go.mod h1:7jOTMgqac46PZcF54q6l2hkLEG8op93fZu61KmxWDV4= github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= +github.com/regclient/regclient v0.5.7 h1:d6bXhvz7UYJM+r20ls60RIVdoYh/rp+PygD/dIsJ9UA= +github.com/regclient/regclient v0.5.7/go.mod h1:5QTWmekWy6+gq13Z6U69zsMQV5lvgxg2T7AefHT6BmA= github.com/rivo/uniseg v0.1.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= github.com/rivo/uniseg v0.4.4 h1:8TfxU8dW6PdqD27gjM8MVNuicgxIjxpm4K7x4jp8sis= @@ -1916,8 +1918,8 @@ github.com/spf13/cobra v0.0.2-0.20171109065643-2da4a54c5cee/go.mod h1:1l0Ry5zgKv github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= github.com/spf13/cobra v1.0.0/go.mod h1:/6GTrnGXV9HjY+aR4k0oJ5tcvakLuG6EuKReYlHNrgE= github.com/spf13/cobra v1.1.3/go.mod h1:pGADOWyqRD/YMrPZigI/zbliZ2wVD/23d+is3pSWzOo= -github.com/spf13/cobra v1.7.0 h1:hyqWnYt1ZQShIddO5kBpj3vu05/++x6tJ6dg8EC572I= -github.com/spf13/cobra v1.7.0/go.mod h1:uLxZILRyS/50WlhOIKD7W6V5bgeIt+4sICxh6uRMrb0= +github.com/spf13/cobra v1.8.0 h1:7aJaZx1B85qltLMc546zn58BxxfZdR/W22ej9CFoEf0= +github.com/spf13/cobra v1.8.0/go.mod h1:WXLWApfZ71AjXPya3WOlMsY9yMs7YeiHhFVlvLyhcho= github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= github.com/spf13/pflag v0.0.0-20170130214245-9ff6c6923cff/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= github.com/spf13/pflag v1.0.1-0.20171106142849-4c012f6dcd95/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= diff --git a/examples/test-buildx/ecr/ts/.gitignore b/examples/test-buildx/ecr/ts/.gitignore new file mode 100644 index 00000000..c6958891 --- /dev/null +++ b/examples/test-buildx/ecr/ts/.gitignore @@ -0,0 +1,2 @@ +/bin/ +/node_modules/ diff --git a/examples/test-buildx/ecr/ts/Pulumi.yaml b/examples/test-buildx/ecr/ts/Pulumi.yaml new file mode 100644 index 00000000..15f575bd --- /dev/null +++ b/examples/test-buildx/ecr/ts/Pulumi.yaml @@ -0,0 +1,3 @@ +name: buildx-ecr +runtime: nodejs +description: A minimal AWS TypeScript Pulumi program diff --git a/examples/test-buildx/ecr/ts/app/Dockerfile b/examples/test-buildx/ecr/ts/app/Dockerfile new file mode 100644 index 00000000..c3e1241d --- /dev/null +++ b/examples/test-buildx/ecr/ts/app/Dockerfile @@ -0,0 +1,3 @@ +FROM nginx +RUN echo "

Hi from Pulumi!

" > \ + /usr/share/nginx/html/index.html diff --git a/examples/test-buildx/ecr/ts/index.ts b/examples/test-buildx/ecr/ts/index.ts new file mode 100644 index 00000000..7b96c27e --- /dev/null +++ b/examples/test-buildx/ecr/ts/index.ts @@ -0,0 +1,53 @@ +import * as aws from "@pulumi/aws"; +import * as docker from "@pulumi/docker"; +import * as pulumi from "@pulumi/pulumi"; + +// Create a private ECR registry WITHOUT force delete -- our image should be +// deleted during teardown. +const repo = new aws.ecr.Repository("my-repo", {}); + +// Get registry info (creds and endpoint) so we can build/publish to it. +const registryInfo = repo.registryId.apply(async (id) => { + const credentials = await aws.ecr.getCredentials({ registryId: id }); + const decodedCredentials = Buffer.from( + credentials.authorizationToken, + "base64" + ).toString(); + const [username, password] = decodedCredentials.split(":"); + if (!password || !username) { + throw new Error("Invalid credentials"); + } + return { + server: credentials.proxyEndpoint, + username: username, + password: password, + }; +}); + +// Build and publish the image. +const image = new docker.buildx.Image("buildx-pushed-multi-plat", { + tags: [pulumi.interpolate`${repo.repositoryUrl}:buildx`], + push: true, + context: { + location: "app", + }, + registries: [ + { + address: registryInfo.server, + username: registryInfo.username, + password: registryInfo.password, + }, + ], +}); + +const notPushed = new docker.buildx.Image("buildx-not-pushed", { + tags: [pulumi.interpolate`${repo.repositoryUrl}:buildx`], + platforms: ["linux/arm64", "linux/amd64"], + push: false, + context: { + location: "app", + }, +}); + +// Export the resulting image name +export const ref = image.ref; diff --git a/examples/test-buildx/ecr/ts/package.json b/examples/test-buildx/ecr/ts/package.json new file mode 100644 index 00000000..8122f8f6 --- /dev/null +++ b/examples/test-buildx/ecr/ts/package.json @@ -0,0 +1,11 @@ +{ + "name": "buildx-ecr", + "devDependencies": { + "@types/node": "^14.0.0" + }, + "dependencies": { + "@pulumi/aws": "^6.10.0", + "@pulumi/pulumi": "^3.0.0", + "@pulumi/random": "^4.14.0" + } +} diff --git a/examples/test-buildx/ecr/ts/tsconfig.json b/examples/test-buildx/ecr/ts/tsconfig.json new file mode 100644 index 00000000..ab65afa6 --- /dev/null +++ b/examples/test-buildx/ecr/ts/tsconfig.json @@ -0,0 +1,18 @@ +{ + "compilerOptions": { + "strict": true, + "outDir": "bin", + "target": "es2016", + "module": "commonjs", + "moduleResolution": "node", + "sourceMap": true, + "experimentalDecorators": true, + "pretty": true, + "noFallthroughCasesInSwitch": true, + "noImplicitReturns": true, + "forceConsistentCasingInFileNames": true + }, + "files": [ + "index.ts" + ] +} diff --git a/provider/cmd/pulumi-resource-docker/schema.json b/provider/cmd/pulumi-resource-docker/schema.json index 8462668d..2ff32397 100644 --- a/provider/cmd/pulumi-resource-docker/schema.json +++ b/provider/cmd/pulumi-resource-docker/schema.json @@ -511,7 +511,7 @@ }, "imageManifest": { "type": "boolean", - "description": "Export cache manifest as an OCI-compatible image manifest instead of a\nmanifest list (requires OCI media types).\n\nDefaults to `false`.", + "description": "Export cache manifest as an OCI-compatible image manifest instead of a\nmanifest list. Requires `ociMediaTypes` to also be `true`.\n\nSome registries like AWS ECR will not work with caching if this is\n`false`.\n\nDefaults to `false` to match Docker's default behavior.", "default": false }, "mode": { @@ -3080,7 +3080,7 @@ }, "resources": { "docker:buildx/image:Image": { - "description": "A Docker image built using buildx -- Docker's interface to the improved\nBuildKit backend.\n\n## Stability\n\n**This resource is experimental and subject to change.**\n\nAPI types are unstable. Subsequent releases _may_ require manual edits\nto your state file(s) in order to adopt API changes.\n\n`retainOnDelete: true` is recommended with this resource until it is\nstable. This enables future API changes to be adopted more easily by renaming\nresources.\n\nOnly use this resource if you understand and accept the risks.\n\n## Migrating v3 and v4 Image resources\n\nThe `buildx.Image` resource provides a superset of functionality over the `Image` resources available in versions 3 and 4 of the Pulumi Docker provider.\nExisting `Image` resources can be converted to `build.Image` resources with minor modifications.\n\n### Behavioral differences\n\nThere are several key behavioral differences to keep in mind when transitioning images to the new `buildx.Image` resource.\n\n#### Previews\n\nVersion `3.x` of the Pulumi Docker provider always builds images during preview operations.\nThis is helpful as a safeguard to prevent \"broken\" images from merging, but users found the behavior unnecessarily redundant when running previews and updates locally.\n\nVersion `4.x` changed build-on-preview behavior to be opt-in.\nBy default, `v4.x` `Image` resources do _not_ build during previews, but this behavior can be toggled with the `buildOnPreview` option.\nSome users felt this made previews in CI less helpful because they no longer detected bad images by default.\n\nThe default behavior of the `buildx.Image` resource has been changed to strike a better balance between CI use cases and manual updates.\nBy default, Pulumi will now only build `buildx.Image` resources during previews when it detects a CI environment like GitHub Actions.\nPreviews run in non-CI environments will not build images.\nThis behavior is still configurable with `buildOnPreview`.\n\n#### Push behavior\n\nVersions `3.x` and `4.x` of the Pulumi Docker provider attempt to push images to remote registries by default.\nThey expose a `skipPush: true` option to disable pushing.\n\nThe `buildx.Image` resource matches the Docker CLI's behavior and does not push images anywhere by default.\n\nTo push images to a registry you can include `push: true` (equivalent to Docker's `--push` flag) or configure an `export` of type `registry` (equivalent to Docker's `--output type=registry`).\nLike Docker, if an image is configured without exports you will see a warning with instructions for how to enable pushing, but the build will still proceed normally.\n\n#### Secrets\n\nVersion `3.x` of the Pulumi Docker provider supports secrets by way of the `extraOptions` field.\n\nVersion `4.x` of the Pulumi Docker provider does not support secrets.\n\nThe `buildx.Image` resource supports secrets but does not require those secrets to exist on-disk or in environment variables.\nInstead, they should be passed directly as values.\n(Please be sure to familiarize yourself with Pulumi's [native secret handling](https://www.pulumi.com/docs/concepts/secrets/).)\nPulumi also provides [ESC](https://www.pulumi.com/product/esc/) to make it easier to share secrets across stacks and environments.\n\n#### Caching\n\nVersion `3.x` of the Pulumi Docker provider exposes `cacheFrom: bool | { stages: [...] }`.\nIt builds targets individually and pushes them to separate images for caching.\n\nVersion `4.x` exposes a similar parameter `cacheFrom: { images: [...] }` which pushes and pulls inline caches.\n\nBoth versions 3 and 4 require specific environment variables to be set and deviate from Docker's native caching behavior.\nThis can result in inefficient builds due to unnecessary image pulls, repeated file transfers, etc.\n\nThe `buildx.Image` resource delegates all caching behavior to Docker.\n`cacheFrom` and `cacheTo` options (equivalent to Docker's `--cache-to` and `--cache-from`) are exposed and provide additional cache targets, such as local disk, S3 storage, etc.\n\n#### Outputs\n\nVersions `3.x` and `4.x` of the provider exposed a `repoDigest` output which was a fully qualified tag with digest.\nIn `4.x` this could also be a single sha256 hash if the image wasn't pushed.\n\nUnlike earlier providers the `buildx.Image` resource can push multiple tags.\nAs a convenience, it exposes a `ref` output consisting of a tag with digest as long as the image was pushed.\nIf multiple tags were pushed this uses one at random.\n\nIf you need more control over tag references you can use the `digest` output, which is always a single sha256 hash as long as the image was exported somewhere.\n\n#### Tag deletion and refreshes\n\nVersions 3 and 4 of Pulumi Docker provider do not delete tags when the `Image` resource is deleted, nor do they confirm expected tags exist during `refresh` operations.\n\nThe `buidx.Image` will query your registries during `refresh` to ensure the expected tags exist.\nIf any are missing a subsequent `update` will push them.\n\nWhen a `buildx.Image` is deleted, it will _attempt_ to also delete any pushed tags.\nDeletion of remote tags is not guaranteed, because not all registries currently support this operation (`docker.io` in particular).\n\nUse the [`retainOnDelete: true`](https://www.pulumi.com/docs/concepts/options/retainondelete/) option if you do not want tags deleted.\n\n### Example migration\n\nExamples of \"fully-featured\" `v3` and `v4` `Image` resources are shown below, along with an example `buildx.Image` resource showing how they would look after migration.\n\nThe `v3` resource leverages `buildx` via a `DOCKER_BUILDKIT` environment variable and CLI flags passed in with `extraOption`.\nAfter migration, the environment variable is no longer needed and CLI flags are now properties on the `buildx.Image`.\nIn almost all cases, properties of `buildx.Image` are named after the Docker CLI flag they correspond to.\n\nThe `v4` resource is less functional than its `v3` counterpart because it lacks the flexibility of `extraOptions`.\nIt it is shown with parameters similar to the `v3` example for completeness.\n\n{{% examples %}}\n## Example Usage\n{{% example %}}\n### v3/v4 migration\n\n```typescript\n\n// v3 Image\nconst v3 = new docker.Image(\"v3-image\", {\n imageName: \"myregistry.com/user/repo:latest\",\n localImageName: \"local-tag\",\n skipPush: false,\n build: {\n dockerfile: \"./Dockerfile\",\n context: \"../app\",\n target: \"mytarget\",\n args: {\n MY_BUILD_ARG: \"foo\",\n },\n env: {\n DOCKER_BUILDKIT: \"1\",\n },\n extraOptions: [\n \"--cache-from\",\n \"type=registry,myregistry.com/user/repo:cache\",\n \"--cache-to\",\n \"type=registry,myregistry.com/user/repo:cache\",\n \"--add-host\",\n \"metadata.google.internal:169.254.169.254\",\n \"--secret\",\n \"id=mysecret,src=/local/secret\",\n \"--ssh\",\n \"default=/home/runner/.ssh/id_ed25519\",\n \"--network\",\n \"host\",\n \"--platform\",\n \"linux/amd64\",\n ],\n },\n registry: {\n server: \"myregistry.com\",\n username: \"username\",\n password: pulumi.secret(\"password\"),\n },\n});\n\n// v3 Image after migrating to buildx.Image\nconst v3Migrated = new docker.buildx.Image(\"v3-to-buildx\", {\n tags: [\"myregistry.com/user/repo:latest\", \"local-tag\"],\n push: true,\n dockerfile: {\n location: \"./Dockerfile\",\n },\n context: {\n location: \"../app\",\n },\n targets: [\"mytarget\"],\n buildArgs: {\n MY_BUILD_ARG: \"foo\",\n },\n cacheFrom: [{ registry: { ref: \"myregistry.com/user/repo:cache\" } }],\n cacheTo: [{ registry: { ref: \"myregistry.com/user/repo:cache\" } }],\n secrets: {\n mysecret: \"value\",\n },\n addHosts: [\"metadata.google.internal:169.254.169.254\"],\n ssh: {\n default: [\"/home/runner/.ssh/id_ed25519\"],\n },\n network: \"host\",\n platforms: [\"linux/amd64\"],\n registries: [{\n address: \"myregistry.com\",\n username: \"username\",\n password: pulumi.secret(\"password\"),\n }],\n});\n\n\n// v4 Image\nconst v4 = new docker.Image(\"v4-image\", {\n imageName: \"myregistry.com/user/repo:latest\",\n skipPush: false,\n build: {\n dockerfile: \"./Dockerfile\",\n context: \"../app\",\n target: \"mytarget\",\n args: {\n MY_BUILD_ARG: \"foo\",\n },\n cacheFrom: {\n images: [\"myregistry.com/user/repo:cache\"],\n },\n addHosts: [\"metadata.google.internal:169.254.169.254\"],\n network: \"host\",\n platform: \"linux/amd64\",\n },\n buildOnPreview: true,\n registry: {\n server: \"myregistry.com\",\n username: \"username\",\n password: pulumi.secret(\"password\"),\n },\n});\n\n// v4 Image after migrating to buildx.Image\nconst v4Migrated = new docker.buildx.Image(\"v4-to-buildx\", {\n tags: [\"myregistry.com/user/repo:latest\"],\n push: true,\n dockerfile: {\n location: \"./Dockerfile\",\n },\n context: {\n location: \"../app\",\n },\n targets: [\"mytarget\"],\n buildArgs: {\n MY_BUILD_ARG: \"foo\",\n },\n cacheFrom: [{ registry: { ref: \"myregistry.com/user/repo:cache\" } }],\n cacheTo: [{ registry: { ref: \"myregistry.com/user/repo:cache\" } }],\n addHosts: [\"metadata.google.internal:169.254.169.254\"],\n network: \"host\",\n platforms: [\"linux/amd64\"],\n registries: [{\n address: \"myregistry.com\",\n username: \"username\",\n password: pulumi.secret(\"password\"),\n }],\n});\n\n```\n\n{{% /example %}}\n\n\n{{% examples %}}\n## Example Usage\n{{% example %}}\n### Push to AWS ECR with caching\n\n```typescript\nimport * as pulumi from \"@pulumi/pulumi\";\nimport * as aws from \"@pulumi/aws\";\nimport * as docker from \"@pulumi/docker\";\n\nconst ecrRepository = new aws.ecr.Repository(\"ecr-repository\", {});\nconst authToken = aws.ecr.getAuthorizationTokenOutput({\n registryId: ecrRepository.registryId,\n});\nconst myImage = new docker.buildx.Image(\"my-image\", {\n cacheFrom: [{\n registry: {\n ref: pulumi.interpolate`${ecrRepository.repositoryUrl}:cache`,\n },\n }],\n cacheTo: [{\n registry: {\n imageManifest: true,\n ociMediaTypes: true,\n ref: pulumi.interpolate`${ecrRepository.repositoryUrl}:cache`,\n },\n }],\n context: {\n location: \"./app\",\n },\n push: true,\n registries: [{\n address: ecrRepository.repositoryUrl,\n password: authToken.apply(authToken =\u003e authToken.password),\n username: authToken.apply(authToken =\u003e authToken.userName),\n }],\n tags: [pulumi.interpolate`${ecrRepository.repositoryUrl}:latest`],\n});\nexport const ref = myImage.ref;\n```\n```python\nimport pulumi\nimport pulumi_aws as aws\nimport pulumi_docker as docker\n\necr_repository = aws.ecr.Repository(\"ecr-repository\")\nauth_token = aws.ecr.get_authorization_token_output(registry_id=ecr_repository.registry_id)\nmy_image = docker.buildx.Image(\"my-image\",\n cache_from=[docker.buildx.CacheFromArgs(\n registry=docker.buildx.CacheFromRegistryArgs(\n ref=ecr_repository.repository_url.apply(lambda repository_url: f\"{repository_url}:cache\"),\n ),\n )],\n cache_to=[docker.buildx.CacheToArgs(\n registry=docker.buildx.CacheToRegistryArgs(\n image_manifest=True,\n oci_media_types=True,\n ref=ecr_repository.repository_url.apply(lambda repository_url: f\"{repository_url}:cache\"),\n ),\n )],\n context=docker.buildx.BuildContextArgs(\n location=\"./app\",\n ),\n push=True,\n registries=[docker.buildx.RegistryAuthArgs(\n address=ecr_repository.repository_url,\n password=auth_token.password,\n username=auth_token.user_name,\n )],\n tags=[ecr_repository.repository_url.apply(lambda repository_url: f\"{repository_url}:latest\")])\npulumi.export(\"ref\", my_image.ref)\n```\n```csharp\nusing System.Collections.Generic;\nusing System.Linq;\nusing Pulumi;\nusing Aws = Pulumi.Aws;\nusing Docker = Pulumi.Docker;\n\nreturn await Deployment.RunAsync(() =\u003e \n{\n var ecrRepository = new Aws.Ecr.Repository(\"ecr-repository\");\n\n var authToken = Aws.Ecr.GetAuthorizationToken.Invoke(new()\n {\n RegistryId = ecrRepository.RegistryId,\n });\n\n var myImage = new Docker.Buildx.Image(\"my-image\", new()\n {\n CacheFrom = new[]\n {\n new Docker.Buildx.Inputs.CacheFromArgs\n {\n Registry = new Docker.Buildx.Inputs.CacheFromRegistryArgs\n {\n Ref = ecrRepository.RepositoryUrl.Apply(repositoryUrl =\u003e $\"{repositoryUrl}:cache\"),\n },\n },\n },\n CacheTo = new[]\n {\n new Docker.Buildx.Inputs.CacheToArgs\n {\n Registry = new Docker.Buildx.Inputs.CacheToRegistryArgs\n {\n ImageManifest = true,\n OciMediaTypes = true,\n Ref = ecrRepository.RepositoryUrl.Apply(repositoryUrl =\u003e $\"{repositoryUrl}:cache\"),\n },\n },\n },\n Context = new Docker.Buildx.Inputs.BuildContextArgs\n {\n Location = \"./app\",\n },\n Push = true,\n Registries = new[]\n {\n new Docker.Buildx.Inputs.RegistryAuthArgs\n {\n Address = ecrRepository.RepositoryUrl,\n Password = authToken.Apply(getAuthorizationTokenResult =\u003e getAuthorizationTokenResult.Password),\n Username = authToken.Apply(getAuthorizationTokenResult =\u003e getAuthorizationTokenResult.UserName),\n },\n },\n Tags = new[]\n {\n ecrRepository.RepositoryUrl.Apply(repositoryUrl =\u003e $\"{repositoryUrl}:latest\"),\n },\n });\n\n return new Dictionary\u003cstring, object?\u003e\n {\n [\"ref\"] = myImage.Ref,\n };\n});\n\n```\n```go\npackage main\n\nimport (\n\t\"fmt\"\n\n\t\"github.com/pulumi/pulumi-aws/sdk/v6/go/aws/ecr\"\n\t\"github.com/pulumi/pulumi-docker/sdk/v4/go/docker/buildx\"\n\t\"github.com/pulumi/pulumi/sdk/v3/go/pulumi\"\n)\n\nfunc main() {\n\tpulumi.Run(func(ctx *pulumi.Context) error {\n\t\tecrRepository, err := ecr.NewRepository(ctx, \"ecr-repository\", nil)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\tauthToken := ecr.GetAuthorizationTokenOutput(ctx, ecr.GetAuthorizationTokenOutputArgs{\n\t\t\tRegistryId: ecrRepository.RegistryId,\n\t\t}, nil)\n\t\tmyImage, err := buildx.NewImage(ctx, \"my-image\", \u0026buildx.ImageArgs{\n\t\t\tCacheFrom: buildx.CacheFromArray{\n\t\t\t\t\u0026buildx.CacheFromArgs{\n\t\t\t\t\tRegistry: \u0026buildx.CacheFromRegistryArgs{\n\t\t\t\t\t\tRef: ecrRepository.RepositoryUrl.ApplyT(func(repositoryUrl string) (string, error) {\n\t\t\t\t\t\t\treturn fmt.Sprintf(\"%v:cache\", repositoryUrl), nil\n\t\t\t\t\t\t}).(pulumi.StringOutput),\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\tCacheTo: buildx.CacheToArray{\n\t\t\t\t\u0026buildx.CacheToArgs{\n\t\t\t\t\tRegistry: \u0026buildx.CacheToRegistryArgs{\n\t\t\t\t\t\tImageManifest: pulumi.Bool(true),\n\t\t\t\t\t\tOciMediaTypes: pulumi.Bool(true),\n\t\t\t\t\t\tRef: ecrRepository.RepositoryUrl.ApplyT(func(repositoryUrl string) (string, error) {\n\t\t\t\t\t\t\treturn fmt.Sprintf(\"%v:cache\", repositoryUrl), nil\n\t\t\t\t\t\t}).(pulumi.StringOutput),\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\tContext: \u0026buildx.BuildContextArgs{\n\t\t\t\tLocation: pulumi.String(\"./app\"),\n\t\t\t},\n\t\t\tPush: pulumi.Bool(true),\n\t\t\tRegistries: buildx.RegistryAuthArray{\n\t\t\t\t\u0026buildx.RegistryAuthArgs{\n\t\t\t\t\tAddress: ecrRepository.RepositoryUrl,\n\t\t\t\t\tPassword: authToken.ApplyT(func(authToken ecr.GetAuthorizationTokenResult) (*string, error) {\n\t\t\t\t\t\treturn \u0026authToken.Password, nil\n\t\t\t\t\t}).(pulumi.StringPtrOutput),\n\t\t\t\t\tUsername: authToken.ApplyT(func(authToken ecr.GetAuthorizationTokenResult) (*string, error) {\n\t\t\t\t\t\treturn \u0026authToken.UserName, nil\n\t\t\t\t\t}).(pulumi.StringPtrOutput),\n\t\t\t\t},\n\t\t\t},\n\t\t\tTags: pulumi.StringArray{\n\t\t\t\tecrRepository.RepositoryUrl.ApplyT(func(repositoryUrl string) (string, error) {\n\t\t\t\t\treturn fmt.Sprintf(\"%v:latest\", repositoryUrl), nil\n\t\t\t\t}).(pulumi.StringOutput),\n\t\t\t},\n\t\t})\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\tctx.Export(\"ref\", myImage.Ref)\n\t\treturn nil\n\t})\n}\n```\n```yaml\ndescription: Push to AWS ECR with caching\nname: ecr\noutputs:\n ref: ${my-image.ref}\nresources:\n ecr-repository:\n type: aws:ecr:Repository\n my-image:\n properties:\n cacheFrom:\n - registry:\n ref: ${ecr-repository.repositoryUrl}:cache\n cacheTo:\n - registry:\n imageManifest: true\n ociMediaTypes: true\n ref: ${ecr-repository.repositoryUrl}:cache\n context:\n location: ./app\n push: true\n registries:\n - address: ${ecr-repository.repositoryUrl}\n password: ${auth-token.password}\n username: ${auth-token.userName}\n tags:\n - ${ecr-repository.repositoryUrl}:latest\n type: docker:buildx/image:Image\nruntime: yaml\nvariables:\n auth-token:\n fn::aws:ecr:getAuthorizationToken:\n registryId: ${ecr-repository.registryId}\n```\n```java\npackage generated_program;\n\nimport com.pulumi.Context;\nimport com.pulumi.Pulumi;\nimport com.pulumi.core.Output;\nimport com.pulumi.aws.ecr.Repository;\nimport com.pulumi.aws.ecr.EcrFunctions;\nimport com.pulumi.aws.ecr.inputs.GetAuthorizationTokenArgs;\nimport com.pulumi.docker.buildx.Image;\nimport com.pulumi.docker.buildx.ImageArgs;\nimport com.pulumi.docker.buildx.inputs.CacheFromArgs;\nimport com.pulumi.docker.buildx.inputs.CacheFromRegistryArgs;\nimport com.pulumi.docker.buildx.inputs.CacheToArgs;\nimport com.pulumi.docker.buildx.inputs.CacheToRegistryArgs;\nimport com.pulumi.docker.buildx.inputs.BuildContextArgs;\nimport com.pulumi.docker.buildx.inputs.RegistryAuthArgs;\nimport java.util.List;\nimport java.util.ArrayList;\nimport java.util.Map;\nimport java.io.File;\nimport java.nio.file.Files;\nimport java.nio.file.Paths;\n\npublic class App {\n public static void main(String[] args) {\n Pulumi.run(App::stack);\n }\n\n public static void stack(Context ctx) {\n var ecrRepository = new Repository(\"ecrRepository\");\n\n final var authToken = EcrFunctions.getAuthorizationToken(GetAuthorizationTokenArgs.builder()\n .registryId(ecrRepository.registryId())\n .build());\n\n var myImage = new Image(\"myImage\", ImageArgs.builder() \n .cacheFrom(CacheFromArgs.builder()\n .registry(CacheFromRegistryArgs.builder()\n .ref(ecrRepository.repositoryUrl().applyValue(repositoryUrl -\u003e String.format(\"%s:cache\", repositoryUrl)))\n .build())\n .build())\n .cacheTo(CacheToArgs.builder()\n .registry(CacheToRegistryArgs.builder()\n .imageManifest(true)\n .ociMediaTypes(true)\n .ref(ecrRepository.repositoryUrl().applyValue(repositoryUrl -\u003e String.format(\"%s:cache\", repositoryUrl)))\n .build())\n .build())\n .context(BuildContextArgs.builder()\n .location(\"./app\")\n .build())\n .push(true)\n .registries(RegistryAuthArgs.builder()\n .address(ecrRepository.repositoryUrl())\n .password(authToken.applyValue(getAuthorizationTokenResult -\u003e getAuthorizationTokenResult).applyValue(authToken -\u003e authToken.applyValue(getAuthorizationTokenResult -\u003e getAuthorizationTokenResult.password())))\n .username(authToken.applyValue(getAuthorizationTokenResult -\u003e getAuthorizationTokenResult).applyValue(authToken -\u003e authToken.applyValue(getAuthorizationTokenResult -\u003e getAuthorizationTokenResult.userName())))\n .build())\n .tags(ecrRepository.repositoryUrl().applyValue(repositoryUrl -\u003e String.format(\"%s:latest\", repositoryUrl)))\n .build());\n\n ctx.export(\"ref\", myImage.ref());\n }\n}\n```\n{{% /example %}}\n{{% example %}}\n### Multi-platform image\n\n```typescript\nimport * as pulumi from \"@pulumi/pulumi\";\nimport * as docker from \"@pulumi/docker\";\n\nconst image = new docker.buildx.Image(\"image\", {\n context: {\n location: \"app\",\n },\n platforms: [\n docker.buildx.image.Platform.Plan9_amd64,\n docker.buildx.image.Platform.Plan9_386,\n ],\n});\n```\n```python\nimport pulumi\nimport pulumi_docker as docker\n\nimage = docker.buildx.Image(\"image\",\n context=docker.buildx.BuildContextArgs(\n location=\"app\",\n ),\n platforms=[\n docker.buildx/image.Platform.PLAN9_AMD64,\n docker.buildx/image.Platform.PLAN9_386,\n ])\n```\n```csharp\nusing System.Collections.Generic;\nusing System.Linq;\nusing Pulumi;\nusing Docker = Pulumi.Docker;\n\nreturn await Deployment.RunAsync(() =\u003e \n{\n var image = new Docker.Buildx.Image(\"image\", new()\n {\n Context = new Docker.Buildx.Inputs.BuildContextArgs\n {\n Location = \"app\",\n },\n Platforms = new[]\n {\n Docker.Buildx.Image.Platform.Plan9_amd64,\n Docker.Buildx.Image.Platform.Plan9_386,\n },\n });\n\n});\n\n```\n```go\npackage main\n\nimport (\n\t\"github.com/pulumi/pulumi-docker/sdk/v4/go/docker/buildx\"\n\t\"github.com/pulumi/pulumi/sdk/v3/go/pulumi\"\n)\n\nfunc main() {\n\tpulumi.Run(func(ctx *pulumi.Context) error {\n\t\t_, err := buildx.NewImage(ctx, \"image\", \u0026buildx.ImageArgs{\n\t\t\tContext: \u0026buildx.BuildContextArgs{\n\t\t\t\tLocation: pulumi.String(\"app\"),\n\t\t\t},\n\t\t\tPlatforms: buildx.PlatformArray{\n\t\t\t\tbuildx.Platform_Plan9_amd64,\n\t\t\t\tbuildx.Platform_Plan9_386,\n\t\t\t},\n\t\t})\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\treturn nil\n\t})\n}\n```\n```yaml\ndescription: Multi-platform image\nname: multi-platform\nresources:\n image:\n properties:\n context:\n location: app\n platforms:\n - plan9/amd64\n - plan9/386\n type: docker:buildx/image:Image\nruntime: yaml\n```\n```java\npackage generated_program;\n\nimport com.pulumi.Context;\nimport com.pulumi.Pulumi;\nimport com.pulumi.core.Output;\nimport com.pulumi.docker.buildx.Image;\nimport com.pulumi.docker.buildx.ImageArgs;\nimport com.pulumi.docker.buildx.inputs.BuildContextArgs;\nimport java.util.List;\nimport java.util.ArrayList;\nimport java.util.Map;\nimport java.io.File;\nimport java.nio.file.Files;\nimport java.nio.file.Paths;\n\npublic class App {\n public static void main(String[] args) {\n Pulumi.run(App::stack);\n }\n\n public static void stack(Context ctx) {\n var image = new Image(\"image\", ImageArgs.builder() \n .context(BuildContextArgs.builder()\n .location(\"app\")\n .build())\n .platforms( \n \"plan9/amd64\",\n \"plan9/386\")\n .build());\n\n }\n}\n```\n{{% /example %}}\n{{% example %}}\n### Registry export\n\n```typescript\nimport * as pulumi from \"@pulumi/pulumi\";\nimport * as docker from \"@pulumi/docker\";\n\nconst image = new docker.buildx.Image(\"image\", {\n context: {\n location: \"app\",\n },\n push: true,\n registries: [{\n address: \"docker.io\",\n password: dockerHubPassword,\n username: \"pulumibot\",\n }],\n tags: [\"docker.io/pulumi/pulumi:3.107.0\"],\n});\nexport const ref = myImage.ref;\n```\n```python\nimport pulumi\nimport pulumi_docker as docker\n\nimage = docker.buildx.Image(\"image\",\n context=docker.buildx.BuildContextArgs(\n location=\"app\",\n ),\n push=True,\n registries=[docker.buildx.RegistryAuthArgs(\n address=\"docker.io\",\n password=docker_hub_password,\n username=\"pulumibot\",\n )],\n tags=[\"docker.io/pulumi/pulumi:3.107.0\"])\npulumi.export(\"ref\", my_image[\"ref\"])\n```\n```csharp\nusing System.Collections.Generic;\nusing System.Linq;\nusing Pulumi;\nusing Docker = Pulumi.Docker;\n\nreturn await Deployment.RunAsync(() =\u003e \n{\n var image = new Docker.Buildx.Image(\"image\", new()\n {\n Context = new Docker.Buildx.Inputs.BuildContextArgs\n {\n Location = \"app\",\n },\n Push = true,\n Registries = new[]\n {\n new Docker.Buildx.Inputs.RegistryAuthArgs\n {\n Address = \"docker.io\",\n Password = dockerHubPassword,\n Username = \"pulumibot\",\n },\n },\n Tags = new[]\n {\n \"docker.io/pulumi/pulumi:3.107.0\",\n },\n });\n\n return new Dictionary\u003cstring, object?\u003e\n {\n [\"ref\"] = myImage.Ref,\n };\n});\n\n```\n```go\npackage main\n\nimport (\n\t\"github.com/pulumi/pulumi-docker/sdk/v4/go/docker/buildx\"\n\t\"github.com/pulumi/pulumi/sdk/v3/go/pulumi\"\n)\n\nfunc main() {\n\tpulumi.Run(func(ctx *pulumi.Context) error {\n\t\t_, err := buildx.NewImage(ctx, \"image\", \u0026buildx.ImageArgs{\n\t\t\tContext: \u0026buildx.BuildContextArgs{\n\t\t\t\tLocation: pulumi.String(\"app\"),\n\t\t\t},\n\t\t\tPush: pulumi.Bool(true),\n\t\t\tRegistries: buildx.RegistryAuthArray{\n\t\t\t\t\u0026buildx.RegistryAuthArgs{\n\t\t\t\t\tAddress: pulumi.String(\"docker.io\"),\n\t\t\t\t\tPassword: pulumi.Any(dockerHubPassword),\n\t\t\t\t\tUsername: pulumi.String(\"pulumibot\"),\n\t\t\t\t},\n\t\t\t},\n\t\t\tTags: pulumi.StringArray{\n\t\t\t\tpulumi.String(\"docker.io/pulumi/pulumi:3.107.0\"),\n\t\t\t},\n\t\t})\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\tctx.Export(\"ref\", myImage.Ref)\n\t\treturn nil\n\t})\n}\n```\n```yaml\ndescription: Registry export\nname: registry\noutputs:\n ref: ${my-image.ref}\nresources:\n image:\n properties:\n context:\n location: app\n push: true\n registries:\n - address: docker.io\n password: ${dockerHubPassword}\n username: pulumibot\n tags:\n - docker.io/pulumi/pulumi:3.107.0\n type: docker:buildx/image:Image\nruntime: yaml\n```\n```java\npackage generated_program;\n\nimport com.pulumi.Context;\nimport com.pulumi.Pulumi;\nimport com.pulumi.core.Output;\nimport com.pulumi.docker.buildx.Image;\nimport com.pulumi.docker.buildx.ImageArgs;\nimport com.pulumi.docker.buildx.inputs.BuildContextArgs;\nimport com.pulumi.docker.buildx.inputs.RegistryAuthArgs;\nimport java.util.List;\nimport java.util.ArrayList;\nimport java.util.Map;\nimport java.io.File;\nimport java.nio.file.Files;\nimport java.nio.file.Paths;\n\npublic class App {\n public static void main(String[] args) {\n Pulumi.run(App::stack);\n }\n\n public static void stack(Context ctx) {\n var image = new Image(\"image\", ImageArgs.builder() \n .context(BuildContextArgs.builder()\n .location(\"app\")\n .build())\n .push(true)\n .registries(RegistryAuthArgs.builder()\n .address(\"docker.io\")\n .password(dockerHubPassword)\n .username(\"pulumibot\")\n .build())\n .tags(\"docker.io/pulumi/pulumi:3.107.0\")\n .build());\n\n ctx.export(\"ref\", myImage.ref());\n }\n}\n```\n{{% /example %}}\n{{% example %}}\n### Caching\n\n```typescript\nimport * as pulumi from \"@pulumi/pulumi\";\nimport * as docker from \"@pulumi/docker\";\n\nconst image = new docker.buildx.Image(\"image\", {\n cacheFrom: [{\n local: {\n src: \"tmp/cache\",\n },\n }],\n cacheTo: [{\n local: {\n dest: \"tmp/cache\",\n mode: docker.buildx.image.CacheMode.Max,\n },\n }],\n context: {\n location: \"app\",\n },\n});\n```\n```python\nimport pulumi\nimport pulumi_docker as docker\n\nimage = docker.buildx.Image(\"image\",\n cache_from=[docker.buildx.CacheFromArgs(\n local=docker.buildx.CacheFromLocalArgs(\n src=\"tmp/cache\",\n ),\n )],\n cache_to=[docker.buildx.CacheToArgs(\n local=docker.buildx.CacheToLocalArgs(\n dest=\"tmp/cache\",\n mode=docker.buildx/image.CacheMode.MAX,\n ),\n )],\n context=docker.buildx.BuildContextArgs(\n location=\"app\",\n ))\n```\n```csharp\nusing System.Collections.Generic;\nusing System.Linq;\nusing Pulumi;\nusing Docker = Pulumi.Docker;\n\nreturn await Deployment.RunAsync(() =\u003e \n{\n var image = new Docker.Buildx.Image(\"image\", new()\n {\n CacheFrom = new[]\n {\n new Docker.Buildx.Inputs.CacheFromArgs\n {\n Local = new Docker.Buildx.Inputs.CacheFromLocalArgs\n {\n Src = \"tmp/cache\",\n },\n },\n },\n CacheTo = new[]\n {\n new Docker.Buildx.Inputs.CacheToArgs\n {\n Local = new Docker.Buildx.Inputs.CacheToLocalArgs\n {\n Dest = \"tmp/cache\",\n Mode = Docker.Buildx.Image.CacheMode.Max,\n },\n },\n },\n Context = new Docker.Buildx.Inputs.BuildContextArgs\n {\n Location = \"app\",\n },\n });\n\n});\n\n```\n```go\npackage main\n\nimport (\n\t\"github.com/pulumi/pulumi-docker/sdk/v4/go/docker/buildx\"\n\t\"github.com/pulumi/pulumi/sdk/v3/go/pulumi\"\n)\n\nfunc main() {\n\tpulumi.Run(func(ctx *pulumi.Context) error {\n\t\t_, err := buildx.NewImage(ctx, \"image\", \u0026buildx.ImageArgs{\n\t\t\tCacheFrom: buildx.CacheFromArray{\n\t\t\t\t\u0026buildx.CacheFromArgs{\n\t\t\t\t\tLocal: \u0026buildx.CacheFromLocalArgs{\n\t\t\t\t\t\tSrc: pulumi.String(\"tmp/cache\"),\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\tCacheTo: buildx.CacheToArray{\n\t\t\t\t\u0026buildx.CacheToArgs{\n\t\t\t\t\tLocal: \u0026buildx.CacheToLocalArgs{\n\t\t\t\t\t\tDest: pulumi.String(\"tmp/cache\"),\n\t\t\t\t\t\tMode: buildx.CacheModeMax,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\tContext: \u0026buildx.BuildContextArgs{\n\t\t\t\tLocation: pulumi.String(\"app\"),\n\t\t\t},\n\t\t})\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\treturn nil\n\t})\n}\n```\n```yaml\ndescription: Caching\nname: caching\nresources:\n image:\n properties:\n cacheFrom:\n - local:\n src: tmp/cache\n cacheTo:\n - local:\n dest: tmp/cache\n mode: max\n context:\n location: app\n type: docker:buildx/image:Image\nruntime: yaml\n```\n```java\npackage generated_program;\n\nimport com.pulumi.Context;\nimport com.pulumi.Pulumi;\nimport com.pulumi.core.Output;\nimport com.pulumi.docker.buildx.Image;\nimport com.pulumi.docker.buildx.ImageArgs;\nimport com.pulumi.docker.buildx.inputs.CacheFromArgs;\nimport com.pulumi.docker.buildx.inputs.CacheFromLocalArgs;\nimport com.pulumi.docker.buildx.inputs.CacheToArgs;\nimport com.pulumi.docker.buildx.inputs.CacheToLocalArgs;\nimport com.pulumi.docker.buildx.inputs.BuildContextArgs;\nimport java.util.List;\nimport java.util.ArrayList;\nimport java.util.Map;\nimport java.io.File;\nimport java.nio.file.Files;\nimport java.nio.file.Paths;\n\npublic class App {\n public static void main(String[] args) {\n Pulumi.run(App::stack);\n }\n\n public static void stack(Context ctx) {\n var image = new Image(\"image\", ImageArgs.builder() \n .cacheFrom(CacheFromArgs.builder()\n .local(CacheFromLocalArgs.builder()\n .src(\"tmp/cache\")\n .build())\n .build())\n .cacheTo(CacheToArgs.builder()\n .local(CacheToLocalArgs.builder()\n .dest(\"tmp/cache\")\n .mode(\"max\")\n .build())\n .build())\n .context(BuildContextArgs.builder()\n .location(\"app\")\n .build())\n .build());\n\n }\n}\n```\n{{% /example %}}\n{{% example %}}\n### Docker Build Cloud\n\n```typescript\nimport * as pulumi from \"@pulumi/pulumi\";\nimport * as docker from \"@pulumi/docker\";\n\nconst image = new docker.buildx.Image(\"image\", {\n builder: {\n name: \"cloud-builder-name\",\n },\n context: {\n location: \"app\",\n },\n exec: true,\n});\n```\n```python\nimport pulumi\nimport pulumi_docker as docker\n\nimage = docker.buildx.Image(\"image\",\n builder=docker.buildx.BuilderConfigArgs(\n name=\"cloud-builder-name\",\n ),\n context=docker.buildx.BuildContextArgs(\n location=\"app\",\n ),\n exec_=True)\n```\n```csharp\nusing System.Collections.Generic;\nusing System.Linq;\nusing Pulumi;\nusing Docker = Pulumi.Docker;\n\nreturn await Deployment.RunAsync(() =\u003e \n{\n var image = new Docker.Buildx.Image(\"image\", new()\n {\n Builder = new Docker.Buildx.Inputs.BuilderConfigArgs\n {\n Name = \"cloud-builder-name\",\n },\n Context = new Docker.Buildx.Inputs.BuildContextArgs\n {\n Location = \"app\",\n },\n Exec = true,\n });\n\n});\n\n```\n```go\npackage main\n\nimport (\n\t\"github.com/pulumi/pulumi-docker/sdk/v4/go/docker/buildx\"\n\t\"github.com/pulumi/pulumi/sdk/v3/go/pulumi\"\n)\n\nfunc main() {\n\tpulumi.Run(func(ctx *pulumi.Context) error {\n\t\t_, err := buildx.NewImage(ctx, \"image\", \u0026buildx.ImageArgs{\n\t\t\tBuilder: \u0026buildx.BuilderConfigArgs{\n\t\t\t\tName: pulumi.String(\"cloud-builder-name\"),\n\t\t\t},\n\t\t\tContext: \u0026buildx.BuildContextArgs{\n\t\t\t\tLocation: pulumi.String(\"app\"),\n\t\t\t},\n\t\t\tExec: pulumi.Bool(true),\n\t\t})\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\treturn nil\n\t})\n}\n```\n```yaml\ndescription: Docker Build Cloud\nname: dbc\nresources:\n image:\n properties:\n builder:\n name: cloud-builder-name\n context:\n location: app\n exec: true\n type: docker:buildx/image:Image\nruntime: yaml\n```\n```java\npackage generated_program;\n\nimport com.pulumi.Context;\nimport com.pulumi.Pulumi;\nimport com.pulumi.core.Output;\nimport com.pulumi.docker.buildx.Image;\nimport com.pulumi.docker.buildx.ImageArgs;\nimport com.pulumi.docker.buildx.inputs.BuilderConfigArgs;\nimport com.pulumi.docker.buildx.inputs.BuildContextArgs;\nimport java.util.List;\nimport java.util.ArrayList;\nimport java.util.Map;\nimport java.io.File;\nimport java.nio.file.Files;\nimport java.nio.file.Paths;\n\npublic class App {\n public static void main(String[] args) {\n Pulumi.run(App::stack);\n }\n\n public static void stack(Context ctx) {\n var image = new Image(\"image\", ImageArgs.builder() \n .builder(BuilderConfigArgs.builder()\n .name(\"cloud-builder-name\")\n .build())\n .context(BuildContextArgs.builder()\n .location(\"app\")\n .build())\n .exec(true)\n .build());\n\n }\n}\n```\n{{% /example %}}\n{{% example %}}\n### Build arguments\n\n```typescript\nimport * as pulumi from \"@pulumi/pulumi\";\nimport * as docker from \"@pulumi/docker\";\n\nconst image = new docker.buildx.Image(\"image\", {\n buildArgs: {\n SET_ME_TO_TRUE: \"true\",\n },\n context: {\n location: \"app\",\n },\n});\n```\n```python\nimport pulumi\nimport pulumi_docker as docker\n\nimage = docker.buildx.Image(\"image\",\n build_args={\n \"SET_ME_TO_TRUE\": \"true\",\n },\n context=docker.buildx.BuildContextArgs(\n location=\"app\",\n ))\n```\n```csharp\nusing System.Collections.Generic;\nusing System.Linq;\nusing Pulumi;\nusing Docker = Pulumi.Docker;\n\nreturn await Deployment.RunAsync(() =\u003e \n{\n var image = new Docker.Buildx.Image(\"image\", new()\n {\n BuildArgs = \n {\n { \"SET_ME_TO_TRUE\", \"true\" },\n },\n Context = new Docker.Buildx.Inputs.BuildContextArgs\n {\n Location = \"app\",\n },\n });\n\n});\n\n```\n```go\npackage main\n\nimport (\n\t\"github.com/pulumi/pulumi-docker/sdk/v4/go/docker/buildx\"\n\t\"github.com/pulumi/pulumi/sdk/v3/go/pulumi\"\n)\n\nfunc main() {\n\tpulumi.Run(func(ctx *pulumi.Context) error {\n\t\t_, err := buildx.NewImage(ctx, \"image\", \u0026buildx.ImageArgs{\n\t\t\tBuildArgs: pulumi.StringMap{\n\t\t\t\t\"SET_ME_TO_TRUE\": pulumi.String(\"true\"),\n\t\t\t},\n\t\t\tContext: \u0026buildx.BuildContextArgs{\n\t\t\t\tLocation: pulumi.String(\"app\"),\n\t\t\t},\n\t\t})\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\treturn nil\n\t})\n}\n```\n```yaml\ndescription: Build arguments\nname: build-args\nresources:\n image:\n properties:\n buildArgs:\n SET_ME_TO_TRUE: \"true\"\n context:\n location: app\n type: docker:buildx/image:Image\nruntime: yaml\n```\n```java\npackage generated_program;\n\nimport com.pulumi.Context;\nimport com.pulumi.Pulumi;\nimport com.pulumi.core.Output;\nimport com.pulumi.docker.buildx.Image;\nimport com.pulumi.docker.buildx.ImageArgs;\nimport com.pulumi.docker.buildx.inputs.BuildContextArgs;\nimport java.util.List;\nimport java.util.ArrayList;\nimport java.util.Map;\nimport java.io.File;\nimport java.nio.file.Files;\nimport java.nio.file.Paths;\n\npublic class App {\n public static void main(String[] args) {\n Pulumi.run(App::stack);\n }\n\n public static void stack(Context ctx) {\n var image = new Image(\"image\", ImageArgs.builder() \n .buildArgs(Map.of(\"SET_ME_TO_TRUE\", \"true\"))\n .context(BuildContextArgs.builder()\n .location(\"app\")\n .build())\n .build());\n\n }\n}\n```\n{{% /example %}}\n{{% example %}}\n### Build target\n\n```typescript\nimport * as pulumi from \"@pulumi/pulumi\";\nimport * as docker from \"@pulumi/docker\";\n\nconst image = new docker.buildx.Image(\"image\", {\n context: {\n location: \"app\",\n },\n target: \"build-me\",\n});\n```\n```python\nimport pulumi\nimport pulumi_docker as docker\n\nimage = docker.buildx.Image(\"image\",\n context=docker.buildx.BuildContextArgs(\n location=\"app\",\n ),\n target=\"build-me\")\n```\n```csharp\nusing System.Collections.Generic;\nusing System.Linq;\nusing Pulumi;\nusing Docker = Pulumi.Docker;\n\nreturn await Deployment.RunAsync(() =\u003e \n{\n var image = new Docker.Buildx.Image(\"image\", new()\n {\n Context = new Docker.Buildx.Inputs.BuildContextArgs\n {\n Location = \"app\",\n },\n Target = \"build-me\",\n });\n\n});\n\n```\n```go\npackage main\n\nimport (\n\t\"github.com/pulumi/pulumi-docker/sdk/v4/go/docker/buildx\"\n\t\"github.com/pulumi/pulumi/sdk/v3/go/pulumi\"\n)\n\nfunc main() {\n\tpulumi.Run(func(ctx *pulumi.Context) error {\n\t\t_, err := buildx.NewImage(ctx, \"image\", \u0026buildx.ImageArgs{\n\t\t\tContext: \u0026buildx.BuildContextArgs{\n\t\t\t\tLocation: pulumi.String(\"app\"),\n\t\t\t},\n\t\t\tTarget: pulumi.String(\"build-me\"),\n\t\t})\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\treturn nil\n\t})\n}\n```\n```yaml\ndescription: Build target\nname: build-target\nresources:\n image:\n properties:\n context:\n location: app\n target: build-me\n type: docker:buildx/image:Image\nruntime: yaml\n```\n```java\npackage generated_program;\n\nimport com.pulumi.Context;\nimport com.pulumi.Pulumi;\nimport com.pulumi.core.Output;\nimport com.pulumi.docker.buildx.Image;\nimport com.pulumi.docker.buildx.ImageArgs;\nimport com.pulumi.docker.buildx.inputs.BuildContextArgs;\nimport java.util.List;\nimport java.util.ArrayList;\nimport java.util.Map;\nimport java.io.File;\nimport java.nio.file.Files;\nimport java.nio.file.Paths;\n\npublic class App {\n public static void main(String[] args) {\n Pulumi.run(App::stack);\n }\n\n public static void stack(Context ctx) {\n var image = new Image(\"image\", ImageArgs.builder() \n .context(BuildContextArgs.builder()\n .location(\"app\")\n .build())\n .target(\"build-me\")\n .build());\n\n }\n}\n```\n{{% /example %}}\n{{% example %}}\n### Named contexts\n\n```typescript\nimport * as pulumi from \"@pulumi/pulumi\";\nimport * as docker from \"@pulumi/docker\";\n\nconst image = new docker.buildx.Image(\"image\", {context: {\n location: \"app\",\n named: {\n \"golang:latest\": {\n location: \"docker-image://golang@sha256:b8e62cf593cdaff36efd90aa3a37de268e6781a2e68c6610940c48f7cdf36984\",\n },\n },\n}});\n```\n```python\nimport pulumi\nimport pulumi_docker as docker\n\nimage = docker.buildx.Image(\"image\", context=docker.buildx.BuildContextArgs(\n location=\"app\",\n named={\n \"golang:latest\": docker.buildx.ContextArgs(\n location=\"docker-image://golang@sha256:b8e62cf593cdaff36efd90aa3a37de268e6781a2e68c6610940c48f7cdf36984\",\n ),\n },\n))\n```\n```csharp\nusing System.Collections.Generic;\nusing System.Linq;\nusing Pulumi;\nusing Docker = Pulumi.Docker;\n\nreturn await Deployment.RunAsync(() =\u003e \n{\n var image = new Docker.Buildx.Image(\"image\", new()\n {\n Context = new Docker.Buildx.Inputs.BuildContextArgs\n {\n Location = \"app\",\n Named = \n {\n { \"golang:latest\", new Docker.Buildx.Inputs.ContextArgs\n {\n Location = \"docker-image://golang@sha256:b8e62cf593cdaff36efd90aa3a37de268e6781a2e68c6610940c48f7cdf36984\",\n } },\n },\n },\n });\n\n});\n\n```\n```go\npackage main\n\nimport (\n\t\"github.com/pulumi/pulumi-docker/sdk/v4/go/docker/buildx\"\n\t\"github.com/pulumi/pulumi/sdk/v3/go/pulumi\"\n)\n\nfunc main() {\n\tpulumi.Run(func(ctx *pulumi.Context) error {\n\t\t_, err := buildx.NewImage(ctx, \"image\", \u0026buildx.ImageArgs{\n\t\t\tContext: \u0026buildx.BuildContextArgs{\n\t\t\t\tLocation: pulumi.String(\"app\"),\n\t\t\t\tNamed: buildx.ContextMap{\n\t\t\t\t\t\"golang:latest\": \u0026buildx.ContextArgs{\n\t\t\t\t\t\tLocation: pulumi.String(\"docker-image://golang@sha256:b8e62cf593cdaff36efd90aa3a37de268e6781a2e68c6610940c48f7cdf36984\"),\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t})\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\treturn nil\n\t})\n}\n```\n```yaml\ndescription: Named contexts\nname: named-contexts\nresources:\n image:\n properties:\n context:\n location: app\n named:\n golang:latest:\n location: docker-image://golang@sha256:b8e62cf593cdaff36efd90aa3a37de268e6781a2e68c6610940c48f7cdf36984\n type: docker:buildx/image:Image\nruntime: yaml\n```\n```java\npackage generated_program;\n\nimport com.pulumi.Context;\nimport com.pulumi.Pulumi;\nimport com.pulumi.core.Output;\nimport com.pulumi.docker.buildx.Image;\nimport com.pulumi.docker.buildx.ImageArgs;\nimport com.pulumi.docker.buildx.inputs.BuildContextArgs;\nimport java.util.List;\nimport java.util.ArrayList;\nimport java.util.Map;\nimport java.io.File;\nimport java.nio.file.Files;\nimport java.nio.file.Paths;\n\npublic class App {\n public static void main(String[] args) {\n Pulumi.run(App::stack);\n }\n\n public static void stack(Context ctx) {\n var image = new Image(\"image\", ImageArgs.builder() \n .context(BuildContextArgs.builder()\n .location(\"app\")\n .named(Map.of(\"golang:latest\", Map.of(\"location\", \"docker-image://golang@sha256:b8e62cf593cdaff36efd90aa3a37de268e6781a2e68c6610940c48f7cdf36984\")))\n .build())\n .build());\n\n }\n}\n```\n{{% /example %}}\n{{% example %}}\n### Remote context\n\n```typescript\nimport * as pulumi from \"@pulumi/pulumi\";\nimport * as docker from \"@pulumi/docker\";\n\nconst image = new docker.buildx.Image(\"image\", {context: {\n location: \"https://raw.githubusercontent.com/pulumi/pulumi-docker/api-types/provider/testdata/Dockerfile\",\n}});\n```\n```python\nimport pulumi\nimport pulumi_docker as docker\n\nimage = docker.buildx.Image(\"image\", context=docker.buildx.BuildContextArgs(\n location=\"https://raw.githubusercontent.com/pulumi/pulumi-docker/api-types/provider/testdata/Dockerfile\",\n))\n```\n```csharp\nusing System.Collections.Generic;\nusing System.Linq;\nusing Pulumi;\nusing Docker = Pulumi.Docker;\n\nreturn await Deployment.RunAsync(() =\u003e \n{\n var image = new Docker.Buildx.Image(\"image\", new()\n {\n Context = new Docker.Buildx.Inputs.BuildContextArgs\n {\n Location = \"https://raw.githubusercontent.com/pulumi/pulumi-docker/api-types/provider/testdata/Dockerfile\",\n },\n });\n\n});\n\n```\n```go\npackage main\n\nimport (\n\t\"github.com/pulumi/pulumi-docker/sdk/v4/go/docker/buildx\"\n\t\"github.com/pulumi/pulumi/sdk/v3/go/pulumi\"\n)\n\nfunc main() {\n\tpulumi.Run(func(ctx *pulumi.Context) error {\n\t\t_, err := buildx.NewImage(ctx, \"image\", \u0026buildx.ImageArgs{\n\t\t\tContext: \u0026buildx.BuildContextArgs{\n\t\t\t\tLocation: pulumi.String(\"https://raw.githubusercontent.com/pulumi/pulumi-docker/api-types/provider/testdata/Dockerfile\"),\n\t\t\t},\n\t\t})\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\treturn nil\n\t})\n}\n```\n```yaml\ndescription: Remote context\nname: remote-context\nresources:\n image:\n properties:\n context:\n location: https://raw.githubusercontent.com/pulumi/pulumi-docker/api-types/provider/testdata/Dockerfile\n type: docker:buildx/image:Image\nruntime: yaml\n```\n```java\npackage generated_program;\n\nimport com.pulumi.Context;\nimport com.pulumi.Pulumi;\nimport com.pulumi.core.Output;\nimport com.pulumi.docker.buildx.Image;\nimport com.pulumi.docker.buildx.ImageArgs;\nimport com.pulumi.docker.buildx.inputs.BuildContextArgs;\nimport java.util.List;\nimport java.util.ArrayList;\nimport java.util.Map;\nimport java.io.File;\nimport java.nio.file.Files;\nimport java.nio.file.Paths;\n\npublic class App {\n public static void main(String[] args) {\n Pulumi.run(App::stack);\n }\n\n public static void stack(Context ctx) {\n var image = new Image(\"image\", ImageArgs.builder() \n .context(BuildContextArgs.builder()\n .location(\"https://raw.githubusercontent.com/pulumi/pulumi-docker/api-types/provider/testdata/Dockerfile\")\n .build())\n .build());\n\n }\n}\n```\n{{% /example %}}\n{{% example %}}\n### Inline Dockerfile\n\n```typescript\nimport * as pulumi from \"@pulumi/pulumi\";\nimport * as docker from \"@pulumi/docker\";\n\nconst image = new docker.buildx.Image(\"image\", {\n context: {\n location: \"app\",\n },\n dockerfile: {\n inline: `FROM busybox\nCOPY hello.c ./\n`,\n },\n});\n```\n```python\nimport pulumi\nimport pulumi_docker as docker\n\nimage = docker.buildx.Image(\"image\",\n context=docker.buildx.BuildContextArgs(\n location=\"app\",\n ),\n dockerfile=docker.buildx.DockerfileArgs(\n inline=\"\"\"FROM busybox\nCOPY hello.c ./\n\"\"\",\n ))\n```\n```csharp\nusing System.Collections.Generic;\nusing System.Linq;\nusing Pulumi;\nusing Docker = Pulumi.Docker;\n\nreturn await Deployment.RunAsync(() =\u003e \n{\n var image = new Docker.Buildx.Image(\"image\", new()\n {\n Context = new Docker.Buildx.Inputs.BuildContextArgs\n {\n Location = \"app\",\n },\n Dockerfile = new Docker.Buildx.Inputs.DockerfileArgs\n {\n Inline = @\"FROM busybox\nCOPY hello.c ./\n\",\n },\n });\n\n});\n\n```\n```go\npackage main\n\nimport (\n\t\"github.com/pulumi/pulumi-docker/sdk/v4/go/docker/buildx\"\n\t\"github.com/pulumi/pulumi/sdk/v3/go/pulumi\"\n)\n\nfunc main() {\n\tpulumi.Run(func(ctx *pulumi.Context) error {\n\t\t_, err := buildx.NewImage(ctx, \"image\", \u0026buildx.ImageArgs{\n\t\t\tContext: \u0026buildx.BuildContextArgs{\n\t\t\t\tLocation: pulumi.String(\"app\"),\n\t\t\t},\n\t\t\tDockerfile: \u0026buildx.DockerfileArgs{\n\t\t\t\tInline: pulumi.String(\"FROM busybox\\nCOPY hello.c ./\\n\"),\n\t\t\t},\n\t\t})\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\treturn nil\n\t})\n}\n```\n```yaml\ndescription: Inline Dockerfile\nname: inline\nresources:\n image:\n properties:\n context:\n location: app\n dockerfile:\n inline: |\n FROM busybox\n COPY hello.c ./\n type: docker:buildx/image:Image\nruntime: yaml\n```\n```java\npackage generated_program;\n\nimport com.pulumi.Context;\nimport com.pulumi.Pulumi;\nimport com.pulumi.core.Output;\nimport com.pulumi.docker.buildx.Image;\nimport com.pulumi.docker.buildx.ImageArgs;\nimport com.pulumi.docker.buildx.inputs.BuildContextArgs;\nimport com.pulumi.docker.buildx.inputs.DockerfileArgs;\nimport java.util.List;\nimport java.util.ArrayList;\nimport java.util.Map;\nimport java.io.File;\nimport java.nio.file.Files;\nimport java.nio.file.Paths;\n\npublic class App {\n public static void main(String[] args) {\n Pulumi.run(App::stack);\n }\n\n public static void stack(Context ctx) {\n var image = new Image(\"image\", ImageArgs.builder() \n .context(BuildContextArgs.builder()\n .location(\"app\")\n .build())\n .dockerfile(DockerfileArgs.builder()\n .inline(\"\"\"\nFROM busybox\nCOPY hello.c ./\n \"\"\")\n .build())\n .build());\n\n }\n}\n```\n{{% /example %}}\n{{% example %}}\n### Remote context\n\n```typescript\nimport * as pulumi from \"@pulumi/pulumi\";\nimport * as docker from \"@pulumi/docker\";\n\nconst image = new docker.buildx.Image(\"image\", {\n context: {\n location: \"https://github.com/docker-library/hello-world.git\",\n },\n dockerfile: {\n location: \"app/Dockerfile\",\n },\n});\n```\n```python\nimport pulumi\nimport pulumi_docker as docker\n\nimage = docker.buildx.Image(\"image\",\n context=docker.buildx.BuildContextArgs(\n location=\"https://github.com/docker-library/hello-world.git\",\n ),\n dockerfile=docker.buildx.DockerfileArgs(\n location=\"app/Dockerfile\",\n ))\n```\n```csharp\nusing System.Collections.Generic;\nusing System.Linq;\nusing Pulumi;\nusing Docker = Pulumi.Docker;\n\nreturn await Deployment.RunAsync(() =\u003e \n{\n var image = new Docker.Buildx.Image(\"image\", new()\n {\n Context = new Docker.Buildx.Inputs.BuildContextArgs\n {\n Location = \"https://github.com/docker-library/hello-world.git\",\n },\n Dockerfile = new Docker.Buildx.Inputs.DockerfileArgs\n {\n Location = \"app/Dockerfile\",\n },\n });\n\n});\n\n```\n```go\npackage main\n\nimport (\n\t\"github.com/pulumi/pulumi-docker/sdk/v4/go/docker/buildx\"\n\t\"github.com/pulumi/pulumi/sdk/v3/go/pulumi\"\n)\n\nfunc main() {\n\tpulumi.Run(func(ctx *pulumi.Context) error {\n\t\t_, err := buildx.NewImage(ctx, \"image\", \u0026buildx.ImageArgs{\n\t\t\tContext: \u0026buildx.BuildContextArgs{\n\t\t\t\tLocation: pulumi.String(\"https://github.com/docker-library/hello-world.git\"),\n\t\t\t},\n\t\t\tDockerfile: \u0026buildx.DockerfileArgs{\n\t\t\t\tLocation: pulumi.String(\"app/Dockerfile\"),\n\t\t\t},\n\t\t})\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\treturn nil\n\t})\n}\n```\n```yaml\ndescription: Remote context\nname: remote-context\nresources:\n image:\n properties:\n context:\n location: https://github.com/docker-library/hello-world.git\n dockerfile:\n location: app/Dockerfile\n type: docker:buildx/image:Image\nruntime: yaml\n```\n```java\npackage generated_program;\n\nimport com.pulumi.Context;\nimport com.pulumi.Pulumi;\nimport com.pulumi.core.Output;\nimport com.pulumi.docker.buildx.Image;\nimport com.pulumi.docker.buildx.ImageArgs;\nimport com.pulumi.docker.buildx.inputs.BuildContextArgs;\nimport com.pulumi.docker.buildx.inputs.DockerfileArgs;\nimport java.util.List;\nimport java.util.ArrayList;\nimport java.util.Map;\nimport java.io.File;\nimport java.nio.file.Files;\nimport java.nio.file.Paths;\n\npublic class App {\n public static void main(String[] args) {\n Pulumi.run(App::stack);\n }\n\n public static void stack(Context ctx) {\n var image = new Image(\"image\", ImageArgs.builder() \n .context(BuildContextArgs.builder()\n .location(\"https://github.com/docker-library/hello-world.git\")\n .build())\n .dockerfile(DockerfileArgs.builder()\n .location(\"app/Dockerfile\")\n .build())\n .build());\n\n }\n}\n```\n{{% /example %}}\n{{% example %}}\n### Local export\n\n```typescript\nimport * as pulumi from \"@pulumi/pulumi\";\nimport * as docker from \"@pulumi/docker\";\n\nconst image = new docker.buildx.Image(\"image\", {\n context: {\n location: \"app\",\n },\n exports: [{\n docker: {\n tar: true,\n },\n }],\n});\n```\n```python\nimport pulumi\nimport pulumi_docker as docker\n\nimage = docker.buildx.Image(\"image\",\n context=docker.buildx.BuildContextArgs(\n location=\"app\",\n ),\n exports=[docker.buildx.ExportArgs(\n docker=docker.buildx.ExportDockerArgs(\n tar=True,\n ),\n )])\n```\n```csharp\nusing System.Collections.Generic;\nusing System.Linq;\nusing Pulumi;\nusing Docker = Pulumi.Docker;\n\nreturn await Deployment.RunAsync(() =\u003e \n{\n var image = new Docker.Buildx.Image(\"image\", new()\n {\n Context = new Docker.Buildx.Inputs.BuildContextArgs\n {\n Location = \"app\",\n },\n Exports = new[]\n {\n new Docker.Buildx.Inputs.ExportArgs\n {\n Docker = new Docker.Buildx.Inputs.ExportDockerArgs\n {\n Tar = true,\n },\n },\n },\n });\n\n});\n\n```\n```go\npackage main\n\nimport (\n\t\"github.com/pulumi/pulumi-docker/sdk/v4/go/docker/buildx\"\n\t\"github.com/pulumi/pulumi/sdk/v3/go/pulumi\"\n)\n\nfunc main() {\n\tpulumi.Run(func(ctx *pulumi.Context) error {\n\t\t_, err := buildx.NewImage(ctx, \"image\", \u0026buildx.ImageArgs{\n\t\t\tContext: \u0026buildx.BuildContextArgs{\n\t\t\t\tLocation: pulumi.String(\"app\"),\n\t\t\t},\n\t\t\tExports: buildx.ExportArray{\n\t\t\t\t\u0026buildx.ExportArgs{\n\t\t\t\t\tDocker: \u0026buildx.ExportDockerArgs{\n\t\t\t\t\t\tTar: pulumi.Bool(true),\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t})\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\treturn nil\n\t})\n}\n```\n```yaml\ndescription: Local export\nname: docker-load\nresources:\n image:\n properties:\n context:\n location: app\n exports:\n - docker:\n tar: true\n type: docker:buildx/image:Image\nruntime: yaml\n```\n```java\npackage generated_program;\n\nimport com.pulumi.Context;\nimport com.pulumi.Pulumi;\nimport com.pulumi.core.Output;\nimport com.pulumi.docker.buildx.Image;\nimport com.pulumi.docker.buildx.ImageArgs;\nimport com.pulumi.docker.buildx.inputs.BuildContextArgs;\nimport com.pulumi.docker.buildx.inputs.ExportArgs;\nimport com.pulumi.docker.buildx.inputs.ExportDockerArgs;\nimport java.util.List;\nimport java.util.ArrayList;\nimport java.util.Map;\nimport java.io.File;\nimport java.nio.file.Files;\nimport java.nio.file.Paths;\n\npublic class App {\n public static void main(String[] args) {\n Pulumi.run(App::stack);\n }\n\n public static void stack(Context ctx) {\n var image = new Image(\"image\", ImageArgs.builder() \n .context(BuildContextArgs.builder()\n .location(\"app\")\n .build())\n .exports(ExportArgs.builder()\n .docker(ExportDockerArgs.builder()\n .tar(true)\n .build())\n .build())\n .build());\n\n }\n}\n```\n{{% /example %}}\n{{% /examples %}}", + "description": "A Docker image built using buildx -- Docker's interface to the improved\nBuildKit backend.\n\n## Stability\n\n**This resource is experimental and subject to change.**\n\nAPI types are unstable. Subsequent releases _may_ require manual edits\nto your state file(s) in order to adopt API changes.\n\n`retainOnDelete: true` is recommended with this resource until it is\nstable. This enables future API changes to be adopted more easily by renaming\nresources.\n\nOnly use this resource if you understand and accept the risks.\n\n## Migrating v3 and v4 Image resources\n\nThe `buildx.Image` resource provides a superset of functionality over the `Image` resources available in versions 3 and 4 of the Pulumi Docker provider.\nExisting `Image` resources can be converted to `build.Image` resources with minor modifications.\n\n### Behavioral differences\n\nThere are several key behavioral differences to keep in mind when transitioning images to the new `buildx.Image` resource.\n\n#### Previews\n\nVersion `3.x` of the Pulumi Docker provider always builds images during preview operations.\nThis is helpful as a safeguard to prevent \"broken\" images from merging, but users found the behavior unnecessarily redundant when running previews and updates locally.\n\nVersion `4.x` changed build-on-preview behavior to be opt-in.\nBy default, `v4.x` `Image` resources do _not_ build during previews, but this behavior can be toggled with the `buildOnPreview` option.\nSome users felt this made previews in CI less helpful because they no longer detected bad images by default.\n\nThe default behavior of the `buildx.Image` resource has been changed to strike a better balance between CI use cases and manual updates.\nBy default, Pulumi will now only build `buildx.Image` resources during previews when it detects a CI environment like GitHub Actions.\nPreviews run in non-CI environments will not build images.\nThis behavior is still configurable with `buildOnPreview`.\n\n#### Push behavior\n\nVersions `3.x` and `4.x` of the Pulumi Docker provider attempt to push images to remote registries by default.\nThey expose a `skipPush: true` option to disable pushing.\n\nThe `buildx.Image` resource matches the Docker CLI's behavior and does not push images anywhere by default.\n\nTo push images to a registry you can include `push: true` (equivalent to Docker's `--push` flag) or configure an `export` of type `registry` (equivalent to Docker's `--output type=registry`).\nLike Docker, if an image is configured without exports you will see a warning with instructions for how to enable pushing, but the build will still proceed normally.\n\n#### Secrets\n\nVersion `3.x` of the Pulumi Docker provider supports secrets by way of the `extraOptions` field.\n\nVersion `4.x` of the Pulumi Docker provider does not support secrets.\n\nThe `buildx.Image` resource supports secrets but does not require those secrets to exist on-disk or in environment variables.\nInstead, they should be passed directly as values.\n(Please be sure to familiarize yourself with Pulumi's [native secret handling](https://www.pulumi.com/docs/concepts/secrets/).)\nPulumi also provides [ESC](https://www.pulumi.com/product/esc/) to make it easier to share secrets across stacks and environments.\n\n#### Caching\n\nVersion `3.x` of the Pulumi Docker provider exposes `cacheFrom: bool | { stages: [...] }`.\nIt builds targets individually and pushes them to separate images for caching.\n\nVersion `4.x` exposes a similar parameter `cacheFrom: { images: [...] }` which pushes and pulls inline caches.\n\nBoth versions 3 and 4 require specific environment variables to be set and deviate from Docker's native caching behavior.\nThis can result in inefficient builds due to unnecessary image pulls, repeated file transfers, etc.\n\nThe `buildx.Image` resource delegates all caching behavior to Docker.\n`cacheFrom` and `cacheTo` options (equivalent to Docker's `--cache-to` and `--cache-from`) are exposed and provide additional cache targets, such as local disk, S3 storage, etc.\n\n#### Outputs\n\nVersions `3.x` and `4.x` of the provider exposed a `repoDigest` output which was a fully qualified tag with digest.\nIn `4.x` this could also be a single sha256 hash if the image wasn't pushed.\n\nUnlike earlier providers the `buildx.Image` resource can push multiple tags.\nAs a convenience, it exposes a `ref` output consisting of a tag with digest as long as the image was pushed.\nIf multiple tags were pushed this uses one at random.\n\nIf you need more control over tag references you can use the `digest` output, which is always a single sha256 hash as long as the image was exported somewhere.\n\n#### Tag deletion and refreshes\n\nVersions 3 and 4 of Pulumi Docker provider do not delete tags when the `Image` resource is deleted, nor do they confirm expected tags exist during `refresh` operations.\n\nThe `buidx.Image` will query your registries during `refresh` to ensure the expected tags exist.\nIf any are missing a subsequent `update` will push them.\n\nWhen a `buildx.Image` is deleted, it will _attempt_ to also delete any pushed tags.\nDeletion of remote tags is not guaranteed because not all registries support the manifest `DELETE` API (`docker.io` in particular).\nManifests are _not_ deleted in the same way during updates -- to do so safely would require a full build to determine whether a Pulumi operation should be an update or update-replace.\n\nUse the [`retainOnDelete: true`](https://www.pulumi.com/docs/concepts/options/retainondelete/) option if you do not want tags deleted.\n\n### Example migration\n\nExamples of \"fully-featured\" `v3` and `v4` `Image` resources are shown below, along with an example `buildx.Image` resource showing how they would look after migration.\n\nThe `v3` resource leverages `buildx` via a `DOCKER_BUILDKIT` environment variable and CLI flags passed in with `extraOption`.\nAfter migration, the environment variable is no longer needed and CLI flags are now properties on the `buildx.Image`.\nIn almost all cases, properties of `buildx.Image` are named after the Docker CLI flag they correspond to.\n\nThe `v4` resource is less functional than its `v3` counterpart because it lacks the flexibility of `extraOptions`.\nIt it is shown with parameters similar to the `v3` example for completeness.\n\n{{% examples %}}\n## Example Usage\n{{% example %}}\n### v3/v4 migration\n\n```typescript\n\n// v3 Image\nconst v3 = new docker.Image(\"v3-image\", {\n imageName: \"myregistry.com/user/repo:latest\",\n localImageName: \"local-tag\",\n skipPush: false,\n build: {\n dockerfile: \"./Dockerfile\",\n context: \"../app\",\n target: \"mytarget\",\n args: {\n MY_BUILD_ARG: \"foo\",\n },\n env: {\n DOCKER_BUILDKIT: \"1\",\n },\n extraOptions: [\n \"--cache-from\",\n \"type=registry,myregistry.com/user/repo:cache\",\n \"--cache-to\",\n \"type=registry,myregistry.com/user/repo:cache\",\n \"--add-host\",\n \"metadata.google.internal:169.254.169.254\",\n \"--secret\",\n \"id=mysecret,src=/local/secret\",\n \"--ssh\",\n \"default=/home/runner/.ssh/id_ed25519\",\n \"--network\",\n \"host\",\n \"--platform\",\n \"linux/amd64\",\n ],\n },\n registry: {\n server: \"myregistry.com\",\n username: \"username\",\n password: pulumi.secret(\"password\"),\n },\n});\n\n// v3 Image after migrating to buildx.Image\nconst v3Migrated = new docker.buildx.Image(\"v3-to-buildx\", {\n tags: [\"myregistry.com/user/repo:latest\", \"local-tag\"],\n push: true,\n dockerfile: {\n location: \"./Dockerfile\",\n },\n context: {\n location: \"../app\",\n },\n targets: [\"mytarget\"],\n buildArgs: {\n MY_BUILD_ARG: \"foo\",\n },\n cacheFrom: [{ registry: { ref: \"myregistry.com/user/repo:cache\" } }],\n cacheTo: [{ registry: { ref: \"myregistry.com/user/repo:cache\" } }],\n secrets: {\n mysecret: \"value\",\n },\n addHosts: [\"metadata.google.internal:169.254.169.254\"],\n ssh: {\n default: [\"/home/runner/.ssh/id_ed25519\"],\n },\n network: \"host\",\n platforms: [\"linux/amd64\"],\n registries: [{\n address: \"myregistry.com\",\n username: \"username\",\n password: pulumi.secret(\"password\"),\n }],\n});\n\n\n// v4 Image\nconst v4 = new docker.Image(\"v4-image\", {\n imageName: \"myregistry.com/user/repo:latest\",\n skipPush: false,\n build: {\n dockerfile: \"./Dockerfile\",\n context: \"../app\",\n target: \"mytarget\",\n args: {\n MY_BUILD_ARG: \"foo\",\n },\n cacheFrom: {\n images: [\"myregistry.com/user/repo:cache\"],\n },\n addHosts: [\"metadata.google.internal:169.254.169.254\"],\n network: \"host\",\n platform: \"linux/amd64\",\n },\n buildOnPreview: true,\n registry: {\n server: \"myregistry.com\",\n username: \"username\",\n password: pulumi.secret(\"password\"),\n },\n});\n\n// v4 Image after migrating to buildx.Image\nconst v4Migrated = new docker.buildx.Image(\"v4-to-buildx\", {\n tags: [\"myregistry.com/user/repo:latest\"],\n push: true,\n dockerfile: {\n location: \"./Dockerfile\",\n },\n context: {\n location: \"../app\",\n },\n targets: [\"mytarget\"],\n buildArgs: {\n MY_BUILD_ARG: \"foo\",\n },\n cacheFrom: [{ registry: { ref: \"myregistry.com/user/repo:cache\" } }],\n cacheTo: [{ registry: { ref: \"myregistry.com/user/repo:cache\" } }],\n addHosts: [\"metadata.google.internal:169.254.169.254\"],\n network: \"host\",\n platforms: [\"linux/amd64\"],\n registries: [{\n address: \"myregistry.com\",\n username: \"username\",\n password: pulumi.secret(\"password\"),\n }],\n});\n\n```\n\n{{% /example %}}\n\n\n{{% examples %}}\n## Example Usage\n{{% example %}}\n### Push to AWS ECR with caching\n\n```typescript\nimport * as pulumi from \"@pulumi/pulumi\";\nimport * as aws from \"@pulumi/aws\";\nimport * as docker from \"@pulumi/docker\";\n\nconst ecrRepository = new aws.ecr.Repository(\"ecr-repository\", {});\nconst authToken = aws.ecr.getAuthorizationTokenOutput({\n registryId: ecrRepository.registryId,\n});\nconst myImage = new docker.buildx.Image(\"my-image\", {\n cacheFrom: [{\n registry: {\n ref: pulumi.interpolate`${ecrRepository.repositoryUrl}:cache`,\n },\n }],\n cacheTo: [{\n registry: {\n imageManifest: true,\n ociMediaTypes: true,\n ref: pulumi.interpolate`${ecrRepository.repositoryUrl}:cache`,\n },\n }],\n context: {\n location: \"./app\",\n },\n push: true,\n registries: [{\n address: ecrRepository.repositoryUrl,\n password: authToken.apply(authToken =\u003e authToken.password),\n username: authToken.apply(authToken =\u003e authToken.userName),\n }],\n tags: [pulumi.interpolate`${ecrRepository.repositoryUrl}:latest`],\n});\nexport const ref = myImage.ref;\n```\n```python\nimport pulumi\nimport pulumi_aws as aws\nimport pulumi_docker as docker\n\necr_repository = aws.ecr.Repository(\"ecr-repository\")\nauth_token = aws.ecr.get_authorization_token_output(registry_id=ecr_repository.registry_id)\nmy_image = docker.buildx.Image(\"my-image\",\n cache_from=[docker.buildx.CacheFromArgs(\n registry=docker.buildx.CacheFromRegistryArgs(\n ref=ecr_repository.repository_url.apply(lambda repository_url: f\"{repository_url}:cache\"),\n ),\n )],\n cache_to=[docker.buildx.CacheToArgs(\n registry=docker.buildx.CacheToRegistryArgs(\n image_manifest=True,\n oci_media_types=True,\n ref=ecr_repository.repository_url.apply(lambda repository_url: f\"{repository_url}:cache\"),\n ),\n )],\n context=docker.buildx.BuildContextArgs(\n location=\"./app\",\n ),\n push=True,\n registries=[docker.buildx.RegistryAuthArgs(\n address=ecr_repository.repository_url,\n password=auth_token.password,\n username=auth_token.user_name,\n )],\n tags=[ecr_repository.repository_url.apply(lambda repository_url: f\"{repository_url}:latest\")])\npulumi.export(\"ref\", my_image.ref)\n```\n```csharp\nusing System.Collections.Generic;\nusing System.Linq;\nusing Pulumi;\nusing Aws = Pulumi.Aws;\nusing Docker = Pulumi.Docker;\n\nreturn await Deployment.RunAsync(() =\u003e \n{\n var ecrRepository = new Aws.Ecr.Repository(\"ecr-repository\");\n\n var authToken = Aws.Ecr.GetAuthorizationToken.Invoke(new()\n {\n RegistryId = ecrRepository.RegistryId,\n });\n\n var myImage = new Docker.Buildx.Image(\"my-image\", new()\n {\n CacheFrom = new[]\n {\n new Docker.Buildx.Inputs.CacheFromArgs\n {\n Registry = new Docker.Buildx.Inputs.CacheFromRegistryArgs\n {\n Ref = ecrRepository.RepositoryUrl.Apply(repositoryUrl =\u003e $\"{repositoryUrl}:cache\"),\n },\n },\n },\n CacheTo = new[]\n {\n new Docker.Buildx.Inputs.CacheToArgs\n {\n Registry = new Docker.Buildx.Inputs.CacheToRegistryArgs\n {\n ImageManifest = true,\n OciMediaTypes = true,\n Ref = ecrRepository.RepositoryUrl.Apply(repositoryUrl =\u003e $\"{repositoryUrl}:cache\"),\n },\n },\n },\n Context = new Docker.Buildx.Inputs.BuildContextArgs\n {\n Location = \"./app\",\n },\n Push = true,\n Registries = new[]\n {\n new Docker.Buildx.Inputs.RegistryAuthArgs\n {\n Address = ecrRepository.RepositoryUrl,\n Password = authToken.Apply(getAuthorizationTokenResult =\u003e getAuthorizationTokenResult.Password),\n Username = authToken.Apply(getAuthorizationTokenResult =\u003e getAuthorizationTokenResult.UserName),\n },\n },\n Tags = new[]\n {\n ecrRepository.RepositoryUrl.Apply(repositoryUrl =\u003e $\"{repositoryUrl}:latest\"),\n },\n });\n\n return new Dictionary\u003cstring, object?\u003e\n {\n [\"ref\"] = myImage.Ref,\n };\n});\n\n```\n```go\npackage main\n\nimport (\n\t\"fmt\"\n\n\t\"github.com/pulumi/pulumi-aws/sdk/v6/go/aws/ecr\"\n\t\"github.com/pulumi/pulumi-docker/sdk/v4/go/docker/buildx\"\n\t\"github.com/pulumi/pulumi/sdk/v3/go/pulumi\"\n)\n\nfunc main() {\n\tpulumi.Run(func(ctx *pulumi.Context) error {\n\t\tecrRepository, err := ecr.NewRepository(ctx, \"ecr-repository\", nil)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\tauthToken := ecr.GetAuthorizationTokenOutput(ctx, ecr.GetAuthorizationTokenOutputArgs{\n\t\t\tRegistryId: ecrRepository.RegistryId,\n\t\t}, nil)\n\t\tmyImage, err := buildx.NewImage(ctx, \"my-image\", \u0026buildx.ImageArgs{\n\t\t\tCacheFrom: buildx.CacheFromArray{\n\t\t\t\t\u0026buildx.CacheFromArgs{\n\t\t\t\t\tRegistry: \u0026buildx.CacheFromRegistryArgs{\n\t\t\t\t\t\tRef: ecrRepository.RepositoryUrl.ApplyT(func(repositoryUrl string) (string, error) {\n\t\t\t\t\t\t\treturn fmt.Sprintf(\"%v:cache\", repositoryUrl), nil\n\t\t\t\t\t\t}).(pulumi.StringOutput),\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\tCacheTo: buildx.CacheToArray{\n\t\t\t\t\u0026buildx.CacheToArgs{\n\t\t\t\t\tRegistry: \u0026buildx.CacheToRegistryArgs{\n\t\t\t\t\t\tImageManifest: pulumi.Bool(true),\n\t\t\t\t\t\tOciMediaTypes: pulumi.Bool(true),\n\t\t\t\t\t\tRef: ecrRepository.RepositoryUrl.ApplyT(func(repositoryUrl string) (string, error) {\n\t\t\t\t\t\t\treturn fmt.Sprintf(\"%v:cache\", repositoryUrl), nil\n\t\t\t\t\t\t}).(pulumi.StringOutput),\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\tContext: \u0026buildx.BuildContextArgs{\n\t\t\t\tLocation: pulumi.String(\"./app\"),\n\t\t\t},\n\t\t\tPush: pulumi.Bool(true),\n\t\t\tRegistries: buildx.RegistryAuthArray{\n\t\t\t\t\u0026buildx.RegistryAuthArgs{\n\t\t\t\t\tAddress: ecrRepository.RepositoryUrl,\n\t\t\t\t\tPassword: authToken.ApplyT(func(authToken ecr.GetAuthorizationTokenResult) (*string, error) {\n\t\t\t\t\t\treturn \u0026authToken.Password, nil\n\t\t\t\t\t}).(pulumi.StringPtrOutput),\n\t\t\t\t\tUsername: authToken.ApplyT(func(authToken ecr.GetAuthorizationTokenResult) (*string, error) {\n\t\t\t\t\t\treturn \u0026authToken.UserName, nil\n\t\t\t\t\t}).(pulumi.StringPtrOutput),\n\t\t\t\t},\n\t\t\t},\n\t\t\tTags: pulumi.StringArray{\n\t\t\t\tecrRepository.RepositoryUrl.ApplyT(func(repositoryUrl string) (string, error) {\n\t\t\t\t\treturn fmt.Sprintf(\"%v:latest\", repositoryUrl), nil\n\t\t\t\t}).(pulumi.StringOutput),\n\t\t\t},\n\t\t})\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\tctx.Export(\"ref\", myImage.Ref)\n\t\treturn nil\n\t})\n}\n```\n```yaml\ndescription: Push to AWS ECR with caching\nname: ecr\noutputs:\n ref: ${my-image.ref}\nresources:\n ecr-repository:\n type: aws:ecr:Repository\n my-image:\n properties:\n cacheFrom:\n - registry:\n ref: ${ecr-repository.repositoryUrl}:cache\n cacheTo:\n - registry:\n imageManifest: true\n ociMediaTypes: true\n ref: ${ecr-repository.repositoryUrl}:cache\n context:\n location: ./app\n push: true\n registries:\n - address: ${ecr-repository.repositoryUrl}\n password: ${auth-token.password}\n username: ${auth-token.userName}\n tags:\n - ${ecr-repository.repositoryUrl}:latest\n type: docker:buildx/image:Image\nruntime: yaml\nvariables:\n auth-token:\n fn::aws:ecr:getAuthorizationToken:\n registryId: ${ecr-repository.registryId}\n```\n```java\npackage generated_program;\n\nimport com.pulumi.Context;\nimport com.pulumi.Pulumi;\nimport com.pulumi.core.Output;\nimport com.pulumi.aws.ecr.Repository;\nimport com.pulumi.aws.ecr.EcrFunctions;\nimport com.pulumi.aws.ecr.inputs.GetAuthorizationTokenArgs;\nimport com.pulumi.docker.buildx.Image;\nimport com.pulumi.docker.buildx.ImageArgs;\nimport com.pulumi.docker.buildx.inputs.CacheFromArgs;\nimport com.pulumi.docker.buildx.inputs.CacheFromRegistryArgs;\nimport com.pulumi.docker.buildx.inputs.CacheToArgs;\nimport com.pulumi.docker.buildx.inputs.CacheToRegistryArgs;\nimport com.pulumi.docker.buildx.inputs.BuildContextArgs;\nimport com.pulumi.docker.buildx.inputs.RegistryAuthArgs;\nimport java.util.List;\nimport java.util.ArrayList;\nimport java.util.Map;\nimport java.io.File;\nimport java.nio.file.Files;\nimport java.nio.file.Paths;\n\npublic class App {\n public static void main(String[] args) {\n Pulumi.run(App::stack);\n }\n\n public static void stack(Context ctx) {\n var ecrRepository = new Repository(\"ecrRepository\");\n\n final var authToken = EcrFunctions.getAuthorizationToken(GetAuthorizationTokenArgs.builder()\n .registryId(ecrRepository.registryId())\n .build());\n\n var myImage = new Image(\"myImage\", ImageArgs.builder() \n .cacheFrom(CacheFromArgs.builder()\n .registry(CacheFromRegistryArgs.builder()\n .ref(ecrRepository.repositoryUrl().applyValue(repositoryUrl -\u003e String.format(\"%s:cache\", repositoryUrl)))\n .build())\n .build())\n .cacheTo(CacheToArgs.builder()\n .registry(CacheToRegistryArgs.builder()\n .imageManifest(true)\n .ociMediaTypes(true)\n .ref(ecrRepository.repositoryUrl().applyValue(repositoryUrl -\u003e String.format(\"%s:cache\", repositoryUrl)))\n .build())\n .build())\n .context(BuildContextArgs.builder()\n .location(\"./app\")\n .build())\n .push(true)\n .registries(RegistryAuthArgs.builder()\n .address(ecrRepository.repositoryUrl())\n .password(authToken.applyValue(getAuthorizationTokenResult -\u003e getAuthorizationTokenResult).applyValue(authToken -\u003e authToken.applyValue(getAuthorizationTokenResult -\u003e getAuthorizationTokenResult.password())))\n .username(authToken.applyValue(getAuthorizationTokenResult -\u003e getAuthorizationTokenResult).applyValue(authToken -\u003e authToken.applyValue(getAuthorizationTokenResult -\u003e getAuthorizationTokenResult.userName())))\n .build())\n .tags(ecrRepository.repositoryUrl().applyValue(repositoryUrl -\u003e String.format(\"%s:latest\", repositoryUrl)))\n .build());\n\n ctx.export(\"ref\", myImage.ref());\n }\n}\n```\n{{% /example %}}\n{{% example %}}\n### Multi-platform image\n\n```typescript\nimport * as pulumi from \"@pulumi/pulumi\";\nimport * as docker from \"@pulumi/docker\";\n\nconst image = new docker.buildx.Image(\"image\", {\n context: {\n location: \"app\",\n },\n platforms: [\n docker.buildx.image.Platform.Plan9_amd64,\n docker.buildx.image.Platform.Plan9_386,\n ],\n});\n```\n```python\nimport pulumi\nimport pulumi_docker as docker\n\nimage = docker.buildx.Image(\"image\",\n context=docker.buildx.BuildContextArgs(\n location=\"app\",\n ),\n platforms=[\n docker.buildx/image.Platform.PLAN9_AMD64,\n docker.buildx/image.Platform.PLAN9_386,\n ])\n```\n```csharp\nusing System.Collections.Generic;\nusing System.Linq;\nusing Pulumi;\nusing Docker = Pulumi.Docker;\n\nreturn await Deployment.RunAsync(() =\u003e \n{\n var image = new Docker.Buildx.Image(\"image\", new()\n {\n Context = new Docker.Buildx.Inputs.BuildContextArgs\n {\n Location = \"app\",\n },\n Platforms = new[]\n {\n Docker.Buildx.Image.Platform.Plan9_amd64,\n Docker.Buildx.Image.Platform.Plan9_386,\n },\n });\n\n});\n\n```\n```go\npackage main\n\nimport (\n\t\"github.com/pulumi/pulumi-docker/sdk/v4/go/docker/buildx\"\n\t\"github.com/pulumi/pulumi/sdk/v3/go/pulumi\"\n)\n\nfunc main() {\n\tpulumi.Run(func(ctx *pulumi.Context) error {\n\t\t_, err := buildx.NewImage(ctx, \"image\", \u0026buildx.ImageArgs{\n\t\t\tContext: \u0026buildx.BuildContextArgs{\n\t\t\t\tLocation: pulumi.String(\"app\"),\n\t\t\t},\n\t\t\tPlatforms: buildx.PlatformArray{\n\t\t\t\tbuildx.Platform_Plan9_amd64,\n\t\t\t\tbuildx.Platform_Plan9_386,\n\t\t\t},\n\t\t})\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\treturn nil\n\t})\n}\n```\n```yaml\ndescription: Multi-platform image\nname: multi-platform\nresources:\n image:\n properties:\n context:\n location: app\n platforms:\n - plan9/amd64\n - plan9/386\n type: docker:buildx/image:Image\nruntime: yaml\n```\n```java\npackage generated_program;\n\nimport com.pulumi.Context;\nimport com.pulumi.Pulumi;\nimport com.pulumi.core.Output;\nimport com.pulumi.docker.buildx.Image;\nimport com.pulumi.docker.buildx.ImageArgs;\nimport com.pulumi.docker.buildx.inputs.BuildContextArgs;\nimport java.util.List;\nimport java.util.ArrayList;\nimport java.util.Map;\nimport java.io.File;\nimport java.nio.file.Files;\nimport java.nio.file.Paths;\n\npublic class App {\n public static void main(String[] args) {\n Pulumi.run(App::stack);\n }\n\n public static void stack(Context ctx) {\n var image = new Image(\"image\", ImageArgs.builder() \n .context(BuildContextArgs.builder()\n .location(\"app\")\n .build())\n .platforms( \n \"plan9/amd64\",\n \"plan9/386\")\n .build());\n\n }\n}\n```\n{{% /example %}}\n{{% example %}}\n### Registry export\n\n```typescript\nimport * as pulumi from \"@pulumi/pulumi\";\nimport * as docker from \"@pulumi/docker\";\n\nconst image = new docker.buildx.Image(\"image\", {\n context: {\n location: \"app\",\n },\n push: true,\n registries: [{\n address: \"docker.io\",\n password: dockerHubPassword,\n username: \"pulumibot\",\n }],\n tags: [\"docker.io/pulumi/pulumi:3.107.0\"],\n});\nexport const ref = myImage.ref;\n```\n```python\nimport pulumi\nimport pulumi_docker as docker\n\nimage = docker.buildx.Image(\"image\",\n context=docker.buildx.BuildContextArgs(\n location=\"app\",\n ),\n push=True,\n registries=[docker.buildx.RegistryAuthArgs(\n address=\"docker.io\",\n password=docker_hub_password,\n username=\"pulumibot\",\n )],\n tags=[\"docker.io/pulumi/pulumi:3.107.0\"])\npulumi.export(\"ref\", my_image[\"ref\"])\n```\n```csharp\nusing System.Collections.Generic;\nusing System.Linq;\nusing Pulumi;\nusing Docker = Pulumi.Docker;\n\nreturn await Deployment.RunAsync(() =\u003e \n{\n var image = new Docker.Buildx.Image(\"image\", new()\n {\n Context = new Docker.Buildx.Inputs.BuildContextArgs\n {\n Location = \"app\",\n },\n Push = true,\n Registries = new[]\n {\n new Docker.Buildx.Inputs.RegistryAuthArgs\n {\n Address = \"docker.io\",\n Password = dockerHubPassword,\n Username = \"pulumibot\",\n },\n },\n Tags = new[]\n {\n \"docker.io/pulumi/pulumi:3.107.0\",\n },\n });\n\n return new Dictionary\u003cstring, object?\u003e\n {\n [\"ref\"] = myImage.Ref,\n };\n});\n\n```\n```go\npackage main\n\nimport (\n\t\"github.com/pulumi/pulumi-docker/sdk/v4/go/docker/buildx\"\n\t\"github.com/pulumi/pulumi/sdk/v3/go/pulumi\"\n)\n\nfunc main() {\n\tpulumi.Run(func(ctx *pulumi.Context) error {\n\t\t_, err := buildx.NewImage(ctx, \"image\", \u0026buildx.ImageArgs{\n\t\t\tContext: \u0026buildx.BuildContextArgs{\n\t\t\t\tLocation: pulumi.String(\"app\"),\n\t\t\t},\n\t\t\tPush: pulumi.Bool(true),\n\t\t\tRegistries: buildx.RegistryAuthArray{\n\t\t\t\t\u0026buildx.RegistryAuthArgs{\n\t\t\t\t\tAddress: pulumi.String(\"docker.io\"),\n\t\t\t\t\tPassword: pulumi.Any(dockerHubPassword),\n\t\t\t\t\tUsername: pulumi.String(\"pulumibot\"),\n\t\t\t\t},\n\t\t\t},\n\t\t\tTags: pulumi.StringArray{\n\t\t\t\tpulumi.String(\"docker.io/pulumi/pulumi:3.107.0\"),\n\t\t\t},\n\t\t})\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\tctx.Export(\"ref\", myImage.Ref)\n\t\treturn nil\n\t})\n}\n```\n```yaml\ndescription: Registry export\nname: registry\noutputs:\n ref: ${my-image.ref}\nresources:\n image:\n properties:\n context:\n location: app\n push: true\n registries:\n - address: docker.io\n password: ${dockerHubPassword}\n username: pulumibot\n tags:\n - docker.io/pulumi/pulumi:3.107.0\n type: docker:buildx/image:Image\nruntime: yaml\n```\n```java\npackage generated_program;\n\nimport com.pulumi.Context;\nimport com.pulumi.Pulumi;\nimport com.pulumi.core.Output;\nimport com.pulumi.docker.buildx.Image;\nimport com.pulumi.docker.buildx.ImageArgs;\nimport com.pulumi.docker.buildx.inputs.BuildContextArgs;\nimport com.pulumi.docker.buildx.inputs.RegistryAuthArgs;\nimport java.util.List;\nimport java.util.ArrayList;\nimport java.util.Map;\nimport java.io.File;\nimport java.nio.file.Files;\nimport java.nio.file.Paths;\n\npublic class App {\n public static void main(String[] args) {\n Pulumi.run(App::stack);\n }\n\n public static void stack(Context ctx) {\n var image = new Image(\"image\", ImageArgs.builder() \n .context(BuildContextArgs.builder()\n .location(\"app\")\n .build())\n .push(true)\n .registries(RegistryAuthArgs.builder()\n .address(\"docker.io\")\n .password(dockerHubPassword)\n .username(\"pulumibot\")\n .build())\n .tags(\"docker.io/pulumi/pulumi:3.107.0\")\n .build());\n\n ctx.export(\"ref\", myImage.ref());\n }\n}\n```\n{{% /example %}}\n{{% example %}}\n### Caching\n\n```typescript\nimport * as pulumi from \"@pulumi/pulumi\";\nimport * as docker from \"@pulumi/docker\";\n\nconst image = new docker.buildx.Image(\"image\", {\n cacheFrom: [{\n local: {\n src: \"tmp/cache\",\n },\n }],\n cacheTo: [{\n local: {\n dest: \"tmp/cache\",\n mode: docker.buildx.image.CacheMode.Max,\n },\n }],\n context: {\n location: \"app\",\n },\n});\n```\n```python\nimport pulumi\nimport pulumi_docker as docker\n\nimage = docker.buildx.Image(\"image\",\n cache_from=[docker.buildx.CacheFromArgs(\n local=docker.buildx.CacheFromLocalArgs(\n src=\"tmp/cache\",\n ),\n )],\n cache_to=[docker.buildx.CacheToArgs(\n local=docker.buildx.CacheToLocalArgs(\n dest=\"tmp/cache\",\n mode=docker.buildx/image.CacheMode.MAX,\n ),\n )],\n context=docker.buildx.BuildContextArgs(\n location=\"app\",\n ))\n```\n```csharp\nusing System.Collections.Generic;\nusing System.Linq;\nusing Pulumi;\nusing Docker = Pulumi.Docker;\n\nreturn await Deployment.RunAsync(() =\u003e \n{\n var image = new Docker.Buildx.Image(\"image\", new()\n {\n CacheFrom = new[]\n {\n new Docker.Buildx.Inputs.CacheFromArgs\n {\n Local = new Docker.Buildx.Inputs.CacheFromLocalArgs\n {\n Src = \"tmp/cache\",\n },\n },\n },\n CacheTo = new[]\n {\n new Docker.Buildx.Inputs.CacheToArgs\n {\n Local = new Docker.Buildx.Inputs.CacheToLocalArgs\n {\n Dest = \"tmp/cache\",\n Mode = Docker.Buildx.Image.CacheMode.Max,\n },\n },\n },\n Context = new Docker.Buildx.Inputs.BuildContextArgs\n {\n Location = \"app\",\n },\n });\n\n});\n\n```\n```go\npackage main\n\nimport (\n\t\"github.com/pulumi/pulumi-docker/sdk/v4/go/docker/buildx\"\n\t\"github.com/pulumi/pulumi/sdk/v3/go/pulumi\"\n)\n\nfunc main() {\n\tpulumi.Run(func(ctx *pulumi.Context) error {\n\t\t_, err := buildx.NewImage(ctx, \"image\", \u0026buildx.ImageArgs{\n\t\t\tCacheFrom: buildx.CacheFromArray{\n\t\t\t\t\u0026buildx.CacheFromArgs{\n\t\t\t\t\tLocal: \u0026buildx.CacheFromLocalArgs{\n\t\t\t\t\t\tSrc: pulumi.String(\"tmp/cache\"),\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\tCacheTo: buildx.CacheToArray{\n\t\t\t\t\u0026buildx.CacheToArgs{\n\t\t\t\t\tLocal: \u0026buildx.CacheToLocalArgs{\n\t\t\t\t\t\tDest: pulumi.String(\"tmp/cache\"),\n\t\t\t\t\t\tMode: buildx.CacheModeMax,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\tContext: \u0026buildx.BuildContextArgs{\n\t\t\t\tLocation: pulumi.String(\"app\"),\n\t\t\t},\n\t\t})\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\treturn nil\n\t})\n}\n```\n```yaml\ndescription: Caching\nname: caching\nresources:\n image:\n properties:\n cacheFrom:\n - local:\n src: tmp/cache\n cacheTo:\n - local:\n dest: tmp/cache\n mode: max\n context:\n location: app\n type: docker:buildx/image:Image\nruntime: yaml\n```\n```java\npackage generated_program;\n\nimport com.pulumi.Context;\nimport com.pulumi.Pulumi;\nimport com.pulumi.core.Output;\nimport com.pulumi.docker.buildx.Image;\nimport com.pulumi.docker.buildx.ImageArgs;\nimport com.pulumi.docker.buildx.inputs.CacheFromArgs;\nimport com.pulumi.docker.buildx.inputs.CacheFromLocalArgs;\nimport com.pulumi.docker.buildx.inputs.CacheToArgs;\nimport com.pulumi.docker.buildx.inputs.CacheToLocalArgs;\nimport com.pulumi.docker.buildx.inputs.BuildContextArgs;\nimport java.util.List;\nimport java.util.ArrayList;\nimport java.util.Map;\nimport java.io.File;\nimport java.nio.file.Files;\nimport java.nio.file.Paths;\n\npublic class App {\n public static void main(String[] args) {\n Pulumi.run(App::stack);\n }\n\n public static void stack(Context ctx) {\n var image = new Image(\"image\", ImageArgs.builder() \n .cacheFrom(CacheFromArgs.builder()\n .local(CacheFromLocalArgs.builder()\n .src(\"tmp/cache\")\n .build())\n .build())\n .cacheTo(CacheToArgs.builder()\n .local(CacheToLocalArgs.builder()\n .dest(\"tmp/cache\")\n .mode(\"max\")\n .build())\n .build())\n .context(BuildContextArgs.builder()\n .location(\"app\")\n .build())\n .build());\n\n }\n}\n```\n{{% /example %}}\n{{% example %}}\n### Docker Build Cloud\n\n```typescript\nimport * as pulumi from \"@pulumi/pulumi\";\nimport * as docker from \"@pulumi/docker\";\n\nconst image = new docker.buildx.Image(\"image\", {\n builder: {\n name: \"cloud-builder-name\",\n },\n context: {\n location: \"app\",\n },\n exec: true,\n});\n```\n```python\nimport pulumi\nimport pulumi_docker as docker\n\nimage = docker.buildx.Image(\"image\",\n builder=docker.buildx.BuilderConfigArgs(\n name=\"cloud-builder-name\",\n ),\n context=docker.buildx.BuildContextArgs(\n location=\"app\",\n ),\n exec_=True)\n```\n```csharp\nusing System.Collections.Generic;\nusing System.Linq;\nusing Pulumi;\nusing Docker = Pulumi.Docker;\n\nreturn await Deployment.RunAsync(() =\u003e \n{\n var image = new Docker.Buildx.Image(\"image\", new()\n {\n Builder = new Docker.Buildx.Inputs.BuilderConfigArgs\n {\n Name = \"cloud-builder-name\",\n },\n Context = new Docker.Buildx.Inputs.BuildContextArgs\n {\n Location = \"app\",\n },\n Exec = true,\n });\n\n});\n\n```\n```go\npackage main\n\nimport (\n\t\"github.com/pulumi/pulumi-docker/sdk/v4/go/docker/buildx\"\n\t\"github.com/pulumi/pulumi/sdk/v3/go/pulumi\"\n)\n\nfunc main() {\n\tpulumi.Run(func(ctx *pulumi.Context) error {\n\t\t_, err := buildx.NewImage(ctx, \"image\", \u0026buildx.ImageArgs{\n\t\t\tBuilder: \u0026buildx.BuilderConfigArgs{\n\t\t\t\tName: pulumi.String(\"cloud-builder-name\"),\n\t\t\t},\n\t\t\tContext: \u0026buildx.BuildContextArgs{\n\t\t\t\tLocation: pulumi.String(\"app\"),\n\t\t\t},\n\t\t\tExec: pulumi.Bool(true),\n\t\t})\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\treturn nil\n\t})\n}\n```\n```yaml\ndescription: Docker Build Cloud\nname: dbc\nresources:\n image:\n properties:\n builder:\n name: cloud-builder-name\n context:\n location: app\n exec: true\n type: docker:buildx/image:Image\nruntime: yaml\n```\n```java\npackage generated_program;\n\nimport com.pulumi.Context;\nimport com.pulumi.Pulumi;\nimport com.pulumi.core.Output;\nimport com.pulumi.docker.buildx.Image;\nimport com.pulumi.docker.buildx.ImageArgs;\nimport com.pulumi.docker.buildx.inputs.BuilderConfigArgs;\nimport com.pulumi.docker.buildx.inputs.BuildContextArgs;\nimport java.util.List;\nimport java.util.ArrayList;\nimport java.util.Map;\nimport java.io.File;\nimport java.nio.file.Files;\nimport java.nio.file.Paths;\n\npublic class App {\n public static void main(String[] args) {\n Pulumi.run(App::stack);\n }\n\n public static void stack(Context ctx) {\n var image = new Image(\"image\", ImageArgs.builder() \n .builder(BuilderConfigArgs.builder()\n .name(\"cloud-builder-name\")\n .build())\n .context(BuildContextArgs.builder()\n .location(\"app\")\n .build())\n .exec(true)\n .build());\n\n }\n}\n```\n{{% /example %}}\n{{% example %}}\n### Build arguments\n\n```typescript\nimport * as pulumi from \"@pulumi/pulumi\";\nimport * as docker from \"@pulumi/docker\";\n\nconst image = new docker.buildx.Image(\"image\", {\n buildArgs: {\n SET_ME_TO_TRUE: \"true\",\n },\n context: {\n location: \"app\",\n },\n});\n```\n```python\nimport pulumi\nimport pulumi_docker as docker\n\nimage = docker.buildx.Image(\"image\",\n build_args={\n \"SET_ME_TO_TRUE\": \"true\",\n },\n context=docker.buildx.BuildContextArgs(\n location=\"app\",\n ))\n```\n```csharp\nusing System.Collections.Generic;\nusing System.Linq;\nusing Pulumi;\nusing Docker = Pulumi.Docker;\n\nreturn await Deployment.RunAsync(() =\u003e \n{\n var image = new Docker.Buildx.Image(\"image\", new()\n {\n BuildArgs = \n {\n { \"SET_ME_TO_TRUE\", \"true\" },\n },\n Context = new Docker.Buildx.Inputs.BuildContextArgs\n {\n Location = \"app\",\n },\n });\n\n});\n\n```\n```go\npackage main\n\nimport (\n\t\"github.com/pulumi/pulumi-docker/sdk/v4/go/docker/buildx\"\n\t\"github.com/pulumi/pulumi/sdk/v3/go/pulumi\"\n)\n\nfunc main() {\n\tpulumi.Run(func(ctx *pulumi.Context) error {\n\t\t_, err := buildx.NewImage(ctx, \"image\", \u0026buildx.ImageArgs{\n\t\t\tBuildArgs: pulumi.StringMap{\n\t\t\t\t\"SET_ME_TO_TRUE\": pulumi.String(\"true\"),\n\t\t\t},\n\t\t\tContext: \u0026buildx.BuildContextArgs{\n\t\t\t\tLocation: pulumi.String(\"app\"),\n\t\t\t},\n\t\t})\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\treturn nil\n\t})\n}\n```\n```yaml\ndescription: Build arguments\nname: build-args\nresources:\n image:\n properties:\n buildArgs:\n SET_ME_TO_TRUE: \"true\"\n context:\n location: app\n type: docker:buildx/image:Image\nruntime: yaml\n```\n```java\npackage generated_program;\n\nimport com.pulumi.Context;\nimport com.pulumi.Pulumi;\nimport com.pulumi.core.Output;\nimport com.pulumi.docker.buildx.Image;\nimport com.pulumi.docker.buildx.ImageArgs;\nimport com.pulumi.docker.buildx.inputs.BuildContextArgs;\nimport java.util.List;\nimport java.util.ArrayList;\nimport java.util.Map;\nimport java.io.File;\nimport java.nio.file.Files;\nimport java.nio.file.Paths;\n\npublic class App {\n public static void main(String[] args) {\n Pulumi.run(App::stack);\n }\n\n public static void stack(Context ctx) {\n var image = new Image(\"image\", ImageArgs.builder() \n .buildArgs(Map.of(\"SET_ME_TO_TRUE\", \"true\"))\n .context(BuildContextArgs.builder()\n .location(\"app\")\n .build())\n .build());\n\n }\n}\n```\n{{% /example %}}\n{{% example %}}\n### Build target\n\n```typescript\nimport * as pulumi from \"@pulumi/pulumi\";\nimport * as docker from \"@pulumi/docker\";\n\nconst image = new docker.buildx.Image(\"image\", {\n context: {\n location: \"app\",\n },\n target: \"build-me\",\n});\n```\n```python\nimport pulumi\nimport pulumi_docker as docker\n\nimage = docker.buildx.Image(\"image\",\n context=docker.buildx.BuildContextArgs(\n location=\"app\",\n ),\n target=\"build-me\")\n```\n```csharp\nusing System.Collections.Generic;\nusing System.Linq;\nusing Pulumi;\nusing Docker = Pulumi.Docker;\n\nreturn await Deployment.RunAsync(() =\u003e \n{\n var image = new Docker.Buildx.Image(\"image\", new()\n {\n Context = new Docker.Buildx.Inputs.BuildContextArgs\n {\n Location = \"app\",\n },\n Target = \"build-me\",\n });\n\n});\n\n```\n```go\npackage main\n\nimport (\n\t\"github.com/pulumi/pulumi-docker/sdk/v4/go/docker/buildx\"\n\t\"github.com/pulumi/pulumi/sdk/v3/go/pulumi\"\n)\n\nfunc main() {\n\tpulumi.Run(func(ctx *pulumi.Context) error {\n\t\t_, err := buildx.NewImage(ctx, \"image\", \u0026buildx.ImageArgs{\n\t\t\tContext: \u0026buildx.BuildContextArgs{\n\t\t\t\tLocation: pulumi.String(\"app\"),\n\t\t\t},\n\t\t\tTarget: pulumi.String(\"build-me\"),\n\t\t})\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\treturn nil\n\t})\n}\n```\n```yaml\ndescription: Build target\nname: build-target\nresources:\n image:\n properties:\n context:\n location: app\n target: build-me\n type: docker:buildx/image:Image\nruntime: yaml\n```\n```java\npackage generated_program;\n\nimport com.pulumi.Context;\nimport com.pulumi.Pulumi;\nimport com.pulumi.core.Output;\nimport com.pulumi.docker.buildx.Image;\nimport com.pulumi.docker.buildx.ImageArgs;\nimport com.pulumi.docker.buildx.inputs.BuildContextArgs;\nimport java.util.List;\nimport java.util.ArrayList;\nimport java.util.Map;\nimport java.io.File;\nimport java.nio.file.Files;\nimport java.nio.file.Paths;\n\npublic class App {\n public static void main(String[] args) {\n Pulumi.run(App::stack);\n }\n\n public static void stack(Context ctx) {\n var image = new Image(\"image\", ImageArgs.builder() \n .context(BuildContextArgs.builder()\n .location(\"app\")\n .build())\n .target(\"build-me\")\n .build());\n\n }\n}\n```\n{{% /example %}}\n{{% example %}}\n### Named contexts\n\n```typescript\nimport * as pulumi from \"@pulumi/pulumi\";\nimport * as docker from \"@pulumi/docker\";\n\nconst image = new docker.buildx.Image(\"image\", {context: {\n location: \"app\",\n named: {\n \"golang:latest\": {\n location: \"docker-image://golang@sha256:b8e62cf593cdaff36efd90aa3a37de268e6781a2e68c6610940c48f7cdf36984\",\n },\n },\n}});\n```\n```python\nimport pulumi\nimport pulumi_docker as docker\n\nimage = docker.buildx.Image(\"image\", context=docker.buildx.BuildContextArgs(\n location=\"app\",\n named={\n \"golang:latest\": docker.buildx.ContextArgs(\n location=\"docker-image://golang@sha256:b8e62cf593cdaff36efd90aa3a37de268e6781a2e68c6610940c48f7cdf36984\",\n ),\n },\n))\n```\n```csharp\nusing System.Collections.Generic;\nusing System.Linq;\nusing Pulumi;\nusing Docker = Pulumi.Docker;\n\nreturn await Deployment.RunAsync(() =\u003e \n{\n var image = new Docker.Buildx.Image(\"image\", new()\n {\n Context = new Docker.Buildx.Inputs.BuildContextArgs\n {\n Location = \"app\",\n Named = \n {\n { \"golang:latest\", new Docker.Buildx.Inputs.ContextArgs\n {\n Location = \"docker-image://golang@sha256:b8e62cf593cdaff36efd90aa3a37de268e6781a2e68c6610940c48f7cdf36984\",\n } },\n },\n },\n });\n\n});\n\n```\n```go\npackage main\n\nimport (\n\t\"github.com/pulumi/pulumi-docker/sdk/v4/go/docker/buildx\"\n\t\"github.com/pulumi/pulumi/sdk/v3/go/pulumi\"\n)\n\nfunc main() {\n\tpulumi.Run(func(ctx *pulumi.Context) error {\n\t\t_, err := buildx.NewImage(ctx, \"image\", \u0026buildx.ImageArgs{\n\t\t\tContext: \u0026buildx.BuildContextArgs{\n\t\t\t\tLocation: pulumi.String(\"app\"),\n\t\t\t\tNamed: buildx.ContextMap{\n\t\t\t\t\t\"golang:latest\": \u0026buildx.ContextArgs{\n\t\t\t\t\t\tLocation: pulumi.String(\"docker-image://golang@sha256:b8e62cf593cdaff36efd90aa3a37de268e6781a2e68c6610940c48f7cdf36984\"),\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t})\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\treturn nil\n\t})\n}\n```\n```yaml\ndescription: Named contexts\nname: named-contexts\nresources:\n image:\n properties:\n context:\n location: app\n named:\n golang:latest:\n location: docker-image://golang@sha256:b8e62cf593cdaff36efd90aa3a37de268e6781a2e68c6610940c48f7cdf36984\n type: docker:buildx/image:Image\nruntime: yaml\n```\n```java\npackage generated_program;\n\nimport com.pulumi.Context;\nimport com.pulumi.Pulumi;\nimport com.pulumi.core.Output;\nimport com.pulumi.docker.buildx.Image;\nimport com.pulumi.docker.buildx.ImageArgs;\nimport com.pulumi.docker.buildx.inputs.BuildContextArgs;\nimport java.util.List;\nimport java.util.ArrayList;\nimport java.util.Map;\nimport java.io.File;\nimport java.nio.file.Files;\nimport java.nio.file.Paths;\n\npublic class App {\n public static void main(String[] args) {\n Pulumi.run(App::stack);\n }\n\n public static void stack(Context ctx) {\n var image = new Image(\"image\", ImageArgs.builder() \n .context(BuildContextArgs.builder()\n .location(\"app\")\n .named(Map.of(\"golang:latest\", Map.of(\"location\", \"docker-image://golang@sha256:b8e62cf593cdaff36efd90aa3a37de268e6781a2e68c6610940c48f7cdf36984\")))\n .build())\n .build());\n\n }\n}\n```\n{{% /example %}}\n{{% example %}}\n### Remote context\n\n```typescript\nimport * as pulumi from \"@pulumi/pulumi\";\nimport * as docker from \"@pulumi/docker\";\n\nconst image = new docker.buildx.Image(\"image\", {context: {\n location: \"https://raw.githubusercontent.com/pulumi/pulumi-docker/api-types/provider/testdata/Dockerfile\",\n}});\n```\n```python\nimport pulumi\nimport pulumi_docker as docker\n\nimage = docker.buildx.Image(\"image\", context=docker.buildx.BuildContextArgs(\n location=\"https://raw.githubusercontent.com/pulumi/pulumi-docker/api-types/provider/testdata/Dockerfile\",\n))\n```\n```csharp\nusing System.Collections.Generic;\nusing System.Linq;\nusing Pulumi;\nusing Docker = Pulumi.Docker;\n\nreturn await Deployment.RunAsync(() =\u003e \n{\n var image = new Docker.Buildx.Image(\"image\", new()\n {\n Context = new Docker.Buildx.Inputs.BuildContextArgs\n {\n Location = \"https://raw.githubusercontent.com/pulumi/pulumi-docker/api-types/provider/testdata/Dockerfile\",\n },\n });\n\n});\n\n```\n```go\npackage main\n\nimport (\n\t\"github.com/pulumi/pulumi-docker/sdk/v4/go/docker/buildx\"\n\t\"github.com/pulumi/pulumi/sdk/v3/go/pulumi\"\n)\n\nfunc main() {\n\tpulumi.Run(func(ctx *pulumi.Context) error {\n\t\t_, err := buildx.NewImage(ctx, \"image\", \u0026buildx.ImageArgs{\n\t\t\tContext: \u0026buildx.BuildContextArgs{\n\t\t\t\tLocation: pulumi.String(\"https://raw.githubusercontent.com/pulumi/pulumi-docker/api-types/provider/testdata/Dockerfile\"),\n\t\t\t},\n\t\t})\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\treturn nil\n\t})\n}\n```\n```yaml\ndescription: Remote context\nname: remote-context\nresources:\n image:\n properties:\n context:\n location: https://raw.githubusercontent.com/pulumi/pulumi-docker/api-types/provider/testdata/Dockerfile\n type: docker:buildx/image:Image\nruntime: yaml\n```\n```java\npackage generated_program;\n\nimport com.pulumi.Context;\nimport com.pulumi.Pulumi;\nimport com.pulumi.core.Output;\nimport com.pulumi.docker.buildx.Image;\nimport com.pulumi.docker.buildx.ImageArgs;\nimport com.pulumi.docker.buildx.inputs.BuildContextArgs;\nimport java.util.List;\nimport java.util.ArrayList;\nimport java.util.Map;\nimport java.io.File;\nimport java.nio.file.Files;\nimport java.nio.file.Paths;\n\npublic class App {\n public static void main(String[] args) {\n Pulumi.run(App::stack);\n }\n\n public static void stack(Context ctx) {\n var image = new Image(\"image\", ImageArgs.builder() \n .context(BuildContextArgs.builder()\n .location(\"https://raw.githubusercontent.com/pulumi/pulumi-docker/api-types/provider/testdata/Dockerfile\")\n .build())\n .build());\n\n }\n}\n```\n{{% /example %}}\n{{% example %}}\n### Inline Dockerfile\n\n```typescript\nimport * as pulumi from \"@pulumi/pulumi\";\nimport * as docker from \"@pulumi/docker\";\n\nconst image = new docker.buildx.Image(\"image\", {\n context: {\n location: \"app\",\n },\n dockerfile: {\n inline: `FROM busybox\nCOPY hello.c ./\n`,\n },\n});\n```\n```python\nimport pulumi\nimport pulumi_docker as docker\n\nimage = docker.buildx.Image(\"image\",\n context=docker.buildx.BuildContextArgs(\n location=\"app\",\n ),\n dockerfile=docker.buildx.DockerfileArgs(\n inline=\"\"\"FROM busybox\nCOPY hello.c ./\n\"\"\",\n ))\n```\n```csharp\nusing System.Collections.Generic;\nusing System.Linq;\nusing Pulumi;\nusing Docker = Pulumi.Docker;\n\nreturn await Deployment.RunAsync(() =\u003e \n{\n var image = new Docker.Buildx.Image(\"image\", new()\n {\n Context = new Docker.Buildx.Inputs.BuildContextArgs\n {\n Location = \"app\",\n },\n Dockerfile = new Docker.Buildx.Inputs.DockerfileArgs\n {\n Inline = @\"FROM busybox\nCOPY hello.c ./\n\",\n },\n });\n\n});\n\n```\n```go\npackage main\n\nimport (\n\t\"github.com/pulumi/pulumi-docker/sdk/v4/go/docker/buildx\"\n\t\"github.com/pulumi/pulumi/sdk/v3/go/pulumi\"\n)\n\nfunc main() {\n\tpulumi.Run(func(ctx *pulumi.Context) error {\n\t\t_, err := buildx.NewImage(ctx, \"image\", \u0026buildx.ImageArgs{\n\t\t\tContext: \u0026buildx.BuildContextArgs{\n\t\t\t\tLocation: pulumi.String(\"app\"),\n\t\t\t},\n\t\t\tDockerfile: \u0026buildx.DockerfileArgs{\n\t\t\t\tInline: pulumi.String(\"FROM busybox\\nCOPY hello.c ./\\n\"),\n\t\t\t},\n\t\t})\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\treturn nil\n\t})\n}\n```\n```yaml\ndescription: Inline Dockerfile\nname: inline\nresources:\n image:\n properties:\n context:\n location: app\n dockerfile:\n inline: |\n FROM busybox\n COPY hello.c ./\n type: docker:buildx/image:Image\nruntime: yaml\n```\n```java\npackage generated_program;\n\nimport com.pulumi.Context;\nimport com.pulumi.Pulumi;\nimport com.pulumi.core.Output;\nimport com.pulumi.docker.buildx.Image;\nimport com.pulumi.docker.buildx.ImageArgs;\nimport com.pulumi.docker.buildx.inputs.BuildContextArgs;\nimport com.pulumi.docker.buildx.inputs.DockerfileArgs;\nimport java.util.List;\nimport java.util.ArrayList;\nimport java.util.Map;\nimport java.io.File;\nimport java.nio.file.Files;\nimport java.nio.file.Paths;\n\npublic class App {\n public static void main(String[] args) {\n Pulumi.run(App::stack);\n }\n\n public static void stack(Context ctx) {\n var image = new Image(\"image\", ImageArgs.builder() \n .context(BuildContextArgs.builder()\n .location(\"app\")\n .build())\n .dockerfile(DockerfileArgs.builder()\n .inline(\"\"\"\nFROM busybox\nCOPY hello.c ./\n \"\"\")\n .build())\n .build());\n\n }\n}\n```\n{{% /example %}}\n{{% example %}}\n### Remote context\n\n```typescript\nimport * as pulumi from \"@pulumi/pulumi\";\nimport * as docker from \"@pulumi/docker\";\n\nconst image = new docker.buildx.Image(\"image\", {\n context: {\n location: \"https://github.com/docker-library/hello-world.git\",\n },\n dockerfile: {\n location: \"app/Dockerfile\",\n },\n});\n```\n```python\nimport pulumi\nimport pulumi_docker as docker\n\nimage = docker.buildx.Image(\"image\",\n context=docker.buildx.BuildContextArgs(\n location=\"https://github.com/docker-library/hello-world.git\",\n ),\n dockerfile=docker.buildx.DockerfileArgs(\n location=\"app/Dockerfile\",\n ))\n```\n```csharp\nusing System.Collections.Generic;\nusing System.Linq;\nusing Pulumi;\nusing Docker = Pulumi.Docker;\n\nreturn await Deployment.RunAsync(() =\u003e \n{\n var image = new Docker.Buildx.Image(\"image\", new()\n {\n Context = new Docker.Buildx.Inputs.BuildContextArgs\n {\n Location = \"https://github.com/docker-library/hello-world.git\",\n },\n Dockerfile = new Docker.Buildx.Inputs.DockerfileArgs\n {\n Location = \"app/Dockerfile\",\n },\n });\n\n});\n\n```\n```go\npackage main\n\nimport (\n\t\"github.com/pulumi/pulumi-docker/sdk/v4/go/docker/buildx\"\n\t\"github.com/pulumi/pulumi/sdk/v3/go/pulumi\"\n)\n\nfunc main() {\n\tpulumi.Run(func(ctx *pulumi.Context) error {\n\t\t_, err := buildx.NewImage(ctx, \"image\", \u0026buildx.ImageArgs{\n\t\t\tContext: \u0026buildx.BuildContextArgs{\n\t\t\t\tLocation: pulumi.String(\"https://github.com/docker-library/hello-world.git\"),\n\t\t\t},\n\t\t\tDockerfile: \u0026buildx.DockerfileArgs{\n\t\t\t\tLocation: pulumi.String(\"app/Dockerfile\"),\n\t\t\t},\n\t\t})\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\treturn nil\n\t})\n}\n```\n```yaml\ndescription: Remote context\nname: remote-context\nresources:\n image:\n properties:\n context:\n location: https://github.com/docker-library/hello-world.git\n dockerfile:\n location: app/Dockerfile\n type: docker:buildx/image:Image\nruntime: yaml\n```\n```java\npackage generated_program;\n\nimport com.pulumi.Context;\nimport com.pulumi.Pulumi;\nimport com.pulumi.core.Output;\nimport com.pulumi.docker.buildx.Image;\nimport com.pulumi.docker.buildx.ImageArgs;\nimport com.pulumi.docker.buildx.inputs.BuildContextArgs;\nimport com.pulumi.docker.buildx.inputs.DockerfileArgs;\nimport java.util.List;\nimport java.util.ArrayList;\nimport java.util.Map;\nimport java.io.File;\nimport java.nio.file.Files;\nimport java.nio.file.Paths;\n\npublic class App {\n public static void main(String[] args) {\n Pulumi.run(App::stack);\n }\n\n public static void stack(Context ctx) {\n var image = new Image(\"image\", ImageArgs.builder() \n .context(BuildContextArgs.builder()\n .location(\"https://github.com/docker-library/hello-world.git\")\n .build())\n .dockerfile(DockerfileArgs.builder()\n .location(\"app/Dockerfile\")\n .build())\n .build());\n\n }\n}\n```\n{{% /example %}}\n{{% example %}}\n### Local export\n\n```typescript\nimport * as pulumi from \"@pulumi/pulumi\";\nimport * as docker from \"@pulumi/docker\";\n\nconst image = new docker.buildx.Image(\"image\", {\n context: {\n location: \"app\",\n },\n exports: [{\n docker: {\n tar: true,\n },\n }],\n});\n```\n```python\nimport pulumi\nimport pulumi_docker as docker\n\nimage = docker.buildx.Image(\"image\",\n context=docker.buildx.BuildContextArgs(\n location=\"app\",\n ),\n exports=[docker.buildx.ExportArgs(\n docker=docker.buildx.ExportDockerArgs(\n tar=True,\n ),\n )])\n```\n```csharp\nusing System.Collections.Generic;\nusing System.Linq;\nusing Pulumi;\nusing Docker = Pulumi.Docker;\n\nreturn await Deployment.RunAsync(() =\u003e \n{\n var image = new Docker.Buildx.Image(\"image\", new()\n {\n Context = new Docker.Buildx.Inputs.BuildContextArgs\n {\n Location = \"app\",\n },\n Exports = new[]\n {\n new Docker.Buildx.Inputs.ExportArgs\n {\n Docker = new Docker.Buildx.Inputs.ExportDockerArgs\n {\n Tar = true,\n },\n },\n },\n });\n\n});\n\n```\n```go\npackage main\n\nimport (\n\t\"github.com/pulumi/pulumi-docker/sdk/v4/go/docker/buildx\"\n\t\"github.com/pulumi/pulumi/sdk/v3/go/pulumi\"\n)\n\nfunc main() {\n\tpulumi.Run(func(ctx *pulumi.Context) error {\n\t\t_, err := buildx.NewImage(ctx, \"image\", \u0026buildx.ImageArgs{\n\t\t\tContext: \u0026buildx.BuildContextArgs{\n\t\t\t\tLocation: pulumi.String(\"app\"),\n\t\t\t},\n\t\t\tExports: buildx.ExportArray{\n\t\t\t\t\u0026buildx.ExportArgs{\n\t\t\t\t\tDocker: \u0026buildx.ExportDockerArgs{\n\t\t\t\t\t\tTar: pulumi.Bool(true),\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t})\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\treturn nil\n\t})\n}\n```\n```yaml\ndescription: Local export\nname: docker-load\nresources:\n image:\n properties:\n context:\n location: app\n exports:\n - docker:\n tar: true\n type: docker:buildx/image:Image\nruntime: yaml\n```\n```java\npackage generated_program;\n\nimport com.pulumi.Context;\nimport com.pulumi.Pulumi;\nimport com.pulumi.core.Output;\nimport com.pulumi.docker.buildx.Image;\nimport com.pulumi.docker.buildx.ImageArgs;\nimport com.pulumi.docker.buildx.inputs.BuildContextArgs;\nimport com.pulumi.docker.buildx.inputs.ExportArgs;\nimport com.pulumi.docker.buildx.inputs.ExportDockerArgs;\nimport java.util.List;\nimport java.util.ArrayList;\nimport java.util.Map;\nimport java.io.File;\nimport java.nio.file.Files;\nimport java.nio.file.Paths;\n\npublic class App {\n public static void main(String[] args) {\n Pulumi.run(App::stack);\n }\n\n public static void stack(Context ctx) {\n var image = new Image(\"image\", ImageArgs.builder() \n .context(BuildContextArgs.builder()\n .location(\"app\")\n .build())\n .exports(ExportArgs.builder()\n .docker(ExportDockerArgs.builder()\n .tar(true)\n .build())\n .build())\n .build());\n\n }\n}\n```\n{{% /example %}}\n{{% /examples %}}", "properties": { "addHosts": { "type": "array", diff --git a/provider/internal/cache.go b/provider/internal/cache.go index e4061693..916c0469 100644 --- a/provider/internal/cache.go +++ b/provider/internal/cache.go @@ -93,9 +93,12 @@ func (c *CacheWithOCI) Annotate(a infer.Annotator) { `)) a.Describe(&c.ImageManifest, dedent(` Export cache manifest as an OCI-compatible image manifest instead of a - manifest list (requires OCI media types). + manifest list. Requires "ociMediaTypes" to also be "true". - Defaults to "false". + Some registries like AWS ECR will not work with caching if this is + "false". + + Defaults to "false" to match Docker's default behavior. `)) a.SetDefault(&c.OCI, true) diff --git a/provider/internal/client.go b/provider/internal/client.go index c8830182..63194718 100644 --- a/provider/internal/client.go +++ b/provider/internal/client.go @@ -21,7 +21,6 @@ import ( "github.com/docker/cli/cli/command" "github.com/docker/cli/cli/flags" "github.com/docker/docker/api/types" - "github.com/docker/docker/api/types/image" "github.com/moby/buildkit/client" "github.com/moby/buildkit/session" "github.com/moby/buildkit/session/auth/authprovider" @@ -41,7 +40,7 @@ type Client interface { Build(ctx provider.Context, b Build) (*client.SolveResponse, error) BuildKitEnabled() (bool, error) Inspect(ctx context.Context, id string) ([]descriptor.Descriptor, error) - Delete(ctx context.Context, id string) ([]image.DeleteResponse, error) + Delete(ctx context.Context, id string) error ManifestCreate(ctx provider.Context, push bool, target string, refs ...string) error ManifestInspect(ctx provider.Context, target string) (string, error) @@ -334,7 +333,7 @@ func (c *cli) ManifestDelete(ctx provider.Context, target string) error { return nil } if err != nil { - return fmt.Errorf("fetching head: %w", err) + return err } return nil @@ -383,11 +382,47 @@ func (c *cli) Inspect(ctx context.Context, r string) ([]descriptor.Descriptor, e return []descriptor.Descriptor{m.GetDescriptor()}, nil } -// Delete deletes an image with the given ID. -func (c *cli) Delete(ctx context.Context, id string) ([]image.DeleteResponse, error) { - return c.Client().ImageRemove(ctx, id, types.ImageRemoveOptions{ +// Delete attempts to delete an image with the given ref. Many registries don't +// support the DELETE API yet, so this operation is not guaranteed to work. +func (c *cli) Delete(ctx context.Context, r string) error { + // Attempt to delete the ref locally if it exists. + _, _ = c.Client().ImageRemove(ctx, r, types.ImageRemoveOptions{ Force: true, // Needed in case the image has multiple tags. }) + + // Attempt to delete the ref remotely if it was pushed -- requires a + // digest. + ref, err := ref.New(r) + if err != nil || ref.Digest == "" { + return nil + } + + rc := c.rc() + + // TODO: Multi-platform manifests are left dangling on ECR. + // m, err := rc.ManifestGet(ctx, ref) + // if err != nil { + // return err + // } + + // if mi, ok := m.(manifest.Indexer); ok { + // ml, err := mi.GetManifestList() + // if err != nil { + // return err + // } + + // for _, mm := range ml { + // rr := ref.SetDigest(mm.Digest.String()) + // err = rc.ManifestDelete(ctx, rr, regclient.WithManifestCheckReferrers()) + // if err != nil { + // return err + // } + // } + // } + + _ = rc.ManifestDelete(ctx, ref) + + return nil } func normalizeReference(ref string) (reference.Named, error) { diff --git a/provider/internal/doc/migration.md b/provider/internal/doc/migration.md index 33926a40..5c344369 100644 --- a/provider/internal/doc/migration.md +++ b/provider/internal/doc/migration.md @@ -74,7 +74,8 @@ The `buidx.Image` will query your registries during `refresh` to ensure the expe If any are missing a subsequent `update` will push them. When a `buildx.Image` is deleted, it will _attempt_ to also delete any pushed tags. -Deletion of remote tags is not guaranteed, because not all registries currently support this operation (`docker.io` in particular). +Deletion of remote tags is not guaranteed because not all registries support the manifest `DELETE` API (`docker.io` in particular). +Manifests are _not_ deleted in the same way during updates -- to do so safely would require a full build to determine whether a Pulumi operation should be an update or update-replace. Use the [`retainOnDelete: true`](https://www.pulumi.com/docs/concepts/options/retainondelete/) option if you do not want tags deleted. diff --git a/provider/internal/image.go b/provider/internal/image.go index 0aff1df2..08f7c725 100644 --- a/provider/internal/image.go +++ b/provider/internal/image.go @@ -8,6 +8,7 @@ import ( "os" "path/filepath" "reflect" + "slices" "strings" // For examples/docs. @@ -28,6 +29,7 @@ import ( "github.com/moby/buildkit/frontend/dockerfile/parser" "github.com/moby/buildkit/session" "github.com/moby/buildkit/session/secrets/secretsprovider" + "github.com/regclient/regclient/types/ref" "github.com/spf13/afero" provider "github.com/pulumi/pulumi-go-provider" @@ -117,10 +119,10 @@ func (ia *ImageArgs) Annotate(a infer.Annotator) { `)) a.Describe(&ia.BuildArgs, dedent(` "ARG" names and values to set during the build. - + These variables are accessed like environment variables inside "RUN" instructions. - + Build arguments are persisted in the image, so you should use "secrets" if these arguments are sensitive. @@ -170,7 +172,7 @@ func (ia *ImageArgs) Annotate(a infer.Annotator) { Images are only stored in the local cache unless "exports" are explicitly configured. - + Exporting to multiple destinations requires a daemon running BuildKit 0.13 or later. @@ -202,7 +204,7 @@ func (ia *ImageArgs) Annotate(a infer.Annotator) { `)) a.Describe(&ia.Platforms, dedent(` Set target platform(s) for the build. Defaults to the host's platform. - + Equivalent to Docker's "--platform" flag. `)) a.Describe(&ia.Pull, dedent(` @@ -475,7 +477,7 @@ func (ia ImageArgs) toBuild( return nil, err } - if len(ia.Exports) == 0 { + if len(ia.Exports) == 0 && !ia.Push && !ia.Load { ctx.Log(diag.Warning, "No exports were specified so the build will only remain in the local build cache. "+ "Use `push` to upload the image to a registry, or silence this warning with a `cacheonly` export.", @@ -727,15 +729,16 @@ func (ia *ImageArgs) toBuildOptions(preview bool) (controllerapi.BuildOptions, e return opts, multierr } -// Update builds the image using buildkit. -func (i *Image) Update( +// Create builds an image using buildkit. +func (i *Image) Create( ctx provider.Context, - _ string, - state ImageState, + name string, input ImageArgs, preview bool, -) (ImageState, error) { - state.ImageArgs = input +) (string, ImageState, error) { + state := ImageState{ImageArgs: input} + id := name + // Default our ref to one of our tags. for _, tag := range state.Tags { if _, err := normalizeReference(tag); err != nil { @@ -747,20 +750,20 @@ func (i *Image) Update( cli, err := i.client(ctx, state, input) if err != nil { - return state, err + return id, state, err } ok, err := cli.BuildKitEnabled() if err != nil { - return state, fmt.Errorf("checking buildkit compatibility: %w", err) + return id, state, fmt.Errorf("checking buildkit compatibility: %w", err) } if !ok { - return state, fmt.Errorf("buildkit is not supported on this host") + return id, state, fmt.Errorf("buildkit is not supported on this host") } build, err := input.toBuild(ctx, preview) if err != nil { - return state, fmt.Errorf("preparing: %w", err) + return id, state, fmt.Errorf("preparing: %w", err) } hash, err := BuildxContext( @@ -769,30 +772,31 @@ func (i *Image) Update( input.Context.Named.Map(), ) if err != nil { - return state, fmt.Errorf("hashing build context: %w", err) + return id, state, fmt.Errorf("hashing build context: %w", err) } state.ContextHash = hash if preview && !input.shouldBuildOnPreview() { - return state, nil + return id, state, nil } if preview && !input.buildable() { ctx.Log(diag.Warning, "Skipping preview build because some inputs are unknown.") - return state, nil + return id, state, nil } result, err := cli.Build(ctx, build) if err != nil { - return state, err + return id, state, err } if d, ok := result.ExporterResponse[exptypes.ExporterImageDigestKey]; ok { state.Digest = d + id = d } if state.Digest == "" { // Can't construct a ref, nothing else to do. - return state, nil + return id, state, nil } // Take the first registry tag we find and add a digest to it. That becomes @@ -807,18 +811,21 @@ func (i *Image) Update( break } - return state, nil + return id, state, nil } -// Create initializes a new resource and performs an Update on it. -func (i *Image) Create( +// Update builds a new image. Normally we create-replace resources, but for +// images built locally there is nothing to delete. We treat those cases as +// updates and simply re-build the image without deleting anything. +func (i *Image) Update( ctx provider.Context, name string, + _ ImageState, input ImageArgs, preview bool, -) (string, ImageState, error) { - state, err := i.Update(ctx, name, ImageState{}, input, preview) - return name, state, err +) (ImageState, error) { + _, state, err := i.Create(ctx, name, input, preview) + return state, err } // Read attempts to read manifests from an image's exports. An image without @@ -884,9 +891,8 @@ func (i *Image) Read( return name, input, state, nil } -// Delete deletes an Image. If the Image was already deleted out-of-band it is treated as a success. -// -// Any tags previously pushed to registries will not be deleted. +// Delete deletes an Image. If the Image was already deleted out-of-band it is +// treated as a success. func (i *Image) Delete( ctx provider.Context, _ string, @@ -897,31 +903,36 @@ func (i *Image) Delete( return err } - var multierr error + if state.Digest == "" { + // Nothing was exported. Just try to delete the local image. + return cli.Delete(ctx, state.Ref) + } + + digests := []string{} + // Construct a ref with digest for each repository we pushed to. for _, tag := range state.Tags { - ref, err := reference.ParseNamed(tag) + ref, err := ref.New(tag) if err != nil { continue } - deletions, err := cli.Delete(context.Context(ctx), ref.String()) + digested := ref.SetDigest(state.Digest) + digests = append(digests, digested.CommonName()) + } + + slices.Sort(digests) + digests = slices.Compact(digests) + + var multierr error + for _, digested := range digests { + err = cli.Delete(context.Context(ctx), digested) if errdefs.IsNotFound(err) { + ctx.Log(diag.Warning, digested+" not found") continue // Nothing to do. } multierr = errors.Join(multierr, err) - - for _, d := range deletions { - if d.Deleted != "" { - ctx.Log(diag.Info, d.Deleted) - } - if d.Untagged != "" { - ctx.Log(diag.Info, d.Untagged) - } - } } - // TODO: Delete tags from registries? - return multierr } @@ -1001,7 +1012,7 @@ func (*Image) Diff( diff["tags"] = update } if !reflect.DeepEqual(olds.Target, news.Target) { - diff["targets"] = update + diff["target"] = update } // pull=true indicates that we want to keep base layers up-to-date. In this diff --git a/provider/internal/image_test.go b/provider/internal/image_test.go index 00394d8c..f1a73302 100644 --- a/provider/internal/image_test.go +++ b/provider/internal/image_test.go @@ -10,7 +10,6 @@ import ( _ "github.com/docker/buildx/driver/docker-container" "github.com/docker/distribution/reference" - "github.com/docker/docker/api/types/image" "github.com/moby/buildkit/client" "github.com/moby/buildkit/exporter/containerimage/exptypes" "github.com/regclient/regclient/types/descriptor" @@ -60,10 +59,9 @@ func TestImageLifecycle(t *testing.T) { }, nil }, ).AnyTimes() - c.EXPECT().Delete(gomock.Any(), "docker.io/pulumibot/buildkit-e2e").Return( - []image.DeleteResponse{{Deleted: "deleted"}, {Untagged: "untagged"}}, nil) - c.EXPECT().Delete(gomock.Any(), "docker.io/pulumibot/buildkit-e2e:main").Return( - []image.DeleteResponse{{Deleted: "deleted"}, {Untagged: "untagged"}}, nil) + c.EXPECT().Delete(gomock.Any(), + "docker.io/pulumibot/buildkit-e2e@sha256:98ea6e4f216f2fb4b69fff9b3a44842c38686ca685f3f55dc48c5d3fb1107be4", + ).Return(nil) return c }, op: func(t *testing.T) integration.Operation { @@ -219,6 +217,7 @@ func TestImageLifecycle(t *testing.T) { }, nil }, ).AnyTimes() + c.EXPECT().Delete(gomock.Any(), "default-dockerfile").Return(nil) return c }, op: func(t *testing.T) integration.Operation { @@ -271,7 +270,7 @@ func TestDelete(t *testing.T) { t.Run("image was already deleted", func(t *testing.T) { ctrl := gomock.NewController(t) client := NewMockClient(ctrl) - client.EXPECT().Delete(gomock.Any(), "docker.io/pulumi/test:foo").Return(nil, errNotFound{}) + client.EXPECT().Delete(gomock.Any(), "docker.io/pulumi/test@sha256:foo").Return(errNotFound{}) s := newServer(client) err := s.Configure(provider.ConfigureRequest{}) diff --git a/provider/internal/index.go b/provider/internal/index.go index 08ab7666..bbc6cbe4 100644 --- a/provider/internal/index.go +++ b/provider/internal/index.go @@ -227,15 +227,19 @@ func (i *Index) Diff( ) (provider.DiffResponse, error) { diff := map[string]provider.PropertyDiff{} update := provider.PropertyDiff{Kind: provider.Update} + replace := provider.PropertyDiff{Kind: provider.UpdateReplace} if olds.Tag != news.Tag { - diff["tag"] = update + diff["tag"] = replace } if !reflect.DeepEqual(olds.Sources, news.Sources) { diff["sources"] = update } if olds.Registry.Address != news.Registry.Address { diff["registry.address"] = update + if olds.Registry.Address != "" { + diff["registry.address"] = replace + } } if olds.Registry.Username != news.Registry.Username { diff["registry.username"] = update diff --git a/provider/internal/mockclient_test.go b/provider/internal/mockclient_test.go index cf46b09b..37722be1 100644 --- a/provider/internal/mockclient_test.go +++ b/provider/internal/mockclient_test.go @@ -13,7 +13,6 @@ import ( reflect "reflect" pb "github.com/docker/buildx/controller/pb" - image "github.com/docker/docker/api/types/image" client "github.com/moby/buildkit/client" session "github.com/moby/buildkit/session" provider "github.com/pulumi/pulumi-go-provider" @@ -123,12 +122,11 @@ func (c *ClientBuildKitEnabledCall) DoAndReturn(f func() (bool, error)) *ClientB } // Delete mocks base method. -func (m *MockClient) Delete(ctx context.Context, id string) ([]image.DeleteResponse, error) { +func (m *MockClient) Delete(ctx context.Context, id string) error { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "Delete", ctx, id) - ret0, _ := ret[0].([]image.DeleteResponse) - ret1, _ := ret[1].(error) - return ret0, ret1 + ret0, _ := ret[0].(error) + return ret0 } // Delete indicates an expected call of Delete. @@ -144,19 +142,19 @@ type ClientDeleteCall struct { } // Return rewrite *gomock.Call.Return -func (c *ClientDeleteCall) Return(arg0 []image.DeleteResponse, arg1 error) *ClientDeleteCall { - c.Call = c.Call.Return(arg0, arg1) +func (c *ClientDeleteCall) Return(arg0 error) *ClientDeleteCall { + c.Call = c.Call.Return(arg0) return c } // Do rewrite *gomock.Call.Do -func (c *ClientDeleteCall) Do(f func(context.Context, string) ([]image.DeleteResponse, error)) *ClientDeleteCall { +func (c *ClientDeleteCall) Do(f func(context.Context, string) error) *ClientDeleteCall { c.Call = c.Call.Do(f) return c } // DoAndReturn rewrite *gomock.Call.DoAndReturn -func (c *ClientDeleteCall) DoAndReturn(f func(context.Context, string) ([]image.DeleteResponse, error)) *ClientDeleteCall { +func (c *ClientDeleteCall) DoAndReturn(f func(context.Context, string) error) *ClientDeleteCall { c.Call = c.Call.DoAndReturn(f) return c } diff --git a/sdk/dotnet/Buildx/Image.cs b/sdk/dotnet/Buildx/Image.cs index b16bcd14..3664099b 100644 --- a/sdk/dotnet/Buildx/Image.cs +++ b/sdk/dotnet/Buildx/Image.cs @@ -102,7 +102,8 @@ namespace Pulumi.Docker.Buildx /// If any are missing a subsequent `update` will push them. /// /// When a `buildx.Image` is deleted, it will _attempt_ to also delete any pushed tags. - /// Deletion of remote tags is not guaranteed, because not all registries currently support this operation (`docker.io` in particular). + /// Deletion of remote tags is not guaranteed because not all registries support the manifest `DELETE` API (`docker.io` in particular). + /// Manifests are _not_ deleted in the same way during updates -- to do so safely would require a full build to determine whether a Pulumi operation should be an update or update-replace. /// /// Use the [`retainOnDelete: true`](https://www.pulumi.com/docs/concepts/options/retainondelete/) option if you do not want tags deleted. /// diff --git a/sdk/dotnet/Buildx/Inputs/CacheToRegistryArgs.cs b/sdk/dotnet/Buildx/Inputs/CacheToRegistryArgs.cs index 28a0c23b..1abdc328 100644 --- a/sdk/dotnet/Buildx/Inputs/CacheToRegistryArgs.cs +++ b/sdk/dotnet/Buildx/Inputs/CacheToRegistryArgs.cs @@ -38,9 +38,12 @@ public sealed class CacheToRegistryArgs : global::Pulumi.ResourceArgs /// /// Export cache manifest as an OCI-compatible image manifest instead of a - /// manifest list (requires OCI media types). + /// manifest list. Requires `ociMediaTypes` to also be `true`. /// - /// Defaults to `false`. + /// Some registries like AWS ECR will not work with caching if this is + /// `false`. + /// + /// Defaults to `false` to match Docker's default behavior. /// [Input("imageManifest")] public Input? ImageManifest { get; set; } diff --git a/sdk/dotnet/Buildx/Outputs/CacheToRegistry.cs b/sdk/dotnet/Buildx/Outputs/CacheToRegistry.cs index 3a4c0cd0..bd98972f 100644 --- a/sdk/dotnet/Buildx/Outputs/CacheToRegistry.cs +++ b/sdk/dotnet/Buildx/Outputs/CacheToRegistry.cs @@ -31,9 +31,12 @@ public sealed class CacheToRegistry public readonly bool? IgnoreError; /// /// Export cache manifest as an OCI-compatible image manifest instead of a - /// manifest list (requires OCI media types). + /// manifest list. Requires `ociMediaTypes` to also be `true`. /// - /// Defaults to `false`. + /// Some registries like AWS ECR will not work with caching if this is + /// `false`. + /// + /// Defaults to `false` to match Docker's default behavior. /// public readonly bool? ImageManifest; /// diff --git a/sdk/go/docker/buildx/image.go b/sdk/go/docker/buildx/image.go index 866adb0a..1b8a17ca 100644 --- a/sdk/go/docker/buildx/image.go +++ b/sdk/go/docker/buildx/image.go @@ -103,7 +103,8 @@ import ( // If any are missing a subsequent `update` will push them. // // When a `buildx.Image` is deleted, it will _attempt_ to also delete any pushed tags. -// Deletion of remote tags is not guaranteed, because not all registries currently support this operation (`docker.io` in particular). +// Deletion of remote tags is not guaranteed because not all registries support the manifest `DELETE` API (`docker.io` in particular). +// Manifests are _not_ deleted in the same way during updates -- to do so safely would require a full build to determine whether a Pulumi operation should be an update or update-replace. // // Use the [`retainOnDelete: true`](https://www.pulumi.com/docs/concepts/options/retainondelete/) option if you do not want tags deleted. // diff --git a/sdk/go/docker/buildx/pulumiTypes.go b/sdk/go/docker/buildx/pulumiTypes.go index c33ac687..9b28d32c 100644 --- a/sdk/go/docker/buildx/pulumiTypes.go +++ b/sdk/go/docker/buildx/pulumiTypes.go @@ -2864,9 +2864,12 @@ type CacheToRegistry struct { // Ignore errors caused by failed cache exports. IgnoreError *bool `pulumi:"ignoreError"` // Export cache manifest as an OCI-compatible image manifest instead of a - // manifest list (requires OCI media types). + // manifest list. Requires `ociMediaTypes` to also be `true`. // - // Defaults to `false`. + // Some registries like AWS ECR will not work with caching if this is + // `false`. + // + // Defaults to `false` to match Docker's default behavior. ImageManifest *bool `pulumi:"imageManifest"` // The cache mode to use. Defaults to `min`. Mode *CacheMode `pulumi:"mode"` @@ -2935,9 +2938,12 @@ type CacheToRegistryArgs struct { // Ignore errors caused by failed cache exports. IgnoreError pulumi.BoolPtrInput `pulumi:"ignoreError"` // Export cache manifest as an OCI-compatible image manifest instead of a - // manifest list (requires OCI media types). + // manifest list. Requires `ociMediaTypes` to also be `true`. + // + // Some registries like AWS ECR will not work with caching if this is + // `false`. // - // Defaults to `false`. + // Defaults to `false` to match Docker's default behavior. ImageManifest pulumi.BoolPtrInput `pulumi:"imageManifest"` // The cache mode to use. Defaults to `min`. Mode CacheModePtrInput `pulumi:"mode"` @@ -3075,9 +3081,12 @@ func (o CacheToRegistryOutput) IgnoreError() pulumi.BoolPtrOutput { } // Export cache manifest as an OCI-compatible image manifest instead of a -// manifest list (requires OCI media types). +// manifest list. Requires `ociMediaTypes` to also be `true`. // -// Defaults to `false`. +// Some registries like AWS ECR will not work with caching if this is +// `false`. +// +// Defaults to `false` to match Docker's default behavior. func (o CacheToRegistryOutput) ImageManifest() pulumi.BoolPtrOutput { return o.ApplyT(func(v CacheToRegistry) *bool { return v.ImageManifest }).(pulumi.BoolPtrOutput) } @@ -3163,9 +3172,12 @@ func (o CacheToRegistryPtrOutput) IgnoreError() pulumi.BoolPtrOutput { } // Export cache manifest as an OCI-compatible image manifest instead of a -// manifest list (requires OCI media types). +// manifest list. Requires `ociMediaTypes` to also be `true`. +// +// Some registries like AWS ECR will not work with caching if this is +// `false`. // -// Defaults to `false`. +// Defaults to `false` to match Docker's default behavior. func (o CacheToRegistryPtrOutput) ImageManifest() pulumi.BoolPtrOutput { return o.ApplyT(func(v *CacheToRegistry) *bool { if v == nil { diff --git a/sdk/java/src/main/java/com/pulumi/docker/buildx/Image.java b/sdk/java/src/main/java/com/pulumi/docker/buildx/Image.java index 59ba59d2..b4d2ca03 100644 --- a/sdk/java/src/main/java/com/pulumi/docker/buildx/Image.java +++ b/sdk/java/src/main/java/com/pulumi/docker/buildx/Image.java @@ -118,7 +118,8 @@ * If any are missing a subsequent `update` will push them. * * When a `buildx.Image` is deleted, it will _attempt_ to also delete any pushed tags. - * Deletion of remote tags is not guaranteed, because not all registries currently support this operation (`docker.io` in particular). + * Deletion of remote tags is not guaranteed because not all registries support the manifest `DELETE` API (`docker.io` in particular). + * Manifests are _not_ deleted in the same way during updates -- to do so safely would require a full build to determine whether a Pulumi operation should be an update or update-replace. * * Use the [`retainOnDelete: true`](https://www.pulumi.com/docs/concepts/options/retainondelete/) option if you do not want tags deleted. * diff --git a/sdk/java/src/main/java/com/pulumi/docker/buildx/inputs/CacheToRegistryArgs.java b/sdk/java/src/main/java/com/pulumi/docker/buildx/inputs/CacheToRegistryArgs.java index 3d603baa..938085fc 100644 --- a/sdk/java/src/main/java/com/pulumi/docker/buildx/inputs/CacheToRegistryArgs.java +++ b/sdk/java/src/main/java/com/pulumi/docker/buildx/inputs/CacheToRegistryArgs.java @@ -83,9 +83,12 @@ public Optional> ignoreError() { /** * Export cache manifest as an OCI-compatible image manifest instead of a - * manifest list (requires OCI media types). + * manifest list. Requires `ociMediaTypes` to also be `true`. * - * Defaults to `false`. + * Some registries like AWS ECR will not work with caching if this is + * `false`. + * + * Defaults to `false` to match Docker's default behavior. * */ @Import(name="imageManifest") @@ -93,9 +96,12 @@ public Optional> ignoreError() { /** * @return Export cache manifest as an OCI-compatible image manifest instead of a - * manifest list (requires OCI media types). + * manifest list. Requires `ociMediaTypes` to also be `true`. + * + * Some registries like AWS ECR will not work with caching if this is + * `false`. * - * Defaults to `false`. + * Defaults to `false` to match Docker's default behavior. * */ public Optional> imageManifest() { @@ -266,9 +272,12 @@ public Builder ignoreError(Boolean ignoreError) { /** * @param imageManifest Export cache manifest as an OCI-compatible image manifest instead of a - * manifest list (requires OCI media types). + * manifest list. Requires `ociMediaTypes` to also be `true`. * - * Defaults to `false`. + * Some registries like AWS ECR will not work with caching if this is + * `false`. + * + * Defaults to `false` to match Docker's default behavior. * * @return builder * @@ -280,9 +289,12 @@ public Builder imageManifest(@Nullable Output imageManifest) { /** * @param imageManifest Export cache manifest as an OCI-compatible image manifest instead of a - * manifest list (requires OCI media types). + * manifest list. Requires `ociMediaTypes` to also be `true`. + * + * Some registries like AWS ECR will not work with caching if this is + * `false`. * - * Defaults to `false`. + * Defaults to `false` to match Docker's default behavior. * * @return builder * diff --git a/sdk/java/src/main/java/com/pulumi/docker/buildx/outputs/CacheToRegistry.java b/sdk/java/src/main/java/com/pulumi/docker/buildx/outputs/CacheToRegistry.java index ac2e0f0b..02df1b5c 100644 --- a/sdk/java/src/main/java/com/pulumi/docker/buildx/outputs/CacheToRegistry.java +++ b/sdk/java/src/main/java/com/pulumi/docker/buildx/outputs/CacheToRegistry.java @@ -38,9 +38,12 @@ public final class CacheToRegistry { private @Nullable Boolean ignoreError; /** * @return Export cache manifest as an OCI-compatible image manifest instead of a - * manifest list (requires OCI media types). + * manifest list. Requires `ociMediaTypes` to also be `true`. * - * Defaults to `false`. + * Some registries like AWS ECR will not work with caching if this is + * `false`. + * + * Defaults to `false` to match Docker's default behavior. * */ private @Nullable Boolean imageManifest; @@ -92,9 +95,12 @@ public Optional ignoreError() { } /** * @return Export cache manifest as an OCI-compatible image manifest instead of a - * manifest list (requires OCI media types). + * manifest list. Requires `ociMediaTypes` to also be `true`. + * + * Some registries like AWS ECR will not work with caching if this is + * `false`. * - * Defaults to `false`. + * Defaults to `false` to match Docker's default behavior. * */ public Optional imageManifest() { diff --git a/sdk/nodejs/buildx/image.ts b/sdk/nodejs/buildx/image.ts index 4fba0d26..d195e18c 100644 --- a/sdk/nodejs/buildx/image.ts +++ b/sdk/nodejs/buildx/image.ts @@ -100,7 +100,8 @@ import * as utilities from "../utilities"; * If any are missing a subsequent `update` will push them. * * When a `buildx.Image` is deleted, it will _attempt_ to also delete any pushed tags. - * Deletion of remote tags is not guaranteed, because not all registries currently support this operation (`docker.io` in particular). + * Deletion of remote tags is not guaranteed because not all registries support the manifest `DELETE` API (`docker.io` in particular). + * Manifests are _not_ deleted in the same way during updates -- to do so safely would require a full build to determine whether a Pulumi operation should be an update or update-replace. * * Use the [`retainOnDelete: true`](https://www.pulumi.com/docs/concepts/options/retainondelete/) option if you do not want tags deleted. * diff --git a/sdk/nodejs/types/input.ts b/sdk/nodejs/types/input.ts index 422a00be..a4451649 100644 --- a/sdk/nodejs/types/input.ts +++ b/sdk/nodejs/types/input.ts @@ -1680,9 +1680,12 @@ export namespace buildx { ignoreError?: pulumi.Input; /** * Export cache manifest as an OCI-compatible image manifest instead of a - * manifest list (requires OCI media types). + * manifest list. Requires `ociMediaTypes` to also be `true`. * - * Defaults to `false`. + * Some registries like AWS ECR will not work with caching if this is + * `false`. + * + * Defaults to `false` to match Docker's default behavior. */ imageManifest?: pulumi.Input; /** diff --git a/sdk/nodejs/types/output.ts b/sdk/nodejs/types/output.ts index b814a593..949bddc8 100644 --- a/sdk/nodejs/types/output.ts +++ b/sdk/nodejs/types/output.ts @@ -1606,9 +1606,12 @@ export namespace buildx { ignoreError?: boolean; /** * Export cache manifest as an OCI-compatible image manifest instead of a - * manifest list (requires OCI media types). + * manifest list. Requires `ociMediaTypes` to also be `true`. * - * Defaults to `false`. + * Some registries like AWS ECR will not work with caching if this is + * `false`. + * + * Defaults to `false` to match Docker's default behavior. */ imageManifest?: boolean; /** diff --git a/sdk/python/pulumi_docker/buildx/_inputs.py b/sdk/python/pulumi_docker/buildx/_inputs.py index 573f5639..569b5c55 100644 --- a/sdk/python/pulumi_docker/buildx/_inputs.py +++ b/sdk/python/pulumi_docker/buildx/_inputs.py @@ -986,9 +986,12 @@ def __init__(__self__, *, :param pulumi.Input[bool] force_compression: Forcefully apply compression. :param pulumi.Input[bool] ignore_error: Ignore errors caused by failed cache exports. :param pulumi.Input[bool] image_manifest: Export cache manifest as an OCI-compatible image manifest instead of a - manifest list (requires OCI media types). + manifest list. Requires `ociMediaTypes` to also be `true`. - Defaults to `false`. + Some registries like AWS ECR will not work with caching if this is + `false`. + + Defaults to `false` to match Docker's default behavior. :param pulumi.Input['CacheMode'] mode: The cache mode to use. Defaults to `min`. :param pulumi.Input[bool] oci_media_types: Whether to use OCI media types in exported manifests. Defaults to `true`. @@ -1088,9 +1091,12 @@ def ignore_error(self, value: Optional[pulumi.Input[bool]]): def image_manifest(self) -> Optional[pulumi.Input[bool]]: """ Export cache manifest as an OCI-compatible image manifest instead of a - manifest list (requires OCI media types). + manifest list. Requires `ociMediaTypes` to also be `true`. + + Some registries like AWS ECR will not work with caching if this is + `false`. - Defaults to `false`. + Defaults to `false` to match Docker's default behavior. """ return pulumi.get(self, "image_manifest") diff --git a/sdk/python/pulumi_docker/buildx/image.py b/sdk/python/pulumi_docker/buildx/image.py index c0f82c9d..2f48e548 100644 --- a/sdk/python/pulumi_docker/buildx/image.py +++ b/sdk/python/pulumi_docker/buildx/image.py @@ -703,7 +703,8 @@ def __init__(__self__, If any are missing a subsequent `update` will push them. When a `buildx.Image` is deleted, it will _attempt_ to also delete any pushed tags. - Deletion of remote tags is not guaranteed, because not all registries currently support this operation (`docker.io` in particular). + Deletion of remote tags is not guaranteed because not all registries support the manifest `DELETE` API (`docker.io` in particular). + Manifests are _not_ deleted in the same way during updates -- to do so safely would require a full build to determine whether a Pulumi operation should be an update or update-replace. Use the [`retainOnDelete: true`](https://www.pulumi.com/docs/concepts/options/retainondelete/) option if you do not want tags deleted. @@ -1139,7 +1140,8 @@ def __init__(__self__, If any are missing a subsequent `update` will push them. When a `buildx.Image` is deleted, it will _attempt_ to also delete any pushed tags. - Deletion of remote tags is not guaranteed, because not all registries currently support this operation (`docker.io` in particular). + Deletion of remote tags is not guaranteed because not all registries support the manifest `DELETE` API (`docker.io` in particular). + Manifests are _not_ deleted in the same way during updates -- to do so safely would require a full build to determine whether a Pulumi operation should be an update or update-replace. Use the [`retainOnDelete: true`](https://www.pulumi.com/docs/concepts/options/retainondelete/) option if you do not want tags deleted. diff --git a/sdk/python/pulumi_docker/buildx/outputs.py b/sdk/python/pulumi_docker/buildx/outputs.py index 225befde..d3660b83 100644 --- a/sdk/python/pulumi_docker/buildx/outputs.py +++ b/sdk/python/pulumi_docker/buildx/outputs.py @@ -1059,9 +1059,12 @@ def __init__(__self__, *, :param bool force_compression: Forcefully apply compression. :param bool ignore_error: Ignore errors caused by failed cache exports. :param bool image_manifest: Export cache manifest as an OCI-compatible image manifest instead of a - manifest list (requires OCI media types). + manifest list. Requires `ociMediaTypes` to also be `true`. - Defaults to `false`. + Some registries like AWS ECR will not work with caching if this is + `false`. + + Defaults to `false` to match Docker's default behavior. :param 'CacheMode' mode: The cache mode to use. Defaults to `min`. :param bool oci_media_types: Whether to use OCI media types in exported manifests. Defaults to `true`. @@ -1141,9 +1144,12 @@ def ignore_error(self) -> Optional[bool]: def image_manifest(self) -> Optional[bool]: """ Export cache manifest as an OCI-compatible image manifest instead of a - manifest list (requires OCI media types). + manifest list. Requires `ociMediaTypes` to also be `true`. + + Some registries like AWS ECR will not work with caching if this is + `false`. - Defaults to `false`. + Defaults to `false` to match Docker's default behavior. """ return pulumi.get(self, "image_manifest")