gRPC 定制 rake-compiler-dock Docker 镜像构建全流程指南
gRPC 定制 rake-compiler-dock Docker 镜像构建全流程指南【免费下载链接】grpcC based gRPC (C, Python, Ruby, Objective-C, PHP, C#)项目地址: https://gitcode.com/GitHub_Trending/gr/grpc导读本文基于 gRPC 仓库的 third_party/rake-compiler-dock/README.md完整还原 gRPC 团队构建内部专用rake-compiler-dockDocker 镜像的方法从克隆上游仓库、打定制补丁、本地构建、重新打标、推送到 Google Artifact Registry到最终把新镜像 digest 写回 CI Dockerfile 并发布。读完本文你将掌握 gRPC Ruby 原生扩展C 扩展跨平台交叉编译镜像的整套维护流程并理解仓库中update_cross_compilers.patch、各平台Dockerfile、.current_version文件与push_testing_images.sh脚本之间的协作关系。⚠️INTERNAL ONLY该文档明确标注为 gRPC 内部流程目标是 gRPC 测试基础设施镜像不面向最终用户。普通用户构建/安装 grpc Ruby gem 时不需要执行本文任何步骤。一、背景gRPC 为何需要定制的 rake-compiler-dockgRPC 的 Ruby 实现包含用 C 写的原生扩展grpc_native扩展需要针对 Windows、macOS、多种 Linux 发行版与 CPU 架构分别编译并发布预编译 gem。rake-compiler-dock是 Ruby 社区用于交叉编译 C 扩展的标准工具链容器它把交叉编译器、Ruby 头文件与构建脚本打包进 Docker 镜像使开发者可以在单台 x86_64 Linux 主机上为x86_64-linux-gnu、aarch64-linux-gnu、arm64-darwin、x64-mingw-ucrt等十余种平台产出原生扩展。gRPC 仓库对上游镜像做了三处关键定制详见下文补丁分析升级到 clang 14 / GCC 10 以获得更好的 C17 支持、固定 musl 工具链版本、升级 osxcross 的 LLVM 与 macOS SDK——这是因为 gRPC 核心本身是大型 C 代码库对编译器的语言标准支持要求远高于普通 Ruby gem。从源码侧也能看到镜像与构建流程的衔接在 src/ruby/ext/grpc/extconf.rb 中gRPC 通过读取环境变量RCD_HOST_RUBY_VERSION该变量由 rake-compiler-dock 在构建容器内设置来判定是否处于交叉编译模式cross_compiling ENV[RCD_HOST_RUBY_VERSION] # set by rake-compiler-dock in build containers同文件 src/ruby/ext/grpc/extconf.rb 还处理了 rake-compiler-dock 交叉编译时在 LDFLAG 中注入-s链接时 strip的问题当需要保留调试符号时会先从标志列表中剔除-s保证先链接共享库、再保存调试符号、最后才 strip的顺序。二、前置条件与仓库布局1. 环境变量执行构建前需要设置两个环境变量export GEM_ROOTpath_to_clone_rake_compiler_dock_repo export GIT_ROOTpath_to_grpc_git_repo变量含义GEM_ROOT本地克隆的上游rake-compiler-dock仓库路径用于打补丁与构建GIT_ROOT当前 gRPC 仓库根目录路径用于引用补丁、Dockerfile 与发布脚本2. gRPC 仓库内的镜像定义目录third_party/rake-compiler-dock/目录下按平台存放 Dockerfile 与版本信息共 10 个平台平台目录目标平台rake_aarch64-linux-gnuARM64 Linuxglibcrake_aarch64-linux-muslARM64 Linuxmuslrake_arm64-darwinApple Silicon macOSrake_x64-mingw-ucrt64 位 WindowsUCRT 运行时rake_x86-linux-gnu32 位 Linuxglibcrake_x86-linux-musl32 位 Linuxmuslrake_x86-mingw3232 位 WindowsMSVCRTrake_x86_64-darwinIntel macOSrake_x86_64-linux-gnu64 位 Linuxglibcrake_x86_64-linux-musl64 位 Linuxmusl每个平台目录包含Dockerfile并配有一个同名.current_version文件记录当前镜像的 tag 与 sha256 digest机制见第六节。另有根级文件update_cross_compilers.patch定制补丁与README.md本文档。三、逐步构建流程上游五步法步骤 1克隆上游仓库(umask 0022; git clone https://github.com/rake-compiler/rake-compiler-dock -b v1.12.0 $GEM_ROOT)为什么用umask 0022构建过程中build/目录下的脚本会在 Docker 内部以另一个 Linux 用户执行。默认umask生成的文件权限可能只对属主可写导致容器内用户无法读取/写入克隆出来的文件。使用umask 0022可以保证其他用户获得必要的读/写权限文件 644、目录 755。注意umask只在子 shell 内生效不影响当前 shell 环境。版本固定为上游v1.12.0与镜像 tag 前缀1.12.0-mri-*一一对应。步骤 2打补丁并本地构建镜像cd $GEM_ROOT git apply ${GIT_ROOT}/third_party/rake-compiler-dock/update_cross_compilers.patch bundle config set --local path .bundle/gems bundle install bundle exec rake build:images执行逻辑git apply把 gRPC 的定制补丁 update_cross_compilers.patch 应用到上游仓库补丁详细内容见第四节bundle config set --local path .bundle/gems把 gem 安装到仓库内局部路径避免污染系统环境bundle install安装 rake-compiler-dock 的构建依赖bundle exec rake build:images使用该 gem 的 Rake 任务构建全部平台镜像。步骤 3重新打标re-tag到 gRPC 测试仓库docker image ls --filter referenceghcr.io/rake-compiler/rake-compiler-dock-image --format {{.Repository}}:{{.Tag}} | grep 1\.12\.0 | sed -E s^[^:]: | xargs -r -n1 -I{} docker tag ghcr.io/rake-compiler/rake-compiler-dock-image:{} us-docker.pkg.dev/grpc-testing/testing-images-public/rake-compiler-dock-image:{}该命令做四件事列出本地镜像中引用前缀为ghcr.io/rake-compiler/rake-compiler-dock-image的所有镜像用grep 1\.12\.0筛选出 1.12.0 系列用sed剥掉仓库前缀只保留 tag如mri-x86_64-linux-gnu用xargs逐一对每个 tag 执行docker tag把镜像从上游参考前缀ghcr.io/rake-compiler/rake-compiler-dock-image打标为 gRPC 公共测试镜像前缀us-docker.pkg.dev/grpc-testing/testing-images-public/rake-compiler-dock-image。步骤 4上传到 Google Artifact Registrydocker image ls --filter referenceghcr.io/rake-compiler/rake-compiler-dock-image --format {{.Repository}}:{{.Tag}} | grep 1\.12\.0 | sed -E s^[^:]: | xargs -r -n1 -I{} docker push us-docker.pkg.dev/grpc-testing/testing-images-public/rake-compiler-dock-image:{}与步骤 3 相同的筛选逻辑把重新打标后的镜像逐张docker push到远程 Artifact Registry。执行前需要先完成 GCP 认证gcloud auth configure-docker us-docker.pkg.dev gcloud auth login这两条认证命令来自发布脚本 tools/dockerfile/push_testing_images.sh 的注释。步骤 5重建 CI Dockerfile 并发布镜像推送到远端后Docker 会为每张镜像生成 sha256 digest。下一步是把 digest 写回 gRPC 仓库内各平台的Dockerfile使这些测试镜像固定引用新构建的基础镜像docker image ls --format {{.Tag}} {{.Repository}}:{{.Tag}}{{.Digest}} \ us-docker.pkg.dev/grpc-testing/testing-images-public/rake-compiler-dock-image \ | rg ^1.12.0-mri \ | while read -r tag image; do dockerfile${GIT_ROOT}/third_party/rake-compiler-dock/rake_${tag#1.12.0-mri-}/Dockerfile if [[ -f $dockerfile ]]; then sed -E -i s|^FROM [^ ]\$|FROM ${image}| $dockerfile fi done脚本逻辑拆解docker image ls --format {{.Tag}} {{.Repository}}:{{.Tag}}{{.Digest}}输出每张镜像的 tag、完整引用含 digest两列rg ^1.12.0-mri只保留1.12.0-mri-*系列${tag#1.12.0-mri-}是 bash 参数展开剥离1.12.0-mri-前缀得到平台名如x86_64-linux-gnu拼出对应 Dockerfile 路径third_party/rake-compiler-dock/rake_platform/Dockerfile若文件存在sed -E -i s|^FROM [^ ]\$|FROM ${image}|把 Dockerfile 中的FROM行替换为仓库:tagsha256:digest的完整引用保证后续构建可复现。最后运行发布脚本推送最终测试镜像tools/dockerfile/push_testing_images.sh该脚本会遍历third_party/rake-compiler-dock/*等目录见第六节把更新后的 Dockerfile 构建成镜像并上传同时同步.current_version文件。四、定制补丁详解update_cross_compilers.patch补丁 update_cross_compilers.patch 改编自上游 rake-compiler-dock 的 PR #201核心动机只有一句安装 clang 14 与 GCC 10以获得更好的 C17 支持gRPC 核心的 C 代码依赖较新的语言特性。补丁共修改上游仓库三个文件1.Dockerfile.mri.erb镜像模板改动最大针对不同平台条件替换编译器平台变更darwinmacOS新增llvm-toolchain-focal-14软件源安装clang-14 llvm-14-dev libc-14-dev libcabi-14-dev python3 lzma-dev libxml2-dev libssl-dev并通过update-alternatives把/usr/bin/clang、/usr/bin/clang指向 14 版arm-linux-gnu32 位 ARM交叉编译包升级为gcc-10-arm-linux-gnueabihf g-10-arm-linux-gnueabihf再用update-alternatives接管arm-linux-gnueabihf-gcc/gx86-linux-gnu32 位升级为gcc-10-i686-linux-gnu g-10-i686-linux-gnu接管i686-linux-gnu-gcc/gaarch64-linux-gnuARM64按TARGETPLATFORM分支在linux/arm64上直接装gcc-10 g-10并以update-alternatives注册为aarch64-linux-gnu-gcc/g否则装交叉编译包gcc-10-aarch64-linux-gnu g-10-aarch64-linux-gnux86_64-linux-gnux86_64按TARGETPLATFORM分支在linux/amd64上装gcc-10 g-10并同时接管gcc/g与x86_64-linux-gnu-gcc/g否则装gcc-x86-64-linux-gnu g-x86-64-linux-gnu关键设计TARGETPLATFORM是 Docker BuildKit 提供的构建参数这里用它区分本机原生编译与真正的交叉编译两种情形——原生平台直接复用宿主架构的 GCC 10其他平台才安装对应的交叉编译器从而同时覆盖同架构与跨架构两种构建路径。2.build/mk_musl_cross.shmusl 工具链新增固定版本参数# Use GCC 10.3.0. Binutils 2.33.1 is the newest version that still has a # verified hash in musl-cross-make and works with GCC 10 - newer versions # (like 2.44, the current default) break the GCC 10 build. GCC_VER 10.3.0 BINUTILS_VER 2.33.1即把 musl 交叉工具链固定为GCC 10.3.0 Binutils 2.33.1。注释说明了原因musl-cross-make 中带校验哈希、且与 GCC 10 兼容的最新 Binutils 是 2.33.1而更新的版本如当时的默认 2.44会破坏 GCC 10 的构建。3.build/mk_osxcross.shmacOS 交叉编译下载的 SDK 固定为MacOSX11.1并设置OSX_VERSION_MIN10.13将 SDK 内嵌入的 C 头文件来源从llvm-10升级为llvm-14/usr/lib/llvm-14/include/cbits 头文件匹配也相应放宽为*通配版本目录llvm-config软链接从llvm-config-10改为llvm-config-14x86_64/aarch64-apple-darwin-objdump软链接从llvm-10/bin/llvm-objdump改为llvm-14/bin/llvm-objdumposxcross 没有自带 objdump借用 LLVM 的同时签入 sigtool 以解决链接行库顺序问题。补丁改动与第一节的源码衔接一致容器内RCD_HOST_RUBY_VERSION环境变量即由这套定制的构建环境注入。五、各平台 Dockerfile 剖析以 rake_x86_64-linux-gnu/Dockerfile 为例镜像分两层FROM us-docker.pkg.dev/grpc-testing/testing-images-public/rake-compiler-dock-image:1.12.0-mri-x86_64-linux-gnusha256:2ce8d74b6072e567a5592b330535d473ffc515857d914158fc66ebea7d12f55b # # Install ccache # Install ccache from source since ccache 3.x packaged with most linux distributions # does not support Redis backend for caching. RUN curl -sSL -o ccache.tar.gz https://github.com/ccache/ccache/releases/download/v4.5.1/ccache-4.5.1.tar.gz \ tar -zxf ccache.tar.gz \ cd ccache-4.5.1 \ mkdir build cd build \ cmake -DCMAKE_BUILD_TYPERelease -DZSTD_FROM_INTERNETON -DHIREDIS_FROM_INTERNETON .. \ make -j4 make install \ cd ../.. \ rm -rf ccache-4.5.1 ccache.tar.gz基础镜像直接引用第三节步骤 3/4 上传的定制镜像1.12.0-mri-x86_64-linux-gnutag 后跟sha256:...digest实现内容寻址、不可变引用额外层从源码编译安装ccache 4.5.1。Dockerfile 注释给出原因——大多数 Linux 发行版自带的 ccache 3.x 不支持 Redis 后端缓存gRPC 的构建缓存使用 Redis 后端因此必须从源码安装新版本。编译时通过-DZSTD_FROM_INTERNETON -DHIREDIS_FROM_INTERNETON从网络拉取 zstd 与 hiredis 依赖。其他平台结构相同仅基础镜像的 tag/digest 不同。其中 rake_arm64-darwin/Dockerfile 与 rake_x86_64-darwin/Dockerfile 是纯基础镜像只含FROM一行无 ccache 层而 Linux 平台镜像glibc/musl 各架构普遍带有 ccache 层。六、发布脚本 push_testing_images.sh 与 .current_version 机制第三节步骤 5 提到的 tools/dockerfile/push_testing_images.sh 是整个 CI 镜像基础设施的总入口它把third_party/rake-compiler-dock/*与tools/dockerfile/test/*、grpc_artifact_*、interoptest/*、distribtest/*一起纳入统一管理脚本第 65-71 行。1. 支持的运行模式环境变量环境变量作用LOCAL_ONLY_MODE仅本地操作不查询 Artifact Registry、不执行上传CHECK_MODE仅校验所有.current_version文件是否最新供 CI sanity 测试使用SKIP_UPLOAD构建后不推送镜像到 Artifact RegistryHOST_ARCH_ONLY只构建与运行主机同架构的镜像ALWAYS_BUILD无论 Dockerfile 是否变化都强制构建构建时追加--no-cache --pullKEEP_GOING单个镜像构建失败不中止继续其余构建MAX_CONCURRENCY并发构建数上限默认 82. 环境自检非 CHECK_MODE 下脚本会先做两项环境检查验证免 sudo 的 Docker 可用docker run --rm debian:11 ...验证 x64 主机能运行 arm64 镜像依赖qemu-user-static的 binfmt-misc 钩子docker run --rm --platformlinux/arm64 arm64v8/debian:11 ...失败时会提示先安装qemu-user-static——这是 ARM_DOCKERFILE_DIRS 列表 中众多 arm64 镜像能在 x64 CI 上构建的前提。3. 镜像 tag 与 .current_version 的对应关系脚本的版本管理核心是Dockerfile 内容哈希即镜像 taglocal DOCKER_IMAGE_TAG$(sha1sum $DOCKERFILE_DIR/Dockerfile | cut -f1 -d\ )Dockerfile 的任何改动都会产生新 tag从而触发重建。镜像构建/发布状态记录在同目录的平台.current_version文件中其内容为镜像仓库/镜像名:sha1-tagsha256:repo-digest例如 rake_x86_64-linux-gnu.current_versionus-docker.pkg.dev/grpc-testing/testing-images-public/rake_x86_64-linux-gnu:caf2c2ae2cabdd2a2f9cd793bea744170d1fb281sha256:80f1b44eaa660b93f696fc338f6c4c9bb05931d36a55d906d45fe1ea9f6bf921关键语义对应 脚本 143-258 行的状态机只有tagsha256:...完整形式才表示镜像已推送、可被测试使用仅含tag无 digest表示本地构建过但尚未推送docker push成功后才把 RepoDigest 补写回.current_version若远端已存在相同 digest 且.current_version已同步则跳过构建CHECK_MODE下任何失同步stale 版本文件、已变更未推送、Dockerfile 已变但版本文件未更新都会被判定为 CHECK FAILED。脚本末尾还会调用tools/bazelify_tests/generate_dockerimage_current_versions_bzl.sh重新生成 bazel 侧的镜像版本映射CHECK_MODE 下则校验其是否为最新保证 Bazel 测试与 Docker 测试引用同一套镜像。七、维护工作流小结一次完整的升级交叉编译器并发布维护周期可归纳为准备设置GEM_ROOT、GIT_ROOTumask 0022克隆上游v1.12.0定制应用 update_cross_compilers.patchclang 14 / GCC 10 / musl 固定版本 / osxcross 升级构建bundle exec rake build:images本地产出全部平台镜像重打标并推送从ghcr.io/rake-compiler/rake-compiler-dock-image改挂到us-docker.pkg.dev/grpc-testing/testing-images-public/rake-compiler-dock-image并docker push固化引用用 digest 回写各平台Dockerfile的FROM行发布运行 tools/dockerfile/push_testing_images.sh构建rake_*系列测试镜像、推送并同步.current_version文件与 Bazel 版本映射。整个体系通过内容哈希 tag sha256 digest .current_version状态文件三重机制保证了 gRPC Ruby 原生扩展跨平台构建环境Windows UCRT/MSVCRT、macOS Intel/Apple Silicon、Linux glibc/musl 的 x86/x86_64/aarch64的可复现性与可审计性也让 CI 能够自动判断何时需要重建、何时可以直接复用远端镜像。【免费下载链接】grpcC based gRPC (C, Python, Ruby, Objective-C, PHP, C#)项目地址: https://gitcode.com/GitHub_Trending/gr/grpc创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考