ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

麒麟V10 ARM离线部署MySQL:依赖补齐、服务自启与踩坑排查

2026/9/19 6:43:40 拓冰建站 浏览量
麒麟V10 ARM离线部署MySQL:依赖补齐、服务自启与踩坑排查 1. 为什么麒麟V10 ARM环境下的MySQL离线部署值得单独写一篇在x86服务器上装MySQL大部分人的体验是下载rpm包yum install一把梭最多处理一下GPG key和SELinux就完事了。但一旦换到麒麟V10 SP3的ARM服务器版本整个游戏规则就变了。你会发现官网下载的通用二进制包解压之后跑不起来ldd一查一堆not found好不容易把依赖凑齐了systemctl start mysqld又给你甩一个Job for mysqld.service failed再往下查可能是libaio版本不对可能是numactl没装也可能是/var/lib/mysql的权限被SELinux拦了。这篇文章要解决的就是这一整条链路的问题。麒麟V10 ARM架构 MySQL离线部署 服务自启这四个关键词叠在一起意味着你面对的是一个没有外网、没有yum源、CPU指令集和x86完全不同、systemd行为和常见发行版有细微差异的环境。任何一个环节没考虑到都会卡住。我前后在麒麟V10 SP3的ARM服务器上部署过MySQL 8.0和5.7两个大版本踩过的坑从依赖库缺失到AppArmor策略拦截从mysql.sock路径冲突到systemd的ProtectHome参数导致服务起不来基本把能遇到的都遇了一遍。这篇文章会按照真实的排查顺序来写先讲清楚ARM环境下离线部署的特殊性再讲依赖怎么补齐然后是MySQL的安装配置接着是服务自启的完整配置最后是几个我实际踩过的坑和排查思路。适合谁看手上有一台麒麟V10 ARM服务器、需要在内网环境部署MySQL、并且希望服务能开机自启的运维或开发人员。如果你用的是x86环境这篇文章的部分内容也有参考价值但ARM相关的依赖问题可以跳过。2. 麒麟V10 ARM环境的前置认知和x86到底差在哪2.1 架构差异带来的依赖连锁反应ARM架构和x86在MySQL部署上最直接的区别体现在二进制包的指令集兼容性上。MySQL官方从8.0版本开始提供aarch64架构的通用二进制包但5.7版本在官方下载页面上ARM包的选择非常有限很多时候需要依赖麒麟系统自带的软件源或者第三方编译版本。更麻烦的是依赖库的版本匹配。x86环境下libaio、numactl、libncurses这些库的版本通常比较统一但麒麟V10 SP3的ARM版本基于特定的内核和glibc版本构建如果你从其他ARM发行版比如Ubuntu ARM拿过来的依赖包很可能因为glibc版本不匹配而无法加载。我遇到过最典型的情况是libaio.so.1在系统里存在但符号版本和MySQL二进制要求的对不上ldd显示正常一运行就报symbol lookup error。所以第一步不是急着装MySQL而是先把系统的架构信息和已安装的依赖库版本摸清楚。下面这几条命令在后续排查中会反复用到# 确认CPU架构和系统版本 uname -m cat /etc/kylin-release cat /etc/os-release # 查看glibc版本 ldd --version # 查看已安装的关键依赖 rpm -qa | grep -E libaio|numactl|ncurses|openssl注意麒麟V10 SP3的/etc/kylin-release内容格式和CentOS的/etc/redhat-release不同不要用cat /etc/redhat-release去判断版本会得到误导性的结果。2.2 离线环境的依赖获取策略离线部署的核心矛盾是MySQL需要一堆依赖但你没有外网去装。常见的解决思路有三种第一种是利用麒麟系统安装镜像作为本地源。麒麟V10的ISO镜像里包含了Packages目录里面有你需要的绝大部分基础依赖。挂载ISO之后配置一个本地yum源就能用yum install从镜像里装依赖。这是最稳妥的方式因为镜像里的包和系统版本是严格匹配的。第二种是从同版本的在网机器上导出rpm包。找一台能联网的、系统版本完全一致的麒麟V10 ARM机器用yumdownloader或者repotrack把依赖包下载下来拷贝到目标机器上用rpm -ivh安装。这种方式的关键是系统版本必须完全一致包括小版本号否则依赖关系可能对不上。第三种是手动编译依赖。这种方式最灵活但也最耗时适合前两种方式都走不通的极端情况。比如某些特定版本的libaio在麒麟的镜像里没有你就需要从源码编译。我个人的建议是优先用第一种把ISO镜像挂载到本地做源。具体操作# 挂载ISO镜像 mkdir -p /mnt/kylin-iso mount -o loop /path/to/Kylin-Server-V10-SP3-Release-ARM64.iso /mnt/kylin-iso # 配置本地yum源 cat /etc/yum.repos.d/kylin-local.repo EOF [kylin-local] nameKylin Local ISO baseurlfile:///mnt/kylin-iso enabled1 gpgcheck0 EOF # 刷新缓存 yum clean all yum makecache配好之后yum install libaio numactl这类命令就能直接从镜像里拉包不用外网。2.3 麒麟V10的安全机制对MySQL的影响麒麟V10默认启用了SELinux和kysec麒麟自己的安全模块。这两个东西在MySQL部署过程中会制造不少麻烦。SELinux会限制MySQL进程对数据目录、日志目录、socket文件的访问权限kysec则可能拦截某些二进制文件的执行。我在实际部署中遇到过MySQL初始化完成后systemctl start mysqld一直失败journalctl -u mysqld显示Permission denied但文件权限明明是mysql:mysql 755。最后发现是SELinux的上下文不对MySQL的数据目录需要mysqld_db_t类型的上下文。处理方式有两种一种是调整SELinux策略给MySQL相关的目录打上正确的上下文标签另一种是临时或永久关闭SELinux。生产环境建议用第一种测试环境可以用第二种快速验证问题。# 查看SELinux状态 getenforce # 临时关闭重启后恢复 setenforce 0 # 永久关闭需要重启 sed -i s/SELINUXenforcing/SELINUXdisabled/ /etc/selinux/config # 如果要用SELinux给MySQL目录打标签 semanage fcontext -a -t mysqld_db_t /data/mysql(/.*)? restorecon -Rv /data/mysqlkysec的处理相对简单一般通过setstatus命令查看状态必要时用setstatus disable关闭。但要注意kysec关闭后可能需要重启才能完全生效。3. MySQL离线包的选型与依赖补齐实操3.1 选哪个MySQL版本和包类型在麒麟V10 ARM环境下MySQL的包类型主要有三种选择包类型优点缺点适用场景通用二进制包tar.gz官方提供aarch64版本版本可控需要手动处理依赖和配置推荐最灵活RPM包安装简单依赖自动处理ARM版本RPM包难找版本受限有现成RPM源时可用源码编译完全适配本机环境耗时长编译依赖多前两种都走不通时我的建议是优先用通用二进制包。MySQL 8.0的官方下载页面有Linux - Generic (glibc 2.17) (ARM, 64-bit)这个选项下载下来解压就能用。5.7版本官方没有提供ARM通用包需要用麒麟系统自带的MariaDB替代或者从第三方获取编译好的二进制。下载地址方面MySQL官网的下载页面需要选择正确的版本和架构。如果你在离线环境需要提前在能联网的机器上下载好然后通过U盘或内网传输到目标服务器。提示下载时注意选择glibc 2.17版本而不是glibc 2.28版本麒麟V10 SP3的glibc版本通常在2.28以下选高了会报GLIBC_2.28 not found。3.2 依赖库的完整清单与安装顺序MySQL 8.0在ARM环境下运行需要以下核心依赖libaio异步IO库MySQL的InnoDB引擎依赖它做异步磁盘IOnumactlNUMA架构支持库ARM服务器通常有NUMA节点没有这个库MySQL会警告libncurses终端界面库mysql命令行客户端需要openssl加密库MySQL的SSL连接和密码加密依赖libtinfo终端信息库ncurses的依赖安装顺序上libaio和numactl是最关键的缺了这两个MySQL直接起不来。libncurses和libtinfo影响的是客户端工具服务端本身不依赖。openssl一般系统自带但版本不能太低。# 从本地源安装核心依赖 yum install -y libaio numactl ncurses-compat-libs openssl # 验证依赖是否满足 ldd /usr/local/mysql/bin/mysqld | grep not found如果ldd输出里有not found说明还有依赖没装。根据缺失的库名去本地源里找对应的包安装。3.3 用ldd和readelf定位依赖问题的完整流程当MySQL二进制跑不起来时ldd是第一排查工具。但ldd有时候会骗你——它显示所有依赖都找到了但运行时报symbol lookup error。这时候需要用到readelf和objdump来深入分析。完整的排查链路是这样的# 第一步ldd查看依赖是否缺失 ldd /usr/local/mysql/bin/mysqld # 第二步如果ldd显示正常但运行报错用readelf查看符号版本需求 readelf -V /usr/local/mysql/bin/mysqld | grep -i glibc # 第三步对比系统实际提供的符号版本 objdump -T /lib/aarch64-linux-gnu/libc.so.6 | grep GLIBC_2.28 # 第四步如果符号版本不匹配需要升级glibc或换MySQL版本我遇到过一次典型情况MySQL 8.0.35的二进制要求GLIBC_2.28但麒麟V10 SP3的glibc是2.28以下的版本。ldd显示所有库都找到了但一运行就报version GLIBC_2.28 not found。最后的解决方案是换用MySQL 8.0.28版本它对glibc的要求更低。注意不要轻易尝试在麒麟V10上手动升级glibc风险极高可能导致系统命令全部不可用。换MySQL版本是更安全的做法。4. MySQL安装配置的完整操作链路4.1 用户、目录与权限的初始化MySQL不建议用root用户运行需要创建一个专用的mysql用户和组。目录规划上我习惯把数据目录放在独立的数据盘上而不是默认的/var/lib/mysql这样后续扩容和备份都方便。# 创建mysql用户和组 groupadd mysql useradd -r -g mysql -s /bin/false mysql # 创建目录结构 mkdir -p /data/mysql/{data,logs,tmp,binlog} chown -R mysql:mysql /data/mysql chmod 750 /data/mysql # 解压MySQL二进制包 tar -xzf mysql-8.0.28-linux-glibc2.17-aarch64.tar.gz -C /usr/local/ mv /usr/local/mysql-8.0.28-linux-glibc2.17-aarch64 /usr/local/mysql chown -R mysql:mysql /usr/local/mysql权限设置上有个容易忽略的点/data/mysql的父目录也需要mysql用户有执行权限否则MySQL进程无法进入子目录。我遇到过/data目录权限是700 root:root导致mysql用户连/data/mysql都进不去。4.2 my.cnf的关键参数配置MySQL 8.0的配置文件我一般放在/etc/my.cnf核心参数如下[mysqld] usermysql basedir/usr/local/mysql datadir/data/mysql/data tmpdir/data/mysql/tmp socket/data/mysql/mysql.sock pid-file/data/mysql/mysqld.pid log-error/data/mysql/logs/error.log log-bin/data/mysql/binlog/mysql-bin server-id1 # InnoDB相关 innodb_buffer_pool_size2G innodb_log_file_size512M innodb_flush_log_at_trx_commit1 innodb_file_per_table1 # 字符集 character-set-serverutf8mb4 collation-serverutf8mb4_general_ci # 连接数 max_connections500 # 禁用DNS反查加速连接 skip-name-resolve [client] socket/data/mysql/mysql.sock default-character-setutf8mb4几个关键参数的解释innodb_buffer_pool_size建议设置为物理内存的50%-70%。ARM服务器的内存通常比较大但也要留够给系统和其他进程。innodb_log_file_size在MySQL 8.0里可以动态调整但初始设置大一点可以减少checkpoint频率。skip-name-resolve在离线环境特别重要因为DNS反查会超时导致连接建立很慢。加上这个参数后MySQL只接受IP地址连接不接受主机名。socket路径我改到了/data/mysql/mysql.sock而不是默认的/tmp/mysql.sock。原因是麒麟V10的/tmp目录有systemd的PrivateTmp保护MySQL服务看到的/tmp和客户端看到的/tmp可能不是同一个导致socket文件找不到。4.3 初始化数据目录与临时密码处理配置写好后用mysqld --initialize初始化数据目录# 初始化数据目录会生成临时密码 /usr/local/mysql/bin/mysqld --defaults-file/etc/my.cnf --initialize --usermysql # 查看临时密码 grep temporary password /data/mysql/logs/error.log初始化完成后先启动MySQL服务然后用临时密码登录并修改# 启动MySQL /usr/local/mysql/bin/mysqld_safe --defaults-file/etc/my.cnf # 用临时密码登录 /usr/local/mysql/bin/mysql -uroot -p -S /data/mysql/mysql.sock # 修改root密码 ALTER USER rootlocalhost IDENTIFIED BY YourNewPassword; FLUSH PRIVILEGES;注意MySQL 8.0的默认认证插件是caching_sha2_password某些老版本的客户端可能不支持。如果遇到连接问题可以把root用户的认证插件改成mysql_native_password。初始化过程中如果报错重点看error.log里的信息。常见的错误包括数据目录不为空、权限不足、libaio缺失。数据目录不为空的话清空后重新初始化即可。5. systemd服务自启配置与开机启动验证5.1 编写mysqld.service的完整配置MySQL 8.0的二进制包里自带了一个mysql.server脚本但那个是SysV风格的在麒麟V10的systemd环境下不如直接写一个service文件来得干净。下面是我实际使用的service配置[Unit] DescriptionMySQL Server Documentationman:mysqld(8) Afternetwork.target Aftersyslog.target [Install] WantedBymulti-user.target [Service] Usermysql Groupmysql Typeforking PIDFile/data/mysql/mysqld.pid TimeoutSec0 PermissionsStartOnlytrue ExecStart/usr/local/mysql/bin/mysqld --defaults-file/etc/my.cnf --daemonize ExecStop/usr/local/mysql/bin/mysqladmin -uroot -pYourPassword -S /data/mysql/mysql.sock shutdown LimitNOFILE65535 Restarton-failure RestartSec5 # 安全加固 PrivateTmptrue ProtectSystemfull ProtectHometrue NoNewPrivilegestrue几个关键点的说明Typeforking配合--daemonize参数让mysqld以守护进程方式运行systemd通过PIDFile追踪主进程。Restarton-failure确保MySQL异常退出后自动重启这对生产环境很重要。PrivateTmptrue给MySQL分配独立的/tmp避免和其他服务的临时文件冲突。但这也意味着如果你在my.cnf里把socket放在/tmp下客户端就连不上了。所以前面我把socket改到了/data/mysql/mysql.sock。ProtectHometrue会阻止MySQL访问/home、/root、/run/user这些目录。如果你的数据目录在/home下这个参数会导致启动失败。我遇到过有人把数据放在/home/mysql/data结果服务一直起不来排查了半天才发现是这个参数的问题。5.2 启动失败时的排查链路systemctl start mysqld失败时按以下顺序排查# 第一步查看服务状态和最近日志 systemctl status mysqld -l journalctl -u mysqld -n 50 --no-pager # 第二步查看MySQL自己的错误日志 tail -100 /data/mysql/logs/error.log # 第三步手动执行ExecStart命令看具体报错 sudo -u mysql /usr/local/mysql/bin/mysqld --defaults-file/etc/my.cnf --daemonize # 第四步检查SELinux是否拦截 ausearch -m avc -ts recent我遇到过的几个典型失败场景场景一Permission denied但文件权限正常。原因是SELinux上下文不对。用ls -Z查看目录的SELinux标签如果显示unconfined_u:object_r:default_t而不是mysqld_db_t就需要用semanage和restorecon修复。场景二Address already in use。说明3306端口被占用可能是之前手动启动的mysqld没关干净。用ss -tlnp | grep 3306找到进程并kill掉。场景三Failed to create PID file。PID文件路径的目录不存在或者mysql用户没有写权限。检查/data/mysql目录的权限和属主。场景四服务启动后立即退出日志显示unknown variable。my.cnf里有MySQL不认识的参数可能是从其他版本复制过来的配置。逐个注释掉可疑参数排查。5.3 开机自启的验证与常见陷阱配置好service文件后执行# 重载systemd配置 systemctl daemon-reload # 设置开机自启 systemctl enable mysqld # 启动服务 systemctl start mysqld # 验证状态 systemctl status mysqld验证开机自启是否真正生效最可靠的方式是重启服务器然后看MySQL是否自动起来了。不要只看systemctl is-enabled mysqld的输出那个只表示enable了不代表启动一定能成功。我踩过的一个坑systemctl enable mysqld显示成功但重启后MySQL没起来。查journalctl -b发现是network.target还没就绪时MySQL就尝试启动了而MySQL配置里绑定了特定IP网络没起来导致绑定失败。解决方案是把Afternetwork.target改成Afternetwork-online.target并加上Wantsnetwork-online.target。另一个坑是**TimeoutSec0**。这个参数表示systemd不限制MySQL的启动超时时间。如果不设这个默认90秒超时对于数据量大的实例InnoDB恢复可能需要更长时间systemd会误判为启动失败并kill掉进程。6. 那些让我加班到凌晨的坑与排查思路6.1 libaio版本不匹配导致的symbol lookup error这个坑我印象最深。系统里rpm -qa | grep libaio显示libaio-0.3.112-1已经装了ldd也显示libaio.so.1 /lib/aarch64-linux-gnu/libaio.so.1但MySQL启动时报/usr/local/mysql/bin/mysqld: symbol lookup error: /usr/local/mysql/bin/mysqld: undefined symbol: io_setupio_setup是libaio的核心函数符号找不到说明系统里的libaio版本太老或者编译选项不对。解决方案是从麒麟的ISO镜像里找到更新的libaio包或者从源码编译一个。# 从源码编译libaio tar -xzf libaio-0.3.113.tar.gz cd libaio-0.3.113 make make install # 编译出的库在/usr/lib/aarch64-linux-gnu/下编译完成后用ldconfig刷新库缓存再ldd确认MySQL链接到了新版本的libaio。6.2 mysql.sock路径冲突引发的客户端连接失败这个问题的表现是MySQL服务正常运行systemctl status mysqld显示active但用mysql -uroot -p连接时报ERROR 2002 (HY000): Cant connect to local MySQL server through socket /tmp/mysql.sock (2)原因是客户端默认去/tmp/mysql.sock找socket文件但服务端的socket在/data/mysql/mysql.sock。解决方案有两种一是在/etc/my.cnf的[client]段里指定socket路径二是创建一个软链接。# 方案一在my.cnf的[client]段添加 [client] socket/data/mysql/mysql.sock # 方案二创建软链接 ln -s /data/mysql/mysql.sock /tmp/mysql.sock我推荐方案一因为软链接在系统重启后可能丢失/tmp目录可能被清理。6.3 systemd的ProtectHome参数导致数据目录不可访问前面提到过这个坑这里展开说一下。ProtectHometrue是systemd的安全加固选项它会用mount --bind把/home、/root、/run/user挂载成空目录或者只读。如果MySQL的数据目录在/home下MySQL进程就看不到这个目录启动直接失败。排查方法# 查看服务的实际挂载命名空间 systemctl show mysqld | grep ProtectHome # 临时覆盖这个参数进行测试 systemctl edit mysqld # 在编辑器中添加 # [Service] # ProtectHomefalse如果确认是这个参数的问题要么把数据目录移到/home外面要么在service文件里把ProtectHome设为false。生产环境建议前者保持安全加固的同时把数据放在标准位置。6.4 离线环境下时间同步对MySQL的影响这个问题比较隐蔽。麒麟V10 ARM服务器如果没配NTP系统时间可能和实际时间偏差很大。MySQL的TIMESTAMP类型和binlog都依赖系统时间时间不对会导致数据写入异常和主从同步问题。离线环境下没有外网NTP服务器解决方案是在内网找一台机器做NTP服务端其他机器指向它。或者至少确保服务器BIOS时间准确并在系统启动时用hwclock同步。# 查看系统时间和硬件时间 date hwclock --show # 从硬件时钟同步到系统 hwclock --hctosys # 配置内网NTP如果有内网NTP服务器 timedatectl set-ntp true7. 部署完成后的验证清单与日常维护建议7.1 服务健康状态的快速检查项部署完成后用以下清单快速验证MySQL是否处于健康状态# 1. 服务状态 systemctl status mysqld # 2. 端口监听 ss -tlnp | grep 3306 # 3. 进程存在 ps aux | grep mysqld # 4. 连接测试 mysql -uroot -p -e SELECT VERSION(); # 5. 数据目录权限 ls -la /data/mysql/data | head -20 # 6. 错误日志无异常 tail -50 /data/mysql/logs/error.log # 7. 开机自启已启用 systemctl is-enabled mysqld这七项都通过基本可以认为部署是成功的。其中第4项连接测试建议用-S指定socket路径避免受客户端默认配置影响。7.2 日志轮转与磁盘空间监控MySQL的error log和binlog会持续增长离线环境下磁盘空间通常比较紧张需要配置日志轮转。error log的轮转可以用logrotatecat /etc/logrotate.d/mysql EOF /data/mysql/logs/error.log { daily rotate 30 missingok compress delaycompress notifempty create 640 mysql mysql postrotate /usr/local/mysql/bin/mysqladmin -uroot -pYourPassword -S /data/mysql/mysql.sock flush-logs endscript } EOFbinlog的清理可以用MySQL自己的PURGE BINARY LOGS命令或者设置expire_logs_days参数自动清理。MySQL 8.0推荐用binlog_expire_logs_seconds参数单位是秒。-- 手动清理7天前的binlog PURGE BINARY LOGS BEFORE DATE_SUB(NOW(), INTERVAL 7 DAY); -- 或者设置自动清理 SET GLOBAL binlog_expire_logs_seconds 604800;7.3 备份策略在离线环境下的调整离线环境下没有云备份服务备份只能落在本地磁盘或内网存储上。我建议至少保留一份逻辑备份mysqldump和一份物理备份xtrabackup或直接拷贝数据目录。逻辑备份的脚本示例#!/bin/bash BACKUP_DIR/data/backup/mysql DATE$(date %Y%m%d) mkdir -p $BACKUP_DIR/$DATE /usr/local/mysql/bin/mysqldump -uroot -pYourPassword \ --single-transaction \ --routines \ --triggers \ --events \ --all-databases \ -S /data/mysql/mysql.sock | gzip $BACKUP_DIR/$DATE/all-databases.sql.gz # 删除30天前的备份 find $BACKUP_DIR -type d -mtime 30 -exec rm -rf {} \;--single-transaction参数对InnoDB表做一致性快照不会锁表。--routines和--triggers确保存储过程和触发器也被备份。物理备份在ARM环境下要注意xtrabackup的ARM版本需要单独获取不是所有版本都有ARM编译。如果没有xtrabackup可以在停库的情况下直接tar数据目录但生产环境不建议频繁停库。7.4 版本升级时的注意事项麒麟V10 ARM环境下升级MySQL最大的风险是新版本的二进制可能依赖更高版本的glibc。升级前务必用readelf -V检查新版本二进制的符号需求和当前系统的glibc版本对比。升级步骤建议备份当前数据目录和配置文件停止MySQL服务替换二进制文件保留旧版本目录以便回滚启动MySQL观察error log是否有升级相关的错误执行mysql_upgradeMySQL 8.0.16之后不需要启动时自动完成验证业务连接和数据完整性如果升级后发现glibc不兼容回滚到旧版本二进制即可数据目录通常不需要回滚除非升级过程中做了不兼容的数据字典变更。8. 写在最后几个让我少走弯路的习惯在麒麟V10 ARM环境折腾MySQL的这段时间我养成了几个习惯分享出来可能对你有用。第一个习惯是每次操作前先记录当前状态。比如装MySQL之前先rpm -qa /tmp/packages-before.txt装完之后再导出一份用diff对比就能清楚知道装了哪些包、有没有引入冲突。这个习惯帮我定位过好几次依赖冲突问题。第二个习惯是所有配置文件改动前先备份。cp /etc/my.cnf /etc/my.cnf.bak.$(date %Y%m%d)一行命令的事但能省掉很多后悔。我有一次改my.cnf时手误删了一行导致MySQL起不来幸好有备份两分钟就恢复了。第三个习惯是用systemd-analyze分析启动耗时。systemd-analyze blame | grep mysql可以看到MySQL服务在启动过程中花了多少时间如果异常长说明某个环节有问题比如InnoDB恢复、DNS反查超时等。第四个习惯是保留一份最小可用的配置。我维护了一个my.cnf.minimal只包含最核心的参数当生产配置出问题时用最小配置启动确认是配置问题还是环境问题能快速缩小排查范围。这些习惯看起来不起眼但在离线环境里每一次排查的成本都比在线环境高得多能快速定位问题就是最大的效率提升。