Skip to content

Commit 6b38532

Browse files
try pulling an image even if docker login fails (#11360)
* try pulling an image even if docker login fails * fixups * Update .changeset/open-donkeys-behave.md Co-authored-by: Edmund Hung <edmund@cloudflare.com> --------- Co-authored-by: Edmund Hung <edmund@cloudflare.com>
1 parent 2aec2b4 commit 6b38532

File tree

9 files changed

+74
-10
lines changed

9 files changed

+74
-10
lines changed

.changeset/open-donkeys-behave.md

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
---
2+
"@cloudflare/vite-plugin": minor
3+
"@cloudflare/containers-shared": minor
4+
"wrangler": minor
5+
---
6+
7+
Containers: Allow users to directly authenticate external image registries in local dev
8+
9+
Previously, we always queried the API for stored registry credentials and used those to pull images. This means that if you are using an external registry (ECR, dockerhub) then you have to configure registry credentials remotely before running local dev.
10+
11+
Now you can directly authenticate with your external registry provider (using `docker login` etc.), and Wrangler or Vite will be able to pull the image specified in the `contaienrs.image` field in your config file.
12+
13+
The Cloudflare-managed registry (registry.cloudflare.com) currently still does not work with the Vite plugin.

packages/containers-shared/src/build.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,12 @@ import type {
55
BuildArgs,
66
ContainerDevOptions,
77
ImageURIConfig,
8-
Logger,
8+
WranglerLogger,
99
} from "./types";
1010

1111
export async function constructBuildCommand(
1212
options: BuildArgs,
13-
logger?: Logger
13+
logger?: WranglerLogger
1414
) {
1515
const platform = options.platform ?? "linux/amd64";
1616
const buildCmd = [

packages/containers-shared/src/client/core/OpenAPI.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
/* istanbul ignore file */
22
/* tslint:disable */
3-
import type { Logger } from "../../types";
3+
import type { WranglerLogger } from "../../types";
44
import type { ApiRequestOptions } from "./ApiRequestOptions";
55

66
type Resolver<T> = (options: ApiRequestOptions) => Promise<T>;
@@ -16,7 +16,7 @@ export type OpenAPIConfig = {
1616
PASSWORD?: string | Resolver<string>;
1717
HEADERS?: Headers | Resolver<Headers>;
1818
ENCODE_PATH?: (path: string) => string;
19-
LOGGER?: Logger | undefined;
19+
LOGGER?: WranglerLogger | undefined;
2020
};
2121

2222
export const OpenAPI: OpenAPIConfig = {

packages/containers-shared/src/images.ts

Lines changed: 43 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10,14 +10,45 @@ import {
1010
runDockerCmd,
1111
verifyDockerInstalled,
1212
} from "./utils";
13-
import type { ContainerDevOptions, DockerfileConfig } from "./types";
13+
import type {
14+
ContainerDevOptions,
15+
DockerfileConfig,
16+
ViteLogger,
17+
WranglerLogger,
18+
} from "./types";
1419

1520
export async function pullImage(
1621
dockerPath: string,
17-
options: Exclude<ContainerDevOptions, DockerfileConfig>
22+
options: Exclude<ContainerDevOptions, DockerfileConfig>,
23+
logger: WranglerLogger | ViteLogger,
24+
isVite: boolean
1825
): Promise<{ abort: () => void; ready: Promise<void> }> {
1926
const domain = new URL(`http://${options.image_uri}`).hostname;
20-
await dockerLoginImageRegistry(dockerPath, domain);
27+
28+
const isExternalRegistry = domain !== getCloudflareContainerRegistry();
29+
try {
30+
// this will fail in two cases:
31+
// 1. this is being called from the vite plugin (doesn't have the appropriate auth context)
32+
// 2. the user has not run `wrangler containers registries configure` yet to set up credentials
33+
await dockerLoginImageRegistry(dockerPath, domain);
34+
} catch (e) {
35+
if (!isExternalRegistry) {
36+
if (isVite) {
37+
throw new UserError(
38+
`Using images from the Cloudflare-managed registry is not currently supported with the Vite plugin.\n` +
39+
`You should use a Dockerfile or a supported external registry and authenticate to that registry separately using \`docker login\` or similar.\n` +
40+
`Supported external registries are currently: ${Object.values(ExternalRegistryKind).join(", ")}.`
41+
);
42+
}
43+
throw e;
44+
}
45+
logger?.warn(
46+
"Unable to retrieve configured registry credentials from Cloudflare." +
47+
"\nUnless this is a public image, you will need to run `wrangler containers registries configure` before deploying." +
48+
"\nAttempting to pull image anyway..."
49+
);
50+
}
51+
2152
const pull = runDockerCmd(dockerPath, [
2253
"pull",
2354
options.image_uri,
@@ -64,7 +95,9 @@ export async function prepareContainerImagesForDev(args: {
6495
onContainerImagePreparationEnd: (args: {
6596
containerOptions: ContainerDevOptions;
6697
}) => void;
67-
}) {
98+
logger: WranglerLogger | ViteLogger;
99+
isVite: boolean;
100+
}): Promise<void> {
68101
const {
69102
dockerPath,
70103
containerOptions,
@@ -94,7 +127,12 @@ export async function prepareContainerImagesForDev(args: {
94127
containerOptions: options,
95128
});
96129
} else {
97-
const pull = await pullImage(dockerPath, options);
130+
const pull = await pullImage(
131+
dockerPath,
132+
options,
133+
args.logger,
134+
args.isVite
135+
);
98136
onContainerImagePreparationStart({
99137
containerOptions: options,
100138
abort: () => {

packages/containers-shared/src/types.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,19 @@ import type {
55
} from "./client";
66
import type { ApplicationAffinityHardwareGeneration } from "./client/models/ApplicationAffinityHardwareGeneration";
77

8-
export interface Logger {
8+
export interface WranglerLogger {
99
debug: (...args: unknown[]) => void;
1010
debugWithSanitization: (label: string, ...args: unknown[]) => void;
1111
log: (...args: unknown[]) => void;
1212
info: (...args: unknown[]) => void;
1313
warn: (...args: unknown[]) => void;
1414
error: (...args: unknown[]) => void;
1515
}
16+
export interface ViteLogger {
17+
info: (msg: string) => void;
18+
warn: (msg: string) => void;
19+
error: (msg: string) => void;
20+
}
1621

1722
export type BuildArgs = {
1823
/** image tag in the format `name:tag`, where tag is optional */

packages/vite-plugin-cloudflare/src/plugins/dev.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -206,6 +206,8 @@ export const devPlugin = createPlugin("dev", (ctx) => {
206206
containerOptions: [...containerTagToOptionsMap.values()],
207207
onContainerImagePreparationStart: () => {},
208208
onContainerImagePreparationEnd: () => {},
209+
logger: viteDevServer.config.logger,
210+
isVite: true,
209211
});
210212

211213
containerImageTags = new Set(containerTagToOptionsMap.keys());

packages/vite-plugin-cloudflare/src/plugins/preview.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,8 @@ export const previewPlugin = createPlugin("preview", (ctx) => {
4747
containerOptions: [...containerTagToOptionsMap.values()],
4848
onContainerImagePreparationStart: () => {},
4949
onContainerImagePreparationEnd: () => {},
50+
logger: vitePreviewServer.config.logger,
51+
isVite: true,
5052
});
5153

5254
const containerImageTags = new Set(containerTagToOptionsMap.keys());

packages/wrangler/src/api/startDevWorker/LocalRuntimeController.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -273,6 +273,8 @@ export class LocalRuntimeController extends RuntimeController {
273273
onContainerImagePreparationEnd: () => {
274274
this.containerBeingBuilt = undefined;
275275
},
276+
logger: logger,
277+
isVite: false,
276278
});
277279
if (this.containerBeingBuilt) {
278280
this.containerBeingBuilt.abortRequested = false;

packages/wrangler/src/api/startDevWorker/MultiworkerRuntimeController.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -169,6 +169,8 @@ export class MultiworkerRuntimeController extends LocalRuntimeController {
169169
onContainerImagePreparationEnd: () => {
170170
this.containerBeingBuilt = undefined;
171171
},
172+
logger: logger,
173+
isVite: false,
172174
});
173175
if (this.containerBeingBuilt) {
174176
this.containerBeingBuilt.abortRequested = false;

0 commit comments

Comments
 (0)