跳转到内容
搜索文档

运行 Docker-in-Docker

最后更新 查看 MarkdownAgent 设置

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

何时使用 Docker-in-Docker

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

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

创建启用 Docker 的镜像

Cloudflare Containers 不以 root 权限运行,因此必须使用 rootless Docker 镜像。创建一个自定义 Dockerfile,将 sandbox 二进制文件与 Docker 组合在一起:

Dockerfiledockerfile
FROM docker:dind-rootless
USER root

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

# Create startup script that starts dockerd with
# iptables disabled, waits for readiness, then keeps running
RUN printf '#!/bin/sh\n\
  set -eu\n\
  dockerd-entrypoint.sh dockerd --iptables=false --ip6tables=false &\n\
  until docker version >/dev/null 2>&1; do sleep 0.2; done\n\
  echo "Docker is ready"\n\
  wait\n' > /home/rootless/boot-docker-for-dind.sh && chmod +x /home/rootless/boot-docker-for-dind.sh

ENTRYPOINT ["/sandbox"]
CMD ["/home/rootless/boot-docker-for-dind.sh"]

在沙箱中使用 Docker

部署完成后,即可通过沙箱运行 Docker 命令:

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

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

// 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");

// 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 的网络隔离功能不可用
  • 仅 rootless 模式 - 不能使用特权 container 或需要 root 的功能
  • 临时存储 - 沙箱休眠后,已构建的镜像和 container 会丢失。你必须自行持久化它们。

相关资源

这篇文档对您有帮助吗?