使用 pulsar-build Docker 镜像可复现构建 Apache Pulsar C++ 客户端与网站
2026/9/23 5:12:18 网站建设 项目流程

使用 pulsar-build Docker 镜像可复现构建 Apache Pulsar C++ 客户端与网站

【免费下载链接】pulsarApache Pulsar - distributed pub-sub messaging system项目地址: https://gitcode.com/gh_mirrors/pulsar28/pulsar

本篇技术指南以 build/docker/README.md 为核心,系统讲解 Apache Pulsar 仓库中build/docker目录下pulsar-build构建镜像的用途、构建与发布流程,并结合仓库内的 Dockerfile、publish.sh 以及pulsar-client-cpp/docker/下的实际调用脚本,深入剖析镜像的软件栈组成与在 C++ 客户端、Python wheel、单元测试、代码格式化等场景中的真实用法。读完本文,你将掌握如何使用该镜像在统一、可复现的环境中编译 Pulsar C++ 客户端库、构建官网并发布镜像。

镜像的用途:为 Pulsar 构建提供可复现环境

build/docker目录下存放了一个用于构建 Apache Pulsar C++ 客户端库(libpulsar)以及官网(website)的 Docker 镜像——pulsar-build。其核心价值在于:将构建所需的一切工具链与依赖固化到镜像中,从而在任何机器上都能得到一致、可复现的编译结果,避免因本地环境差异(如系统库版本、编译器版本、工具链缺失)导致的"在我机器上能编译"问题。

该镜像已经在 Docker Hub 的apachepulsar组织下发布,命名规则为apachepulsar/pulsar-build:<tag>,例如apachepulsar/pulsar-build:ubuntu-16.04(这也是build/docker目录下 Dockerfile 构建出的默认标签)。

在仓库的实际工程流程中,pulsar-build镜像承担了多种构建职责,主要包括:

使用场景入口脚本用途
构建 C++ 客户端库pulsar-client-cpp/docker/build-client-lib.shmanylinux镜像内编译libpulsar
构建 Python wheelpulsar-client-cpp/docker/build-wheels.sh为多个 Python 版本打包发布 wheel
运行单元测试pulsar-client-cpp/docker-tests.sh在镜像内执行 C++ 单元测试
代码格式化pulsar-client-cpp/docker-format.sh使用镜像内的 clang-format 统一格式
常规编译入口pulsar-client-cpp/docker-build.sh通用编译脚本,默认使用apachepulsar/pulsar-build

这些脚本统一通过环境变量BUILD_IMAGE_NAME覆盖镜像名(默认值均为apachepulsar/pulsar-build),例如 build-client-lib.sh、build-wheels.sh。

本地构建 pulsar-build 镜像

在仓库根目录下执行以下命令即可在本地构建镜像(默认 Dockerfile 位于build/docker,基础镜像为ubuntu:16.04):

docker build -t pulsar-build .

该命令使用 build/docker/Dockerfile 完成构建。需要说明的是,此命令生成的镜像 tag 为pulsar-build,而仓库内 C++ 客户端脚本默认引用的完整镜像名为apachepulsar/pulsar-build;如需在本地替代线上镜像使用,可改用完整命名:

docker build -t apachepulsar/pulsar-build:ubuntu-16.04 .

深入 Dockerfile:镜像内预置的完整工具链

build/docker/Dockerfile 基于ubuntu:16.04,依次安装并配置了 C++ 客户端编译、网站构建所需的全部依赖,其内容可直接视为该镜像的技术规格说明。

基础镜像与工作目录

FROM ubuntu:16.04 # prepare the directory for pulsar related files RUN mkdir /pulsar

镜像内预建了/pulsar目录,用于挂载 Pulsar 源码。仓库中的实际调用脚本正是利用这一约定:build-client-lib.shbuild-wheels.sh都以-v $ROOT_DIR:/pulsar的方式将仓库根目录挂载进容器,然后在容器内执行/pulsar/pulsar-client-cpp/docker/...下的构建脚本。

