如何使用大使模式在CoreOS上动态配置服务
介绍
Docker 链接功能启用了一种动态配置容器之间网络连接的方法,称为 大使模式 。 大使模式促进了 provider 和 consumer 容器之间的服务可移植性。 在 CoreOS 中,可以利用 etcd
来实现分布在集群中多台机器上的大使模式。
在本教程中,我们将演示如何部署一个注册到 etcd
的 Apache HTTP 容器。 Apache 容器将代表我们的提供者容器,我们将使用 HAProxy 作为我们的消费者容器。 我们将使用来自 这个 CoreOS 大使演示 的 Docker 镜像作为我们的大使容器,我们将从头开始创建我们自己的 Apache 和 HAProxy Docker 镜像。
先决条件
您必须在 DigitalOcean 上有一个至少由三台机器组成的 CoreOS 集群。 以下是如何设置的教程:如何在 CoreOS 集群上创建和运行服务
您必须具备使用 CoreOS、etcdctl、fleetctl、设置服务和运行 Docker 容器的基本知识。 这些主题在 CoreOS 入门教程系列 中有介绍。
您必须拥有 Docker Hub 帐户或私有 Docker 注册表。 这在 How To Create and Run a Service on a CoreOS Cluster 教程的 Creating the Docker Container 部分中有介绍。
有关大使模式如何工作的完整详细信息,请查看来自 Docker 的通过大使容器 链接的 链接。 另外,请查看 CoreOS 博客上发布的这篇文章:Dynamic Docker links with an Ambassador by etcd。
我们的目标
在本教程结束时,我们将在两台机器上运行六个容器。 本节将简要介绍每一项,以及如何将它们组合在一起。 这种确切的设置对大多数人来说没有用,但可以对其进行调整以允许对您自己的服务进行动态服务发现。
机器A
机器 A 将运行提供者容器,即 Apache Web 服务器,以及其他几个支持它的容器。
- Apache Web 服务器:我们将从头开始创建的基本 Apache 容器,类似于 如何在 CoreOS 集群上创建和运行服务 教程中描述的容器。 这是我们的制作人
- polvi/docker-register:一个注册容器,它将通过Docker API读取Apache的IP地址和端口并将其写入
etcd
- polvi/simple-amb:一个简单的大使容器,将流量转发到指定位置。 在这种情况下,我们会将流量转发到
etcd
并将其链接到docker-register
容器,以提供该容器对etcd
的访问。 在CoreOS中,由于etcd
的位置是静态的,如果将docker-register
修改为直接访问etcd
可以去掉
机器 B
机器 B 是将运行消费者容器的 CoreOS 机器,即 HAProxy,以及主要的大使容器。
- HAProxy Reverse Proxy:一个基本的 HAProxy 容器,我们将从头开始创建,它将代表我们的 consumer。 这将用于证明大使设置有效
- polvi/dynamic-etcd-amb:主大使容器。 一个动态代理,它监视提供者容器的 IP 地址和端口的指定
etcd
键,并将所有流量路由到提供者容器。 可以更新key的值,代理会自己更新 - polvi/simple-amb:在另一台机器上使用的相同容器,但用于将
dynamic-etcd-amb
链接到etcd
创建 Apache Docker 映像
SSH 到您的一台 CoreOS 机器,并传递您的 SSH 代理(替换为公共 IP 地址):
ssh -A core@coreos-1_public_IP
然后登录 Docker:
docker login
出现提示时输入您的 用户名 、密码和电子邮件地址。
接下来,创建一个新目录来将您的 Apache Dockerfile 写入:
mkdir -p ambassador/apache
现在切换到目录并打开Dockerfile
进行编辑:
cd ambassador/apache vi Dockerfile
基于 How To Create and Run a Service on a CoreOS Cluster 中的 Apache 容器设置,我们可以创建以下 Dockerfile(用您自己的 Docker 用户名替换 user_name
):
FROM ubuntu:14.04 MAINTAINER user_name RUN apt-get update && \ DEBIAN_FRONTEND=noninteractive apt-get -y install apache2 && \ echo "<h1>Running from Docker on CoreOS</h1>" > /var/www/html/index.html EXPOSE 80 ENTRYPOINT ["/usr/sbin/apache2ctl"] CMD ["-D", "FOREGROUND"]
保存并退出。
现在我们有了一个安装 Apache 并用基本消息替换 index.html 的 Dockerfile,构建您的 Docker 映像并使用以下命令将其命名为“apache”(替换您自己的用户名):
docker build --tag="user_name/apache" .
现在,为了让您的其他 CoreOS 机器可以使用该映像,使用以下命令将其 push
到您的 Docker 注册表:
docker push user_name/apache
现在您的 Apache 映像已经可以使用了。 让我们继续创建 HAProxy 映像。
创建 HAProxy Docker 映像
我们将基于 HAproxy Dockerfile 创建一个 HAProxy Docker 映像,用于可信的自动化 Docker 构建 。 我们将稍微修改提供的 haproxy.cfg
和 start.bash
文件。
在 ambassador
目录中,使用 git
克隆 HAProxy 存储库:
cd ~/ambassador git clone https://github.com/dockerfile/haproxy.git
这将创建一个 haproxy
目录,其中包含 Dockerfile
、haproxy.cfg
和 start.bash
文件。
Dockerfile 基本上安装了 HAProxy 并暴露了 80 和 443 端口,所以我们可以保持原样。
我们将修改 haproxy.cfg
文件以添加 frontend
和 backend
。 打开haproxy.cfg
进行编辑:
cd haproxy vi haproxy.cfg
现在找到并删除以下行:
listen stats :80 stats enable stats uri /
然后在文件末尾添加以下行:
frontend www-http bind :80 default_backend www-backend backend www-backend server apache private_ipv4:80 check
这将 HAProxy 配置为侦听端口 80 并将传入流量转发到由单个服务器组成的 www-backend
。 当 HAProxy 容器启动时,我们将使用 start.bash
脚本将 private_ipv4
替换为该容器将在其上运行的 CoreOS 机器的私有 IP 地址。 我们的动态大使容器(HAProxy 会将流量转发到 Apache 容器)将在同一台机器上运行。
打开start.bash
文件进行编辑:
vi start.bash
在文件的底部,您将找到将在此容器中启动 HAProxy 进程的行。 它看起来像这样:
haproxy -f /etc/haproxy/haproxy.cfg -p "$PIDFILE"
在此行的正上方,插入以下行:
# Set backend IP address to machine's private IP address PRIVATE_IPV4=$(curl -sw "\n" http://169.254.169.254/metadata/v1/interfaces/private/0/ipv4/address) sed -i -e "s/server apache private_ipv4:80 check/server apache ${PRIVATE_IPV4}:80 check/g" $HAPROXY/$CONFIG
保存并退出。 curl
命令将通过 DigitalOcean 元数据服务检索容器将在其上运行的机器的私有 IP 地址。 sed
命令将 haproxy.cfg
中的 private_ipv4
字符串替换为从元数据中检索到的实际 IP 地址。 该脚本从 HAProxy 容器内部运行,因此私有 IP 地址将在运行时配置。
现在我们已经准备好构建 HAProxy docker 镜像了。 使用以下命令构建您的 Docker 映像并将其命名为“haproxy”(替换您自己的用户名):
docker build --tag="user_name/haproxy" .
现在,为了让您的其他 CoreOS 机器可以使用该映像,使用以下命令将其 push
到您的 Docker 注册表:
docker push user_name/haproxy
您的 HAProxy 映像已准备好使用。 我们准备好编写我们的车队服务单元文件了!
车队服务单位文件
现在所有必需的 Docker 映像都可用于我们的 CoreOS 集群,让我们开始处理部署容器所需的文件。 因为我们使用的是 CoreOS 集群,所以我们可以从单个 CoreOS 机器创建和调度我们所有的队列服务单元文件。
我们将在之前创建的 ~/ambassador
目录中创建所有服务文件,因此现在切换到该目录:
cd ~/ambassador
阿帕奇服务
apache.service
单元将在 Host A 上运行。
我们将创建的第一个服务文件用于 Apache Web 服务器容器 user_name/apache
。 现在打开一个名为 apache.service
的文件进行编辑:
vi apache.service
添加以下行(在两个地方替换您的 Docker 用户名):
[Unit] Description=Apache web server service [Service] EnvironmentFile=/etc/environment ExecStartPre=-/usr/bin/docker kill %n ExecStartPre=-/usr/bin/docker rm %n ExecStartPre=/usr/bin/docker pull user_name/apache ExecStart=/usr/bin/docker run --rm --name %n -p ${COREOS_PRIVATE_IPV4}::80 user_name/apache ExecStop=/usr/bin/docker stop -t 3 %n
保存并退出。 这是一个相当简单的服务文件,它以前台模式启动 Apache。 特别值得注意的是,我们将容器内的端口 80 绑定到专用网络接口 (-p ${COREOS_PRIVATE_IPV4}::80
) 上的动态端口。
etcd-amb-apache.service
etcd-amb-apache.service
单元将在 Host A 上运行。
接下来,我们将要为我们的简单大使容器 (simple-amb
) 创建一个服务文件,该文件将允许 Apache 注册容器访问 etcd
。 现在打开一个名为 etcd-amb-apache.service
的文件:
vi etcd-amb-apache.service
添加以下行:
[Unit] Description=Simple Apache ambassador After=apache.service BindsTo=apache.service [Service] ExecStartPre=-/usr/bin/docker kill %n ExecStartPre=-/usr/bin/docker rm %n ExecStart=/usr/bin/docker run --rm --name %n polvi/simple-amb 172.17.42.1:4001 ExecStop=/usr/bin/docker stop -t 3 %n [X-Fleet] X-ConditionMachineOf=apache.service
保存并退出。
simple-amb
容器将它在端口 10000 上接收到的所有流量转发到它启动时提供的参数,即 172.17.42.1:4001
,即etcd
在CoreOS中的标准位置。
X-ConditionMachineOf=apache.service
告诉 Fleet 将其安排在与 Apache 容器相同的机器上,这很关键,因为 docker-register
容器使用它来注册 Apache 使用的 IP 地址和端口到 [X206X ]。
apache-docker-reg.service
apache-docker-reg.service
单元将在 Host A 上运行。
让我们为我们的容器创建服务文件,该文件将在 etcd
、docker-register
中注册 Apache 的 IP 地址和端口。 现在打开一个名为 apache-docker-reg.service
的文件:
vi apache-docker-reg.service
插入以下行:
[Unit] Description=Register Apache After=etcd-amb-apache.service BindsTo=etcd-amb-apache.service [Service] ExecStartPre=-/usr/bin/docker kill %n ExecStartPre=-/usr/bin/docker rm %n ExecStart=/usr/bin/docker run --link etcd-amb-apache.service:etcd -v /var/run/docker.sock:/var/run/docker.sock --rm polvi/docker-register apache.service 80 apache-A [X-Fleet] X-ConditionMachineOf=etcd-amb-apache.service
保存并退出。 以下是 docker run
命令值得注意的部分的细分:
--link etcd-amb-apache.service:etcd
将此容器链接到简单大使,它将用于将 Apache 的连接信息传递给etcd
-v /var/run/docker.sock:/var/run/docker.sock
允许此容器通过它将运行的机器的 Docker API 确定 Apache 绑定到的动态端口。apache.service 80 apache-A
将这些参数传递给容器。 前两个参数指定要查找的 docker 容器的名称和端口,第三个参数指定要写入的etcd
键的名称。 该容器启动后,会将apache.service
的动态端口和IP地址写入/services/apache-A/apache.service
键。
X-ConditionMachineOf=etcd-amb-apache.service
告诉 Fleet 将其安排在与简单大使容器相同的机器上,这很关键,因为它们与 Docker 链接链接,以便为注册容器提供查找 etcd
的方法。
etcd-amb-apache2.service
etcd-amb-apache2.service
单元将在 Host B 上运行。
为我们的第二个简单大使容器 (simple-amb
) 创建一个服务文件,该文件将允许动态大使容器访问 etcd
。 现在打开一个名为 etcd-amb-apache2.service
的文件:
vi etcd-amb-apache2.service
添加以下行:
[Unit] Description=Simple Apache ambassador 2 [Service] ExecStartPre=-/usr/bin/docker kill %n ExecStartPre=-/usr/bin/docker rm %n ExecStart=/usr/bin/docker run --rm --name %n polvi/simple-amb 172.17.42.1:4001 ExecStop=/usr/bin/docker stop -t 3 %n [X-Fleet] X-Conflicts=apache.service
保存并退出。
这与 etcd-amb-apache.service
几乎相同的服务文件,除了 X-Conflicts=apache.service
告诉 Fleet 将其安排在与 Apache 容器不同的机器上,它将用于将动态大使链接到 etcd
。
apache-dyn-amb.service
apache-dyn-amb.service
单元将在 Host B 上运行。
为我们的动态大使容器 (dynamic-etd-amb
) 创建一个服务文件,该文件将允许动态大使容器访问 etcd
。 现在打开一个名为 apache-dyn-amb.service
的文件:
vi apache-dyn-amb.service
添加以下行:
[Unit] Description=Dynamic ambassador for Apache After=etcd-amb-apache2.service BindsTo=etcd-amb-apache2.service [Service] EnvironmentFile=/etc/environment ExecStartPre=-/usr/bin/docker kill %n ExecStartPre=-/usr/bin/docker rm %n ExecStartPre=/usr/bin/docker pull polvi/dynamic-etcd-amb ExecStart=/usr/bin/docker run --link etcd-amb-apache2.service:etcd --rm --name %n -p ${COREOS_PRIVATE_IPV4}:80:80 polvi/dynamic-etcd-amb apache-A 80 ExecStop=/usr/bin/docker stop -t 3 %n [X-Fleet] X-ConditionMachineOf=etcd-amb-apache2.service
保存并退出。 以下是 docker run
命令值得注意的部分的细分:
--link etcd-amb-apache2.service:etcd
将此容器链接到第二个简单大使,它将用于从etcd
检索 Apache 的连接信息-p ${COREOS_PRIVATE_IPV4}:80:80
暴露容器上的 80 端口和机器的私有网络接口apache-A 80
是指定端口 80 流量的两个参数(即 专用网络接口上的端口 80)应代理到在etcd
中注册为apache-A
的服务
X-ConditionMachineOf=etcd-amb-apache2.service
告诉 Fleet 将其安排在与第二个简单大使容器相同的机器上,这很关键,因为它们与 Docker 链接链接,以便为动态大使容器提供查找 etcd
的方法。
haproxy.service
haproxy.service
单元将在 Host B 上运行。
为我们的 HAProxy 容器 (haproxy
) 创建一个服务文件,该文件将用于通过动态大使容器连接到 Apache 容器。 现在打开一个名为 haproxy.service
的文件:
vi haproxy.service
添加以下行(在两个地方替换您的 Docker 用户名):
[Unit] Description=HAProxy consumer [Service] EnvironmentFile=/etc/environment ExecStartPre=-/usr/bin/docker kill %n ExecStartPre=-/usr/bin/docker rm %n ExecStartPre=/usr/bin/docker pull user_name/haproxy ExecStart=/usr/bin/docker run --name %n -p ${COREOS_PUBLIC_IPV4}:80:80 user_name/haproxy ExecStop=/usr/bin/docker stop -t 3 %n [X-Fleet] X-ConditionMachineOf=apache-dyn-amb.service
保存并退出。 这是一个简单的服务文件,它启动 HAProxy 并在其主机的公共 IP 地址上公开端口 80。 请记住,后端服务器将在端口 80 上配置为主机的私有 IP 地址,这恰好是动态大使正在侦听代理到 Apache 服务的流量的地方。
X-ConditionMachineOf=apache-dyn-amb.service
告诉 Fleet 将其安排在与动态大使容器相同的机器上,这很重要,因为动态大使为 HAProxy 容器提供了到达 Apache 容器的路由。
随舰队部署
现在我们拥有了所有必要的车队服务文件,我们终于可以部署我们的大使设置了。 在包含所有服务文件的目录中,运行以下命令:
fleetctl start apache.service fleetctl start etcd-amb-apache.service fleetctl start apache-docker-reg.service fleetctl start etcd-amb-apache2.service fleetctl start apache-dyn-amb.service fleetctl start haproxy.service
您应该会看到消息说每个服务都已加载。 要检查您的舰队单位的状态,请运行以下命令:
fleetctl list-units
您应该会看到类似于以下内容的输出:
UNIT MACHINE ACTIVE SUB apache-docker-reg.service ceb3ead2.../10.132.233.107 active running apache-dyn-amb.service 3ce87ca7.../10.132.233.106 active running apache.service ceb3ead2.../10.132.233.107 active running etcd-amb-apache.service ceb3ead2.../10.132.233.107 active running etcd-amb-apache2.service 3ce87ca7.../10.132.233.106 active running haproxy.service 3ce87ca7.../10.132.233.106 active running
所有状态应为 active
和 running
。 另一件需要注意的是,“机器 A”单元应该在同一台机器上,而“机器 B”单元应该在不同的机器上——只需查看每个单元的 IP 地址即可确认这一点。
测试您的设置
确保 HAProxy 可以访问 Apache
因为我们没有指定 HAProxy 容器应该在特定的机器上运行,所以我们需要找到它在哪里运行。 一个简单的方法是使用 fleetctl ssh
命令:
fleetctl ssh haproxy.service
这会将您连接到运行 haproxy.service
容器的机器。 现在您可以使用 /etc/environment
文件获取运行 HAProxy 的 CoreOS 机器的公共 IP 地址:
. /etc/environment echo $COREOS_PUBLIC_IPV4
获取生成的 IP 地址并使用 Web 浏览器访问它。 您将看到以下图像:
请注意,您正在访问 HAProxy,而 HAProxy 正在通过动态大使代理访问 Apache。
现在您可以退出当前的 SSH 会话以返回原始 SSH 会话:
exit
测试故障转移
现在您已确认大使设置工作正常,让我们看看当提供程序服务 (apache.service
) 更改其 IP 地址和端口时会发生什么。
使用 fleetctl
连接到正在运行 apache.service
的机器:
fleetctl ssh apache.service
现在重新启动运行 Apache 的机器:
sudo reboot
注意: 如果 apache.service
正在您最初通过 SSH 连接的机器上运行,您将被断开连接。 如果是这种情况,只需通过 SSH 连接到同一 CoreOS 集群中的另一台机器。
现在等一下,检查哪些单元正在运行:
fleetctl list-units
根据您等待的时间,您可能会看到与“主机 A”相关的三个单元(apache.service
、etcd-amb-apache.service
和 apache-docker-reg.service
)正在重新启动或处于活动状态。 最终,它们都应该回到 active 状态。 一旦他们这样做了,请注意他们现在在与以前不同的机器上运行。
现在返回连接到 HAProxy 的 Web 浏览器,然后点击刷新。 您应该会看到与之前相同的测试页面,表明 HAProxy 仍然能够通过动态大使连接到 Apache!
结论
现在您已经设置了自己的大使模式,您应该能够将本教程中介绍的概念应用到您自己的服务中。 这是一种在运行时配置消费者服务的独特方式,它允许您轻松地在机器之间移动后端提供者服务。 在更现实的设置中,您可能会用一个或多个应用程序容器替换 Apache 服务,并且您可能会为 HAProxy 配置多个后端服务器(或使用完全不同的消费者服务)。