clickhouse 官方 docker 镜像无法在老的 arm64 cpu 上运行,需要编译
由来
业务方有在使用 clickhouse,当时版本是 22.8.5.29
,随着后面也有 arm64 需求,在 arm64 机器上部署了 ck 后即使没有业务数据内存占用也非常高,在持续刷下面日志:
1 | __1::__function::__policy_storage const*) @ 0x8e8379c in /usr/bin/clickhouse |
搜索了看到几个 issue 都建议升级版本:
- https://github.com/ClickHouse/ClickHouse/issues/47642
- https://github.com/ClickHouse/ClickHouse/issues/40215
过程
arm64 运行环境
1 | $ lscpu |
升级后起不来
根据 ck 官方 update 文档 里可知官方努力保持一年兼容期,两个版本之前差异小于一年或者 LTS 版本少于两个可以升级。而 23 的 LTS 版本是 v23.8.16.40-lts
。然后换了镜像后运行不起来:
1 | /entrypoint.sh: line 40: 23 Illegal instruction (core dumped) clickhouse extract-from-config --config-file "$CLICKHOUSE_CONFIG" --key='storage_configuration.disks.*.path' |
然后尝试了下列版本:
1 | 23.5.5.92 |
发现 22.9 才能启动,查看 changelog https://clickhouse.com/docs/en/whats-new/changelog/2022#-clickhouse-release-2210-2022-10-25
1 | Aarch64 binaries now require at least ARMv8.2, released in 2016. Most notably, this enables use of ARM LSE, i.e. native atomic operations. \ |
22.10 开始使用 arm LSE 指令集做原子操作,但是该指令集 armv8.2 才有,但是也在 Cmake 添加了选项 NO_ARMV81_OR_HIGHER
对于 armv8.0 编译支持。
查看编译文档
官方虽然文档写得比较多,但是感觉比较琐碎。跟着前面 changelog 的 pr #41987 看了下官方是 github action 编译的。github action 构建历史有上限,找 pr 里的 BuilderBinAarch64V80Compat
找不到,然后在新版本 .github/workflows/master.yml
里找到了 build_arm_v80compat
。但是用的是下面编译命令:
1 | python3 -m praktika run 'Build (arm_v80compat)' --workflow "MasterCI" --ci |
praktika
这个 pip 仓库上找不到,于是找到相关最新的 action 里看下具体怎么编译的,找到了相关日志:
1 | INFO:root:Pulling image clickhouse/binary-builder:54b46bb22708 - done |
搜了下相关源码相关关键字 binary-builder
,大体了解了下官方编译步骤:
docker/packager
下提供了packager
二进制(实际是python脚本)来编译docker/packager/binary-builder
是利用 docker 打包一个镜像,里面包含 llvm、rust、clang 之类的编译环境
该容器镜像由 CI 构建定期推送到 dockerhub 上,然后不想宿主机上安装环境可以使用它来进行编译,具体参数查看:
1 | $ cd docker/packager |
编译
并且官方文档有 building-in-docker ,所以打算使用官方的 docker 镜像构建,机器要提前安装好 docker,硬盘最好有 50G 容量,源码非常大,自备稳定猫咪之类的。拉取源码和编译全程建议开个 screen 里操作:
拉取源码
因为子模块非常多,建议使用 git2 避免一些奇怪问题。
1 | git clone https://github.com/ClickHouse/ClickHouse.git |
切到指定分支和拉取子模块:
1 | git checkout v23.8.16.40-lts |
查看子模块完整性
1 | git status |
确认拉取完成后再开始后面操作
失败的编译
查看 docker/packager/packager
内容编译 arm64v8.0 执行下面命令:
1 | cd ./docker/packager |
然后报错 clang 版本相关,默认拉取的 clickhouse/binary-builder:latest
,查看了下 packager
源码和 --help
有选项 --docker-image-version
指定镜像 tag,去 dockerhub 上找了下 clickhouse/binary-builder
的 clang 16 版本,发现 tag 好像是 commitid 相关:
1 | $ git log -n1 |
搜索了下 e143a903 找到了 tag 54187-e143a9039ba36ad0c25f2ed85503f36e88f61063
,但是镜像比较大,然后用 daoCloud 的同步了下,拉取下:
1 | docker pull m.daocloud.io/docker.io/clickhouse/binary-builder:54187-e143a9039ba36ad0c25f2ed85503f36e88f61063 |
然后编译:
1 | ./docker/packager/packager --package-type=binary --compiler=clang-16-aarch64-v80compat \ |
相关报错一直无法解决,提了 issue 75923,官方说该版本已经不维护不提供帮助,让我不要自己编译,而是去下载官方编译的。下载了当然是 core dump。然后自己找了下官方编译的 build_arm_v80compat
,只有一个下载直链,不存在老版本,action 里可以看到下载链接:
1 | 2025-02-10 22:46:45,343 Output placed into /home/ubuntu/actions-runner/_work/ClickHouse/ClickHouse/ci/tmp/build |
每个 action 里都有链接,但是太早的就没有了,因为 github action 只保留上限的构建历史。看了下应该是构建都存在 s3 上:
1 | === Post run script [Build (arm_v80compat)], workflow [MasterCI] === |
根据链接规则推断了下下载 url,发现 403:
1 | wget https://clickhouse-builds.s3.amazonaws.com/REFs/master/e143a9039ba36ad0c25f2ed85503f36e88f61063/build_arm_v80compat/clickhouse |
既然说 v23 不维护,然后尝试了 v24 的 lts 版本也一样,相关报错也提了 issue 75960
成功的编译
报错都是 contrib/sysroot
和 contrib/thrift
这俩子模块,github 上看了下历史记录,这俩模块基本没怎么更新到新版本,感觉不是模块问题。搜了一些相关编译,发现都是编译 22.10 之前的版本居多。麒麟的 yum 源里版本也比较老,联系了麒麟有没有新版本 rpm 包,然后麒麟发了个新版本源码编译安装的文档过来,看了下是在 arm64 上编译的 25 版本,大体步骤为:
- rpm 包安装 cmake 3.26
- 编译安装 gcc-11.3.0 并换 std 库
- 编译安装 clang-18.1.0
- 编译安装 llvm-18.1.0
- 安装 rust 1.80.0
- 安装 ccache src.rpm
- 声明 CC=clang CXX=clang++ 后
mkdir build && cd build
cmake .. -DCMAKE_INSTALL_PREFIX=/opt/clickhouse-bin -DNO_ARMV81_OR_HIGHER=1
ninja -j32
ninja install
根据编译相关,packager
的 --compiler=clang-16-aarch64-v80compat
相关逻辑:
1 | ARM_V80COMPAT_SUFFIX = "-aarch64-v80compat" |
-DNO_ARMV81_OR_HIGHER=1
是必填的,而插入的 -DCMAKE_TOOLCHAIN_FILE
则是配置使用交叉编译工具链。交叉编译一直失败,是不是可以 arm64 机器上和麒麟那样源码编译 clang 等相关再尝试编译 ck,但是新开的麒麟 arm64 机器上没猫咪 gcc 和 llvm 下载非常慢。就同步看了下 clickhouse/binary-builder
发现还提供了 arm64 的镜像,想着直接 arm64 上不指定 ARM_V80COMPAT_SUFFIX
那就会用内置的 arm64 gcc 了,然后再指定 -DNO_ARMV81_OR_HIGHER=1
编译选项那就和麒麟一样了。和之前一样找了个高配置 arm64 机器上:
- 拉源码,进去 checkout 到
v23.8.16.40-lts
,拉取子模块源码 - 拉取对应的
clickhouse/binary-builder
并 tag
查看脚本得到编译命令和选项:
1 | CMAKE_FLAGS='-DNO_ARMV81_OR_HIGHER=1' ./docker/packager/packager --package-type=binary \ |
执行后终于没卡在 contrib/sysroot
和 contrib/thrift
了,但是最后报错:
1 | Feb 12 08:22:09 [3590/10884] Building CXX object contrib/llvm-project/llvm/utils/TableGen/CMakeFiles/llvm-tblgen.dir/SubtargetFeatureInfo.cpp.o |
报错说 rust 版本 1.72 低了,要求 1.73,搜了下 nightly-2023-07-04
搜不到有用的,nightly
是每日发行版本,找不到对应的 1.73
是啥日期。如果直接使用新版本 binary-builder
,里面的 clang 和要编译的 ck 版本对不上,于是根据 clickhouse/binary-builder
的 Dockerfile 找了下 rust 的临近更新是 nightly-2024-12-01
:
1 | RUN curl https://sh.rustup.rs -sSf | bash -s -- -y && \ |
前面编译报错结尾会有一个 docker run ...
完整命令,结尾加一个 bash
run 起来后内部升级下 rust 尝试:
1 | # 记得依旧使用 screen |
实际 clickhouse/binary-builder
和 它的 Dockerfile CMD 都是执行:
1 | CMD ["bash" "-c" "/build.sh 2>&1"] |
所以上面的容器里继续执行 /build.sh
就可以编译了,编译期间看了下 build.sh
存在以下逻辑:
1 | if check_prebuild_exists /build/packages/pre-build |
所以如果不交互式直接使用脚本自动化编译的步骤,在拉取 clickhouse/binary-builder
对应镜像后可以是下面:
1 | mkdir -p packages/pre-build |
最后编译出来 2.9G 大小:
1 | Feb 12 10:39:51 Average compiler 0.000 s |
然后加一些选项编译:
1 | CMAKE_FLAGS='-DNO_ARMV81_OR_HIGHER=1 -DCMAKE_BUILD_TYPE=Release -DENABLE_TESTS=OFF -DENABLE_DEBUG=OFF -DSPLIT_DEBUG_SYMBOLS=ON' \ |
1 | Feb 13 01:24:21 Failed distributed compilations 0 |
上面的文件打包,然后 core dump 机器上测试下没问题:
1 | ./clickhouse local -q 'select 1' |
打包 Docker 镜像
根据 docker histort --no-trunc
确认了 Dockerfile 是用的 docker/server/Dockerfile.ubuntu,但是编译的镜像是基于 ubuntu:22.04 的:
1 | # cat /etc/os-release |
避免意外和 CVE,还是用 ubuntu:22.04
稳妥些,参考了下最新的 master 分支上的 22.04 整了下 docker/server/Dockerfile.fix
:
1 | FROM ubuntu:22.04 |
直接拷贝二进制进去执行 clickhouse install 会造成 overlay diff 浪费,所以需要起一个 web 下载,编译容器镜像:
1 | RANDOM_PORT=50358 |
一些其他信息
clickhouse/binary-builder
新版本的 tag 似乎不是 commidID 了,找了下一些版本 tag 和 clang 对应:
- dd5e777b6745 18
- 54187-e143a9039ba36ad0c25f2ed85503f36e88f61063 16
官方和编译的二进制文件 file 信息对比:
1 | clickhouse: ELF 64-bit LSB shared object, ARM aarch64, version 1 (SYSV), dynamically linked, interpreter /lib/ld-linux-aarch64.so.1, for GNU/Linux 3.7.0, BuildID[sha1]=3e70066de2db0f08f97ca310827184d61111dc22, not stripped |
切换其他版本的时候要处理下子模块,相关命令:
1 | git submodule update --recursive --checkout |
切版本还要记得清理 build_docker
目录
参考
其实也没参考多少,就是这些是能搜到的 arm64 编译相关