将虚拟主机分配给Docker端口


83

我设置了一个通配符DNS,以便对自定义域(* .foo)的所有Web请求都映射到Docker主机的IP地址。如果我有多个运行Apache(或Nginx)实例的容器,则每个容器会将Apache端口(80)映射到某个外部入站端口。

我想做的是向容器-1.foo发送请求,该容器已经通过我的自定义DNS服务器映射到正确的(Docker主机的)IP地址,但是将默认端口80请求代理到正确的外部Docker端口,以便来自指定容器的正确Apache实例能够基于自定义域进行响应。同样,container-2.foo将代理第二个容器的apache,依此类推。

是否有一个预先构建的解决方案,是在Docker主机上运行Nginx代理的最佳选择,还是我应该编写一个具有管理Docker容器潜力的node.js代理(通过Web启动/停止/重新启动) ), 要么...?我有什么选择可以使使用Docker容器更像是自然事件,而不是带有多余端口和容器摆弄的东西?


我也有这个问题-据我所知,在Docker容器中运行每个应用程序,然后使用nginx服务器(也许在它自己的容器中)在主机上进行路由是做到这一点的方法。我想知道我应该独立运行应用程序服务器(即公开php-fpm,puma等服务器)还是包括一个(毫无意义的)nginx实例。
罗斯,

看看github.com/dotcloud/hipache,它是可通过redis配置的反向代理。
ZeissS 2013年

Answers:


81

这个答案可能有点晚,但是您需要的是一个自动反向代理。为此,我使用了两种解决方案:

  • jwilder / nginx代理
  • 特拉菲克