C++ 客户端编译依赖

RUN apt-get update && \ apt-get install -y software-properties-common && \ add-apt-repository ppa:openjdk-r/ppa && \ apt-get update && \ apt-get install -y tig g++ cmake libssl-dev libcurl4-openssl-dev \ liblog4cxx-dev google-mock libgtest-dev \ libboost-dev libboost-program-options-dev libboost-system-dev libboost-python-dev \ libxml2-utils protobuf-compiler wget \ curl doxygen openjdk-8-jdk-headless openjdk-11-jdk-headless clang-format-5.0 \ gnupg2 golang-1.13-go zip unzip libzstd-dev libsnappy-dev python3-pip libpython-dev wireshark-dev

这一行包罗了编译libpulsar所需的完整工具链,逐项对应的作用如下:

依赖在构建中的作用
g++cmakeC++ 编译与 CMake 构建系统(见 pulsar-client-cpp/CMakeLists.txt)
libssl-devlibcurl4-openssl-devTLS 加密与 HTTP 相关功能(lookup、OAuth2 认证等)
liblog4cxx-dev日志框架 Log4cxx(Log4cxxLogger.cc)
libboost-devlibboost-*-dev系列Boost 库(线程、program-options、Python 绑定等)
libgtest-devgoogle-mock单元测试框架(对应 pulsar-client-cpp/tests/ 下的测试代码)
protobuf-compiler编译.proto定义(Pulsar 协议,见 pulsar-common/src/main/proto/)
openjdk-8-jdk-headlessopenjdk-11-jdk-headless双 JDK 环境,供 Pulsar 多版本 Java 代码编译与测试使用
clang-format-5.0代码格式化,供 docker-format.sh 调用
golang-1.13-go编译 Go 相关组件(如 pulsar-function-go)
libzstd-devlibsnappy-dev压缩算法支持(ZStd、Snappy,对应 CompressionCodecZstd.cc 等)
python3-piplibpython-devPython 客户端绑定构建
wireshark-devWireshark 协议解析插件构建(wireshark/pulsarDissector.cc)

源码编译 protobuf 3.x

Ubuntu 16.04 自带 apt 源的 protobuf 为 2.x,无法满足 Pulsar 对 protobuf 3.x 的要求,因此 Dockerfile 采用从源码编译的方式安装 protobuf 3.17.3:

RUN curl -O -L https://github.com/protocolbuffers/protobuf/releases/download/v3.17.3/protobuf-cpp-3.17.3.tar.gz && \ tar xvfz protobuf-cpp-3.17.3.tar.gz && \ cd protobuf-3.17.3/ && \ CXXFLAGS=-fPIC ./configure && \ make -j8 && make install && \ cd .. && rm -rf protobuf-3.17.3/ protobuf-cpp-3.17.3.tar.gz ENV LD_LIBRARY_PATH /usr/local/lib

注意CXXFLAGS=-fPIC:因为编译产物需要链接进共享库/静态库,位置无关代码是必须的。LD_LIBRARY_PATH=/usr/local/lib则确保make install安装到/usr/local/lib下的 protobuf 运行时库能被后续链接期找到。从源码结构看,Pulsar C++ 客户端使用 protobuf 生成协议消息的序列化代码(见 pulsar-common/src/main/proto/PulsarApi.proto),因此版本一致性是保证二进制兼容的前提。

gtest 与 google-mock 的编译安装

# Compile and install gtest RUN cd /usr/src/gtest && cmake . && make && cp libgtest.a /usr/lib # Compile and install google-mock RUN cd /usr/src/gmock && cmake . && make && cp libgmock.a /usr/lib # Include gtest parallel to speed up unit tests RUN git clone https://github.com/google/gtest-parallel.git

