在网上,我找到了很多关于使用 Nginx/Confd(或 Haproxy 或 Vulcand)代理到同一主机上运行的不同 Docker 容器的教程。然而,我需要做的是不同的。以下是我的基础设施概述:
- 一个有 5 个节点的在线 CoreOS 集群,所有节点都运行 etcd
- 在集群的每个节点上都使用 fleet 启动不同的 Docker 容器(运行 WordPress 应用程序的 Nginx 网络服务器),无需暴露端口并在 etcd 上写入它们的 ips(使用 docker inspect 获取的 Docker ip)。
- 如果某个节点发生故障,我的服务将自动转移到另一个可用节点
现在,我需要做的是,假设有一个 Nginx 代理,根据 vhost 将我的流量路由到各种容器。以下是示例:
Nginx(使用公共 IP)接收请求xxx.domain.com
--> node-1
-->container
使用自动分配的 IP(监听端口 80)
Nginx(使用公共 IP)接收请求yyy.domain.com
--> node-2
-->container
使用自动分配的 IP(监听端口 80)
这是我的问题:
- 我的设想正确吗?我的想法有误吗?
- 我的 Nginx 代理必须位于 CoreOS 集群之外?还是必须在每个 CoreOS 节点上运行它?
- 我如何实现此配置?最好的方法是什么?
先感谢您!
答案1
您需要某种类型的服务发现,以便 nginx 能够“找到”节点上运行的容器。您可以在容器启动时将记录写入 etcd,并在退出时删除,然后让 nginx 检查这些记录。
对于移动服务,您可以查看车队以进行简单的调度。
答案2
我不知道我是否理解正确。但我的做法如下:
在集群外部放置一个负载均衡器(HAProxy、Nginx、Amazon ELB(如果您使用 EC2))来路由集群内部的每个流量。
在里面你可以尝试 Gogeta: https://github.com/arkenio/gogeta
它是一个全局运行(在每个节点上)的反向代理,并根据 etcd 中的域条目将流量路由到特定的容器。然后,您可以设置您的服务文件,向 gogeta 监控的 etcd 添加和删除它们的存在。
ExecStart=<do something>
ExecStartPost=/usr/bin/etcdctl set /services/<your_service>/%i/location '{\"host\": "%H", \"port\": <your containers exposed port>}'
ExecStop=/usr/bin/docker stop <your service>
ExecStopPost=/usr/bin/etcdctl rm --recursive /services/<your_service>/%i
它工作正常,并使用轮询策略平衡请求负载。不过我提交了一个问题https://github.com/arkenio/gogeta/issues/10
这对你有帮助吗?
答案3
您可以使用 nginx、etcd 和 confd 三者来完成此操作。有一篇很棒的博客文章,标题为“使用 CoreOS、confd 和 nginx 进行负载平衡“引导您运行三个容器。
- 您需要一个共享的“数据”容器,您可以在其中存储动态生成的 nginx 配置
- 你需要一个运行的容器confd,它将读取来自etcd并为您动态生成 nginx 配置(这保存在共享“数据”容器的卷中)
- 最后,您将需要 nginx,它仅使用共享的“数据”卷进行配置。
关键是让每个 HTTP 后端通过 etcd 宣布自己,然后 confd 将获取更改并动态重新配置 nginx。这个过程与 @Julian 在上一个回答中提到的非常接近:
ExecStart=<do something>
ExecStartPost=/usr/bin/etcdctl set /services/<your_service>/%i/location '{\"host\": "%H", \"port\": <your containers exposed port>}'
ExecStop=/usr/bin/docker stop <your service>
ExecStopPost=/usr/bin/etcdctl rm --recursive /services/<your_service>/%i
查看confd 模板文档欲了解更多示例,但您将获得大致如下的内容:
{{range $dir := lsdir "/services/web"}}
upstream {{base $dir}} {
{{$custdir := printf "/services/web/%s/*" $dir}}{{range gets $custdir}}
server {{$data := json .Value}}{{$data.IP}}:80;
{{end}}
}
server {
server_name {{base $dir}}.example.com;
location / {
proxy_pass {{base $dir}};
}
}
{{end}}
需要注意的是,您只需要运行其中一个“三重奏”,除非您想要更高可用性的设置,在这种情况下您将需要两个或更多。当您使用 HA 时,您可能希望在它们前面放置一个 ELB 实例。