Skip to content

Commit 05adc61

Browse files
Build containers without account ID (#9765)
* Build container without account ID This allows us to build containers in dry run mode. When we push the container to the managed registry, we re-tag it to include the account ID. We only ever push when not in dry run mode though, so when pushing we can safely grab the account information. Co-authored-by: Hasip Timurtaş <[email protected]> * Always check for Docker when using containers Even in dry run mode we should check that Docker is installed, because dry run mode uses docker commands too. --------- Co-authored-by: Greg Anders <[email protected]>
1 parent d2fe58b commit 05adc61

File tree

10 files changed

+266
-103
lines changed

10 files changed

+266
-103
lines changed

.changeset/container-dry-run-fix.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
---
2+
"wrangler": patch
3+
---
4+
5+
Build container images without the user's account ID. This allows containers to be built and verified in dry run mode (where we do not necessarily have the user's account info).
6+
7+
When we push the image to the managed registry, we first re-tag the image to include the user's account ID so that the image has the full resolved image name.

packages/containers-shared/src/images.ts

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
import { buildImage } from "./build";
2-
import { isCloudflareRegistryLink } from "./knobs";
2+
import {
3+
getCloudflareContainerRegistry,
4+
isCloudflareRegistryLink,
5+
} from "./knobs";
36
import { dockerLoginManagedRegistry } from "./login";
47
import { ContainerDevOptions } from "./types";
58
import {
@@ -61,3 +64,31 @@ export async function prepareContainerImagesForDev(
6164
await checkExposedPorts(dockerPath, options);
6265
}
6366
}
67+
68+
/**
69+
* Resolve an image name to the full unambiguous name.
70+
*
71+
* For now, this only converts images stored in the managed registry to contain
72+
* the user's account ID in the path.
73+
*/
74+
export async function resolveImageName(
75+
accountId: string,
76+
image: string
77+
): Promise<string> {
78+
let url: URL;
79+
try {
80+
url = new URL(`http://${image}`);
81+
} catch (_) {
82+
return image;
83+
}
84+
85+
if (url.hostname !== getCloudflareContainerRegistry()) {
86+
return image;
87+
}
88+
89+
if (url.pathname.startsWith(`/${accountId}`)) {
90+
return image;
91+
}
92+
93+
return `${url.hostname}/${accountId}${url.pathname}`;
94+
}

packages/wrangler/src/__tests__/cloudchamber/build.test.ts

