1. 概述

Docker 是一个用于开发、分发和运行容器化应用的平台。Docker 技术栈包括独立的容器、Docker Compose 等多种技术。

MySQL 是一个开源的关系型数据库管理系统。

在 Docker Compose 环境中无法访问 MySQL 容器可能由多种原因造成,理解 MySQL 客户端如何选择连接方式是解决问题的关键

本文将介绍常见的连接问题及排查方法。在开始前,请确保已在 Linux 系统上安装了 Docker 和 Docker Compose。


2. MySQL 客户端如何选择连接方式

MySQL 客户端程序(如 mysql 命令行工具)可以通过 TCP/IP 或 Unix 套接字文件协议连接到运行在 Docker 中的 MySQL 服务。在 Linux 上,本地连接默认使用 Unix 套接字文件(/var/run/mysqld/mysqld.sock),而远程连接则必须使用 TCP/IP。

2.1. 本地与远程连接的区别

  • 本地连接:不指定 --host 或使用 localhost 时,默认尝试使用 Unix 套接字连接。
  • 远程连接:必须使用 IP 地址(如 127.0.0.1)并指定 --protocol=TCP

2.2. 连接协议的选择机制

MySQL 客户端通过 --host--protocol 参数决定使用哪种协议。若未显式指定,则根据操作系统和连接目标(本地或远程)自动选择。

2.3. 使用 TCP/IP 协议连接

以下命令均可使用 TCP/IP 连接本地 MySQL:

$ mysql -u root --protocol=TCP
$ mysql -u root --host=127.0.0.1
$ mysql -u root --host=127.0.0.1 --protocol=TCP
$ mysql -u root --host=localhost --protocol=TCP

注意:使用 127.0.0.1 而非 localhost 会强制使用 TCP/IP。

2.4. 使用 Unix 套接字文件协议连接

以下命令使用 Unix 套接字文件协议:

$ mysql -u root
$ mysql -u root --host=localhost
$ mysql -u root --protocol=SOCKET
$ mysql -u root --host=localhost --protocol=SOCKET

注意localhost 会被解释为 Unix 套接字连接,而不是 TCP/IP。


3. 常见问题与排查方法

3.1. Docker 容器并非“本地”主机

误区:认为本地运行的 MySQL 容器就是“本地主机”,其实它是独立的虚拟环境,需通过 TCP/IP 连接。

示例:获取容器 IP 地址并连接:

$ docker inspect -f '{{range.NetworkSettings.Networks}}{{.IPAddress}}{{end}}' mysql-db-1
172.21.0.2

使用 IP 地址远程连接:

$ mysql -h 172.21.0.2 -P 3306 -u root -p --protocol=tcp

结论:不要使用 localhost 连接容器内的 MySQL。


3.2. Docker Compose 的网络隔离

Docker Compose 会为服务创建一个自定义网络,容器之间通过服务名(或别名)进行通信。

示例:假设 docker-compose.yml 中定义了服务 db,则其他容器可通过服务名 db 访问 MySQL:

services:
  db:
    image: mysql:8.4.2
    ports:
      - "3306:3306"

结论:使用服务名而非 IP 地址更便于维护。


3.3. Root 用户密码未提供导致拒绝访问

如果设置了 root 密码,但连接时未加 -p,会提示:

ERROR 1045 (28000): Access denied for user 'root'@'localhost' (using password: NO)

解决方法:添加 -p 参数并输入密码:

mysql -u root -p

3.4. 使用了错误的协议

示例:使用 --protocol=SOCKET 但指定了 IP 地址:

$ mysql -u root --protocol=SOCKET --host=127.0.0.1

报错:

ERROR 2047 (HY000): Wrong or unknown protocol

解决方法:确保 --host--protocol 匹配:

  • 使用 SOCKET 时,--host 必须是 localhost
  • 使用 TCP 时,--host 可以是 IP 地址

3.5. 无法通过 Unix 套接字连接 MySQL

报错:

ERROR 2002 (HY000): Can't connect to local MySQL server through socket '/var/run/mysqld/mysqld.sock' (2)

常见原因:

  • MySQL 服务未启动
  • 套接字路径配置错误
  • 套接字文件权限不足

示例:启动容器后未等待 MySQL 初始化完成就尝试连接:

$ docker run -e MYSQL_ALLOW_EMPTY_PASSWORD=yes -it mysql:8.4.2 bash
bash-5.1# mysql -u root

⚠️ 踩坑提醒:进入容器后不要立即连接,等待几秒确保服务启动。


3.6. Docker Compose 配置错误:environment 不是 mapping

错误配置示例:

services:
  db:
    image: mysql:8.4.2
    environment:
      MYSQL_ROOT_PASSWORD=${MYSQL_ROOT_PASSWORD}

报错:

validating docker-compose.yml: services.db.environment must be a mapping

解决方法:使用列表格式(添加 -):

services:
  db:
    image: mysql:8.4.2
    environment:
     - MYSQL_ROOT_PASSWORD=${MYSQL_ROOT_PASSWORD}

或者直接写值:

environment:
  MYSQL_ROOT_PASSWORD: mysecretpassword

4. 总结

本文分析了在 Docker Compose 环境中无法访问 MySQL 容器的常见原因,并提供了排查思路和解决方法。重点包括:

  • MySQL 客户端连接方式的选择逻辑
  • 容器不是“本地”主机,需用 TCP/IP 连接
  • Docker Compose 的网络机制
  • 配置环境变量的格式问题
  • 套接字连接失败的排查

掌握这些内容,有助于快速定位并解决连接问题。

如需查看完整示例代码,请访问:GitHub 仓库地址


原始标题:Unable to Access MySQL Container in Docker-Compose Setup