简体   繁体   English

将虚拟主机分配给 Docker 端口

[英]Assigning vhosts to Docker ports

I have a wildcard DNS set up so that all web requests to a custom domain (*.foo) map to the IP address of the Docker host.我设置了通配符 DNS,以便对自定义域 (*.foo) 的所有 Web 请求都映射到 Docker 主机的 IP 地址。 If I have multiple containers running Apache (or Nginx) instances, each container maps the Apache port (80) to some external inbound port.如果我有多个容器运行 Apache(或 Nginx)实例,每个容器都会将 Apache 端口 (80) 映射到某个外部入站端口。

What I would like to do is make a request to container-1.foo, which is already mapped to the correct IP address (of the Docker host) via my custom DNS server, but proxy the default port 80 request to the correct Docker external port such that the correct Apache instance from the specified container is able to respond based on the custom domain.我想要做的是向 container-1.foo 发出请求,该请求已通过我的自定义 DNS 服务器映射到正确的 IP 地址(Docker 主机的),但将默认端口 80 请求代理到正确的 Docker 外部端口,以便指定容器中的正确 Apache 实例能够基于自定义域进行响应。 Likewise, container-2.foo would proxy to a second container's apache, and so on.同样,container-2.foo 将代理到第二个容器的 apache,依此类推。

Is there a pre-built solution for this, is my best bet to run an Nginx proxy on the Docker host, or should I write up a node.js proxy with the potential to manage Docker containers (start/stop/reuild via the web), or...?是否有一个预先构建的解决方案,是我在 Docker 主机上运行 Nginx 代理的最佳选择,还是我应该编写一个具有管理 Docker 容器潜力的 node.js 代理(通过 Web 启动/停止/reuild ), 要么...? What options do I have that would make using the Docker containers more like a natural event and not something with extraneous ports and container juggling?我有什么选择可以使使用 Docker 容器更像是一个自然事件,而不是带有无关端口和容器杂耍的东西?

This answer might be a bit late, but what you need is an automatic reverse proxy.这个答案可能有点晚了,但您需要的是一个自动反向代理。 I have used two solutions for that:我为此使用了两种解决方案:

  • jwilder/nginx-proxy jwilder/nginx 代理
  • Traefik特拉菲克

With time, my preference is to use Traefik.随着时间的推移,我更喜欢使用 Traefik。 Mostly because it is well documented and maintained, and comes with more features (load balancing with different strategies and priorities, healthchecks, circuit breakers, automatic SSL certificates with ACME/Let's Encrypt, ...).主要是因为它有良好的文档记录和维护,并且具有更多功能(具有不同策略和优先级的负载平衡、健康检查、断路器、带有 ACME/Let's Encrypt 的自动 SSL 证书,......)。


Using jwilder/nginx-proxy使用 jwilder/nginx-proxy

When running a Docker container Jason Wilder's nginx-proxy Docker image , you get a nginx server set up as a reverse proxy for your other containers with no config to maintain.运行 Docker 容器Jason Wilder 的 nginx-proxy Docker 镜像时,您将获得一个 nginx 服务器,作为其他容器的反向代理,无需维护配置。

Just run your other containers with the VIRTUAL_HOST environment variable and nginx-proxy will discover their ip:port and update the nginx config for you.只需使用VIRTUAL_HOST环境变量运行其他容器,nginx-proxy 就会发现它们的 ip:port 并为您更新 nginx 配置。

Let say your DNS is set up so that *.test.local maps to the IP address of your Docker host, then just start the following containers to get a quick demo running:假设您的 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

Using Traefik使用 Traefik

When running a Traefik container, you get a reverse proxy server set up which will reconfigure its forwarding rules given docker labels found on your containers.运行Traefik容器时,您会设置一个反向代理服务器,该服务器将根据容器上的docker标签重新配置其转发规则。

Let say your DNS is set up so that *.test.local maps to the IP address of your Docker host, then just start the following containers to get a quick demo running:假设您的 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

Here are two possible answers: (1) setup ports directly with Docker and use Nginx/Apache to proxy the vhosts, or (2) use Dokku to manage ports and vhosts for you (which is how I learned to do Method 1).这里有两个可能的答案:(1) 直接使用 Docker 设置端口并使用 Nginx/Apache 来代理虚拟主机,或者 (2) 使用Dokku为您管理端口和虚拟主机(这是我学会的方法 1)。

Method 1a (directly assign ports with docker)方法1a(直接用docker分配端口)

Step 1: Setup nginx.conf or Apache on the host, with the desired port number assignments.第 1 步:在主机上设置 nginx.conf 或 Apache,并分配所需的端口号。 This web server, running on the host, will do the vhost proxying.这个在主机上运行的 Web 服务器将执行 vhost 代理。 There's nothing special about this with regard to Docker - it is normal vhost hosting.关于 Docker,这没有什么特别之处——它是普通的虚拟主机托管。 The special part comes next, in Step 2, to make Docker use the correct host port number.接下来是特殊部分,在第 2 步中,使 Docker 使用正确的主机端口号。

