从主机连接到 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' <container name or id>
你可以联系到:
mysql -h <IP provided by inspect command> -P <port> -u <user> -p <db name>
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 <EXPOSED_DOCKER_PORT_HERE> -h <YOUR_HOST_IP_ADDRESS_HERE> --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 <mysql image>
。
然后修改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 容器内部连接到主机的 localhost