Docker容器的本地主机名

Docker容器的本地主机名,docker,docker-compose,Docker,Docker Compose,这里是初学者Docker问题 所以我有一个开发环境,在其中我运行一个模块化应用程序,它使用Docker Compose运行3个容器:服务器、客户端和数据库 docker compose.yml的如下所示: ############################# # Server ############################# server: container_name: server domainname: server.dev hostname: server

这里是初学者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内部网络)查看一台计算机,例如,这里我正在从
客户端.dev
的CLI ping
服务器.dev

    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
这在内部非常有效,但在我的主机操作系统网络上不起作用。

为了方便起见,我想在本地网络而不是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
是否有一种自动/方便的方法可以做到这一点,而不需要我手动将IP添加到/etc/hosts文件中

顺便说一句,如果有什么关系的话,我在OSX上

谢谢

编辑:我发现这个Github问题,似乎与此相关:

据我所知,他们似乎在说,这是一种在盒子外无法获得的东西,他们建议使用以下外部工具:

对吗?如果是这样,在我的特定场景中,我应该选择哪一个呢?

好的

因此,从那时起,我最终选择了Ryan Armstrong的方法,这包括动态更新
/etc/hosts
文件

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

下面的示例创建一个名为docker.local的主机条目,该条目 将解析为您的docker机器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

无论如何,正如我在研究中发现的,除了编辑主机文件外,您还可以通过以下方式解决此问题:

在Github上还发现了几个显然旨在解决此问题的项目,尽管我没有尝试:


根据@eduwass自己的答案,下面是我手动完成的操作(没有脚本)

  • 如问题中所述,在
    docker compose.yml
    文件中定义
    domainname:myapp.dev
    hostname:www
  • 像平常一样把你的Docker集装箱搬上来
  • 运行
    docker compose exec client cat/etc/hosts
    以获取容器主机文件的输出(其中
    client
    是您的服务名称) (输出示例:
    172.18.0.6 www.myapp.dev
  • 打开本地(主机)
    /etc/hosts
    文件并添加该行:
    172.18.0.6 server.server.dev

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

    为了使整个域成为您可以使用的本地主机。在这种情况下,如果选择域.dev,则任何子域都将指向您的容器。但是你必须知道如何使用.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
    

    另一种解决方案是使用带有代理扩展的浏览器,通过代理容器发送请求,该容器将知道将域解析到何处。如果您考虑使用生产模式,那么您的问题可以很容易地解决。 以下是基于原始堆栈的示例:

    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服务器解析域名
      • 如果域不是“本地”域,它会将请求转发到“真正的”internet
      • 但是如果域是“本地”域,它将把请求转发给
        nginx代理
    • nginx代理将请求转发到包含我们想要访问的服务的适当容器

    旁注:

    • 链接
      因过时而被删除,并被Docker networks取代
    • 您不需要将域名添加到
      服务器
      数据库
      容器中<代码>客户端
    将能够在
    服务器
    数据库
    域上访问它们,因为它们都在同一网络中(类似于
    链接
    以前所做的操作)
  • 您不需要在
    服务器
    数据库
    容器上使用
    端口
    ,因为它只转发通过
    127.0.0.1
    使用的端口。
    client
    容器中的PHP将只对其他容器执行“后端”请求,因为这些容器位于同一网络中,您已经可以使用
    数据库:5432
    服务器:3000
    访问它们。
    服务器数据库
    连接也是如此
  • 我是mitm nginx proxy companion的作者

  • 我的带别名的Bash脚本,不带docker机器 基于


    我从未使用过docker,但127.0.0.0/8范围内的IPv4地址被定义为环回。这将不允许机器外的任何通信。这不是一个很好的码头工人
    
    #!/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