从主机连接到 Docker 容器中的 MySQL。

271

简而言之

我想在docker容器中运行mysql,并从我的主机连接它。到目前为止,我所能做到的最好的是:

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

更多细节

我正在使用以下的Dockerfile:

FROM ubuntu:14.04.3
RUN apt-get update && apt-get install -y mysql-server

# Ensure we won't bind to localhost only
RUN grep -v bind-address /etc/mysql/my.cnf > temp.txt \
  && mv temp.txt /etc/mysql/my.cnf

# It doesn't seem needed since I'll use -p, but it can't hurt
EXPOSE 3306

CMD /etc/init.d/mysql start && tail -F /var/log/mysql.log

在包含此文件的目录中,我可以成功地构建图像并运行它:
> docker build -t my-image .
> docker run -d -p 12345:3306 my-image

当我连接到图像时,它似乎能正常工作:
# from the host
> docker exec -it <my_image_name> bash

#inside of the container now
$ mysql -u root
Welcome to the MySQL monitor.  Commands end with ; or \g.
[...]

然而我从主机那里并没有取得太多成功:

> mysql -P 12345 -uroot
ERROR 2002 (HY000): Can't connect to local MySQL server through socket '/var/run/mysqld/mysqld.sock' (2)

更多细节

  • 我看到有一个问题与我的问题类似。但是,它不相同(而且它没有任何答案)。
  • 我看到了专门用于mysql的镜像,但是我在使用它们时并没有更多的成功。
  • 我的grep -v可能感觉很奇怪。诚然,可能有更干净的方法来做到这一点。但是当我附加我的镜像时,我可以观察到它实际上按预期工作(即:删除了bind-address)。我可以在容器/var/log/mysql/error.log中看到:

服务器主机名(bind-address):'0.0.0.0';端口:3306 - '0.0.0.0'解析为'0.0.0.0'; 服务器套接字在IP上创建:'0.0.0.0'。


9
也许不是那么愚蠢。我已经偶然发现这个东西10次了,现在终于有时间在家里试试看。 - kiltek
注意:有些人可能会在这里,想要连接到在Docker中运行的mysql镜像,但端口没有暴露。当您使用docker run命令运行它时,请确保打开端口,例如,docker run -p 3306:3306 ...否则您将无法连接。当然,这也可以在Dockerfile中完成,但您不需要自定义Docker镜像来完成此操作! - Brad Parks
1
对于像我一样将开发凭据存储在 .my.cnf 文件中,然后想知道为什么无法使用 root 连接的人,请注意:即使未指定值,.my.cnf 中的密码也将被用于 -p。为了避免这种情况,--no-defaults 对我有用。完整命令为 mysql --no-defaults --protocol=tcp -uroot -p - Dario Seidl
22个回答

349

如果您的 Docker MySQL 主机正在正常运行,则可以从本地计算机连接到它,但是您应该像这样指定主机、端口和协议:

如果您的 Docker MySQL 主机正在正常运行,则可以从本地计算机连接到它,但是您应该像这样指定主机、端口和协议:

mysql -h localhost -P 3306 --protocol=tcp -u root

将3306更改为您从Docker容器转发的端口号(在您的情况下,它将是12345)。

因为您正在Docker容器内运行MySQL,所以套接字不可用,您需要通过TCP连接。在mysql命令中设置“--protocol”将更改这一点。


3
你能解释一下为什么mysql套接字不可用吗?你的命令行可以运行,但我想知道是否有一种方法将mysql套接字从容器挂载到主机。 - Lucas
16
我不是Unix通信专家,但据我所知,套接字是一个表示连接的文件。由于套接字文件在Docker容器和主机MySQL客户端之间不共享,因此MySQL客户端无法从Docker容器内部使用该客户端。要从主机机器连接到Docker容器内的MySQL服务器,您可以:
  1. 设置MySQL服务器将套接字放置在指定位置 --socket=/var/run/mysqld/mysqld.sock
  2. 将此文件挂载到Docker容器外部
  3. 在MySQL客户端中指定套接字路径为 --socket=/host/mysql.sock
