从 docker 容器访问主机数据库

Access host database from a docker container

如果我在某个主机上有一个 mysql 数据库 运行,并且该主机也 运行 一个 docker 容器:我将如何访问mysql 来自 运行 主机上 docker 容器内的数据库?

例如,有没有办法将主机端口发布到容器(与 docker 运行 -p 的作用相反)?

关于如何以一致、易于理解和可移植的方式执行此操作,存在多个长期讨论。没有完整的解决方案,但我会 link 你参与下面的讨论。

在任何情况下,您都想尝试使用 --add-host 选项 docker 运行 将主机的 IP 地址添加到容器的 /etc/host 文件中。从那里连接到任何所需端口上的主机是微不足道的:

Adding entries to a container hosts file

You can add other hosts into a container's /etc/hosts file by using one or more --add-host flags. This example adds a static address for a host named docker:

 $ docker run --add-host=docker:10.180.0.1 --rm -it debian
    $$ ping docker
    PING docker (10.180.0.1): 48 data bytes
    56 bytes from 10.180.0.1: icmp_seq=0 ttl=254 time=7.600 ms
    56 bytes from 10.180.0.1: icmp_seq=1 ttl=254 time=30.705 ms
    ^C--- docker ping statistics ---
    2 packets transmitted, 2 packets received, 0% packet loss
    round-trip min/avg/max/stddev = 7.600/19.152/30.705/11.553 ms

Note: Sometimes you need to connect to the Docker host, which means getting the IP address of the host. You can use the following shell commands to simplify this process:

 $ alias hostip="ip route show 0.0.0.0/0 | grep -Eo 'via \S+' | awk '{ print  }'"
 $ docker run  --add-host=docker:$(hostip) --rm -it debian

文档:

https://docs.docker.com/engine/reference/commandline/run/

关于从容器访问主机的讨论:

https://github.com/docker/docker/issues/1143

https://github.com/docker/docker/issues/10023

从 Docker 17.06 开始,一个特殊的 Mac-only DNS 名称在 docker 容器中可用,解析为主机的 IP 地址。它是:

docker.for.mac.localhost

文档在这里: https://docs.docker.com/docker-for-mac/networking/#httphttps-proxy-support

从 Docker 18.03 开始​​使用 host.docker.internal

来自 18.03 文档:

I want to connect from a container to a service on the host

The host has a changing IP address (or none if you have no network access). From 18.03 onwards our recommendation is to connect to the special DNS name host.docker.internal, which resolves to the internal IP address used by the host.

The gateway is also reachable as gateway.docker.internal.

示例: 这是我用于容器内的 MySQL 连接字符串以访问主机上的 MySQL 实例的内容:

mysql://host.docker.internal:3306/my_awesome_database

其他答案对我来说效果不佳。我的容器无法使用 host.docker.internal 解析主机 IP。有两种方式

  1. 共享主机网络--net=host:

    docker run -it --net=host  myimage
    
  2. 使用docker的ip地址,通常是172.17.0.1。 您可以通过调用 ifconfig 命令并获取 docker 接口

    的 inet 地址来检查它
    user@ubuntu:~$ ifconfig
    docker0   Link encap:Ethernet  HWaddr 02:42:a4:a2:b2:f1  
      inet addr:172.17.0.1  Bcast:0.0.0.0  Mask:255.255.0.0
      inet6 addr: fe80::42:a4ff:fea2:b2f1/64 Scope:Link
    

一旦你有了这个 ip 地址,你可以将它作为参数传递给 docker 运行 然后传递给应用程序或者像我一样,映射 jdbc.properties 的位置通过卷到主机上的目录,因此您可以在外部管理文件。

  docker run -it -v /host_dir/docker_jdbc_config:${jetty_base}/var/config myimage

注意:您的数据库可能不允许外部连接。对于 postgresql,您需要编辑 2 个文件,如 here and here:

所述
  1. 编辑 postgresql.conf 以侦听所有地址。默认情况下它将指向本地主机。

    listen_addresses = '*'
    
  2. 编辑 pg_hba.conf 以允许来自所有地址的连接。在最后一行添加:

    host     all             all             0.0.0.0/0               md5
    

重要提示:不建议将最后一步更新数据库访问用于生产用途,除非您真的确定自己在做什么。

仅限Linux
Case 1:-Mysqldb 运行 on localhost not on docker
你可以修复主机Ip来连接并连接到那个 ip 而不是本地主机。
对于 linux dockerhost 是固定的,即 172.17.0.1。所以连接到 172.17.0.1 而不是本地主机。
Case2:- 如果 mysqldb 在 docker 上也是 运行 那么最好的做法是连接 docker 容器名称 而不是 IP 地址。
所以 docker-compose 文件应该是这样的

version: '3.8'
services:
  mysqldb:
    image: mysql:5.7
    restart: unless-stopped
    env_file: ./.env
    environment:
      - MYSQL_ROOT_PASSWORD=$MYSQLDB_ROOT_PASSWORD
      - MYSQL_DATABASE=$MYSQLDB_DATABASE
    ports:
      - $MYSQLDB_LOCAL_PORT:$MYSQLDB_DOCKER_PORT
    volumes:
      - db:/var/lib/mysql
producer:
     build: .
     ports:
      - '$LOCAL_PORT:$DOCKER_PORT' 
     depends_on:
         - mysqlsb
     volumes:
         - ./:/usr/src/app

现在不用 ip 或 localhost 连接到 mysqlsb

var mysql = require('mysql');

var con = mysql.createConnection({
  host: mysqldb,
  user: "yourusername",
  password: "yourpassword"
});

con.connect(function(err) {
  if (err) throw err;
  console.log("Connected!");
});