
Optimism 仓库 Dockerfile 编写指南为每个外部网络请求配置重试消除 CI 抖动【免费下载链接】optimismOptimism is Ethereum, scaled.项目地址: https://gitcode.com/GitHub_Trending/op/optimism导读在 Optimism 这个大型 Go/Rust 单体仓库monorepo中所有组件镜像op-node、op-batcher、op-challenger、cannon、kona 系列等都由统一的 Dockerfile 流水线构建。构建过程高度依赖外部网络Alpine 软件源、Wolfi 软件源、Debian/Ubuntu 镜像源、GitHub Releases 以及 Go/Rust 模块代理。这些远端服务会间歇性地丢包或返回瞬时 5xx 错误——每一次未被处理的重试都意味着一次 CI 随机失败flake。本文基于 docs/ai/docker.md 总结的仓库级规范系统讲解如何在 Optimism 各 Dockerfile 中为apt-get、curl/wget、apk、go mod download等网络步骤配置正确的重试策略并结合仓库内真实 Dockerfile 给出可复制的写法。最高原则每个外部网络拉取都必须重试仓库内所有 Dockerfile 编写遵循一条覆盖性规则overriding rule每一次外部网络拉取都必须具备重试能力。构建所依赖的软件源与 CDN——dl-cdn.alpinelinux.org、packages.wolfi.dev、Debian/Ubuntu 镜像源、GitHub Releases——会间歇性断开连接或返回瞬时服务器错误。如果不做重试包装每一个这样的远端错误都会直接变成 CI 抖动。实现这条规则的方式是使用每个工具自带的原生重试机制而不是维护一个共享的重试脚本。原因很实际共享脚本意味着多一份需要与各 Dockerfile 同步维护的代码而工具原生机制apt 的Acquire::Retries、curl 的--retry、wget 的--tries在语义上更精确、更少出错。这一约定在仓库源码中有大量落地的实例可查详见下文各小节引用的 Dockerfile。apt / apt-get统一追加-o Acquire::Retries8Debian/Ubuntu 系的软件包管理器 apt 原生支持下载重试。规范要求对每一次apt-get调用包括update、upgrade、install都追加选项-o Acquire::Retries8例如RUN apt-get -o Acquire::Retries8 update \ apt-get -o Acquire::Retries8 install -y --no-install-recommends ca-certificates参数含义-o是向 apt 传递配置项的命令行开关Acquire::Retries8表示对单次下载最多重试 8 次。仓库内的真实落地示例op-up/Dockerfile 基于debian:bookworm安装ca-certificates时update与install两条命令均带-o Acquire::Retries8ops/docker/deployment-utils/Dockerfile 与 ops/docker/deployment-utils/Dockerfile 在构建工具链镜像时对curl git jq build-essential等安装同样如此rust/kona/docker/apps/kona_app_generic.dockerfile 在 Ubuntu 22.04 基础阶段安装 Rust 编译依赖build-essential、libssl-dev、clang、protobuf-compiler等时update与install均带该选项rust/op-reth/DockerfileOp 对update、upgrade、install三种操作全部追加-o Acquire::Retries8。值得一提的是ops/docker/op-stack-go/Dockerfile 中op-deployer-contracts阶段还遵循了安装后清理缓存的做法rm -rf /var/lib/apt/lists/*以缩小镜像体积。curl / wget使用内置重试标志curl 与 wget 都自带成熟的重试机制直接使用即可。重试标志可以出现在 URL 之前或之后RUN curl -fL --retry 5 --retry-all-errors --retry-delay 2 -o out.tgz $URL RUN wget --tries5 --waitretry5 --retry-connrefused -O out.tgz $URL各标志说明curl -f服务器返回 HTTP 4xx/5xx 时静默失败配合重试避免把错误响应当成功-L跟随重定向curl --retry 5最多重试 5 次--retry-delay 2两次重试间隔 2 秒curl --retry-all-errors对所有瞬时错误包括连接失败、HTTP 5xx 等都进行重试。该标志要求 curl ≥ 7.71而仓库内使用的所有基础镜像Alpine、Debian、Ubuntu、Wolfi 等均满足此版本要求wget --tries5最多尝试 5 次--waitretry5重试前等待 5 秒--retry-connrefused连接被拒绝时也重试默认仅对超时重试。对于curl ... | sh这种管道式安装重试仍然覆盖脚本本身的下载过程——curl 的重试针对的是下载这个请求只要下载成功后续执行脚本即使失败也不会被误判为重试问题。仓库内的真实落地示例ops/docker/op-stack-go/Dockerfile 下载 Foundry 压缩包时使用curl -fL --retry 5 --retry-all-errors --retry-delay 2 -o ${DOWNLOAD_PATH} ${FOUNDRY_URL}随后还校验 sha256 校验和ops/docker/deployment-utils/Dockerfile 用curl --proto https --tlsv1.2 -sSf --retry 5 --retry-all-errors --retry-delay 2下载 rustup 安装脚本并用同样的参数执行https://foundry.paradigm.xyz | bashcannon/Dockerfile.diff 用curl -sSf --retry 5 --retry-all-errors --retry-delay 2 https://just.systems/install.sh | bash从 GitHub Releases 安装固定版本--tag 1.46.0的 justrust/kona/docker/apps/kona_app_generic.dockerfile 下载 rustup 与 cargo-binstall 安装脚本时也使用完全一致的标志组合。apkapk 无内置重试必须用有界循环包装Alpine 的包管理器apk add没有内置的下载重试能力因此规范要求用一个有界循环bounded loop把它包起来。这个循环有一个关键要求预算耗尽时必须非零退出这样真正的问题例如包被改名、源仓库彻底不可用仍然会让构建失败而不是被掩盖# ~5 min budget: up to 15 attempts, 20s apart. RUN n0; until apk add --no-cache ca-certificates openssl; do n$((n1)); [ $n -ge 15 ] exit 1; echo apk add retry $n/15 in 20s 2; sleep 20; done逐段解释这段写法n0初始化计数until apk add ...在命令成功退出码 0时立即结束循环失败时n$((n1))自增[ $n -ge 15 ] exit 1表示最多尝试 15 次、第 15 次仍失败就以退出码 1 终止构建echo apk add retry $n/15 in 20s 2把进度写到 stderr便于在构建日志中观察sleep 20两次尝试间隔 20 秒总预算约 5 分钟15 × 20s。明确的禁令不要写for i in ...; do apk add ... break; done这种形式——当apk add每次都失败时循环体里所有命令都失败但 for 循环本身仍然以退出码 0 结束把真实错误完全掩盖构建会带着残缺的镜像成功。此外规范强调保留--no-cache它强制每次构建都拉取最新的包索引而一旦用 BuildKit cache mount 去缓存包索引就会破坏这一语义。综合来看apk 是 CI 中抖动最频繁的软件源因此它获得了最慷慨的约 5 分钟重试预算。仓库内的真实落地示例ops/docker/op-stack-go/Dockerfile 与 ops/docker/op-stack-go/Dockerfile 分别在builder_foundry与builder阶段用until apk add --no-cache ...循环安装 curl、bash、git、jq 等工具均为15 次、间隔 20 秒的同一预算ops/docker/op-stack-go/Dockerfile 中op-challenger-target阶段使用了一个指数退避的变体attempt1; delay1; until apk add ...; do [ $attempt -ge 11 ] exit 1; ...; sleep $delay; attempt$((attempt1)); delay$((delay*2)); [ $delay -le 60 ] || delay60; done最多 11 次、延迟从 1s 翻倍到上限 60scannon/Dockerfile.diff、rust/kona/docker/apps/kona_app_generic.dockerfile、rust/op-reth/DockerfileOp 均遵循同一循环模式。从源码延伸go mod download 与 go install 同样需要重试包装虽然docs/ai/docker.md只显式列出 apt/curl/wget/apk 四种工具但仓库内大量 Dockerfile 把同一原则延伸到了Go 模块下载——go mod download与go install同样没有内置重试。仓库的标准写法与 apk 循环思路一致# go mod download has no built-in retry; loop so a transient module proxy drop doesnt flake CI. RUN --mounttypecache,target/go/pkg/mod --mounttypecache,target/root/.cache/go-build n0; until go mod download; do n$((n1)); [ $n -ge 5 ] exit 1; echo go mod download retry $n/5 in 10s 2; sleep 10; done这一模式出现在 ops/docker/op-stack-go/Dockerfile、ops/docker/op-stack-go/Dockerfileop-deployer-contracts阶段、cannon/Dockerfile.diff 中ops/docker/deployment-utils/Dockerfile 则用同样的循环包装go install。注意这里与 apk 的区别Go 模块已有本地缓存重试只会重新拉取缺失的部分因此预算可以更小5 次、间隔 10 秒并且配合 BuildKit cache mount--mounttypecache在依赖不变时跳过整个步骤。这印证了规范的核心理念——重试只包裹网络步骤绝不包裹编译步骤编译本身没有网络依赖给它加重试反而会掩盖真实的编译错误。另外值得一提的是ops/docker/op-stack-go/Dockerfile 中op-deployer-contracts阶段对 forge 的 solc 下载也做了类似处理until forge build --use ${version}5 次、间隔 2 秒并预装0.8.15 0.8.19 0.8.25 0.8.28四个版本以避免 forge 并行任务竞争安装这同样遵循远端下载必须可重试的同一原则。修改 Dockerfile 时的最终检查清单改动仓库内任意 Dockerfile 之前对照docs/ai/docker.md给出的清单逐项确认每一条apt-get/apt安装命令都携带-o Acquire::Retries8每一条curl/wget都携带对应的重试标志curl--retry 5 --retry-all-errors --retry-delay 2wget--tries5 --waitretry5 --retry-connrefused每一次apk add都被包裹在上文的重试循环中且循环在预算耗尽时非零退出重试只包裹网络步骤——永远不要把编译/构建步骤放进重试循环。提交前可以对照仓库现有实现自查以 ops/docker/op-stack-go/Dockerfile 为基准文件检查新建的 Dockerfile 是否覆盖了它用到的全部重试模式apt、curl、apk、go mod download 四种。结语Optimism 仓库把每个外部网络拉取都必须重试确立为 Dockerfile 编写的最优先规则并坚决采用各工具自带的原生机制避免共享脚本的维护成本。apk 因缺少内置重试而获得约 5 分钟的有界循环预算apt/curl/wget/go 则各用其原生能力。这套约定在 ops/docker/op-stack-go/Dockerfile、ops/docker/deployment-utils/Dockerfile、cannon/Dockerfile.diff、rust/kona/docker/apps/kona_app_generic.dockerfile 与 rust/op-reth/DockerfileOp 中均有完整的落地实现可作为编写或评审任何新镜像构建脚本时的直接参照。【免费下载链接】optimismOptimism is Ethereum, scaled.项目地址: https://gitcode.com/GitHub_Trending/op/optimism创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考