- jozala
16
经过长时间的奋斗,我找到了这个黄金答案,“--protocol=tcp” 最终使连接工作。感谢 @maniekq 提供的精彩答案和通过评论对套接字进行解释! - panepeter
2
这不应该被接受的答案,因为他明确表示自己对UNIX文件通信一无所知。 - kiltek
3
这对我有用。我只需要在末尾添加“-p”,这样MySQL就会要求输入密码。 - asherbret
显示剩余7条评论

116

如果您使用“127.0.0.1”而不是localhost,则mysql将使用tcp方法,您应该能够连接容器:

mysql -h 127.0.0.1 -P 3306 -u root

3
我不相信这是真的。我没有点踩是因为我不是100%确定,但根据我的经验,localhost和127.0.0.1总是尝试使用套接字,除非你添加--protocol=tcp。 - andrew lorien
9
我可以确认,一旦我将localhost更改为127.0.0.1并移除协议标志,它的工作方式是相同的。 - Craig Wayne
2
我认为这是一个简短而最佳的答案 ;) - rezam
1
虽然可能很短,但这并不是答案,因为TCP是与mysql通信的较慢方法(需要更多的CPU和更高的延迟)。 - John
2
这是我为任何高负载数据库推荐的方法。只需使用“-v socketfile.sock”,然后使用mysql --socket /path/file.sock,而不会污染TCP/IP堆栈。 - John
显示剩余4条评论

52

我建议查看docker-compose。以下是如何操作:

创建一个名为docker-compose.yml的文件,其内容如下:

version: '2'

services:

  mysql:
    image: mariadb:10.1.19
    ports:
      - 8083:3306
    volumes:
      - ./mysql:/var/lib/mysql
    environment:
      MYSQL_ROOT_PASSWORD: wp

接下来,运行:

$ docker-compose up

说明:

现在,您可以通过以下方式访问mysql控制台:

$ mysql -P 8083 --protocol=tcp -u root -p

Enter password:
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 8
Server version: 5.5.5-10.1.19-MariaDB-1~jessie mariadb.org binary distribution

Copyright (c) 2000, 2016, Oracle and/or its affiliates. All rights reserved.

Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

mysql>

注意:

  • 您可以传递-d标志以在分离/后台模式下运行mysql/mariadb容器。

  • 密码是“wp”,它在docker-compose.yml文件中定义。

  • 与maniekq的建议相同,但使用docker-compose提供完整示例。


5
“--protocol=tcp” 对我来说解决了所有问题。谢谢! - Charlie L
谢谢您的回答,我遇到了与主题相同的问题,但是在使用--protocol=tcp之后,问题得到了解决。我原以为是Docker网络出了问题。 - jiriki
欢迎,@tiago-elias。提醒一下,我希望尽快在我的书中发布另一章节"深度数据分析": https://leanpub.com/dataengineeringhandbook - l3x
没有显式设置IP地址对我起了作用,谢谢! - Andresa Martins

21

简单的方法是将mysql unix socket共享到主机上,然后通过socket连接。

步骤:

  • 为主机创建共享文件夹,例如:mkdir /host
  • 使用卷挂载选项运行docker容器:docker run -it -v /host:/shared <mysql镜像>
  • 然后更改mysql配置文件/etc/my.cnf,并将文件中的socket项更改为socket=/shared/mysql.sock
  • 在docker中重启MySQL服务service mysql restart
  • 最后通过socket从主机连接到MySQL服务器mysql -u root --socket=/host/mysql.sock。如果有密码,请使用-p选项

1
如果MySQL客户端在另一个容器中,你必须这样做吗? - Stephane
1
我不知道那个。我选择了这种方法,因为tcp-ip端口方法对我无效。如果您正在为服务器和客户端使用两个容器,则可以将一个共享目录提供给两个容器,并使用Unix套接字连接到MySQL。 - Jobin
1
当我在容器上使用docker-compose链接时,我的问题的答案是否定的。 - Stephane
这个可以工作,但是使用主机连接不上。 - Arif

20

好的,我终于解决了这个问题。以下是我在https://sqlflow.org/sqlflow中使用的解决方案。

完整的解决方案

为了使演示自包含,我将所有必要的代码移动到https://github.com/wangkuiyi/mysql-server-in-docker

解决方案的关键

我不使用DockerHub.com上的官方镜像https://hub.docker.com/r/mysql/mysql-server。相反,我通过在Ubuntu 18.04上安装MySQL来制作我的自己的镜像。这种方法给了我一个机会来启动mysqld并将其绑定到0.0.0.0(所有IP)

