使用Musl静态编译Rust Diesel连接MySQL 8.0时caching_sha2_password插件加载失败
问题背景
我正在开发一个用musl编译的Rust应用,目标是生成静态链接二进制文件来构建轻量Docker镜像。已经手动为musl重新编译了mysqlclient库,但连接MySQL 8.0数据库时遇到以下错误:
gateway | thread 'main' panicked at src/db/setup.rs:25:10: gateway | Failed to create DB Pool: Error(Some("Plugin caching_sha2_password could not be loaded: Dynamic loading not supported")) gateway | note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
应用采用Diesel ORM的MySQL后端,Dockerfile相关编译配置如下:
FROM messense/rust-musl-cross:${BUILD_PLATFORM}-musl AS builder ... # Manually compile MariaDB client library for musl WORKDIR /tmp RUN curl -LO https://downloads.mariadb.com/Connectors/c/connector-c-3.3.4/mariadb-connector-c-3.3.4-src.tar.gz RUN tar xzf mariadb-connector-c-3.3.4-src.tar.gz RUN mkdir build WORKDIR /tmp/build RUN sed 's/STRING(STRIP ${extra_dynamic_LDFLAGS} extra_dynamic_LDFLAGS)//' -i ../mariadb-connector-c-3.3.4-src/mariadb_config/CMakeLists.txt RUN sed 's/LIST(REMOVE_DUPLICATES extra_dynamic_LDFLAGS)//' -i ../mariadb-connector-c-3.3.4-src/mariadb_config/CMakeLists.txt RUN CC=aarch64-unknown-linux-musl-gcc \ LDFLAGS=-L/usr/local/musl/lib \ cmake \ -DWITH_SSL=OPENSSL \ -DWITH_TLS=OPENSSL \ -DOPENSSL_ROOT_DIR=/usr/local/musl \ -DOPENSSL_USE_STATIC_LIBS=1 \ -DWITH_CURL=0 \ ../mariadb-connector-c-3.3.4-src RUN make mariadbclient RUN cp libmariadb/libmariadbclient.a /usr/local/musl/lib/libmysqlclient.a ...
错误原因推测是Musl静态链接不支持动态加载,而MySQL 8.0默认的caching_sha2_password认证插件需要动态加载机制。虽然已静态编译mariadbclient,二进制可正常运行,但数据库连接失败。
更新尝试
尝试切换到MySQL官方客户端库编译,使用以下配置:
# Manually compile MySQL client library for musl WORKDIR /tmp RUN curl -LO https://dev.mysql.com/get/Downloads/MySQL-8.0/mysql-8.0.36.tar.gz RUN tar xzf mysql-8.0.36.tar.gz RUN mkdir build WORKDIR /tmp/build RUN CC=aarch64-unknown-linux-musl-gcc \ LDFLAGS="-L/usr/local/musl/lib" \ cmake \ -DDOWNLOAD_BOOST=1 \ -DWITH_BOOST=/tmp/boost \ -DWITH_SSL=system \ -DOPENSSL_ROOT_DIR=/usr/local/musl \ -DOPENSSL_USE_STATIC_LIBS=1 \ -DWITHOUT_SERVER=ON \ -DWITH_UNIT_TESTS=OFF \ -DWITH_SYSTEMD=OFF \ -DWITH_ROUTER=OFF \ -DFORCE_UNSUPPORTED_COMPILER=ON \ ../mysql-8.0.36
但出现多个编译错误:
- Boost解压失败:
2.312 -- cd /tmp/boost; tar xfj /tmp/boost/boost_1_77_0.tar.bz2 2.322 CMake Error: Problem with archive_read_open_file(): Unrecognized archive format 2.322 CMake Error: Problem extracting tar: /tmp/boost/boost_1_77_0.tar.bz2 2.323 CMake Error at cmake/boost.cmake:256 (MESSAGE): 2.323 Giving up. 2.323 Call Stack (most recent call first): 2.323 CMakeLists.txt:1550 (INCLUDE) 2.323 2.323 2.323 -- WITH_BOOST /tmp/boost. 2.323 -- Failed to extract files. 2.323 Please try downloading and extracting yourself. 2.323 The url is: https://boostorg.jfrog.io/artifactory/main/release/1.77.0/source/boost_1_77_0.tar.bz2 2.323 -- Configuring incomplete, errors occurred!
- LIBEVENT版本不足:
LIBEVENT version must be at least 2.1, found No such file or directory.
- OpenSSL版本不兼容:
Not a supported openssl version in WITH_SSL=system. Make sure you have specified a supported SSL version.
希望找到可直接用于静态链接Rust应用的MySQL musl包,或正确的解决方向。
解决方案
方案1:修改MariaDB Connector-C编译配置,静态包含认证插件
你的MariaDB Connector-C编译步骤缺少静态编译认证插件的配置,默认插件是动态加载的,而Musl环境不支持动态加载。调整CMake参数,强制将插件编译进静态库:
修改cmake命令,添加以下参数:
-DPLUGIN_CACHING_SHA2_PASSWORD=STATIC \ -DPLUGIN_SHA256_PASSWORD=STATIC \ -DWITH_EMBEDDED_SERVER=OFF \
完整的cmake命令应为:
RUN CC=aarch64-unknown-linux-musl-gcc \ LDFLAGS=-L/usr/local/musl/lib \ cmake \ -DWITH_SSL=OPENSSL \ -DWITH_TLS=OPENSSL \ -DOPENSSL_ROOT_DIR=/usr/local/musl \ -DOPENSSL_USE_STATIC_LIBS=1 \ -DWITH_CURL=0 \ -DPLUGIN_CACHING_SHA2_PASSWORD=STATIC \ -DPLUGIN_SHA256_PASSWORD=STATIC \ -DWITH_EMBEDDED_SERVER=OFF \ ../mariadb-connector-c-3.3.4-src
这样会把caching_sha2_password和sha256_password插件直接编译进libmariadbclient.a静态库,无需动态加载。
方案2:使用预编译的Musl兼容MySQL客户端库
无需手动编译,可通过以下方式简化:
- 编译Rust应用时,通过环境变量指定预编译的静态库路径:
export MYSQLCLIENT_LIB_DIR=/path/to/musl-compiled-lib export MYSQLCLIENT_INCLUDE_DIR=/path/to/musl-compiled-include - 检查
messense/rust-musl-cross镜像是否内置静态编译的mysqlclient库,若没有,可基于Alpine镜像添加apk add mariadb-connector-c-static(需调整镜像适配)。
方案3:临时切换MySQL用户认证方式(应急方案)
如果只是临时测试,可将MySQL用户的认证方式改为mysql_native_password,避开动态加载插件的问题:
ALTER USER 'your_user'@'%' IDENTIFIED WITH mysql_native_password BY 'your_password'; FLUSH PRIVILEGES;
注意:该方案不推荐生产环境使用,mysql_native_password安全性低于caching_sha2_password。
解决MySQL官方库编译错误的方法(若坚持使用)
手动下载并解压Boost:
替换自动下载为手动操作,避免CMake解压失败:WORKDIR /tmp RUN curl -LO https://boostorg.jfrog.io/artifactory/main/release/1.77.0/source/boost_1_77_0.tar.bz2 RUN mkdir -p /tmp/boost && tar xjf boost_1_77_0.tar.bz2 -C /tmp/boost --strip-components=1然后cmake时指定
-DWITH_BOOST=/tmp/boost,去掉-DDOWNLOAD_BOOST=1。安装LIBEVENT依赖:
手动编译静态LIBEVENT库:WORKDIR /tmp RUN curl -LO https://github.com/libevent/libevent/releases/download/release-2.1.12-stable/libevent-2.1.12-stable.tar.gz RUN tar xzf libevent-2.1.12-stable.tar.gz WORKDIR /tmp/libevent-2.1.12-stable RUN CC=aarch64-unknown-linux-musl-gcc ./configure --prefix=/usr/local/musl --disable-shared --enable-static RUN make && make install指定兼容的OpenSSL版本:
检查镜像中OpenSSL版本,若不兼容,手动编译指定版本的静态OpenSSL库,cmake时指定-DWITH_SSL=/path/to/static-openssl而非system。
内容的提问来源于stack exchange,提问作者A. Vreeswijk

