Docker 个容器的本地主机名

Local hostnames for Docker containers

初学者Docker问题在这里,

所以我有一个开发环境,我在其中 运行 安装了一个模块化应用程序,它正在使用 Docker Compose 到 运行 3 个容器:服务器、客户端、数据库.

docker-compose.yml 看起来像这样:

#############################
# Server
#############################
server:
  container_name: server
  domainname: server.dev
  hostname: server
  build: ./server
  working_dir: /app
  ports:
    - "3000:3000"
  volumes:
    - ./server:/app
  links:
    - database

#############################
# Client
#############################
client:
  container_name: client
  domainname: client.dev
  hostname: client
  image: php:5.6-apache
  ports:
     - "80:80"
  volumes:
   - ./client:/var/www/html

#############################
# Database
#############################
database:
  container_name: database
  domainname: database.dev
  hostname: database
  image: postgres:9.4
  restart: always
  environment:
    - POSTGRES_USER=postgres
    - POSTGRES_PASSWORD=root
    - POSTGRES_DB=dbdev
    - PG_TRUST_LOCALNET=true
  ports:
    - "5432:5432"
  volumes:
    - ./database/scripts:/docker-entrypoint-initdb.d # init scripts

你可以看到我正在为每个人分配一个 .dev 域名,这可以很好地从另一台机器(Docker 内部网络)中查看一台机器,例如我正在 ping [=15] =] 来自 client.dev 的 CLI:

    root@client:/var/www/html# ping server.dev
    PING server.dev (127.0.53.53): 56 data bytes
    64 bytes from 127.0.53.53: icmp_seq=0 ttl=64 time=0.036 ms

这在内部运行良好,但在我的主机 OS 网络上运行不佳。

为方便起见,我想在我的本地网络中分配域,而不是 Docker 容器网络,这样我就可以在浏览器 URL 上输入:client.dev 和加载 Docker 容器。

现在,我只能使用动态的Docker IP才能访问:

client: 192.168.99.100:80
server: 192.168.99.100:3000
database: 192.168.99.100:5432

是否有一种 automated/convenient 方法可以做到这一点而不需要我手动将 IP 添加到我的 /etc/hosts 文件中?

顺便说一句,如果有任何相关性,我会在 OSX 上。

谢谢!

编辑: 我发现这个 Github 问题似乎是相关的:https://github.com/docker/docker/issues/2335

据我了解,他们似乎说这是开箱即用的东西,他们建议使用外部工具,例如:

对吗?如果是这样,在我的特定情况下我应该选择哪一个?

好的,

所以自从 it seems that there is no native way to do this with Docker, I finally opted for this alternate solution 来自 Ryan Armstrong,这包括动态更新 /etc/hosts 文件。

我选择这个是因为它对我来说很方便,因为它可以用作脚本,而且我已经有了一个启动脚本,所以我可以将这个函数附加到其中。

The following example creates a hosts entry named docker.local which will resolve to your docker-machine IP:

update-docker-host(){
    # clear existing docker.local entry from /etc/hosts
    sudo sed -i '' '/[[:space:]]docker\.local$/d' /etc/hosts

    # get ip of running machine
    export DOCKER_IP="$(echo ${DOCKER_HOST} | grep -oE '[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}')"

    # update /etc/hosts with docker machine ip
    [[ -n $DOCKER_IP ]] && sudo /bin/bash -c "echo \"${DOCKER_IP}   docker.local\" >> /etc/hosts"
}

update-docker-host

当我通过启动脚本启动 Docker 机器时,这将在我的主机 OS 上自动添加或更新 /etc/hosts 行。

无论如何,正如我在研究过程中发现的那样,除了编辑hosts文件外,您还可以通过setting up a custom DNS server:

来解决这个问题

还在 Github 上找到了几个显然旨在解决这个问题的项目,虽然我没有尝试它们:

扩展@eduwass 自己的回答,这是我手动完成的(没有脚本)。

  1. 如问题中所述,在docker-compose.yml文件中定义domainname: myapp.devhostname: www
  2. 正常启动您的 Docker 个容器
  3. 运行 docker-compose exec client cat /etc/hosts 获取容器主机文件的输出(其中 client 是您的服务名称) (输出示例:172.18.0.6 www.myapp.dev
  4. 打开您的本地(主机)/etc/hosts 文件并添加该行:172.18.0.6 server.server.dev

如果您的 Docker 服务容器更改 IP 或做任何花哨的事情,您将需要一个更复杂的解决方案,但目前这只是满足我的简单需求。

为了为本地主机创建整个域,您可以使用 dnsmasq. In this case if you chose the domain .dev any subdomain will point to your container. But you have to know about problems.dev 区域

或者您可以使用 bash 脚本来启动您的 docker-compose,它在开始时会向 /etc/hosts 添加行,并且在您终止此进程后,此行将被删除

#!/usr/bin/env bash

sudo sed -i '1s;^;127.0.0.1    example.dev\n;' /etc/hosts

trap 'sudo sed -i "/example.dev/d" /etc/hosts' 2

docker-compose up

另一种解决方案是使用带有代理扩展的浏览器,通过代理容器发送请求,代理容器将知道将域解析到何处。如果您考虑使用 jwilder/nginx-proxy for production mode, then your issue can be easily solved with mitm-nginx-proxy-companion.

这是一个基于您的原始堆栈的示例:

version: '3.3'

services:

  server:
    build: ./server
    working_dir: /app
    volumes:
      - ./server:/app

  client:
    environment:
      - VIRTUAL_HOST: client.dev
    image: php:5.6-apache
    volumes:
    - ./client:/var/www/html

  database:
    image: postgres:9.4
    restart: always
    environment:
      - POSTGRES_USER=postgres
      - POSTGRES_PASSWORD=root
      - POSTGRES_DB=dbdev
      - PG_TRUST_LOCALNET=true
    volumes:
      - ./database/scripts:/docker-entrypoint-initdb.d # init scripts

  nginx-proxy:
    image: jwilder/nginx-proxy
    labels:
      - "mitmproxy.proxyVirtualHosts=true"
    volumes:
      - /var/run/docker.sock:/tmp/docker.sock:ro

  nginx-proxy-mitm:
    dns:
      - 127.0.0.1
    image: artemkloko/mitm-nginx-proxy-companion
    ports:
      - "8080:8080"
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock:ro
  • 运行 docker-compose up
  • 在浏览器中添加代理扩展,代理地址为127.0.0.1:8080
  • 访问http://client.dev

请求将遵循以下路线:

  • 在浏览器中访问本地开发域
  • 代理扩展将该请求转发到 mitm-nginx-proxy-companion 而不是“真实的”互联网
  • mitm-nginx-proxy-companion尝试通过同一容器内的dns服务器解析域名
    • 如果域不是“本地”域,它将请求转发到“真实”互联网
    • 但是如果域是“本地”域,它会将请求转发到 nginx-proxy
  • nginx-proxy 依次将请求转发到包含我们要访问的服务的适当容器

旁注:

  • links 已过时并被 Docker 网络
  • 取代
  • 您不需要将域名添加到 serverdatabase 容器。 client 将能够在 serverdatabase 域上访问它们,因为它们都在同一个网络中(类似于 link 之前所做的)
  • 您不需要在 serverdatabase 容器上使用 ports,因为它只转发要通过 127.0.0.1 使用的端口。 client 容器中的 PHP 只会对其他容器发出 "back-end" 请求,因为这些容器在同一网络中,您已经可以使用 database:5432 和 [=31 访问它们=]. server <-> database 连接也是如此。
  • 我是 mitm-nginx-proxy-companion
  • 的作者

我的 Bash 带别名的脚本没有 docker-machine 基于 http://cavaliercoder.com/blog/update-etc-hosts-for-docker-machine.html


#!/bin/bash

#alias
declare -A aliasArr
aliasArr[docker_name]="alias1,alias2"

# clear existing *.docker.local entries from /etc/hosts
sudo sed -i '/\.docker\.local$/d' /etc/hosts

# iterate over each machine
docker ps -a --format "{{.Names}}" \
| while read -r MACHINE; do

    MACHINE_IP="$(docker inspect --format='{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' ${MACHINE} 2>/dev/null)"
    
    if [[ ${aliasArr[$MACHINE]} ]]
    then
        DOMAIN_NAME=$(echo ${aliasArr[$MACHINE]} | tr "," "\n")
    else
        DOMAIN_NAME=( ${MACHINE} )
    fi

    for addr in $DOMAIN_NAME
    do
        echo "add ${MACHINE_IP} ${addr}.docker.local"
        [[ -n $MACHINE_IP ]] && sudo /bin/bash -c "echo \"${MACHINE_IP} ${addr}.docker.local\" >> /etc/hosts"
        export no_proxy=$no_proxy,$MACHINE_IP
    done
        
done