Ubuntu 的 gtest 包只提供源码,需要手动编译后将静态库复制到/usr/lib。同时克隆gtest-parallel,用于并行加速单元测试(pulsar-client-cpp/tests/ 目录下有大量测试用例,并行执行可显著缩短 CI 时间)。

Java 与网站构建工具链

ENV JAVA_HOME=/usr/lib/jvm/java-1.8.0-openjdk-amd64 ENV JAVA_HOME_11=/usr/lib/jvm/java-1.11.0-openjdk-amd64

JAVA_HOMEJAVA_HOME_11分别指向 JDK 8 与 JDK 11。从buildtoolspulsar-broker等模块的构建配置可以推断,Pulsar 的 Maven 构建在部分模块编译/测试时需要在 JDK 8 与 JDK 11 之间切换,因此镜像同时预置两套 JDK 并暴露对应的环境变量。

紧接着是网站构建相关的依赖:RVM 安装 Ruby 2.4.1(对应 site2/website 的构建环境)、Node.js 12 与 Yarn(前端依赖管理)、crowdin(文档翻译同步)、pip + pdoc(Python 文档生成,用于 site2/docs 相关内容的辅助构建)。

Maven 安装

ARG MAVEN_VERSION=3.6.3 ARG MAVEN_FILENAME="apache-maven-${MAVEN_VERSION}-bin.tar.gz" ARG MAVEN_HOME=/opt/maven ARG MAVEN_URL="http://archive.apache.org/dist/maven/maven-3/${MAVEN_VERSION}/binaries/${MAVEN_FILENAME}" ARG MAVEN_TMP="/tmp/${MAVEN_FILENAME}" RUN wget --no-verbose -O ${MAVEN_TMP} ${MAVEN_URL} RUN tar xzf ${MAVEN_TMP} -C /opt/ \ && ln -s /opt/apache-maven-${MAVEN_VERSION} ${MAVEN_HOME} \ && ln -s ${MAVEN_HOME}/bin/mvn /usr/local/bin

镜像固定安装 Apache Maven 3.6.3,并通过符号链接将mvn暴露到PATH,保证仓库内所有 Maven 构建(根 pom.xml 及各模块 pom)在一致版本下执行。构建完成后该构建参数即被释放(unset MAVEN_VERSION),不影响运行时环境。

发布 pulsar-build 镜像

只有具备相应权限的 committer 才有权向apachepulsar这个 Docker Hub 组织推送镜像。

发布流程分为两步:先构建镜像,再推送镜像。

构建镜像

docker build -t apachepulsar/pulsar-build:ubuntu-16.04 .

推送镜像

publish.sh

publish.sh 的完整逻辑如下:

ROOT_DIR=$(git rev-parse --show-toplevel) cd $ROOT_DIR/build/docker if [ -z "$DOCKER_USER" ]; then echo "Docker user in variable \$DOCKER_USER was not set. Skipping image publishing" exit 1 fi if [ -z "$DOCKER_PASSWORD" ]; then echo "Docker password in variable \$DOCKER_PASSWORD was not set. Skipping image publishing" exit 1 fi DOCKER_ORG="${DOCKER_ORG:-apachepulsar}" docker login ${DOCKER_REGISTRY} -u="$DOCKER_USER" -p="$DOCKER_PASSWORD" if [ $? -ne 0 ]; then echo "Failed to loging to Docker Hub" exit 1 fi if [[ -z ${DOCKER_REGISTRY} ]]; then docker_registry_org=${DOCKER_ORG} else docker_registry_org=${DOCKER_REGISTRY}/${DOCKER_ORG} echo "Starting to push images to ${docker_registry_org}..." fi set -x # Fail if any of the subsequent commands fail set -e # Push all images and tags docker push ${docker_registry_org}/pulsar-build:ubuntu-16.04 echo "Finished pushing images to ${docker_registry_org}"

