Docker环境下php8.1-fpm-alpine无法连接mysql8.0服务问题求助
问题描述
如果我的提问存在表述不够准确的地方还请谅解,这是我首次在此平台提问。
我当前正在搭建Docker服务栈,遇到了PHP容器(基于php:8.1-fpm-alpine镜像)与MySQL服务端(基于mysql:8.0镜像)的连接故障。
现有配置
- PHP镜像构建所用Dockerfile:
FROM php:8.1-fpm-alpine # 安装连接MySQL所需的PHP PDO扩展 RUN docker-php-ext-install mysqli pdo pdo_mysql WORKDIR /var/www/html/web-root
- MySQL镜像构建所用Dockerfile:
FROM mysql:8.0 EXPOSE 3307
- 宿主机连接验证:通过Beekeeper-Studio使用以下参数可正常连接MySQL服务:
host: 127.0.0.1 port: 3307 user: root password: 空
- PHP测试连接代码:
<?php require_once "/logs/log.php"; $MYSQL_ADDRESS = "127.0.0.1"; // 注释标注127.0.0.1对应mysql容器IP 172.22.0.5 $MYSQL_DATABASE = "version_db"; $MYSQL_USER = "root"; $MYSQL_PASS = ""; $MYSQL_PORT = "3307"; $MYSQL_DSN = "mysql:host=${MYSQL_ADDRESS};port=${MYSQL_PORT};charset=UTF8;dbname=${MYSQL_DATABASE}"; $logger = new Log(); $logger->log("Update Databases!"); if (!in_array('pdo_mysql', get_loaded_extensions())) { $logger->log("pdo_mysql not loaded!"); exit("pdo_mysql not loaded!"); } $logger->log("MYSQL_DSN: " . $MYSQL_DSN); try { $pdo = new PDO($MYSQL_DSN, $MYSQL_USER, $MYSQL_PASS, [PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION, PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC, PDO::MYSQL_ATTR_FOUND_ROWS => TRUE]); } catch (PDOException $e) { $logger->log("No connection to database possible"); $logger->log($e); exit("No connection to database possible"); } $logger->log("connected to database");
运行测试代码后日志记录数据库连接失败,报错为连接被拒绝。
故障原因与修复方案
核心问题点
你踩了三个Docker容器互联的典型配置错误:
- 数据库地址配置错误
PHP容器内的127.0.0.1指向PHP容器自身的回环接口,既不是宿主机地址也不是MySQL容器地址。你注释里写的172.22.0.5是Docker临时分配的容器IP,容器重启后会发生变化,不能硬编码使用。 - 连接端口配置错误
MySQL Dockerfile里的EXPOSE 3307是无效配置:MySQL官方镜像内部服务默认监听3306端口,你能在宿主机通过3307端口连上,是因为启动容器时做了-p 3307:3306的端口映射,这个映射规则仅对宿主机访问容器生效。同网络下的容器之间通信,必须使用MySQL容器内部实际监听的3306端口。 - MySQL账号权限配置错误
MySQL8.0官方镜像默认root用户仅允许从容器本地localhost登录,未开放其他IP的访问权限,即使地址和端口配置正确,跨容器访问也会被权限规则拦截,同时MySQL8.0默认的caching_sha2_password认证插件也可能和旧版pdo_mysql扩展存在兼容问题。
分步修复
- 配置容器网络
不要使用默认的bridge网络,创建自定义桥接网络,两个容器启动时都加入该网络,给MySQL容器设置固定服务名,Docker内置DNS会自动把服务名解析到对应容器IP。
docker启动命令参考:
# 创建自定义网络 docker network create app-stack # 启动MySQL容器,指定服务名、所属网络、端口映射和初始化参数 docker run -d \ --name mysql \ --network app-stack \ -p 3307:3306 \ -e MYSQL_ALLOW_EMPTY_PASSWORD=yes \ -e MYSQL_DATABASE=version_db \ mysql:8.0 # 启动PHP容器,加入同一个网络 docker run -d \ --name php-fpm \ --network app-stack \ -v /local/code/path:/var/www/html/web-root \ your-custom-php-image:latest
如果使用docker-compose部署,同一compose文件下的服务默认加入同一个网络,直接用服务名做主机名即可,无需额外创建网络。
2. 修改PHP数据库连接参数
把代码里的连接配置调整为:
$MYSQL_ADDRESS = "mysql"; // 和MySQL容器的服务名/网络别名保持一致 $MYSQL_PORT = "3306"; // 填写MySQL容器内部实际监听端口
- 开放MySQL远程访问权限
进入MySQL容器,登录MySQL控制台后执行以下命令,放开root用户的远程访问限制并切换兼容的认证插件(生产环境建议单独创建业务账号并限制访问源,不要直接用root):
ALTER USER 'root'@'%' IDENTIFIED WITH mysql_native_password BY ''; FLUSH PRIVILEGES;
- 清理无效配置
删掉MySQL Dockerfile里的EXPOSE 3307行,EXPOSE只是镜像元数据标记,不会修改服务实际监听端口,保留只会产生误导。
内容的提问来源于stack exchange,提问作者cbehl
相关产品推荐
相关产品推荐

