跳转到内容
本站为社区维护的非官方中文翻译,与 Cloudflare, Inc. 无关联。本站不提供账户登录,请勿在任何非官方站点输入您的 Cloudflare 账户信息。官方文档:developers.cloudflare.com

运行 Docker-in-Docker

最后更新 查看 MarkdownAgent 设置

本指南说明如何在 Sandbox 中运行 Docker,从而在安全沙箱内构建并运行 container 镜像。

何时使用 Docker-in-Docker

在以下场景使用 Docker-in-Docker:

  • 开发容器化应用 - 运行 docker build,根据 Dockerfile 创建镜像
  • 在 CI/CD 中运行 Docker - 响应代码变更,并使用 Cloudflare Containers 构建和推送镜像
  • 运行任意 container 镜像 - 从最终用户提供的镜像启动 container

创建启用 Docker 的镜像

创建一个自定义 Dockerfile,将 sandbox 二进制文件与 Docker 组合使用。Docker 守护进程以 root 身份运行:

Dockerfiledockerfile
FROM docker:dind

# Use the musl build so it runs on Alpine-based docker:dind
COPY --from=docker.io/cloudflare/sandbox:0.12.14-musl /container-server/sandbox /sandbox
COPY --from=docker.io/cloudflare/sandbox:0.12.14-musl /usr/lib/libstdc++.so.6 /usr/lib/libstdc++.so.6
COPY --from=docker.io/cloudflare/sandbox:0.12.14-musl /usr/lib/libgcc_s.so.1 /usr/lib/libgcc_s.so.1
COPY --from=docker.io/cloudflare/sandbox:0.12.14-musl /bin/bash /bin/bash
COPY --from=docker.io/cloudflare/sandbox:0.12.14-musl /usr/lib/libreadline.so.8 /usr/lib/libreadline.so.8
COPY --from=docker.io/cloudflare/sandbox:0.12.14-musl /usr/lib/libreadline.so.8.2 /usr/lib/libreadline.so.8.2

# Start dockerd without iptables or IP forwarding, wait up to 60 seconds
# for it to accept connections, then keep running
RUN printf '#!/bin/sh\n\
set -eu\n\
dockerd-entrypoint.sh dockerd --iptables=false --ip6tables=false --ip-forward=false --exec-opt native.cgroupdriver=cgroupfs &\n\
timeout 60 sh -c "until docker version >/dev/null 2>&1; do sleep 0.2; done"\n\
echo "Docker is ready"\n\
wait\n' > /usr/local/bin/start-docker.sh && chmod +x /usr/local/bin/start-docker.sh

# Mount /tmp before the sandbox starts. Otherwise the docker:dind
# entrypoint mounts a new /tmp over the sandbox's session files.
ENTRYPOINT ["/bin/sh", "-c", "mountpoint -q /tmp || mount -t tmpfs none /tmp; exec /sandbox \"$@\"", "--"]
CMD ["/usr/local/bin/start-docker.sh"]

将 cloudflare/sandbox 镜像标签与 Worker 中 @cloudflare/sandbox 的版本保持一致。

sandbox 启动时会运行 CMD 脚本:

  • --iptables=false、--ip6tables=false 和 --ip-forward=false 可阻止 Docker 更改 Containers 不允许更改的网络设置。
  • --exec-opt native.cgroupdriver=cgroupfs 让 Docker 直接管理 cgroups,而不是通过容器中未运行的 systemd 管理。
  • 如果 dockerd 在 60 秒内未接受连接,脚本会退出,sandbox 也会停止,因此日志中会显示故障。将 SANDBOX_LOG_LEVEL 设为 debug 可记录 dockerd 的输出。请参阅 Sandbox 选项。

该脚本不会显示在 listProcesses() 中,因为 sandbox 在其进程列表之外启动该脚本。

在沙箱中使用 Docker

部署后,你可以通过 sandbox 运行 Docker 命令。sandbox 启动几秒后 Docker 才会就绪,因此请先等待 docker version 成功:

import { getSandbox } from "@cloudflare/sandbox";

const sandbox = getSandbox(env.Sandbox, "docker-sandbox");

// Wait for the Docker daemon
const ready = await sandbox.exec(
	"timeout 60 sh -c 'until docker version >/dev/null 2>&1; do sleep 0.2; done'",
);
if (!ready.success) {
	throw new Error("Docker did not start");
}

// Build an image
await sandbox.writeFile(
	"/workspace/Dockerfile",
	`
FROM alpine:latest
RUN apk add --no-cache curl
CMD ["echo", "Hello from Docker!"]
`,
);

const build = await sandbox.exec(
	"docker build --network=host -t my-image /workspace",
);
if (!build.success) {
	console.error("Build failed:", build.stderr);
}

// Run a container
const run = await sandbox.exec("docker run --network=host --rm my-image");
console.log(run.stdout); // "Hello from Docker!"
import { getSandbox } from "@cloudflare/sandbox";

const sandbox = getSandbox(env.Sandbox, "docker-sandbox");

// Wait for the Docker daemon
const ready = await sandbox.exec(
    "timeout 60 sh -c 'until docker version >/dev/null 2>&1; do sleep 0.2; done'",
);
if (!ready.success) {
    throw new Error("Docker did not start");
}

// Build an image
await sandbox.writeFile(
    "/workspace/Dockerfile",
    `
FROM alpine:latest
RUN apk add --no-cache curl
CMD ["echo", "Hello from Docker!"]
`,
);

const build = await sandbox.exec(
    "docker build --network=host -t my-image /workspace",
);
if (!build.success) {
    console.error("Build failed:", build.stderr);
}

// Run a container
const run = await sandbox.exec("docker run --network=host --rm my-image");
console.log(run.stdout); // "Hello from Docker!"

限制

Cloudflare Containers 中的 Docker-in-Docker 有以下限制:

  • 无 iptables - 依赖 iptables 的网络隔离功能不可用
  • 临时存储 - 沙箱休眠后,已构建的镜像和 container 会丢失。你必须自行持久化它们。
  • 不支持本地开发 - Docker 无法在 wrangler dev 下启动

相关资源

这篇文档对您有帮助吗?