从主机连接到Docker容器中的mysql


109

(由于我对Docker或mysql管理的了解有限,这可能是一个愚蠢的问题,但是由于我在这个问题上花费了一整夜,所以我敢问这个问题。)

简而言之

我想在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

服务器主机名(绑定地址):“ 0.0.0.0”;端口:3306-“ 0.0.0.0”解析为“ 0.0.0.0”;在IP:“ 0.0.0.0”上创建的服务器套接字。


1
可能不是那么愚蠢。我第十次偶然发现了这个问题,终于有时间在家中尝试它。
kiltek

Answers:


171

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

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

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

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


1
您能否阐明为什么mysql套接字不可用?您的命令有效,但是我想知道是否有一种方法可以从容器将mysql套接字安装到主机。
卢卡斯

9
我不是Unix通信方面的专家,但是据我了解,套接字是一个表示为文件的连接。由于套接字文件未在Docker容器和主机之间共享,因此MySQL客户端无法在Docker容器内部使用一个套接字文件。要连接到MySQL服务器泊坞容器内从主机你可以:1.设置MySQL服务器把插座在指定的位置--socket=/var/run/mysqld/mysqld.sock2.安装此文件中的泊坞容器3.指定插座的MySQL客户端与路径之外--socket=/host/mysql.sock
maniekq

@maniekq很棒的评论!但是您是否验证了所有三种可能性?他们都真的工作吗?
安德鲁

7
经过长期的奋斗,我找到了这个黄金答案,--protocol=tcp终于使连接工作了。感谢@maniekq提供的好答案以及您通过评论对套接字的解释!
panepeter

1
这不是公认的答案,因为他明确指出他不了解UNIX文件通信。
kiltek

50

如果使用“ 127.0.0.1”代替localhost,则mysql将使用tcp方法,并且您应该能够使用以下方式连接容器:

mysql -h 127.0.0.1 -P 3306 -u root

4
我可以验证一下,一旦将localhost更改为127.0.0.1并删除了协议标志,它的工作
Craig Wayne

2
我认为这是一个简短而最佳的答案;)
rezam

