进阶 getfoundry.sh 2026-10-10 09:32:10 · 6 阅读
第3章 Docker 与容器化部署 Foundry
Docker 与容器
本指南介绍如何在 Docker 中运行 Foundry,以实现可复现的构建、CI 流水线和隔离的开发环境。
官方 Foundry Docker 镜像
从 GitHub Container Registry 拉取官方 Foundry 镜像:
$ docker pull ghcr.io/foundry-rs/foundry:latest
可用标签:
| 标签 | 说明 |
|---|---|
| latest | 最新稳定版本 |
| nightly | 每夜构建版 |
| v1.0.0 | 指定版本 |
使用 Podman
官方 Foundry 容器镜像兼容 OCI,也可以配合 Podman 使用。
拉取镜像:
$ podman pull ghcr.io/foundry-rs/foundry:latest
下文提到的 Docker 命令都可以用 Podman 运行,只需把 docker 替换为 podman。例如:
# 用 Podman 运行 forge build
$ podman run --rm -v $(pwd):/app -w /app --entrypoint forge ghcr.io/foundry-rs/foundry build
注意
在某些 rootless Podman 配置下,需要写入 bind 挂载目录的命令(如
forge init)可能需要额外的 user namespace 配置(例如--userns=keep-id)来避免权限问题。
运行 Foundry 命令
镜像默认以 /bin/sh -c 作为 entrypoint。可以通过 --entrypoint 指定 Foundry 可执行文件,让镜像名后面的参数传给它:
# 运行 forge build
$ docker run --rm -v $(pwd):/app -w /app --entrypoint forge ghcr.io/foundry-rs/foundry build
# 运行测试
$ docker run --rm -v $(pwd):/app -w /app --entrypoint forge ghcr.io/foundry-rs/foundry test
# 运行 cast
$ docker run --rm --entrypoint cast ghcr.io/foundry-rs/foundry block-number --rpc-url https://ethereum.reth.rs/rpc
也可以保留默认 entrypoint,把整条命令作为一个参数传入:
$ docker run --rm ghcr.io/foundry-rs/foundry "cast wallet new-mnemonic"
方便起见的 shell 别名
在 shell 配置文件中添加:
~/.bashrc$ alias dforge='docker run --rm -v $(pwd):/app -w /app --entrypoint forge ghcr.io/foundry-rs/foundry'
$ alias dcast='docker run --rm --entrypoint cast ghcr.io/foundry-rs/foundry'
$ alias danvil='docker run --rm -p 8545:8545 --entrypoint anvil ghcr.io/foundry-rs/foundry --host 0.0.0.0'
然后就可以这样使用:
$ dforge build
$ dforge test
$ dcast balance 0x1234...
自定义 Dockerfile
创建包含项目依赖的项目专属镜像:
DockerfileFROM ghcr.io/foundry-rs/foundry:latest
WORKDIR /app
# 先复制依赖清单以便利用缓存
COPY foundry.toml .
COPY remappings.txt .
# 安装 git 用于管理依赖
RUN apk add --no-cache git
# 复制源码文件
COPY src ./src
COPY test ./test
COPY script ./script
COPY lib ./lib
# 构建项目
RUN forge build
# 默认命令
ENTRYPOINT ["forge"]
CMD ["test"]
构建并运行:
$ docker build -t my-project .
$ docker run --rm my-project
$ docker run --rm my-project test -vvv
Docker Compose 配置
适合需要在测试的同时运行 Anvil 的项目:
docker-compose.ymlservices:
anvil:
image: ghcr.io/foundry-rs/foundry:latest
entrypoint: ["anvil"]
command: ["--host", "0.0.0.0"]
ports:
- "8545:8545"
healthcheck:
test: ["CMD", "cast", "block-number", "--rpc-url", "http://localhost:8545"]
interval: 2s
timeout: 5s
retries: 10
test:
image: ghcr.io/foundry-rs/foundry:latest
entrypoint: ["forge"]
volumes:
- .:/app
working_dir: /app
depends_on:
anvil:
condition: service_healthy
command: ["test", "--fork-url", "http://anvil:8545"]
deploy:
image: ghcr.io/foundry-rs/foundry:latest
entrypoint: ["forge"]
volumes:
- .:/app
working_dir: /app
depends_on:
anvil:
condition: service_healthy
command: script script/Deploy.s.sol --broadcast --rpc-url http://anvil:8545 --private-key 0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80
运行测试:
$ docker compose up test
部署到本地 Anvil:
$ docker compose up deploy
GitHub Actions CI
.github/workflows/test.ymlname: Test
on: [push, pull_request]
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
submodules: recursive
- name: Install Foundry
uses: foundry-rs/foundry-toolchain@v1
- name: Build
run: forge build
- name: Test
run: forge test -vvv
- name: Check formatting
run: forge fmt --check
- name: Gas snapshot
run: forge snapshot --check --tolerance 5
基于 Docker 的 CI 运行器
适合自托管 runner 或没有 foundry-toolchain 的环境:
.github/workflows/test.ymlname: Test
on: [push, pull_request]
jobs:
test:
runs-on: ubuntu-latest
container:
image: ghcr.io/foundry-rs/foundry:latest
steps:
- uses: actions/checkout@v4
with:
submodules: recursive
- name: Build
run: forge build
- name: Test
run: forge test -vvv
可复现构建
固定 Foundry 版本以实现可复现构建:
DockerfileFROM ghcr.io/foundry-rs/foundry:v1.0.0
# ... 其余 Dockerfile 内容
或在 CI 中:
.github/workflows/test.yml- name: Install Foundry
uses: foundry-rs/foundry-toolchain@v1
with:
version: v1.0.0
在 Docker 中运行 Anvil
把 Anvil 暴露给宿主机:
$ docker run --rm -p 8545:8545 --entrypoint anvil ghcr.io/foundry-rs/foundry --host 0.0.0.0
Anvil 必须绑定 0.0.0.0(而不是 127.0.0.1),才能从容器外部访问。
持久化状态:
$ docker run --rm -p 8545:8545 -v anvil-state:/state --entrypoint anvil ghcr.io/foundry-rs/foundry \
--host 0.0.0.0 --state /state/anvil.json
多阶段构建
使用多阶段构建优化镜像体积:
Dockerfile# 构建阶段
FROM ghcr.io/foundry-rs/foundry:latest AS builder
WORKDIR /app
COPY . .
RUN forge build --optimize
# 运行阶段
FROM ghcr.io/foundry-rs/foundry:latest AS runtime
WORKDIR /app
COPY --from=builder /app/out ./out
COPY --from=builder /app/broadcast ./broadcast
# 只保留部署所需的内容
ENTRYPOINT ["forge"]
CMD ["script", "script/Deploy.s.sol", "--broadcast"]
环境变量
传入密钥和配置:
$ docker run --rm \
-v $(pwd):/app \
-w /app \
-e PRIVATE_KEY \
-e ETHERSCAN_API_KEY \
--entrypoint forge \
ghcr.io/foundry-rs/foundry \
script script/Deploy.s.sol --broadcast --verify
或通过 env 文件:
$ docker run --rm \
-v $(pwd):/app \
-w /app \
--env-file .env \
--entrypoint forge \
ghcr.io/foundry-rs/foundry \
script script/Deploy.s.sol --broadcast
最佳实践
| 实践 | 说明 |
|---|---|
| 固定版本 | 使用具体标签而非 latest,保证可复现性 |
| 缓存依赖 | 先复制依赖清单再复制源码,充分利用层缓存 |
| 多阶段构建 | 排除构建产物,减小最终镜像体积 |
| 合理挂载 | 本地开发用 -v,CI 中用 COPY |
| 正确暴露端口 | 容器中的 Anvil 需使用 --host 0.0.0.0 |
这篇文档有帮助吗?在 GitHub 上提交修改建议