我有一个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地址的可达性。


当前回答

我做了一个类似于上述帖子的黑客,获取本地IP以映射到容器中的别名(DNS)。主要问题是使用一个在Linux和OSX中都有效的简单脚本动态获取主机IP地址。我在两种环境中都使用了这个脚本(即使在配置了“$LANG”!=“en_*”的Linux发行版中也是如此):

ifconfig | grep -E "([0-9]{1,3}\.){3}[0-9]{1,3}" | grep -v 127.0.0.1 | awk '{ print $2 }' | cut -f2 -d: | head -n1

因此,使用Docker Compose,完整的配置将是:

启动脚本(docker run.sh):

export DOCKERHOST=$(ifconfig | grep -E "([0-9]{1,3}\.){3}[0-9]{1,3}" | grep -v 127.0.0.1 | awk '{ print $2 }' | cut -f2 -d: | head -n1)
docker-compose -f docker-compose.yml up

docker-compose.yml文件:

myapp:
  build: .
  ports:
    - "80:80"
  extra_hosts:
    - "dockerhost:$DOCKERHOST"

然后改变http://localhost到http://dockerhost在您的代码中。

有关如何定制DOCKERHOST脚本的更高级指南,请阅读本文并解释其工作原理。

其他回答

您可以使用alpine映像获取主机ip

docker run --rm alpine ip route | awk 'NR==1 {print $3}'

这将更加一致,因为您总是使用alpine来运行命令。

类似于Mariano的回答,您可以使用相同的命令设置环境变量

DOCKER_HOST=$(docker run --rm alpine ip route | awk 'NR==1 {print $3}') docker-compose up

对于我来说,在主机上执行此命令以获取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"

要使一切正常工作,您需要为服务器(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 network inspect bridge | grep Gateway
                    "Gateway": "172.17.0.1"

确保主机上的进程正在侦听此接口或所有接口,并在docker之后启动。如果使用systemd,可以添加以下内容以确保在docker之后启动。

[Unit]
After=docker.service

实例

❯ python -m http.server &> /dev/null &
[1] 149976

❯ docker run --rm python python -c  "from urllib.request import urlopen;print(b'Directory listing for' in urlopen('http://172.17.0.1:8000').read())" 
True

对于Windows上的应用程序,假设您使用的是网桥网络驱动程序,则需要将MySQL专门绑定到hyper-v网络接口的IP地址。

这是通过通常隐藏的C:\ProgramData\MySQL文件夹下的配置文件完成的。

绑定到0.0.0.0将不起作用。所需的地址也显示在docker配置中,在我的例子中是10.0.75.1。