alpine官方仓库无mysql服务端包,仅提供mysql-client;执行apk add mysql会报错,因oracle未提供musl编译版,强行兼容易崩溃;推荐用原生支持的mariadb替代,apk add mariadb即装即用,语法与mysql99%兼容。

为什么不能直接用 apk add mysql
Alpine 官方仓库里没有 mysql 服务端包,只有 mysql-client。执行 apk add mysql 会报错:ERROR: unable to select packages —— 因为这个包名在 Alpine 的 main 或 community 源中根本不存在。Oracle 官方不提供 musl 编译版的 mysql-community-server,强行桥接 glibc-compat 会导致启动时 Segmentation fault 或静默退出,不可靠。
用 mariadb 替代 mysql 是最稳的方案
MariaDB 是 Alpine 原生支持的完整服务端数据库,apk add mariadb 即装即用,无 ABI 兼容问题,SQL 语法、权限模型、复制协议与 MySQL 99% 兼容(MySQL 5.7/8.0 场景下基本无需改代码)。关键点:
-
mariadb包含mysqld二进制、systemd/init 脚本、默认配置和数据初始化逻辑 - 默认监听
127.0.0.1:3306,需显式绑定0.0.0.0才能被外部访问 - 首次启动会自动运行
mariadb-install-db初始化/var/lib/mysql - 用户密码策略、SSL 默认行为与 MySQL 一致,但可通过
my.cnf统一调整
Dockerfile 极简写法(体积
以下是最小可行 Dockerfile,基于 alpine:3.18(LTS 版本,避免 latest 不可控):
FROM alpine:3.18
RUN apk add --no-cache mariadb=10.11.11-r0 && \
mkdir -p /var/lib/mysql /run/mysqld && \
chown -R mysql:mysql /var/lib/mysql /run/mysqld
COPY my.cnf /etc/my.cnf
EXPOSE 3306
CMD ["mysqld", "--user=mysql", "--bind-address=0.0.0.0"]
注意几个实操细节:
-
mariadb=10.11.11-r0显式指定版本,防止后续apk upgrade引入不兼容变更 -
--bind-address=0.0.0.0必须加,否则容器内其他服务(如 PHP)连不上本地 MySQL -
my.cnf至少包含[mysqld]段和skip-name-resolve(避免 DNS 查询阻塞启动) - 不要挂载
/var/lib/mysql到宿主机再RUN mysqld --initialize—— 初始化必须在容器运行时做,否则权限错乱
启动时初始化 root 密码的可靠方式
Alpine 的 mariadb 不支持 MYSQL_ROOT_PASSWORD 环境变量(那是官方 MySQL 镜像的逻辑)。必须用初始化脚本或 entrypoint。推荐做法:
- 构建镜像时**不初始化数据库**,只装软件、配好目录权限
- 运行容器时通过
docker run -v $(pwd)/init.sql:/docker-entrypoint-initdb.d/init.sql挂载 SQL 初始化脚本 - entrypoint 脚本检查
/var/lib/mysql/mysql是否存在,不存在则调用mariadb-install-db+mysqld --bootstrap执行 init.sql - 避免在
CMD中硬编码密码:密码应通过-e MYSQL_ROOT_PASSWORD=xxx传入,并在 entrypoint 中用mysql -u root -e "SET PASSWORD = PASSWORD('$MYSQL_ROOT_PASSWORD')"设置
musl libc 下的信号处理和文件锁行为与 glibc 有细微差异,任何跳过初始化流程、直接拷贝 data 目录的做法都可能在重启后卡死或报 Table 'mysql.plugin' doesn't exist —— 这不是配置错误,是数据字典未正确生成。