1
可能很短,但这不是答案,因为TCP是与mysql通信的较慢方法。(更多的CPU和更高的延迟)
约翰·约翰(John John

1
@John,您是对的,它的速度较慢,但​​确实存在。当然,您可以在主机和容器之间共享/var/run/mysqld/mysqld.sock。
Vasili Pascal

2
这是我建议用于任何更高性能的DB的建议。就像“ -v socketfile.sock”和mysql --socket /path/file.sock一样简单,而不会污染tcp / ip堆栈。
约翰

27

我建议签出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根-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的完整示例。


3
--protocol=tcp为我解决了所有问题。谢谢!
查理L

感谢您的回答,我遇到了与主题相同的问题,但是在使用--protocol = tcp之后,它已修复。我认为Docker网络出了点问题。
jiriki

16

简单的方法是将mysql unix套接字共享给主机。然后通过插座连接

脚步:

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

1
如果MySQL客户端在另一个容器中,您是否必须这样做?
Stephane

我不知道 我选择此方法是因为tcp-ip port方法对我不起作用。如果将两个容器用于服务器和客户端,则可以为两个容器共享一个公共目录,并使用Unix套接字连接到MySQL。
Jobin

1
当我在容器上使用带有链接的docker-compose时,我的问题的答案是否定的。
Stephane

9

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

执行以获取IP:

docker-machine ip <machine>

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

mysql -h<docker-machine-ip>

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

5

我通过对服务器运行一个临时docker容器来做到这一点,所以我不必担心主机上安装了什么。首先,我定义我需要的(您应该针对自己的目的进行修改):

export MYSQL_SERVER_CONTAINER=mysql-db
export MYSQL_ROOT_PASSWORD=pswd 
export DB_DOCKER_NETWORK=db-net
export MYSQL_PORT=6604

我总是创建一个新的docker网络,任何其他容器都需要:

docker network create --driver bridge $DB_DOCKER_NETWORK

启动一个mySQL数据库服务器:

docker run --detach --name=$MYSQL_SERVER_CONTAINER --net=$DB_DOCKER_NETWORK --env="MYSQL_ROOT_PASSWORD=$MYSQL_ROOT_PASSWORD" -p ${MYSQL_PORT}:3306 mysql

捕获新服务器容器的IP地址

export DBIP="$(docker inspect ${MYSQL_SERVER_CONTAINER} | grep -i 'ipaddress' | grep -oE '((1?[0-9][0-9]?|2[0-4][0-9]|25[0-5])\.){3}(1?[0-9][0-9]?|2[0-4][0-9]|25[0-5])')"

打开服务器的命令行界面:

docker run -it -v ${HOST_DATA}:/data --net=$DB_DOCKER_NETWORK --link ${MYSQL_SERVER_CONTAINER}:mysql --rm mysql sh -c "exec mysql -h${DBIP} -uroot -p"

当您退出mySQL接口时,最后一个容器将自行删除,而服务器将继续运行。您还可以在服务器和主机之间共享卷,以使导入数据或脚本更加容易。希望这可以帮助!


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

切记更改用户,端口和主机,使其与您的配置匹配。如果您的数据库用户配置了密码,则-p标志是必需的


2

为了进行转换,您可以~/.my.cnf在主机中创建 文件:

[Mysql]
user=root
password=yourpass
host=127.0.0.1
port=3306

然后下一次只需运行mysqlmysql客户端以打开连接。


1

我可以使用以下命令连接在主机上运行的sql server5.7:mysql -h 10.10.1.7 -P 3307 --protocol = tcp -u root -p其中给出的ip是我的主机ip,3307是在mysql docker中覆盖了端口。输入命令后,输入myql的密码。


0

运行以下命令以运行容器

docker run --name db_name -e MYSQL_ROOT_PASSWORD=PASS--publish 8306:3306 db_name

运行此命令以在主机中获取mysql db

mysql -h 127.0.0.1 -P 8306 -uroot  -pPASS

在你的情况下

mysql -h 127.0.0.1 -P 12345 -uroot  -pPASS

仅当您使用127.0.0.1作为地址时才有效。如果您使用主机的非本地地址,则需要添加--protocol=tcp标记,如其他一些注释/答案所述。就我而言,这更加令人困惑,因为我也运行了本地的,非dockerized的mysql实例。默认情况下,即使指定了端口,即使端口不正确,“ mysql”命令也会通过套接字文件连接到本地实例。
丰富的

@Rich,那么您做了什么来解决这个问题?甚至我也有类似的设置,一个MySql在主机上运行,​​另一个在docker容器中运行。
NITHIN RAJ T

@NITHINRAJT有两种方法可以确保您的docker实例不在同一端口上侦听(例如,在此答案中为8306),以完成此操作。(1)试试这个回答,一个我们在评论(例如,连接到127.0.0.1(2)尝试下一个答案- mysql -u root -P <EXPOSED_DOCKER_PORT_HERE> -h <YOUR_HOST_IP_ADDRESS_HERE> --protocol=tcp -p标志。--protocol=tcp关键是使这项工作。
丰富的


0

好。我终于解决了这个问题。这是我在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克隆上述回购。
    git clone https://github.com/wangkuiyi/mysql-server-in-docker
    cd mysql-server-in-docker
  2. 构建MySQL服务器Docker映像
    docker build -t mysql:yi .
  3. 在容器中启动MySQL服务器
    docker run --rm -d -p 23306:3306 mysql:yi
  4. 如果尚未在主机上安装MySQL客户端。我在主机(我的工作站)上运行Ubuntu 18.04,所以我使用apt-get
    sudo apt-get install -y mysql-client
  5. 从主机连接到容器中运行的MySQL服务器。
    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


-5

将“ localhost”更改为真正的con ip addr,
因为它更改为mysql_connect()

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.