Docker容器的本地主机名

时间:2016-03-22 10:31:53

标签: docker docker-compose

初学者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内部网络),例如这里我正在{{1} ping server.dev CLI:

client.dev

这在内部效果很好,但在主机操作系统网络上却不行。

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

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

    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

是否有自动/方便的方法来执行此操作,而不涉及我手动将IP添加到我的/ etc / hosts文件中?

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

谢谢!

修改:我发现这个似乎有关的Github问题:https://github.com/docker/docker/issues/2335

据我了解,他们似乎表示这是一种不可用的东西,他们建议使用外部工具:

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

5 个答案:

答案 0 :(得分:21)

行,

所以自it seems that there is no native way to do this with Docker以来,我终于选择了来自Ryan Armstrong的alternate solution,其中包括动态更新/etc/hosts文件。

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

  

以下示例创建一个名为docker.local的主机条目   将解析你的码头机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机器时,这将自动添加或更新主机操作系统上的/etc/hosts行。

无论如何,正如我在研究期间发现的那样,除了编辑主机文件外,你还可以通过setting up a custom DNS server来解决这个问题:

在Github上也找到了几个项目,显然是为了解决这个问题,虽然我没有尝试过:

答案 1 :(得分:10)

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

  1. 如问题中所述,在domainname: myapp.dev文件中定义hostname: wwwdocker-compose.yml
  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
  5. 如果你的Docker服务容器改变IP或做任何想象力,你会想要一个更复杂的解决方案,但这对我目前的简单需求是有效的。

答案 2 :(得分:1)

另一种解决方案是使用具有代理扩展名的浏览器通过代理容器发送请求,代理容器将知道将域解析到的位置。如果您考虑将jwilder/nginx-proxy用于生产模式,那么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之前所做的事情)
  • 您不需要在portsserver容器上使用database,因为它只转发要通过127.0.0.1使用的端口。 client容器中的PHP仅会对其他容器执行“后端”请求,并且由于这些容器位于同一网络中,因此您已经可以使用database:5432server:3000访问它们。 server <-> database连接也是如此。
  • 我是mitm-nginx-proxy-companion
  • 的作者

答案 3 :(得分:0)

为了为localhost创建整个域,您可以使用dnsmasq。在这种情况下,如果您选择域 .dev ,则任何子域都将指向您的容器。但您必须通过 .dev 区域

了解problems

或者您可以使用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

答案 4 :(得分:0)

我的 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