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