有关详细信息,请参阅我的GitHub存储库中的这些行

SQLFLOW_MYSQL_HOST=${SQLFLOW_MYSQL_HOST:-0.0.0.0}

echo "Start mysqld ..."
sed -i "s/.*bind-address.*/bind-address = ${SQLFLOW_MYSQL_HOST}/" \
    /etc/mysql/mysql.conf.d/mysqld.cnf
service mysql start

验证我的解决方案

  1. Git clone the aforementioned repo.
    git clone https://github.com/wangkuiyi/mysql-server-in-docker
    cd mysql-server-in-docker
    
  2. Build the MySQL server Docker image
    docker build -t mysql:yi .
    
  3. Start MySQL server in a container
    docker run --rm -d -p 23306:3306 mysql:yi
    
  4. Install the MySQL client on the host, if not yet. I am running Ubuntu 18.04 on the host (my workstation), so I use apt-get.
    sudo apt-get install -y mysql-client
    
  5. Connect from the host to the MySQL server running in the container.
    mysql --host 127.0.0.1 --port 23306 --user root -proot
    

在同一主机上的另一个容器中连接

我们甚至可以从另一个容器(在同一主机上)运行MySQL客户端。

docker run --rm -it --net=host mysql/mysql-server mysql \
   -h 127.0.0.1 -P 13306 -u root -proot

从另一台主机连接

在我的iMac上,我使用Homebrew安装MySQL客户端。

brew install mysql-client
export PATH="/usr/local/opt/mysql-client/bin:$PATH"

接下来,我可以访问上述Ubuntu主机(192.168.1.22)。

mysql -h 192.168.1.22 -P 13306 -u root -proot

从另一台主机上运行的容器连接

我甚至可以在 iMac 上运行的容器中运行 MySQL 客户端,以连接到 Ubuntu 工作站上容器中的 MySQL 服务器。

docker run --rm -it --net=host mysql/mysql-server mysql \
    -h 192.168.1.22 -P 13306 -u root -proot

一个特殊情况

如果我们在同一主机上运行分别位于不同容器中的MySQL客户端和服务器,这种情况可能发生在设置CI时,我们不需要构建自己的MySQL服务器Docker镜像。相反,我们可以在运行客户端容器时使用--net=container:mysql_server_container_name

启动服务器:

docker run --rm -d --name mysql mysql/mysql-server

启动客户端

docker run --rm -it --net=container:mysql mysql/mysql-server mysql \
 -h 127.0.0.1 -P 3306 -u root -proot

10

如果您正在docker-machine下运行Docker?

执行以下命令获取IP地址:

docker-machine ip <machine>

返回机器的IP地址并尝试连接MySQL:

mysql -h<docker-machine-ip>

已在Docker-Toolbox中解决 :) 非常感谢。 - Vuong

8
在您的终端中运行:docker exec -it container_name /bin/bash 然后输入:mysql

如果您在Windows上运行,就不能在Git Bash上运行此程序,但可以在CMD MS-DOS上运行。 - duchuy
2
问题要求如何从主机连接。问题描述说明他们能够从容器内部连接。 - Marvo

8

2
谢谢,这正是我想要的通过mysql客户端连接到数据库的方法。 - Daniyal Nasir
1
那个IP地址通常不是很有用,特别是在使用Docker Desktop等系统时,并且您不需要查找它。 - David Maze

6
  • docker run -e MYSQL_ROOT_PASSWORD=pass --name sql-db -p 3306:3306 mysql

  • docker exec -it sql-db bash

  • mysql -u root -p

使用 Docker 运行 MySQL 数据库,并指定 root 用户密码为 pass,容器名称为 sql-db,映射本地端口 3306 到容器端口 3306。然后在容器内部运行 Bash 终端,并进入 MySQL 数据库,使用 root 用户身份登录。

ERROR 1524 (HY000):未加载插件“unix_socket”。 - Enerccio
@Enerccio 你能再试一次吗? - Ajay Singh

5
mysql -u root -P 4406 -h localhost --protocol=tcp -p

请记得更改用户、端口和主机以匹配您的配置。如果您的数据库用户配置有密码,那么必须使用-p标志。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接