脚本行为可以归纳为:

  1. 权限校验:通过git rev-parse --show-toplevel定位仓库根目录并切换到build/docker;若未设置DOCKER_USERDOCKER_PASSWORD环境变量,则直接退出并跳过推送(返回码 1)。
  2. 组织与注册表DOCKER_ORG默认apachepulsar;可通过环境变量DOCKER_REGISTRY指定自定义注册表,此时推送目标变为${DOCKER_REGISTRY}/${DOCKER_ORG}/pulsar-build:ubuntu-16.04
  3. 登录与推送:使用docker login完成认证(失败即退出),随后在set -e保护下执行docker push,将ubuntu-16.04标签推送至目标组织。

由此可见,发布权限的控制体现在两点:一是仓库访问权限(仅 committer 拥有apachepulsar组织的推送权限),二是脚本对DOCKER_USER/DOCKER_PASSWORD的强校验。对普通用户而言,直接使用 Docker Hub 上已发布的镜像即可,无需自行推送。

镜像的工程落地:以 C++ 客户端与 Python wheel 构建为例

pulsar-build镜像是 Pulsar 官方 CI 发布链路的基石,下面以两个真实脚本说明它的用法。

构建 C++ 客户端库

build-client-lib.sh 使用manylinux系列镜像编译客户端库:

BUILD_IMAGE_NAME="${BUILD_IMAGE_NAME:-apachepulsar/pulsar-build}" PYTHON_VERSIONS=( '3.6 cp36-cp36m' ) for line in "${PYTHON_VERSIONS[@]}"; do read -r -a PY <<< "$line" PYTHON_VERSION=${PY[0]} PYTHON_SPEC=${PY[1]} IMAGE_NAME=$BUILD_IMAGE_NAME:manylinux-$PYTHON_SPEC VOLUME_OPTION=${VOLUME_OPTION:-"-v $ROOT_DIR:/pulsar"} COMMAND="/pulsar/pulsar-client-cpp/docker/build-client-lib-within-docker.sh" DOCKER_CMD="docker run -i ${VOLUME_OPTION} ${IMAGE_NAME}" $DOCKER_CMD bash -c "${COMMAND}" done

关键点:-v $ROOT_DIR:/pulsar将仓库挂载到镜像预建的/pulsar目录,容器内执行仓库自带的build-client-lib-within-docker.sh。这也印证了 Dockerfile 中mkdir /pulsar的设计意图。

构建 Python wheel 并推送

build-wheels.sh 支持按 Python 版本循环构建 wheel,并允许通过命令行参数只构建指定版本(从 python-versions.sh 读取受支持的版本组合,未匹配则报错退出);构建完成后,push-images.sh 将各变体镜像打上apachepulsar/pulsar-build:<base>-<pythonspec>-<arch>标签并推送,从而覆盖不同 Python 版本与架构的组合需求。

运行测试与格式化

  • docker-tests.sh 在镜像内运行 C++ 单元测试;
  • docker-format.sh 调用镜像内预装的clang-format-5.0统一代码风格。

这些脚本共同说明:pulsar-build不只是"编译一次"的工具,而是贯穿 Pulsar C++ 客户端"编译—打包—测试—格式化"全流程的标准环境。

小结

build/docker目录下的pulsar-build镜像通过把 C++ 编译链(g++/CMake/protobuf/gtest)、Java 双 JDK、Maven、以及网站构建所需的 Ruby/Node/Yarn/crowdin/pdoc 全部固化在ubuntu:16.04基础镜像中,为 Apache Pulsar 的 C++ 客户端与官网构建提供了统一、可复现的执行环境。普通用户可直接使用 Docker Hub 上发布的apachepulsar/pulsar-build:<tag>镜像;committer 则可通过 publish.sh 完成新版本镜像的发布。理解该镜像的构成与用法,是参与 Pulsar C++ 客户端开发、排障与发布的前提。

【免费下载链接】pulsarApache Pulsar - distributed pub-sub messaging system项目地址: https://gitcode.com/gh_mirrors/pulsar28/pulsar

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询