Step 2: Force port number assignments in Docker with "-p" to set Docker's port mappings, and "-e" to set custom environment variables within Docker, as follows:第二步:在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

Method 1b Hard-coded application port方法 1b 硬编码应用程序端口

...if you're application uses a hardcoded port, for example port 5000 (ie cannot be configured via PORT environment variable, as in Method 1a), then it can be hardcoded through Docker like this: ...如果您的应用程序使用硬编码端口,例如端口 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.

Method 2 (let Dokku figure out the ports)方法二(让Dokku算出端口)

At the moment, a pretty good option for managing Docker vhosts is Dokku .目前,管理 Docker 虚拟主机的一个不错的选择是Dokku An upcoming option may be to use Flynn , but as of right now Flynn is just getting started and not quite ready.一个即将到来的选择可能是使用Flynn ,但截至目前,Flynn 才刚刚开始,还没有完全准备好。 Therefore we go with Dokku for now: After following the Dokku install instructions, for a single domain, enable vhosts by creating the "VHOST" file:因此,我们暂时使用 Dokku:按照 Dokku 安装说明进行操作后,对于单个域,通过创建“VHOST”文件启用虚拟主机:

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

Now, when an app is pushed via SSH to Dokku (see Dokku docs for how to do this), Dokku will look at the VHOST file and for the particular app pushed (let's say you pushed "container-1"), it will generate the following file:现在,当应用通过 SSH 推送到 Dokku 时(请参阅 Dokku 文档了解如何执行此操作),Dokku 将查看 VHOST 文件并针对推送的特定应用(假设您推送“container-1”),它会生成以下文件:

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

And it will have the following contents:它将具有以下内容:

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;
  }
}

When the server is rebooted, Dokku will ensure that Docker starts the application with the port mapped to its initially deployed port (49162 here), rather than getting assigned randomly another port.当服务器重新启动时,Dokku 将确保 Docker 使用映射到其初始部署端口(此处为 49162)的端口启动应用程序,而不是随机分配另一个端口。 To achieve this deterministic assignment, Dokku saves the initially assigned port into /home/git/container-1/PORT and on the next launch it sets the PORT environment to this value, and also maps Docker's port assignments to be this port on both the host-side and the app-side.为了实现这种确定性分配,Dokku 将最初分配的端口保存到/home/git/container-1/PORT并在下次启动时将PORT环境设置为此值,并将 Docker 的端口分配映射到主机端和应用端。 This is opposed to the first launch, when Dokku will set PORT=5000 and then figure out whatever random port Dokku maps on the VPS side to 5000 on the app side.这与第一次启动相反,当 Dokku 将设置PORT=5000 ,然后在应用程序端计算 Dokku 在 VPS 端映射到 5000 的任何随机端口。 It's round about (and might even change in the future), but it works!它是圆形的(甚至可能在未来改变),但它有效!

The way VHOST works, under the hood, is: upon doing a git push of the app via SSH, Dokku will execute hooks that live in /var/lib/dokku/plugins/nginx-vhosts . VHOST 的工作原理是:在通过 SSH 对应用程序执行 git push 时,Dokku 将执行/var/lib/dokku/plugins/nginx-vhosts钩子。 These hooks are also located in the Dokku source code here and are responsible for writing the nginx.conf files with the correct vhost settings.这些钩子也位于此处的 Dokku 源代码中,负责使用正确的 vhost 设置编写nginx.conf文件。 If you don't have this directory under /var/lib/dokku , then try running dokku plugins-install .如果/var/lib/dokku下没有此目录,请尝试运行dokku plugins-install

With docker, you want the internal ips to remain normal (eg 80) and figure out how to wire up the random ports.使用 docker,您希望内部 ips 保持正常(例如 80)并弄清楚如何连接随机端口。

One way to handle them, is with a reverse proxy like hipache.处理它们的一种方法是使用像 hipache 这样的反向代理。 Point your dns at it, and then you can reconfigure the proxy as your containers come up and down.将您的 dns 指向它,然后您可以在容器出现和关闭时重新配置代理。 Take a look athttp://txt.fliglio.com/2013/09/protyping-web-stuff-with-docker/ to see how this could work.看看http://txt.fliglio.com/2013/09/protyping-web-stuff-with-docker/看看它是如何工作的。

If you're looking for something more robust, you may want to take a look at "service discovery."如果您正在寻找更强大的东西,您可能需要查看“服务发现”。 (a look at service discovery with docker: http://txt.fliglio.com/2013/12/service-discovery-with-docker-docker-links-and-beyond/ ) (使用 docker 进行服务发现: http : //txt.fliglio.com/2013/12/service-discovery-with-docker-docker-links-and-beyond/

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM