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

Posted

技术标签:

【中文标题】从主机连接到 docker 容器中的 mysql【英文标题】:Connect to mysql in a docker container from the host 【发布时间】:2016-01-05 05:55:33 【问题描述】:

(由于我对 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)

更多细节

我看到有一个looks like mine 的问题。但是,它不一样(无论如何它没有任何答案) 我看到有图片dedicated to 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'。

【问题讨论】:

可能没那么笨。我现在第 10 次偶然发现这个,终于有时间在家里尝试一下。 【参考方案1】:

首先看日志有没有错误。

docker ps -a
docker logs container_name

如果有任何错误,请搜索该特定错误的解决方案,如果没有错误则可以继续下一步。

请记住,启动容器后 MySQL 需要几分钟才能启动,因此请在 3-4 分钟后运行这些命令。

docker exec -it container_name bash
# ONCE YOU ARE INSIDE CONTAINER 
mysql -u root -p
SHOW DATABASES;
exit

从终端或命令提示符连接

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

【讨论】:

【参考方案2】:

根据照片,进入docker桌面应用中的项目-> MySQL->inspect选项卡,修改数据库.env文件的信息。

.env 文件示例:

DB_CONNECTION=mysql
DB_HOST=0.0.0.0:3306
DB_PORT=3306
DB_DATABASE=testdb
DB_USERNAME=sail
DB_PASSWORD=password

【讨论】:

【参考方案3】:

您应该检查分配给正在运行的容器的 IP 地址,然后连接到该主机:

docker inspect -f 'range .NetworkSettings.Networks.IPAddressend' &lt;container name or id&gt;

你可以联系到:

mysql -h &lt;IP provided by inspect command&gt; -P &lt;port&gt; -u &lt;user&gt; -p &lt;db name&gt;

https://mariadb.com/kb/en/installing-and-using-mariadb-via-docker/#connecting-to-mariadb-from-outside-the-container

【讨论】:

【参考方案4】:

好的。我终于解决了这个问题。下面是我在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 repo 中的these lines。

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

验证我的解决方案

    Git 克隆上述存储库。
    git clone https://github.com/wangkuiyi/mysql-server-in-docker
    cd mysql-server-in-docker
    
    构建 MySQL 服务器 Docker 映像
    docker build -t mysql:yi .
    
    在容器中启动 MySQL 服务器
    docker run --rm -d -p 23306:3306 mysql:yi
    
    如果还没有,在主机上安装 MySQL 客户端。我在主机(我的工作站)上运行 Ubuntu 18.04,所以我使用apt-get
    sudo apt-get install -y mysql-client
    
    从主机连接到容器中运行的 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】:

在终端运行:docker exec -it container_name /bin/bash 然后:mysql

【讨论】:

如果你在 windows 上运行,你不能在 git-bash 上运行它,但在 cmd ms-dos 上运行【参考方案6】:

我能够使用以下命令连接在我的主机上运行的 sql server5.7: mysql -h 10.10.1.7 -P 3307 --protocol=tcp -u root -p 其中给出的ip是我的主机ip,3307是mysql docker中转发的端口。输入命令后输入myql的密码。就是这样.现在你已经从你的主机连接了 mysql docker 容器

【讨论】:

【参考方案7】:

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

docker exec -it sql-db bash

mysql -u root -p

【讨论】:

ERROR 1524 (HY000): Plugin 'unix_socket' is not loaded结尾 @Enerccio 你能再试一次吗?【参考方案8】:

运行以下命令来运行容器

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 标志,如其他几个 cmets/answers 中所述。就我而言,这更加令人困惑,因为我还运行了一个本地的、非 dockerized 的 mysql 实例。默认情况下,即使指定了端口,即使端口不正确,'mysql'命令也会通过socket文件连接到本地实例。 @Rich 那么你做了什么来解决这个问题?即使我有类似的设置,一个 MySql 在主机上运行,​​另一个在 docker 容器中。 @NITHINRAJT 在确保您的 docker 实例不在同一个端口上侦听(例如,在这个答案中,8306)之后,有两种方法可以完成此操作。 (1) 试试这个答案,我们正在评论的那个(例如,连接到 127.0.0.1。(2) 试试下一个答案 - mysql -u root -P &lt;EXPOSED_DOCKER_PORT_HERE&gt; -h &lt;YOUR_HOST_IP_ADDRESS_HERE&gt; --protocol=tcp -p。标志 --protocol=tcp 是完成这项工作的关键。 【参考方案9】:
mysql -u root -P 4406 -h localhost --protocol=tcp -p

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

【讨论】:

【参考方案10】:

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

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

那么下次只需运行mysql 让mysql客户端打开连接。

【讨论】:

【参考方案11】:

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

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

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

因为你在 Docker 容器中运行 MySQL,所以 socket 不可用,你需要通过 TCP 连接。在 mysql 命令中设置“--protocol”会改变这一点。

【讨论】:

你能解释一下为什么mysql套接字不可用吗?您的命令有效,但我想知道是否有办法将 mysql 套接字从容器安装到主机。 我不是 Unix 通信方面的专家,但据我了解,socket 是一个表示为文件的连接。由于 Docker 容器和主机之间不共享套接字文件,因此 MySQL 客户端不能使用 Docker 容器内部的一个。要从主机连接到 Docker 容器内的 MySQL 服务器,您可以: 1. 设置 MySQL 服务器以将套接字放在指定的位置 --socket=/var/run/mysqld/mysqld.sock 2. 将此文件挂载到 Docker 容器之外 3. 在 MySQL 客户端中指定套接字的路径--socket=/host/mysql.sock @maniekq 很棒的评论!但是您是否验证了所有三种可能性?它们真的都有效吗? 经过长时间的奋斗,我找到了这个黄金答案,--protocol=tcp 终于使连接工作了。感谢@maniekq 通过您的评论提供了不错的答案和对套接字的解释! 这不应该是公认的答案,因为他明确表示他不知道 UNIX 文件通信。【参考方案12】:

我通过在我的服务器上运行一个临时 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 界面时,最后一个容器将自行删除,而服务器将继续运行。您还可以在服务器和主机之间共享一个卷,以便更轻松地导入数据或脚本。希望这会有所帮助!

【讨论】:

【参考方案13】:

我建议查看 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

注意事项:

最新的 mariadb 镜像标签见https://hub.docker.com/_/mariadb/

现在,你可以访问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 提供完整示例。

【讨论】:

--protocol=tcp 为我修复了所有问题。谢谢! 感谢您的回答,我遇到了与主题相同的问题,但在使用 --protocol=tcp 后它已修复。我认为 docker 网络有问题。 不客气@tiago-elias。作为提醒,我希望尽快在我的书中发布另一章“深度数据分析”:leanpub.com/dataengineeringhandbook 没有明确设置 IP 地址对我有用,谢谢!【参考方案14】:

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

mysql -h 127.0.0.1 -P 3306 -u root

【讨论】:

我不相信是这样的。不反对,因为我不是 100% 确定,但根据我的经验 localhost 和 127.0.0.1 总是尝试使用套接字,除非你添加 --protocol=tcp 我可以验证,一旦我将 localhost 更改为 127.0.0.1 并删除了协议标志,它的工作原理是一样的 我认为这是简短而最佳的答案;) 可能很短,但这不是答案,因为 TCP 是与 mysql 通信的较慢方法。 (更多的 CPU 和更高的延迟) 这就是我对任何更高职责的数据库的推荐。它就像“-v socketfile.sock”然后 mysql --socket /path/file.sock 一样简单,不会污染 tcp/ip 堆栈。【参考方案15】:

将“localhost”更改为您的真实 con ip 地址 因为是mysql_connect()

【讨论】:

【参考方案16】:

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

执行获取ip:

docker-machine ip <machine>

返回机器的ip并尝试连接mysql:

mysql -h<docker-machine-ip>

【讨论】:

已在 Docker-Toolbox 中解决 :) 非常感谢。【参考方案17】:

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

步骤:

为主机创建共享文件夹,例如:mkdir /host 使用卷挂载选项运行 docker 容器docker run -it -v /host:/shared &lt;mysql image&gt;。 然后修改mysql配置文件/etc/my.cnf,将文件中的socket入口修改为socket=/shared/mysql.sock 在docker中重启MySQL服务service mysql restart 最终通过套接字mysql -u root --socket=/host/mysql.sock从主机连接到MySQL服务器。如果密码使用 -p 选项

【讨论】:

如果MySQL客户端在另一个容器中,你必须这样做吗? 我不知道。我选择了这种方法,因为 tcp-ip 端口方法对我不起作用。如果服务器和客户端使用两个容器,则可以将两个容器共享一个公共目录,并使用 Unix 套接字连接到 MySQL。 当我使用带有容器链接的 docker-compose 时,我的问题的答案是否定的。

以上是关于从主机连接到 docker 容器中的 mysql的主要内容,如果未能解决你的问题,请参考以下文章

docker从容器连接到主机隧道

从 docker 容器连接到主机 mongodb

无法从我的 Docker 容器内部连接到主机的 localhost

从主机连接到 mongo docker 容器

如何从 Windows 10 上的容器连接到 docker 主机(Docker for Windows)

从 Docker 容器连接到主机上的服务的规范方法