我有一个Nginx在码头集装箱里运行。我在主机系统上运行了MySql。我想从我的容器中连接到MySql。MySql仅绑定到本地主机设备。

是否有任何方法可以从这个docker容器连接到这个MySql或本地主机上的任何其他程序?

这个问题与“如何从docker容器中获取docker主机的IP地址”不同,因为docker主机IP地址可以是网络中的公共IP或私有IP,而这些IP可能在docker容器内无法访问(如果托管在AWS或其他地方,我指的是公共IP)。即使你有docker主机的IP地址,这并不意味着你可以从容器内连接到docker主机,因为你的docker网络可能是overlay、host、bridge、macvlan、none等,这限制了该IP地址的可达性。


当前回答

要使一切正常工作,您需要为服务器(caddy,nginx)创建一个配置,其中主域将为“docker.for.mac.localhost”http://localhost/api“在”http://docker.for.mac.localhost/api"

码头组合.yml

backend:
  restart: always
  image: backend
  build:
    dockerfile: backend.Dockerfile
    context: .
  environment:
    # add django setting.py os.getenv("var") to bd config and ALLOWED_HOSTS CORS_ORIGIN_WHITELIST
    DJANGO_ALLOWED_PROTOCOL: http
    DJANGO_ALLOWED_HOSTS: docker.for.mac.localhost
    POSTGRES_PASSWORD: 123456
    POSTGRES_USER: user
    POSTGRES_DB: bd_name
    WAITDB: "1"
  volumes:
    - backend_static:/app/static
    - backend_media:/app/media
  depends_on:
    - db

frontend:
  restart: always
  build:
    dockerfile: frontend.Dockerfile
    context: .
  image: frontend
  environment:
    #  replace baseURL for axios
    API_URL: http://docker.for.mac.localhost/b/api
    API_URL_BROWSER: http://docker.for.mac.localhost/b/api
    NUXT_HOST: 0.0.0.0
  depends_on:
    - backend

caddy:
  image: abiosoft/caddy
  restart: always
  volumes:
    - $HOME/.caddy:/root/.caddy
    - ./Caddyfile.local:/etc/Caddyfile
    - backend_static:/static
    - backend_media:/media
  ports:
  - 80:80
  depends_on:
    - frontend
    - backend
    - db

Caddyfile.local(Caddyfile.local)

http://docker.for.mac.localhost {

  proxy /b backend:5000 {
    header_upstream Host {host}
    header_upstream X-Real-IP {remote}
    header_upstream X-Forwarded-For {remote}
    header_upstream X-Forwarded-Port {server_port}
    header_upstream X-Forwarded-Proto {scheme}
  }

  proxy / frontend:3000 {
    header_upstream Host {host}
    header_upstream X-Real-IP {remote}
    header_upstream X-Forwarded-For {remote}
    header_upstream X-Forwarded-Port {server_port}
    header_upstream X-Forwarded-Proto {scheme}
  }

  root /

  log stdout
  errors stdout
  gzip
}

http://docker.for.mac.localhost/static {
  root /static
}

http://docker.for.mac.localhost/media {
  root /media
}

django设置.py

ALLOWED_HOSTS = [os.getenv("DJANGO_ALLOWED_HOSTS")]
    
CORS_ORIGIN_WHITELIST = [f'{os.getenv("DJANGO_ALLOWED_PROTOCOL")}://{os.getenv("DJANGO_ALLOWED_HOSTS")}']

DATABASES = {
    "default": {
        "ENGINE": "django.db.backends.postgresql_psycopg2",
        "NAME": os.getenv("POSTGRES_DB"),
        "USER": os.getenv("POSTGRES_USER"),
        "PASSWORD": os.getenv("POSTGRES_PASSWORD"),
        "HOST": "db",
        "PORT": "5432",
    }
}

nuxt.config.js(baseURL变量将覆盖环境的API_URL)

