简介:面向需要在ARM服务器、开发板及嵌入式设备上运行MySQL的开发者与运维人员,提供一份基于Ubuntu 22.04的MySQL 5.7.44 Docker镜像编译包,专为树莓派、NVIDIA Jetson等ARM平台设计。资源整体约520MB,共5个文件,包含Dockerfile、my.cnf配置、初始化与启动脚本,以及ARM64镜像压缩包,分别用于镜像构建、参数设定、容器初始化和数据库启停,结构简洁便于按需改造。已有434人学习。借助该资源,使用者可跳过在ARM环境手动编译MySQL及其依赖的繁琐步骤,直接构建或导入镜像即可运行容器化数据库,并利用Docker的轻量特性在集群中灵活迁移扩展。镜像基于Ubuntu 22.04,具备良好的兼容性与稳定性,适合物联网应用、轻量级数据库服务及特定硬件平台验证;同时便于统一开发、测试和生产环境,降低环境差异带来的排错成本。使用时需注意仅在ARM架构环境运行,并保持镜像与系统补丁更新以防范安全风险。
1. 在 ARM 设备上跑 mysql 5.7.44:为什么编译好的 docker 镜像包更省事
mysql 5.7.44 的 ARM 版 docker 镜像包,在飞腾、鲲鹏、树莓派这类 aarch64 设备上属于“早该有人做好的东西”。我接过好几个内网项目,环境里既没有外网权限,服务器又是 ARM 架构,想跑 MySQL 5.7.44 时官方镜像仓库不一定有对应的 ARM 小版本,拉回来的镜像还可能因为 glibc、libaio 这些运行依赖对不上直接在启动时崩掉。自己从源码编译 mysql 5.7.44 又绕不开 boost、cmake、bison 三个组件的版本匹配,整套折腾下来大半天就没了。这个包做的就是把源码编译、依赖校准、初始化脚本这些前置工作全部做完,交付一个 docker load 就能导入的镜像 tar 文件,架构是纯 arm64,行为按 5.7.44 校准过。适合两类人:ARM 服务器上要尽快把 MySQL 5.7 跑起来的运维,以及在 x86 开发机上想复现 ARM 镜像构建流程的研发。
2. 镜像包到手后的第一步:导入、核对架构与容器启动
拿到这个包之后,它就是一份镜像归档 tar 文件。和从 registry 拉镜像不同,docker load 是纯本地操作,不需要网络,这一点在内网环境里非常关键。很多离线服务器连 docker hub 根本不通,有这份 tar 就能绕开所有网络问题。
2.1 用 docker load 导入镜像并确认版本
先做导入和确认,这两步走完,你就知道手上的包到底是不是目标物。
docker load -i mysql-5.7.44-arm64.tar docker images | grep mysqldocker load会把 tar 里所有镜像层写入本地 docker 存储,完成时会输出Loaded image: mysql:5.7.44-arm64这样的提示。第二行命令是为了确认镜像已经被 docker 识别,并且 tag 正确。如果你机器上之前已经存在同名镜像,docker load会用 tar 里的内容覆盖同名 tag,这一步多留意一下就好。
接着用 inspect 确认架构,这一步别省,尤其是你在 x86 机器上加载它、准备后续 push 到别的服务器时:
docker image inspect mysql:5.7.44-arm64 --format '{{.Architecture}} {{.Os}}'正常情况下会输出arm64 linux。如果输出的是amd64,说明这个包被重新打过 tag,内容已经被替换过了,不要去跑生产。
2.2 用默认配置把容器跑起来
第一次跑我不建议直接挂载自定义 my.cnf,先用镜像内置配置把链路走通,有问题也方便排查。
docker run -d --name mysql57-arm \ -p 3306:3306 \ -v /data/mysql/data:/var/lib/mysql \ mysql:5.7.44-arm64这里-p 3306:3306把容器内 MySQL 端口暴露到宿主机,-v /data/mysql/data:/var/lib/mysql把数据目录落到宿主机磁盘上。首次启动时镜像里的 entrypoint 脚本会自动执行mysqld --initialize-insecure初始化数据目录,root 用户初始状态是无密码的。
启动后看几行日志:
docker logs mysql57-arm --tail 30看到mysqld: ready for connections就说明初始化成功。然后进入容器确认版本:
docker exec -it mysql57-arm mysql -uroot -e "SELECT VERSION();"返回5.7.44并且没有报错,说明这个镜像包在你这台机器上已经能用了。注意:这一步查到的无密码 root 只是初始化脚本给的临时状态,生产环境接下来第一件事就是设密码、建普通账号、关掉 root 远程登录。
2.3 数据目录的属主问题要提前处理
上一节的docker run里,宿主机的/data/mysql/data会被 docker 自动创建,但属主是 root。镜像里的 mysqld 进程是以 mysql 用户跑的,mysql 用户在容器内的 uid 是 999,遇到宿主机目录属主不对时,写入会直接报 Permissions denied。
常见做法是在宿主机上先把目录属主改掉:
mkdir -p /data/mysql/data chown -R 999:999 /data/mysql/data999 是官方 MySQL 镜像固定给 mysql 用户的 uid,和容器内useradd -r -g mysql mysql分配出来的 uid 是一致的。如果不做这一步,mysqld 初始化数据目录时会有概率写不进去,表现就是日志里出现failed to create directory /var/lib/mysql/mysql。我第 4 章会专门把这类坑拆开讲。
到这里镜像包的基本使用已经闭环了。如果你只是为了跑起来,第 2 章就够了。但如果你想确认这个包是不是值得信任、出了奇怪问题怎么排查,或者想基于它定制自己的版本,下面第 3 章讲的是这个包到底怎么编译出来的。
3. 镜像怎么编译出来的:基础镜像、cmake 参数与多阶段 Dockerfile
这一章完整还原 ARM 版 MySQL 5.7.44 镜像的构建过程。你不一定需要自己跑一遍,但了解参数和结构之后,遇到镜像行为异常时你知道该往哪里查。整个构建思路是:在 x86 机器上模拟出 arm64 环境做“伪本地编译”,然后把编译产物拷贝进一个干净的运行镜像。
3.1 没有 ARM 真机时,用 qemu 在 x86 上准备 arm64 构建环境
如果你手里恰好有 ARM 服务器,这一节可以跳过去。但没有 ARM 真机的场景很常见,开发机是 x86,目标机是鲲鹏或者飞腾。要在 x86 上构建 arm64 镜像,最省心的方案不是交叉编译,而是注册 binfmt 之后跑 arm64 容器。
docker run --rm --privileged multiarch/qemu-user-static --reset -p yes docker run --rm --platform linux/arm64 arm64v8/ubuntu:20.04 uname -m第一行把 qemu-user-static 注册进内核的 binfmt 机制,让 x86 内核能识别并执行 aarch64 的 ELF 文件。第二行是验证:如果输出aarch64,说明 arm64 容器已经可以在 x86 机器上正常启动了。
这里要说一下为什么不用传统的 aarch64-linux-gnu-gcc 交叉编译。MySQL 的 cmake 配置过程会运行大量探测程序,这些程序被编译出来是 aarch64 的,交叉编译环境下它们会被直接执行,可宿主是 x86,探测结果拿到的是 x86 的 CPU 特性和库路径。结果就是配置期不报错,编译到一半或者 target 机上运行时报错,非常难查。qemu 方案让这些探测程序在模拟层里以 aarch64 身份运行,整个编译过程和真机趋近一致。代价是编译速度慢,我在 8 核 x86 上用 qemu 跑完整个 MySQL 源码大约花了 50 分钟,真机上大概一半时间。
3.2 构建容器里的依赖清单
进入构建容器,装依赖:
docker run --rm -it --platform linux/arm64 \ -v $(pwd):/mysql-src \ arm64v8/ubuntu:20.04 bash apt-get update apt-get install -y cmake gcc g++ make bison \ libncurses5-dev pkg-config libssl-dev \ libaio-dev zlib1g-dev wget各依赖的作用分别是:gcc/g++提供 C/C++ 编译器;bison用于生成 SQL 语法解析器,缺失时 cmake 会直接终止;libncurses5-dev提供终端库,cmake 检测不到 curses 也会中止;libssl-dev是 SSL/TLS 支持的头文件和库;libaio-dev是 Linux 异步 IO 接口,编译期和运行期都需要。注意libaio-dev只是编译期依赖,运行时镜像里还需要libaio1,这个坑在第 4 章会专门讲。
3.3 cmake 配置与编译参数解读
MySQL 5.7 的构建系统和 8.0 有差别,不少 8.0 的参数在 5.7.44 上是不认识的。下面这组是我验证过的完整配置:
cd /mysql-src/mysql-5.7.44 mkdir -p build && cd build cmake .. \ -DCMAKE_BUILD_TYPE=Release \ -DCMAKE_INSTALL_PREFIX=/usr/local/mysql \ -DMYSQL_DATADIR=/var/lib/mysql \ -DSYSCONFDIR=/etc/mysql \ -DDOWNLOAD_BOOST=1 \ -DWITH_BOOST=/mysql-src/boost \ -DWITH_SSL=system \ -DWITH_UNIT_TESTS=OFF \ -DWITH_INNODB_MEMCACHED=OFF \ -DWITHOUT_FEDERATED=1 \ -DENABLED_LOCAL_INFILE=1 \ -DWITH_EXTRA_CHARSETS=all make -j$(nproc) make install参数核心逻辑:
CMAKE_BUILD_TYPE=Release让编译器启用 O3 优化,这是生产环境必须的,Debug 版性能差很多。CMAKE_INSTALL_PREFIX=/usr/local/mysql是安装目录,后面运行镜像里拷贝的就是这个目录。MYSQL_DATADIR和SYSCONFDIR分别声明数据目录和配置文件目录,MySQL 编译期会把这些路径写进二进制,后期改动要重新编译。DOWNLOAD_BOOST=1让 cmake 自动下载与 5.7.44 匹配的 boost 版本,省去手动对版本。离线环境要先下载 boost 源码放到指定目录,再把DOWNLOAD_BOOST改成 0。WITH_SSL=system使用系统 OpenSSL。这里有个容易混淆的点:8.0 里是WITH_SSL,5.7 也是,但 5.7 还认EXTERNAL_SYSTEM_SSL旧写法。用WITH_SSL=system即可。WITH_UNIT_TESTS=OFF关掉单元测试编译,省时间。WITH_INNODB_MEMCACHED=OFF、WITHOUT_FEDERATED=1是裁剪非必要引擎,5.7 的 engine 编译选项在这版已经不像老版本那么折腾了,保守起见我只关了明显用不上的。
编译完成后,验证产物架构:
file /usr/local/mysql/bin/mysqld输出应该包含ARM aarch64。这一步能确认产物是目标架构,而不是构建环境自身的 x86 二进制。
3.4 多阶段 Dockerfile 组装运行镜像
编译产物不能直接当一个镜像用,运行时镜像需要的是最小化的运行环境。我用多阶段构建,第一阶段编译,第二阶段只拷贝产物:
FROM arm64v8/ubuntu:20.04 AS builder RUN apt-get update && apt-get install -y --no-install-recommends \ wget cmake gcc g++ make bison libncurses5-dev pkg-config \ libssl-dev libaio-dev zlib1g-dev && \ rm -rf /var/lib/apt/lists/* WORKDIR /mysql-src COPY mysql-5.7.44.tar.gz . RUN tar -xzf mysql-5.7.44.tar.gz && mkdir -p mysql-5.7.44/build WORKDIR /mysql-src/mysql-5.7.44/build RUN cmake .. \ -DCMAKE_BUILD_TYPE=Release \ -DCMAKE_INSTALL_PREFIX=/usr/local/mysql \ -DMYSQL_DATADIR=/var/lib/mysql \ -DSYSCONFDIR=/etc/mysql \ -DDOWNLOAD_BOOST=1 \ -DWITH_BOOST=/mysql-src/boost \ -DWITH_SSL=system \ -DWITH_UNIT_TESTS=OFF \ -DWITH_INNODB_MEMCACHED=OFF \ -DWITHOUT_FEDERATED=1 \ -DENABLED_LOCAL_INFILE=1 \ -DWITH_EXTRA_CHARSETS=all \ && make -j"$(nproc)" && make install FROM arm64v8/ubuntu:20.04 RUN groupadd -r mysql && useradd -r -g mysql mysql \ && mkdir -p /var/lib/mysql /var/run/mysqld /etc/mysql \ && chown -R mysql:mysql /var/lib/mysql /var/run/mysqld RUN apt-get update && apt-get install -y --no-install-recommends \ libaio1 libnuma1 libncurses5 \ && rm -rf /var/lib/apt/lists/* COPY --from=builder /usr/local/mysql /usr/local/mysql ENV PATH=/usr/local/mysql/bin:/usr/local/mysql/sbin:$PATH COPY docker-entrypoint.sh /usr/local/bin/ RUN chmod +x /usr/local/bin/docker-entrypoint.sh EXPOSE 3306 ENTRYPOINT ["docker-entrypoint.sh"] CMD ["mysqld"]第二阶段里的libaio1 libnuma1是 mysqld 运行时的动态库依赖,少了任何一个都会在启动时报 cannot open shared object file。libncurses5是 mysql client 工具的终端依赖,不加的话mysql -uroot进去会提示终端库缺失。
对应的 entrypoint 脚本:
#!/bin/bash set -e if [ ! -d "/var/lib/mysql/mysql" ]; then echo "Initializing data directory..." mysqld --initialize-insecure --user=mysql --datadir=/var/lib/mysql fi exec "$@"这个脚本的逻辑很直接:数据目录里没有 mysql 系统库就执行初始化,--initialize-insecure表示 root 初始无密码,方便首次进入容器,之后你要设密码是业务层面的事。exec "$@"把容器主命令交还给 mysqld,保证 mysqld 是 PID 1,信号能正确传递。
构建命令在 Dockerfile 同级目录执行:
docker build -t mysql:5.7.44-arm64 . docker save mysql:5.7.44-arm64 -o mysql-5.7.44-arm64.tardocker save出来的 tar 就是你要分发的镜像包。
4. 避坑与常见问题:编译和首启最容易翻车的五个点
这一章的坑,一部分是我在编译阶段踩的,一部分是拿这个镜像部署到不同客户机时反复遇到的。每一条都是现象、原因、解决三段式,你在定位问题时可以对照着看。
4.1 编译刚起步就翻车:Curses library not found
现象:cmake 配置阶段直接终止,终端输出类似Could NOT find Curses (missing: CURSES_LIBRARY)。
原因:构建容器里只装了 gcc、make、cmake,没装 ncurses 开发库。MySQL 客户端工具和部分配置脚本依赖 curses,缺失时 cmake 不给任何回旋余地。
解决:Ubuntu 20.04 里安装libncurses5-dev,装完重新跑 cmake。注意 Debian 11 和 Ubuntu 22.04 的libncurses-dev包名、版本路径都和 20.04 不同,如果换基础镜像,这句要跟着换。
4.2 交叉编译产物在目标机上跑不起来:gcc 探测脚本的坑
现象:在 x86 上用交叉编译器编译出的 mysqld,拷贝到 ARM 服务器上执行时,进程直接崩溃或者报 illegal instruction,没有任何日志。
原因:前面 3.1 说过,MySQL 的 cmake 会运行大量探测程序来检测 CPU 特性、指令集、库路径。交叉编译环境下这些 aarch64 探测程序被拿到 x86 宿主上执行,拿到的是 x86 的特性值。编译出来的代码里可能混入了与目标机不匹配的指令。
解决:放弃传统交叉编译,用 qemu-user-static 方案。执行完docker run --rm --privileged multiarch/qemu-user-static --reset -p yes之后,arm64 容器里的编译就是一套“伪本地编译”,探测程序通过模拟层运行时行为与真机一致。
4.3 mysqld 起不来:libaio.so.1 找不到
现象:容器启动后秒退,docker logs看到error while loading shared libraries: libaio.so.1: cannot open shared object file。
原因:libaio 是编译依赖,也是运行依赖。构建容器里装了libaio-dev所以编译过了,但运行镜像只拷贝了/usr/local/mysql目录,动态库是系统层的,拷贝不进去。
解决:运行阶段的基础镜像里单独装libaio1和libnuma1。这也是为什么我在 3.4 的 Dockerfile 第二阶段单独写了那行apt-get install libaio1 libnuma1,这一行当时是血泪经验换来的。
4.4 挂载自定义 my.cnf 后报 unknown variable
现象:docker run 时挂了宿主机准备好的 my.cnf,容器启动失败,日志里一连串unknown variable 'mysqlx=1'、unknown variable 'binlog_expire_logs_seconds'。
原因:很多现成的 my.cnf 模板是从 MySQL 8.0 或者 Percona 那边拷来的,参数名在 5.7.44 上根本不存在。5.7 的参数解析器遇到未知变量会直接拒绝启动,不会跳过。
解决:确认手头参数确实是 5.7 支持的。我自己习惯的做法是,不确定的参数先加loose-前缀,例如loose-binlog_expire_logs_seconds=86400。loose-前缀是 MySQL 专门为兼容多版本配置设计的,遇到不认识的参数会忽略而不是报错。但这只是过渡手段,生产环境建议还是把参数表对着 5.7 官方文档核一遍。
4.5 初始化时报 Permission denied:数据目录属主
现象:宿主机挂载了数据目录,容器首次初始化时日志报failed to create directory /var/lib/mysql/mysql,或者直接Permission denied。
原因:mysqld 以 mysql 用户运行,镜像内 mysql 用户的 uid 是 999,宿主机挂载目录属主是 root,跨容器写数据时 uid 不匹配就被拒绝。这跟 2.3 节说的是同一件事,在不需要挂载自定义配置的简单场景里,很多人会漏掉。
解决:宿主机执行chown -R 999:999 /data/mysql/data。如果你用的是别的 uid 构建的镜像,先docker exec -it <container> id mysql查 uid,再按实际值改。
5. 验证镜像包能不能用:版本、位数与性能三个命令
镜像加载、容器启动这些基本动作做完之后,我习惯再用三个维度确认这个包真的是“可信任的 ARM 版 5.7.44”,而不是启动成功就完事了。
先确认架构和产物文件:
docker image inspect mysql:5.7.44-arm64 --format '{{.Architecture}} {{.Os}}' docker cp mysql57-arm:/usr/local/mysql/bin/mysqld /tmp/mysqld file /tmp/mysqld第一条输出arm64 linux。第二条把 mysqld 从容器里拷出来,第三条在主机的file命令下确认它是ELF 64-bit LSB executable, ARM aarch64。如果生产环境是鲲鹏 920 或者飞腾 FT-2000 这一代处理器,跑一下这段能省后面很多怀疑。
然后是版本正确性的硬核验证:
docker exec -it mysql57-arm mysql -uroot -e "SELECT VERSION(), @@version_comment;"输出应该是5.7.44加(MySQL Community Server (GPL))。到这里版本、架构都确认了。
最后做一个性能摸底。MySQL 自带mysqlslap压测工具,不需要额外装 sysbench:
docker exec -it mysql57-arm mysqlslap -uroot \ --concurrency=20 --iterations=3 \ --number-int-cols=5 --number-char-cols=5 \ --auto-generate-sql --engine=innodb这个工具会自动生成压测 SQL 并返回平均耗时。耗时稳定说明编译优化生效了,可以放心切流量。如果耗时波动异常,先查innodb_buffer_pool_size和innodb_log_file_size,这俩参数对 ARM 平台的性能影响最大。
顺手给出一个适合 ARM 服务器起步的 my.cnf 参考:
[mysqld] user = mysql datadir = /var/lib/mysql socket = /var/run/mysqld/mysqld.sock pid-file = /var/run/mysqld/mysqld.pid character-set-server = utf8mb4 collation-server = utf8mb4_general_ci default-storage-engine = InnoDB innodb_buffer_pool_size = 512M innodb_log_file_size = 256M skip-name-resolve max_connections = 500utf8mb4相比 5.7 默认的utf8能完整存下四字节表情符号,现在新库直接就上 utf8mb4。bufffer_pool_size按物理内存的四分之一起步,内存少就降到 256M。
这套验证流程走完之后,我对这个镜像包的信任度才算拉满。从那以后我每次拿到 ARM 架构的 MySQL 镜像包,都会强制走一遍docker image inspect加file确认架构再启动,这个习惯帮我拦下了不止一次用错架构包的事故。镜像和配置都确认无误之后,再把它纳入自己的镜像仓库做分发,后续交付就踏实了。希望帮到你。
本文还有配套的精品资源,点击获取