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
据我了解,他们似乎说这是开箱即用的东西,他们建议使用外部工具,例如:
- https://github.com/jpetazzo/pipework
- https://github.com/bnfinet/docker-dns
- https://github.com/gliderlabs/resolvable
对吗?如果是这样,在我的特定情况下我应该选择哪一个?
好的,
所以自从 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 自己的回答,这是我手动完成的(没有脚本)。
- 如问题中所述,在
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 或做任何花哨的事情,您将需要一个更复杂的解决方案,但目前这只是满足我的简单需求。
为了为本地主机创建整个域,您可以使用 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 网络 取代
- 您不需要将域名添加到
server
和 database
容器。 client
将能够在 server
和 database
域上访问它们,因为它们都在同一个网络中(类似于 link
之前所做的)
- 您不需要在
server
和 database
容器上使用 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
初学者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
据我了解,他们似乎说这是开箱即用的东西,他们建议使用外部工具,例如:
- https://github.com/jpetazzo/pipework
- https://github.com/bnfinet/docker-dns
- https://github.com/gliderlabs/resolvable
对吗?如果是这样,在我的特定情况下我应该选择哪一个?
好的,
所以自从 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 自己的回答,这是我手动完成的(没有脚本)。
- 如问题中所述,在
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 或做任何花哨的事情,您将需要一个更复杂的解决方案,但目前这只是满足我的简单需求。
为了为本地主机创建整个域,您可以使用 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 网络 取代
- 您不需要将域名添加到
server
和database
容器。client
将能够在server
和database
域上访问它们,因为它们都在同一个网络中(类似于link
之前所做的) - 您不需要在
server
和database
容器上使用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