axios: {
  baseURL: 'http://127.0.0.1:8000/b/api'
},

其他回答

适用于所有平台

Docker v 20.10及以上(自2020年12月14日起)

使用内部IP地址或连接到特殊DNS名称host.docker.internal,该名称将解析为主机使用的内部IP地址。

在Linux上,使用Docker命令,将--add host=host.Docker.internal:host gateway添加到Docker命令以启用此功能。

要在Linux上的Docker Compose中启用此功能,请在容器定义中添加以下行:

extra_hosts:
    - "host.docker.internal:host-gateway"

对于较旧的macOS和Windows版本的Docker

Docker v 18.03及以上(自2018年3月21日起)

使用内部IP地址或连接到特殊DNS名称host.docker.internal,该名称将解析为主机使用的内部IP地址。

Linux支持待定https://github.com/docker/for-linux/issues/264

对于Docker的旧macOS版本

Mac版本17.12至18.02的Docker

同上,但改用docker.for.mac.host.internal。

Mac版Docker 17.06至17.11

同上,但改用docker.for.mac.localhost。

适用于Mac 17.05及以下版本的Docker

要从docker容器访问主机,必须将IP别名附加到网络接口。您可以绑定任何您想要的IP,只需确保您没有将其用于其他任何内容。

sudo ifconfig lo0别名123.123.123.123/24

然后确保您的服务器正在侦听上面提到的IP或0.0.0.0。如果它在本地主机127.0.0.1上侦听,它将不接受连接。

然后只需将docker容器指向该IP,即可访问主机!

为了测试,可以在容器内运行类似curl-X GET 123.123.123.123:3000的命令。

别名将在每次重新启动时重置,因此如果需要,请创建启动脚本。

此处的解决方案和更多文档:https://docs.docker.com/docker-for-mac/networking/#use-案例和解决方案

首先查看此答案,了解解决此问题所需的选项。但如果使用docker compose,则可以将network_mode:host添加到服务中,然后使用127.0.0.1连接到本地主机。这只是上述答案中描述的选项之一。下面你可以看到我是如何修改docker-compose.yml的https://github.com/geerlingguy/php-apache-container.git:

 ---
 version: "3"
 services:
   php-apache:
+    network_mode: host
     image: geerlingguy/php-apache:latest
     container_name: php-apache
...

+表示我添加的行。


[附加信息]这在2.2版中也有效。和“host”或“host”都在docker compose中工作。

 ---
 version: "2.2"

 services:
   php-apache:
+    network_mode: "host"
        or
+    network_mode: host
...

您可以在主机上简单地进行ifconfig以检查您的主机IP,然后从容器中连接到IP,这对我来说非常有用。

对于我来说,在主机上执行此命令以获取ip的做法是:

docker run busybox ping -c 1 host.docker.internal | awk 'FNR==2 {print $4}' | sed s'/.$//'

或在mac上

docker run busybox ping -c 1 docker.for.mac.localhost | awk 'FNR==2 {print $4}' | sed s'/.$//'

码头组合.yml

version: '3.8'

services:
  spring-app-container:
    image: spring-app:1
    build:
      context: ./
      dockerfile: Dockerfile
    ports:
      - "50800:50800"

我不同意托马斯列维尔的回答。

将mysql绑定到172.17.42.1将阻止其他程序使用主机上的数据库来访问它。只有在所有数据库用户都已固定的情况下,这才有效。

将mysql绑定到0.0.0.0将向外部世界打开数据库,这不仅是一件非常糟糕的事情,而且与最初的问题作者想要做的相反

回答ivant的评论

“为什么不将mysql也绑定到docker0?”

这是不可能的。mysql/mariadb文档明确表示不可能绑定到多个接口。只能绑定到0、1或所有接口。

因此,我还没有找到从docker容器访问主机上(仅限于本地主机)数据库的任何方法。这显然是一种非常常见的模式,但我不知道怎么做。