最近在 ARM64 架构的机器上部署一套老业务系统指定 CentOS 7数据库锁定 MySQL 5.7。说实话这套组合今天看来有点复古CentOS 7 官方维护已进入收尾状态MySQL 5.7 也早已不是社区主推版本ARM64 生态又不像 x86_64 那样“闭眼装”就行。三个条件叠在一起网上教程要么年代久远要么抄来抄去全是 x86_64 的坑真正针对 ARM64 的完整实操记录少之又少。我把整个安装流程完整走了一遍从系统镜像、yum 源修复、依赖包安装到 MySQL 5.7 的 tarball 解压、数据目录初始化、systemd 托管、远程授权和常见问题排查基本把所有能踩的坑都踩了一遍。这篇文章就是一份可以直接抄作业的完整记录适合需要在 ARM64 服务器或开发板上部署 CentOS 7 MySQL 5.7 的运维、开发同学参考。1. 为什么要在 ARM64 上折腾 CentOS 7 MySQL 5.7方案选型与整体思路1.1 为什么不直接用 yum 装 MySQL 5.7很多人习惯一上来就执行 yum install mysql-community-server但在 CentOS 7 上这条路并不好走。CentOS 7 自带仓库里的数据库默认是 MariaDB而且版本停留在 5.5 左右和 MySQL 5.7 在功能、参数、数据字典上都差别很大直接顶替不现实。想用官方 MySQL 5.7第一反应是配置 MySQL 官方 Yum 仓库。问题来了MySQL 官方 Yum 仓库对 ARM64 的支持并没有想象中完整至少在 5.7 系列的 el7 包上aarch64 的 rpm 经常找不到或者安装时出现依赖冲突。我试过在 aarch64 机器上装 mysql-community-release-el7然后 yum install mysql-community-server结果提示 no package available折腾一圈还是没装上。所以在这类架构上优先考虑通用二进制分发包Generic Tarball方式也就是直接从官方下载编译好的独立包。它不依赖系统包管理器的版本索引只要 glibc 版本满足要求就能直接跑起来。CentOS 7 的 glibc 是 2.17官方 MySQL 5.7 二进制包要求 glibc 2.12 以上条件满足所以这条路是通的。1.2 为什么优先考虑 Tarball 而不是 DockerARM64 下 Docker 跑 MySQL 5.7 确实很方便官方镜像也有 arm64v8 变体。但考虑到很多老业务对裸机部署、目录规划、内核参数调优有硬性要求加上部分 ARM 服务器或开发板本身内存紧张跑容器还要额外承担镜像层、存储驱动和容器网络的开销。直接在宿主机上部署一方面资源占用更低另一方面排查问题也更直接——日志就在 /var/log/mysql 下socket 文件就在指定目录里不用进容器看。Tarball 安装的缺点是它不自带 systemd 服务文件也不一定自动创建 mysql 用户所有初始化、权限、启动脚本都得自己弄。但也正因为如此整个过程是透明的每一步做了什么我都清楚出了问题能顺着日志追到底。对于生产环境来说可控性反而更高。1.3 这次安装的整体流程整体分为五个阶段准备系统环境安装 ARM64 版 CentOS 7修复 yum 源装齐依赖包。获取安装包下载 MySQL 5.7 官方 aarch64 二进制包做完整性校验。部署目录与配置解压到指定路径创建 mysql 用户编写 my.cnf。初始化与启动用 mysqld --initialize 初始化数据目录用 systemd 管理服务。收尾与验证修改 root 密码、创建业务账号、配置防火墙和开机自启。下文按这个顺序展开期间会把涉及到的关键参数和踩坑点逐一说明。2. 环境准备ARM64 版 CentOS 7 的系统与依赖处理2.1 镜像下载和系统安装要点ARM64 版的 CentOS 7 在官方镜像站里有专门的 altarch 分支文件名一般类似 CentOS-7-aarch64-Minimal-2009.iso。如果没有现成机器装机时建议单独划分一个数据分区比如把剩余磁盘全部挂到 /data 目录后续 MySQL 数据目录就放在这里。数据目录单独分区的价值在于系统盘故障或重装时数据文件还在独立分区里也方便用 LVM 做快照和扩容。内存方面如果机器内存不到 2GB强烈建议提前分配 swap。MySQL 启动和 InnoDB 缓冲池初始化对内存比较敏感ARM 开发板上内存经常吃紧swap 可以避免因内存不足被 OOM Killer 误杀。可以用 dd 命令创建 swapfile也可以安装时规划 swap 分区这一步别省。2.2 yum 源失效后的补救CentOS 7 进入维护尾声后默认的 mirrorlist 地址经常连不上yum 装包时会报 “Cannot find a valid baseurl for repo”。ARM64 平台同样会遇到这个问题。处理方式是把仓库源切换到 vault 归档地址mv /etc/yum.repos.d/CentOS-Base.repo /etc/yum.repos.d/CentOS-Base.repo.bak cat /etc/yum.repos.d/CentOS-Base.repo EOF [base] nameCentOS-$releasever - Base baseurlhttps://vault.centos.org/7.9.2009/os/$basearch/ gpgcheck1 enabled1 [updates] nameCentOS-$releasever - Updates baseurlhttps://vault.centos.org/7.9.2009/updates/$basearch/ gpgcheck1 enabled1 [extras] nameCentOS-$releasever - Extras baseurlhttps://vault.centos.org/7.9.2009/extras/$basearch/ gpgcheck1 enabled1 EOF$basearch 在 ARM64 环境下会自动解析为 aarch64所以这套配置可以直接用。如果你还需要 epel 源也建议从镜像站下载 aarch64 版本的 epel-release rpm 安装避免默认源失效。修好 yum 之后先执行 yum clean all yum makecache 验证源是否可用再继续后续操作。这里花五分钟排查源比装到一半再发现依赖装不上要省心得多。2.3 补齐 MySQL 5.7 前置依赖MySQL 5.7 的通用二进制包在启动时会动态加载一些系统库最常见的有三个libaio.so.1异步 IO 库MySQL 的 InnoDB 引擎在启动时会强制加载。libnuma.so.1NUMA 内存管理库mysqld 在多路 CPU 环境下会用到。libncurses.so.5 / libtinfo.so.5终端相关库某些工具和初始化脚本依赖。CentOS 7 自带 ncurses-libs 的版本通常能满足要求但 libaio 和 numactl-libs 有可能是缺失的。如果系统里没有安装启动时会直接报 “error while loading shared libraries”根本起不来。在 ARM64 系统上先统一装好yum install -y libaio numactl-libs ncurses-libs另外建议把 perl 也装上。虽然 5.7 官方推荐用 mysqld --initialize 初始化但后续一些工具脚本和性能分析脚本会调用 perl提前装好不亏yum install -y perl依赖装完后可以用 ldconfig -p | grep libaio 确认库文件已经存在再做下一步。3. 核心安装过程Tarball 方式部署 MySQL 5.73.1 下载并校验 ARM64 版本安装包MySQL 官方提供的 5.7 系列通用包glibc 2.12 版本的 aarch64 包文件名一般是mysql-5.7.44-linux-glibc2.12-aarch64.tar.gz这里强调一点不要下成 x86_64 包。个别国内镜像站文件名不够规范或者下载链接跳转后拿到了错误架构解压后一启动就会报 Exec format error。下载后一定先确认架构wget https://dev.mysql.com/get/Downloads/MySQL-5.7/mysql-5.7.44-linux-glibc2.12-aarch64.tar.gz如果官网下载慢可以选国内镜像源但下载完务必做 sha256 校验。官网每个文件都提供对应的 .sha256 校验文件比如sha256sum mysql-5.7.44-linux-glibc2.12-aarch64.tar.gz把算出来的值和控制台给出的值对比一致再继续。这一步看似多余但在公共网络环境下下载二进制包不做完整性校验就不是一个合格的运维习惯。3.2 目录规划与 mysql 用户创建我习惯把软件和数据分开存放/usr/local/mysqlMySQL 程序主目录/data/mysql数据目录/var/log/mysql日志目录先解压安装包到 /usr/localtar -xzf mysql-5.7.44-linux-glibc2.12-aarch64.tar.gz -C /usr/local cd /usr/local ln -s mysql-5.7.44-linux-glibc2.12-aarch64 mysql然后创建 mysql 系统用户。这个用户不需要登录 shell也不要分配 home 目录只用来跑 mysqld 进程groupadd mysql useradd -r -g mysql -s /bin/false mysql创建数据目录和日志目录并设置属主mkdir -p /data/mysql /var/log/mysql chown -R mysql:mysql /data/mysql /var/log/mysql这里有个很小的细节/data/mysql 如果是一个独立分区格式化后通常会自动生成 lostfound 目录。初始化时 MySQL 要求数据目录为空这个 lostfound 就会导致初始化失败。建议在初始化前把这个目录删掉rm -rf /data/mysql/lostfound这个坑非常经典专门写出来提醒一下。3.3 编写一份足够生产使用的 my.cnfMySQL 5.7 的参数比较多但初次部署不需要追求极致调优先把“能稳定跑起来、字符集正确、日志可查”这几个基础目标实现。下面是一份我在 ARM64 机器上验证过的配置可以直接复制[client] port 3306 socket /data/mysql/mysql.sock default-character-set utf8mb4 [mysqld] basedir /usr/local/mysql datadir /data/mysql socket /data/mysql/mysql.sock pid-file /data/mysql/mysql.pid log-error /var/log/mysql/mysql-error.log port 3306 character-set-server utf8mb4 collation-server utf8mb4_general_ci skip-external-locking max_connections 500 max_connect_errors 100000 innodb_buffer_pool_size 4G innodb_log_file_size 512M innodb_flush_log_at_trx_commit 1 innodb_file_per_table 1 slow_query_log 1 slow_query_log_file /var/log/mysql/mysql-slow.log long_query_time 2 # 如果不想用 systemd 管理用户可以打开下面的 user 配置 # user mysql sql_mode NO_ENGINE_SUBSTITUTION,STRICT_TRANS_TABLES说说几个关键参数basedir 和 datadir 必须和实际路径完全一致尤其是软链接场景下basedir 写了 /usr/local/mysql 之后mysqld 会通过它定位 share、bin 等子目录。socket 路径放在 /data/mysql 下可以有效避开 /tmp 目录被清理导致客户端连接失败的问题在 CentOS 7 的 tmpwatch 场景下很实用。character-set-server 和 collation-server 明确指定 utf8mb4避免数据库默认字符集跟着系统 locale 走导致中文乱码。innodb_buffer_pool_size 设置为物理内存的 50%~70% 比较合理。如果内存只有 4GB建议改成 1G 到 2G别照抄。sql_mode 里的 STRICT_TRANS_TABLES 建议保留避免写入超长字段时静默截断。3.4 初始化数据目录与临时密码处理MySQL 5.7 开始官方不再推荐 mysql_install_db 脚本而是用 mysqld --initialize 完成初始化。这个命令会在数据目录下生成系统库和初始数据同时生成 root 临时密码。执行前确保 my.cnf 已经放到 /etc/my.cnf或者启动时显式指定 --defaults-file 参数。我习惯显式指定避免从其他路径加载到不期望的配置/usr/local/mysql/bin/mysqld --defaults-file/etc/my.cnf --initialize --usermysql执行过程通常几十秒到几分钟不等取决于磁盘速度和系统负载。执行完后查看日志文件重点是 root 的临时密码grep temporary password /var/log/mysql/mysql-error.log日志里会有一行类似[Note] A temporary password is generated for rootlocalhost: xxxxxx如果你更希望在初始化时设置一个空密码方便首次登录控制可以改用 --initialize-insecure但生产环境不建议这样干。本质上就是一个密码强度问题临时密码麻烦一点但安全收益是值得的。如果初始化时报错先不要急着重复执行把日志完整读一遍。最常见的有这几类缺动态库比如 libaio.so.1 not found说明前置依赖没装。数据目录不是空目录比如 lostfound 存在清掉再初始化。权限问题确保执行命令的用户对 basedir、datadir、log-error 目录有读写权限。3.5 用 systemd 管理 mysqld 服务Tarball 包没有自带 init 脚本所以需要手工创建一个 systemd unit 文件路径为 /etc/systemd/system/mysqld.service[Unit] DescriptionMySQL 5.7 Database Server Documentationman:mysqld(8) Afternetwork.target [Service] Typesimple Usermysql Groupmysql ExecStart/usr/local/mysql/bin/mysqld --defaults-file/etc/my.cnf ExecReload/bin/kill -HUP $MAINPID Restarton-failure LimitNOFILE65535 [Install] WantedBymulti-user.target这里有几个容易踩的细节Type 用了 simple因为直接执行 mysqld 并不会 daemonize如果用了 mysqld_safe则需要考虑 Typeforking 和 PIDFile 的配合。建议直接用 mysqld依赖 systemd 管理。User 和 Group 指定为 mysqlmy.cnf 里的 user 参数就不要再写避免出现以 mysql 用户切换时的权限冲突。LimitNOFILE 务必调大。MySQL 在高并发连接下会打开大量文件描述符系统默认的 1024 根本不够用。写完后执行systemctl daemon-reload systemctl start mysqld systemctl status mysqld看到 active (running) 后先用 mysqladmin ping 验证连通性/usr/local/mysql/bin/mysqladmin --socket/data/mysql/mysql.sock -uroot -p ping输入临时密码后如果能得到 mysqld is alive说明服务已经正常起来了。4. 配置收尾修改密码、授权远程访问与开机自启4.1 首次登录与 root 密码修改服务起来后先用 root 临时密码登录mysql -uroot -p --socket/data/mysql/mysql.sock如果临时密码里包含特殊字符比如括号、感叹号建议直接复制日志里整段密码避免手工输入转义出错。登录后第一件事就是修改 root 密码。MySQL 5.7 默认启用 validate_password 插件对密码强度有要求至少需要包含大小写字母、数字和特殊符号长度一般不少于 8 位ALTER USER rootlocalhost IDENTIFIED BY NewPassw0rd!;如果公司内部密码策略对长度和复杂度有特殊要求可以先临时调低校验等级修改完再恢复SET GLOBAL validate_password_policyLOW; SET GLOBAL validate_password_length6; ALTER USER rootlocalhost IDENTIFIED BY 123456; SET GLOBAL validate_password_policyMEDIUM; SET GLOBAL validate_password_length8;改完密码后建议再创建一个只用于日常运维的账号比如 admin避免所有操作都拿 root 来跑。root 账号日常保持禁用远程登录是一个好习惯。4.2 创建业务账号与最小权限授权业务账号建议使用网段限制而不是直接用 % 通配所有来源。比如只允许内网 10.0.0.0/24 网段访问CREATE USER app10.0.0.% IDENTIFIED BY AppPassw0rd!; GRANT SELECT, INSERT, UPDATE, DELETE ON yourdb.* TO app10.0.0.%; FLUSH PRIVILEGES;授权原则是最小权限只给业务实际需要的增删改查权限不要图省事直接 GRANT ALL。尤其不要把 PROCESS、SUPER、FILE 这类管理权限授给业务账号否则一旦业务代码被注入攻击者能拿到远超预期的数据库控制权。如果需要从外部工具远程连接记得确认 root 或 admin 账号只允许 localhost 登录并设置合理的 bind-address。如果需要绑定所有网卡my.cnf 里可以设置 bind-address 0.0.0.0但要注意防火墙务必放行这是安全隐患的底线。4.3 防火墙放行与 SELinux 配置CentOS 7 默认使用 firewalld如果远程客户端连不上 MySQL先检查防火墙firewall-cmd --zonepublic --add-port3306/tcp --permanent firewall-cmd --reload另外还有一个容易忽略的坑是 SELinux。手工解压到 /data 的 MySQL 数据文件SELinux 文件上下文可能没有被正确标记mysqld 读取数据目录时会被拒绝日志里出现 Permission denied。处理办法有两个生产环境如果确实没有严格安全合规要求可以临时 setenforce 0再改配置文件永久关闭。如果不想关闭 SELinux需要给数据目录设置正确的上下文yum install -y policycoreutils-python semanage fcontext -a -t mysqld_db_t /data/mysql(/.*)? restorecon -Rv /data/mysql我个人的倾向是在风险可控的内网环境里把 SELinux 暂时改为 permissive 或直接在 /etc/selinux/config 中关闭减少后续升级、扩容时不必要的文件上下文问题。但这是权衡后的选择不是通用建议。4.4 设置开机自启与常用命令软链配置好服务后执行systemctl enable mysqld顺便把常用的 MySQL 客户端工具软链到 /usr/local/bin 或 /usr/bin方便后续执行 mysql、mysqldump 等命令时不用带全路径ln -s /usr/local/mysql/bin/mysql /usr/local/bin/mysql ln -s /usr/local/mysql/bin/mysqldump /usr/local/bin/mysqldump ln -s /usr/local/mysql/bin/mysqladmin /usr/local/bin/mysqladmin做完这一步重新登录一个终端直接 mysql -uroot -p 就能连接日常操作会顺手很多。5. 常见问题与避坑记录ARM64 平台最容易翻车的地方5.1 初始化阶段常见报错与处理初始化阶段报错是最多的我把典型问题汇总成一个表方便对照排查报错信息原因解决办法mysqld: error while loading shared libraries: libaio.so.1缺少 libaio 动态库yum install -y libaioerror while loading shared libraries: libnuma.so.1缺少 NUMA 库yum install -y numactl-libs[ERROR] --initialize specified but the data directory has existing files数据目录不为空清空或改用新的数据目录[ERROR] Cant create/write to file /data/mysql/mysql.pid数据目录权限不对确保 mysql 用户对 /data/mysql 有写权限[ERROR] InnoDB: Operating system error number 13 in a file operation文件权限或 SELinux 拦截chown 或 restorecon 数据目录[ERROR] unknown variable ...my.cnf 参数名写错或版本不支持根据 5.7 文档核对参数名有一个特别容易犯的低级错误看到日志里的临时密码后手快直接复制带空格或换行的内容导致登录失败。建议用 grep awk 提取纯密码再保存或者直接鼠标选中日志行复制。5.2 启动阶段常见报错与处理启动阶段出现 Exec format error几乎可以肯定是下载了错误的架构包——x86_64 的 MySQL 二进制在 ARM64 系统上无法执行系统提示“cannot execute binary file”。解决方法是重新下载 aarch64 版本。服务启动后马上退出大概率是日志和数据目录权限问题。先看状态systemctl status mysqld -l journalctl -u mysqld --no-pager | tail -50再配合 /var/log/mysql/mysql-error.log 最后 30 行判断具体原因。如果错误日志里出现 “Permission denied”优先检查 SELinux 和目录属主其次再考虑磁盘空间是否耗尽。很多 ARM 设备磁盘空间本身不大数据分区写满后 MySQL 会直接挂掉日志里不一定有明显的“disk full”字样但错误日志会突然停止写入。5.3 ARM64 平台特有的注意事项有些问题在 x86_64 平台上根本不存在但在 ARM64 下需要特别留意二进制包架构这是最典型的问题。下载前确认系统架构是 aarch64不是 armv7l更不是 x86_64。可以用 uname -m 确认。glibc 兼容性官方 5.7 的 aarch64 包要求 glibc 2.12 以上CentOS 7 的 glibc 2.17 满足要求。但如果你在更精简的定制系统上部署建议先检查 glibc 版本避免出现 version GLIBC_2.14 not found 之类的报错。ARM 设备内存偏小很多 ARM 开发板内存只有 1GB~2GBinnodb_buffer_pool_size 如果配置过大启动时内存直接被打满触发 OOM。建议初期把缓冲池调到 256M~512M观察运行平稳后再逐步扩大。性能调优不要只看 CPU 核数ARM 多核环境下InnoDB 线程参数设置不当会导致上下文切换严重。如果机器核心数较多可以用 innodb_buffer_pool_instances 把缓冲池拆分成多个实例减少并发访问时的锁竞争。5.4 忘记 root 密码的应急处理MySQL 5.7 忘记 root 密码或者临时密码过期这是最常被问到的问题。在 my.cnf 的 [mysqld] 段临时加一行 skip-grant-tables重启服务获得无密码登录能力systemctl restart mysqld mysql -uroot --socket/data/mysql/mysql.sock进入后先刷新授权表再修改密码FLUSH PRIVILEGES; ALTER USER rootlocalhost IDENTIFIED BY NewPassw0rd!;然后在 my.cnf 里删掉 skip-grant-tables重启服务恢复正常验证。这里强调一下skip-grant-tables 状态下任何人都可以无密码访问数据库绝对不能长期开着处理完立刻删除。写在最后的一点体会这套组合在 ARM64 上部署整体难度并不高真正考验人的是对架构差异的敏感度和对错误日志的耐心。我一开始也抱着“yum 一把梭”的想法结果在官方源上浪费了不少时间。后来回归到 tarball 安装把所有环节拆开每一步出了问题都能立刻定位反而顺利很多。如果这台机器后续要承载真实业务建议再做两件事一是把慢查询日志和错误日志接入统一的日志采集别等磁盘被日志占满才发现问题二是针对 innodb_buffer_pool_size、max_connections 等核心参数做压测不要一直沿用初始化配置。MySQL 5.7 本身处于成熟稳定期调优空间是有的但不能脱离业务空谈参数。最后再分享一个小技巧在 ARM64 机器上安装这类带有大量动态依赖的软件时装完一个包就用 ldconfig -p 检查对应库文件是否存在比到最后一起排查要高效得多。高效率的运维从来都是把问题扼杀在更早的阶段。