Lines changed: 27 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ describe("buildAndMaybePush", () => {
6262
buildCmd: [
6363
"build",
6464
"-t",
65-
`${getCloudflareContainerRegistry()}/some-account-id/test-app:tag`,
65+
`${getCloudflareContainerRegistry()}/test-app:tag`,
6666
"--platform",
6767
"linux/amd64",
6868
"--provenance=false",
@@ -73,7 +73,7 @@ describe("buildAndMaybePush", () => {
7373
dockerfile,
7474
});
7575
expect(dockerImageInspect).toHaveBeenCalledWith("/custom/docker/path", {
76-
imageTag: `${getCloudflareContainerRegistry()}/some-account-id/test-app:tag`,
76+
imageTag: `${getCloudflareContainerRegistry()}/test-app:tag`,
7777
formatString:
7878
"{{ .Size }} {{ len .RootFS.Layers }} {{json .RepoDigests}}",
7979
});
@@ -94,7 +94,7 @@ describe("buildAndMaybePush", () => {
9494
buildCmd: [
9595
"build",
9696
"-t",
97-
`${getCloudflareContainerRegistry()}/some-account-id/test-app:tag`,
97+
`${getCloudflareContainerRegistry()}/test-app:tag`,
9898
"--platform",
9999
"linux/amd64",
100100
"--provenance=false",
@@ -104,14 +104,26 @@ describe("buildAndMaybePush", () => {
104104
],
105105
dockerfile,
106106
});
107-
expect(runDockerCmd).toHaveBeenCalledTimes(1);
108-
expect(runDockerCmd).toHaveBeenCalledWith("docker", [
107+
108+
// 3 calls: docker tag + docker push + docker rm
109+
expect(runDockerCmd).toHaveBeenCalledTimes(3);
110+
expect(runDockerCmd).toHaveBeenNthCalledWith(1, "docker", [
111+
"tag",
112+
`${getCloudflareContainerRegistry()}/test-app:tag`,
113+
`${getCloudflareContainerRegistry()}/some-account-id/test-app:tag`,
114+
]);
115+
expect(runDockerCmd).toHaveBeenNthCalledWith(2, "docker", [
109116
"push",
110117
`${getCloudflareContainerRegistry()}/some-account-id/test-app:tag`,
111118
]);
119+
expect(runDockerCmd).toHaveBeenNthCalledWith(3, "docker", [
120+
"image",
121+
"rm",
122+
`${getCloudflareContainerRegistry()}/some-account-id/test-app:tag`,
123+
]);
112124
expect(dockerImageInspect).toHaveBeenCalledOnce();
113125
expect(dockerImageInspect).toHaveBeenCalledWith("docker", {
114-
imageTag: `${getCloudflareContainerRegistry()}/some-account-id/test-app:tag`,
126+
imageTag: `${getCloudflareContainerRegistry()}/test-app:tag`,
115127
formatString:
116128
"{{ .Size }} {{ len .RootFS.Layers }} {{json .RepoDigests}}",
117129
});
@@ -121,7 +133,7 @@ describe("buildAndMaybePush", () => {
121133
it("should be able to build image and not push if it already exists in remote", async () => {
122134
vi.mocked(runDockerCmd).mockResolvedValueOnce();
123135
vi.mocked(dockerImageInspect).mockResolvedValue(
124-
'53387881 2 ["registry.cloudflare.com/some-account-id/test-app@sha256:three"]'
136+
'53387881 2 ["registry.cloudflare.com/test-app@sha256:three"]'
125137
);
126138
await runWrangler(
127139
"containers build ./container-context -t test-app:tag -p"
@@ -130,7 +142,7 @@ describe("buildAndMaybePush", () => {
130142
buildCmd: [
131143
"build",
132144
"-t",
133-
`${getCloudflareContainerRegistry()}/some-account-id/test-app:tag`,
145+
`${getCloudflareContainerRegistry()}/test-app:tag`,
134146
"--platform",
135147
"linux/amd64",
136148
"--provenance=false",
@@ -154,11 +166,11 @@ describe("buildAndMaybePush", () => {
154166
expect(runDockerCmd).toHaveBeenNthCalledWith(2, "docker", [
155167
"image",
156168
"rm",
157-
`${getCloudflareContainerRegistry()}/some-account-id/test-app:tag`,
169+
`${getCloudflareContainerRegistry()}/test-app:tag`,
158170
]);
159171
expect(dockerImageInspect).toHaveBeenCalledOnce();
160172
expect(dockerImageInspect).toHaveBeenCalledWith("docker", {
161-
imageTag: `${getCloudflareContainerRegistry()}/some-account-id/test-app:tag`,
173+
imageTag: `${getCloudflareContainerRegistry()}/test-app:tag`,
162174
formatString:
163175
"{{ .Size }} {{ len .RootFS.Layers }} {{json .RepoDigests}}",
164176
});
@@ -172,7 +184,7 @@ describe("buildAndMaybePush", () => {
172184
buildCmd: [
173185
"build",
174186
"-t",
175-
`${getCloudflareContainerRegistry()}/some-account-id/test-app`,
187+
`${getCloudflareContainerRegistry()}/test-app`,
176188
"--platform",
177189
"linux/amd64",
178190
"--provenance=false",
@@ -194,7 +206,7 @@ describe("buildAndMaybePush", () => {
194206
buildCmd: [
195207
"build",
196208
"-t",
197-
`${getCloudflareContainerRegistry()}/some-account-id/test-app`,
209+
`${getCloudflareContainerRegistry()}/test-app`,
198210
"--platform",
199211
"linux/amd64",
200212
"--provenance=false",
@@ -270,27 +282,24 @@ describe("buildAndMaybePush", () => {
270282
});
271283

272284
describe("resolveAppDiskSize", () => {
273-
const accountBase = {
274-
limits: { disk_mb_per_deployment: 2000 },
275-
} as CompleteAccountCustomer;
276285
it("should return parsed app disk size", () => {
277-
const result = resolveAppDiskSize(accountBase, {
286+
const result = resolveAppDiskSize({
278287
...defaultConfiguration,
279288
configuration: { image: "", disk: { size: "500MB" } },
280289
});
281290
expect(result).toBeCloseTo(500 * 1000 * 1000, -5);
282291
});
283292

284293
it("should return default size when disk size not set", () => {
285-
const result = resolveAppDiskSize(accountBase, {
294+
const result = resolveAppDiskSize({
286295
...defaultConfiguration,
287296
configuration: { image: "" },
288297
});
289298
expect(result).toBeCloseTo(2 * 1000 * 1000 * 1000, -5);
290299
});
291300

292301
it("should return undefined if app is not passed", () => {
293-
expect(resolveAppDiskSize(accountBase, undefined)).toBeUndefined();
302+
expect(resolveAppDiskSize(undefined)).toBeUndefined();
294303
});
295304
});
296305
});

0 commit comments

Comments
 (0)