Docker容器内MariaDB服务无法停止的问题求助
问题:基于Debian构建MariaDB Docker容器启动/停止失败
环境配置
Dockerfile
FROM debian:buster RUN apt-get update -y && apt-get upgrade -y && apt-get install wget mariadb-server procps -y COPY ./tools/init.sh /tmp/init.sh RUN chmod +x /tmp/init.sh EXPOSE 3306 RUN sed -i 's/^bind-address\s*=.*/bind-address=0.0.0.0/' /etc/mysql/mariadb.conf.d/50-server.cnf ENTRYPOINT [ "sh", "/tmp/init.sh" ] CMD [ "mysqld_safe" , "--verbose"]
初始化脚本 init.sh
service mysql start && service mysql stop
错误现象
容器启动后出现如下报错:
db | Starting MariaDB database server: mysqld. db | ERROR 1045 (28000): Access denied for user 'root'@'localhost' (using password: NO) db | Stopping MariaDB database server: mysqld failed! db exited with code 1
已尝试的排查动作
- 手动进入Debian容器,逐行执行Dockerfile中的指令,能正常启动、停止数据库服务
- 在Dockerfile中添加RUN指令尝试重置root密码,未解决问题:
RUN service mysql start && mysql -u root -e "ALTER USER 'root'@'localhost' IDENTIFIED BY '$MYSQL_ROOT_PASSWORD'; FLUSH PRIVILEGES;"
原因分析
- Docker构建与运行阶段的差异:RUN指令在镜像构建时执行,此时启动的mysql服务不会保留到容器运行阶段。运行阶段启动的是全新的数据库实例,未完成初始化流程。
service命令的适配问题:service mysql stop本质是调用mysqladmin连接数据库发送停止信号,但容器首次启动时,数据库刚完成启动初始化,root用户默认使用unix_socket认证方式(而非密码),mysqladmin默认尝试TCP连接,导致认证失败,无法停止服务。- 容器主进程设计问题:Docker容器应直接以数据库进程为主进程,而非通过
service命令启停管理,否则无法正确处理信号、保证容器生命周期与进程一致。
解决方案
修改初始化脚本 init.sh
将脚本改为首次启动时完成数据库初始化,直接运行数据库主进程,而非启停服务:
#!/bin/sh # 检查数据库是否已初始化(判断mysql系统库是否存在) if [ ! -d "/var/lib/mysql/mysql" ]; then # 初始化无密码的root用户 mysqld --initialize-insecure # 启动临时数据库实例,用于配置权限 mysqld_safe & # 等待数据库完全启动 until mysqladmin ping -h localhost --silent; do sleep 1 done # 配置root本地无密码访问(保持默认行为) mysql -u root -e "ALTER USER 'root'@'localhost' IDENTIFIED BY ''; FLUSH PRIVILEGES;" # 可选:允许root远程访问(根据需求开启) # mysql -u root -e "CREATE USER 'root'@'%' IDENTIFIED BY ''; GRANT ALL PRIVILEGES ON *.* TO 'root'@'%' WITH GRANT OPTION; FLUSH PRIVILEGES;" # 停止临时实例 mysqladmin -u root shutdown fi # 以exec方式启动数据库主进程,确保容器能接收信号 exec mysqld_safe --verbose
调整Dockerfile(可选优化)
可以移除CMD指令,因为初始化脚本最后已经用exec启动了主进程,或者保持原配置不影响:
FROM debian:buster RUN apt-get update -y && apt-get upgrade -y && apt-get install mariadb-server procps -y && rm -rf /var/lib/apt/lists/* COPY ./tools/init.sh /tmp/init.sh RUN chmod +x /tmp/init.sh EXPOSE 3306 RUN sed -i 's/^bind-address\s*=.*/bind-address=0.0.0.0/' /etc/mysql/mariadb.conf.d/50-server.cnf ENTRYPOINT [ "sh", "/tmp/init.sh" ]
验证方式
构建镜像后启动容器:
docker build -t my-mariadb . docker run -d -p 3306:3306 --name db my-mariadb
查看容器日志确认无报错,即可通过mysql -h localhost -u root连接数据库。
内容的提问来源于stack exchange,提问作者interesting
相关产品推荐
相关产品推荐