随着时间的推移,我更喜欢使用Traefik。主要是因为它已被很好地记录和维护,并且具有更多功能(具有不同策略和优先级的负载平衡,运行状况检查,断路器,带有ACME / Let's Encrypt的自动SSL证书等)。


使用jwilder / nginx-proxy

当运行Docker容器Jason Wilder的nginx-proxy Docker映像时,您将设置一个nginx服务器作为其他容器的反向代理,而无需维护任何配置。

只需使用VIRTUAL_HOST环境变量运行其他容器,nginx-proxy就会发现它们的ip:port并为您更新nginx配置。

假设您的DNS已设置为*.test.local映射到Docker主机的IP地址,然后只需启动以下容器即可运行快速演示:

# start the reverse proxy
docker run -d -p 80:80 -v /var/run/docker.sock:/tmp/docker.sock jwilder/nginx-proxy

# start a first container for http://tutum.test.local
docker run -d -e "VIRTUAL_HOST=tutum.test.local" tutum/hello-world

# start a second container for http://deis.test.local
docker run -d -e "VIRTUAL_HOST=deis.test.local" deis/helloworld

使用Traefik

运行Traefik容器时,您将获得一个反向代理服务器设置,该服务器将根据在容器上找到的docker标签重新配置其转发规则。

假设您的DNS已设置为*.test.local映射到Docker主机的IP地址,然后只需启动以下容器即可运行快速演示:

# start the reverse proxy
docker run --rm -it -p 80:80 -v /var/run/docker.sock:/var/run/docker.sock traefik:1.7 --docker

# start a first container for http://tutum.test.local
docker run -d -l "traefik.frontend.rule=Host:tutum.test.local" tutum/hello-world

# start a second container for http://deis.test.local
docker run -d -l "traefik.frontend.rule=Host:deis.test.local" deis/helloworld

-v /var/run/docker.sock:/tmp/docker.sock这是危险的解决方案吗?此Nginx代理可以访问Docker主机守护程序的容器吗?这可能是安全漏洞吗?
Mikl 2014年

可能的。另请注意,不共享/var/run/docker.sock并不表示不能从容器中利用Docker主机。Docker安全性本身就是一个主题。
Thomasleveil 2014年

是否存在任何已知的安全问题?当您可以从容器访问Docker主机时。
Mikl 2014年

过去存在漏洞利用,现在已解决此问题,但将来可能会发现新的漏洞利用。Docker并不是要增加安全性,而是要简化部署
Thomasleveil 2014年

5
您还可以分别运行nginx-proxy和docker-gen,以便将docker套接字未安装在nginx容器上。
杰森·怀尔德2014年

42

这里有两个可能的答案:(1)直接使用Docker设置端口并使用Nginx / Apache代理虚拟主机,或(2)使用Dokku为您管理端口和虚拟主机(这是我学会的方法1)。

方法1a(使用docker直接分配端口)

步骤1:在主机上设置nginx.conf或Apache,并分配所需的端口号。在主机上运行的此Web服务器将执行vhost代理。关于Docker,这没有什么特别的-它是正常的vhost托管。接下来是特殊部分,即步骤2,使Docker使用正确的主机端口号。

第2步:使用以下命令强制在Docker中分配端口号:“ -p”设置Docker的端口映射,“-e”设置Docker中的自定义环境变量,如下所示:

port=12345 # <-- the vhost port setting used in nginx/apache
IMAGE=myapps/container-1
id=$(docker run -d -p :$port -e PORT=$port $IMAGE)
# -p :$port will establish a mapping of 12345->12345 from outside docker to
# inside of docker.
# Then, the application must observe the PORT environment variable
# to launch itself on that port; This is set by -e PORT=$port.

# Additional goodies:
echo $id # <-- the running id of your container
echo $id > /app/files/CONTAINER # <-- remember Docker id for this instance
docker ps # <-- check that the app is running
docker logs $id # <-- look at the output of the running instance
docker kill $id # <-- to kill the app

方法1b硬编码的应用程序端口

...如果您的应用程序使用硬编码端口,例如端口5000(即无法通过PORT环境变量配置,如方法1a),则可以通过Docker进行硬编码,如下所示:

publicPort=12345
id=$(docker run -d -p $publicPort:5000 $IMAGE)
# -p $publicPort:5000 will map port 12345 outside of Docker to port 5000 inside
# of Docker. Therefore, nginx/apache must be configured to vhost proxy to 12345,
# and the application within Docker must be listening on 5000.

方法2(让Dokku找出端口)

目前,Dokku是管理Docker虚拟主机的一个不错的选择。即将出现的选择可能是使用Flynn,但是截至目前,Flynn才刚刚起步,还没有准备好。因此,我们现在开始使用Dokku:在遵循Dokku安装说明之后,对于单个域,通过创建“ VHOST”文件来启用虚拟主机:

echo yourdomain.com > /home/git/VHOST
# in your case: echo foo > /home/git/VHOST

现在,当通过SSH将应用程序推送到Dokku时(请参阅Dokku文档以了解如何执行此操作),Dokku将查看VHOST文件,并针对推送的特定应用程序(假设您推送了“ container-1”),它将生成以下文件:

/home/git/container-1/nginx.conf

它将具有以下内容:

upstream container-1 { server 127.0.0.1:49162; }
server {
  listen      80;
  server_name container-1.yourdomain.com;
  location    / {
    proxy_pass  http://container-1;
    proxy_http_version 1.1;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection "upgrade";
    proxy_set_header Host $http_host;
    proxy_set_header X-Forwarded-For $remote_addr;
  }
}

重新启动服务器后,Dokku将确保Docker使用映射到其最初部署的端口(此处为49162)的端口启动应用程序,而不是随机分配其他端口。为了实现此确定性分配,Dokku将最初分配的端口保存到其中,/home/git/container-1/PORT并在下次启动时将PORT环境设置为此值,并且还将Docker的端口分配映射为主机端和应用程序端的该端口。这与第一次启动相反,第一次启动时,Dokku将进行设置PORT=5000,然后找出在VPS侧上Dokku映射到应用程序侧5000的任何随机端口。它是可以解决的(将来甚至可能会改变),但是可以!

在后台,VHOST的工作方式是:通过SSH对应用程序进行git push时,Dokku将执行live中的钩子/var/lib/dokku/plugins/nginx-vhosts。这些挂钩也位于此处的Dokku源代码中,它们负责nginx.conf使用正确的vhost设置写入文件。如果您没有此目录/var/lib/dokku,请尝试运行dokku plugins-install


3

使用docker,您希望内部ip保持正常(例如80)并弄清楚如何连接随机端口。

处理它们的一种方法是使用反向代理(例如,头痛)。将您的dns指向它,然后您可以在容器上下时重新配置代理。看看http://txt.fliglio.com/2013/09/protyping-web-stuff-with-docker/看看它如何工作。

如果您正在寻找更强大的功能,则可能需要看看“服务发现”。(通过docker了解服务发现:http : //txt.fliglio.com/2013/12/service-discovery-with-docker-docker-links-and-beyond/

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.