本指南说明如何在 Sandbox 中运行 Docker,从而在安全沙箱内构建并运行 container 镜像。
在以下场景使用 Docker-in-Docker:
- 开发容器化应用 - 运行
docker build,根据 Dockerfile 创建镜像 - 在 CI/CD 中运行 Docker - 响应代码变更,并使用 Cloudflare Containers 构建和推送镜像
- 运行任意 container 镜像 - 从最终用户提供的镜像启动 container
Cloudflare Containers 不以 root 权限运行,因此必须使用 rootless Docker 镜像。创建一个自定义 Dockerfile,将 sandbox 二进制文件与 Docker 组合在一起:
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 命令:
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 会丢失。你必须自行持久化它们。
- Dockerfile 参考 - 自定义沙箱镜像
- 执行命令 - 在沙箱中运行命令
- 后台进程 - 管理长时间运行的进程