如何使用大使模式在 CoreOS 上动态配置服务

介绍

Docker 链接功能允许在容器之间动态配置网络连接的方法,称为 _ambassador 模式。大使模式促进了 providerconsumer 容器之间的服务可移植性。

在本教程中,我们将演示如何部署与etcd注册的Apache HTTP容器。Apache容器将代表我们的供应商容器,我们将使用HAProxy作为我们的消费者容器。

前提条件

您必须在DigitalOcean上拥有至少由三台机器组成的CoreOS集群,以下是如何设置该集群的教程: 如何在CoreOS集群上创建和运行服务

您必须具备使用CoreOS、 etcdctl、 fleetctl、设置服务和运行Docker容器的基本知识,这些主题都涵盖在《开始使用CoreOS的教程》(https://www.digitalocean.com/community/tutorial_series/getting-started-with-coreos-2)中。

您必须拥有 Docker Hub 帐户或私人 Docker 注册表,这是在 CoreOS 集群上如何创建和运行服务的 Creating the Docker Container 部分中描述的。

有关大使模式的完整细节,请参阅 Docker 的 链接通过大使容器文章。

我们的目标

在本教程的结尾,我们将有六个集装箱运行在两个机器上。本节将提供一个简要的描述,每一个,以及他们将如何组合在一起。

机器 A

机器A将运行提供商容器,即Apache网页服务器,以及支持它的一对其他容器。

机器B

机器B是一个CoreOS机器,它将运行消费容器,即HAProxy和主要大使容器。

  • HAProxy Reverse Proxy:一个基本的HAProxy容器,我们将从头开始创建,它将代表我们的 consumer. 这将被用来证明大使设置工作
  • polvi/dynamic-etcd-amb:主要的大使容器. 一个动态代理,它会监视提供商容器的IP地址和端口的指定etcd密钥,并将所有流量路由到供应商容器。

创建 Apache Docker 图像

SSH 到您的 CoreOS 机器之一,并传递您的 SSH 代理(在公共 IP 地址中代替):

1ssh -A core@coreos-1_public_IP

然后进入Docker:

1docker login

提示时输入您的用户名、密码和电子邮件地址。

接下来,创建一个新的目录,将您的 Apache Dockerfile 编写到:

1mkdir -p ambassador/apache

现在转到目录并打开Dockerfile进行编辑:

1cd ambassador/apache
2vi Dockerfile

基于从 [CoreOS 集群上如何创建和运行服务] 的 Apache 容器设置(https://andsky.com/tech/tutorials/how-to-create-and-run-a-service-on-a-coreos-cluster#creating-the-docker-container),我们可以创建以下 Dockerfile(用自己的 Docker 用户名替换 user_name):

 1FROM ubuntu:14.04
 2MAINTAINER user_name
 3
 4RUN apt-get update && \
 5    DEBIAN_FRONTEND=noninteractive apt-get -y install apache2 && \
 6    echo "<h1>Running from Docker on CoreOS</h1>" > /var/www/html/index.html
 7
 8EXPOSE 80
 9
10ENTRYPOINT ["/usr/sbin/apache2ctl"]
11CMD ["-D", "FOREGROUND"]

保存和停止。

现在我们有一个 Dockerfile 安装了 Apache 并用基本消息代替 index.html,请创建您的 Docker 图像并用以下命令命名为apache(取代您的用户名):

1docker build --tag="user_name/apache" .

现在,要将图像提供给其他 CoreOS 机器,请用以下命令将其到您的 Docker 注册表:

1docker push user_name/apache

现在您的 Apache 图像已经准备好使用,让我们继续创建一个 HAProxy 图像。

创建 HAProxy Docker 图像

我们将基于 HAproxy Dockerfile for trusted automated Docker builds创建一个 HAProxy Docker 图像,我们将稍微修改提供的 haproxy.cfgstart.bash 文件。

大使目录中,使用git来克隆HAProxy存储库:

1cd ~/ambassador
2git clone https://github.com/dockerfile/haproxy.git

这将创建一个haproxy目录,包含Dockerfile,haproxy.cfgstart.bash文件。

Dockerfile 基本上安装了 HAProxy 并暴露了端口 80 和 443,所以我们可以把它留在原地。

我们将修改haproxy.cfg文件以添加一个前端后端

1cd haproxy
2vi haproxy.cfg

现在找到并删除以下行:

1listen stats :80
2  stats enable
3  stats uri /

然后在文件末尾添加以下行:

1frontend www-http
2        bind :80
3        default_backend www-backend
4
5backend www-backend
6        server apache private_ipv4:80 check

这样,HAProxy 就可以在端口 80 上聆听,然后将流量传送到由一个服务器组成的www-backend。我们将使用start.bash脚本来代替private_ipv4以此容器在启动HAProxy容器时运行的CoreOS机器的私人IP地址。

打开start.bash文件来编辑:

1vi start.bash

在文件的底部,你会发现一个行,将启动这个容器中的HAProxy过程。

1haproxy -f /etc/haproxy/haproxy.cfg -p "$PIDFILE"

直接在这个行之上,插入以下行:

1# Set backend IP address to machine's private IP address
2PRIVATE_IPV4=$(curl -sw "\n" http://169.254.169.254/metadata/v1/interfaces/private/0/ipv4/address)
3sed -i -e "s/server apache private_ipv4:80 check/server apache ${PRIVATE_IPV4}:80 check/g" $HAPROXY/$CONFIG

保存和退出. curl 命令会检索容器将通过 DigitalOcean Metadata 服务运行的机器的私人 IP 地址. sed 命令将 haproxy.cfg 中的private_ipv4 字符串替换为从 Metadata 获取的实际 IP 地址. 此脚本从 HAProxy 容器内部运行,因此在运行时将配置私人 IP 地址。

现在我们已经准备好构建HAProxy docker图像了,构建您的Docker图像,并用以下命令命名为haproxy(取代您的用户名):

1docker build --tag="user_name/haproxy" .

现在,要将图像提供给其他 CoreOS 机器,请用以下命令将其到您的 Docker 注册表:

1docker push user_name/haproxy

您的HAProxy图像已经准备好使用,我们准备好写我们的车队服务单元文件!

舰队服务单元文件

现在,所有所需的Docker图像都可用于我们的CoreOS集群,让我们开始处理部署我们的集装箱所需的文件。

我们将创建我们之前创建的~/ambassador目录中的所有服务文件,所以现在更改到该目录:

1cd ~/ambassador

apache.服务

apache.service单元将运行在 Host A 上。

我们将创建的第一个服务文件是为Apache网页服务器容器, user_name/apache. 打开名为 apache.service 的文件,现在可以编辑:

1vi apache.service

添加以下行(在两个地方取代您的 Docker 用户名):

 1[Unit]
 2Description=Apache web server service
 3
 4[Service]
 5EnvironmentFile=/etc/environment
 6ExecStartPre=-/usr/bin/docker kill %n
 7ExecStartPre=-/usr/bin/docker rm %n
 8ExecStartPre=/usr/bin/docker pull user_name/apache
 9ExecStart=/usr/bin/docker run --rm --name %n -p ${COREOS_PRIVATE_IPV4}::80 user_name/apache
10ExecStop=/usr/bin/docker stop -t 3 %n

这是一个相当简单的服务文件,在前台模式下启动Apache,特别注意的是,我们将容器内部的端口80绑定到私人网络接口上的动态端口(-p ${COREOS_PRIVATE_IPV4}::80)。

etcd-amb-apache.服务

etcd-amb-apache.service单元将运行在 Host A 上。

接下来,我们要为我们的简单大使容器(‘simple-amb’)创建一个服务文件,允许Apache注册容器访问‘etcd’。

1vi etcd-amb-apache.service

添加以下几行:

 1[Unit]
 2Description=Simple Apache ambassador
 3After=apache.service
 4BindsTo=apache.service
 5
 6[Service]
 7ExecStartPre=-/usr/bin/docker kill %n
 8ExecStartPre=-/usr/bin/docker rm %n
 9ExecStart=/usr/bin/docker run --rm --name %n polvi/simple-amb 172.17.42.1:4001
10ExecStop=/usr/bin/docker stop -t 3 %n
11
12[X-Fleet]
13X-ConditionMachineOf=apache.service

保存和退出。

Simple-amb容器将其在端口 10000 上接收的所有流量转移到启动时提供的参数,即172.17.42.1:4001,即etcd在CoreOS中的默认位置。

X-ConditionMachineOf=apache.service告诉车队在与Apache容器相同的机器上计划此事,这至关重要,因为它被docker-register容器用来注册Apache正在使用的IP地址和端口etcd

使用 apache-docker-reg.service

apache-docker-reg.service单元将运行在 Host A 上。

让我们为我们的容器创建服务文件,将Apache的IP地址和端口记录在etcd,docker-register

1vi apache-docker-reg.service

插入以下几行:

 1[Unit]
 2Description=Register Apache
 3After=etcd-amb-apache.service
 4BindsTo=etcd-amb-apache.service
 5
 6[Service]
 7ExecStartPre=-/usr/bin/docker kill %n
 8ExecStartPre=-/usr/bin/docker rm %n
 9ExecStart=/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
10
11[X-Fleet]
12X-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 将这些参数传输给容器。

「X-ConditionMachineOf=etcd-amb-apache.service」告訴艦隊在同一台機器上安排此事,因為它們連接到Docker連結,所以它們很重要,以便為註冊容器提供找到「etcd」的方法。

etcd-amb-apache2服务

etcd-amb-apache2.service单元将运行在 Host B 上。

创建我们的第二个简单大使容器(‘simple-amb’)的服务文件,这将允许动态大使容器访问‘etcd’。

1vi etcd-amb-apache2.service

添加以下几行:

 1[Unit]
 2Description=Simple Apache ambassador 2
 3
 4[Service]
 5ExecStartPre=-/usr/bin/docker kill %n
 6ExecStartPre=-/usr/bin/docker rm %n
 7ExecStart=/usr/bin/docker run --rm --name %n polvi/simple-amb 172.17.42.1:4001
 8ExecStop=/usr/bin/docker stop -t 3 %n
 9
10[X-Fleet]
11X-Conflicts=apache.service

保存和退出。

这是与etcd-amb-apache.service几乎相同的服务文件,但X-Conflicts=apache.service告诉车队在与Apache容器不同的机器上安排它,它将被用来将动态大使链接到etcd

服务 服务 服务

apache-dyn-amb.service单元将运行在 Host B 上。

创建我们的动态大使容器(‘dynamic-etd-amb’)的服务文件,使动态大使容器可以访问‘etcd’。

1vi apache-dyn-amb.service

添加以下几行:

 1[Unit]
 2Description=Dynamic ambassador for Apache
 3After=etcd-amb-apache2.service
 4BindsTo=etcd-amb-apache2.service
 5
 6[Service]
 7EnvironmentFile=/etc/environment
 8ExecStartPre=-/usr/bin/docker kill %n
 9ExecStartPre=-/usr/bin/docker rm %n
10ExecStartPre=/usr/bin/docker pull polvi/dynamic-etcd-amb
11ExecStart=/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
12ExecStop=/usr/bin/docker stop -t 3 %n
13
14[X-Fleet]
15X-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」告訴艦隊在與第二個簡單大使容器相同的機器上安排此事,這很重要,因為它們與Docker連結,以便為動態大使容器提供尋找「etcd」的方法。

服务

haproxy.service单元将运行在 Host B 上。

创建我们的 HAProxy 容器(‘haproxy’)的服务文件,将用于通过动态大使容器连接到 Apache 容器。

1vi haproxy.service

添加以下行(在两个地方取代您的 Docker 用户名):

 1[Unit]
 2Description=HAProxy consumer
 3
 4[Service]
 5EnvironmentFile=/etc/environment
 6ExecStartPre=-/usr/bin/docker kill %n
 7ExecStartPre=-/usr/bin/docker rm %n
 8ExecStartPre=/usr/bin/docker pull user_name/haproxy
 9ExecStart=/usr/bin/docker run --name %n -p ${COREOS_PUBLIC_IPV4}:80:80 user_name/haproxy
10ExecStop=/usr/bin/docker stop -t 3 %n
11
12[X-Fleet]
13X-ConditionMachineOf=apache-dyn-amb.service

这是一个简单的服务文件,它启动了HAProxy并将端口80暴露在其主机的公共IP地址上。 请记住,后端服务器将配置为主机的私人IP地址在端口80上,这就是动态大使正在听取流量到Apache服务的代理。

「X-ConditionMachineOf=apache-dyn-amb.service」告訴艦隊在與動態大使容器相同的機器上安排此事,這很重要,因為動態大使為HAProxy容器提供通往Apache容器的路線。

与舰队一起部署

现在我们有所有必要的舰队服务文件,我们终于可以部署我们的大使设置. 在包含所有服务文件的目录中,运行以下命令:

1fleetctl start apache.service
2fleetctl start etcd-amb-apache.service
3fleetctl start apache-docker-reg.service
4fleetctl start etcd-amb-apache2.service
5fleetctl start apache-dyn-amb.service
6fleetctl start haproxy.service

您应该看到消息表示每个服务都已加载. 若要检查您的车队单位的状态,请运行以下命令:

1fleetctl list-units

您应该看到类似于以下的输出:

1UNIT MACHINE ACTIVE SUB
2apache-docker-reg.service ceb3ead2.../10.132.233.107 active running
3apache-dyn-amb.service 3ce87ca7.../10.132.233.106 active running
4apache.service ceb3ead2.../10.132.233.107 active running
5etcd-amb-apache.service	   ceb3ead2.../10.132.233.107 active running
6etcd-amb-apache2.service 3ce87ca7.../10.132.233.106 active running
7haproxy.service	           3ce87ca7.../10.132.233.106 active running

另一个值得注意的事情是机器A单元应该在同一台机器上,而机器B单元应该在不同的机器上 - 只需查看每个单元的IP地址才能确认这一点。

测试你的设置

确保 HAProxy 可以达到 Apache

由于我们没有指定HAProxy容器应该在特定机器上运行,所以我们需要找到它在哪里运行。

1fleetctl ssh haproxy.service

这将将您连接到运行haproxy.service容器的机器,现在您可以源于/etc/environment文件,以获取运行HAProxy的CoreOS机器的公共IP地址:

1. /etc/environment
2echo $COREOS_PUBLIC_IPV4

拿出所产生的IP地址,并使用网页浏览器访问它,您将看到以下图像:

Running from Docker on CoreOS

请注意,您正在访问 HAProxy,并且 HAProxy 正在通过动态大使代理访问 Apache。

现在您可以退出当前的 SSH 会话以返回原始的 SSH 会话:

1exit

试验失败

现在你已经确认大使设置工作了,让我们看看当服务提供商(apache.service)更改其IP地址和端口时会发生什么。

使用fleetctl连接到运行apache.service的机器:

1fleetctl ssh apache.service

现在重新启动 Apache 正在运行的机器:

1sudo reboot

** 注意:** 如果「apache.service」在您最初通过SSH连接的机器上运行,则将被断开连接。

现在等一分钟,看看哪些单元正在运行:

1fleetctl list-units

取决于你等了多久,你可能会看到与Host A相关的三个单元(apache.service,etcd-amb-apache.serviceapache-docker-reg.service)正在重新启动或激活。

现在回到连接到 HAProxy 的 Web 浏览器,然后点击更新. 您应该看到与之前相同的测试页面,表明 HAProxy 仍然可以通过动态大使连接到 Apache!

结论

现在你已经设置了自己的大使模式,你应该能够将本教程中的概念适应自己的服务. 这是一个独特的方式来配置你的消费者服务在运行时,这允许你轻松地在机器之间移动你的后端提供商服务。

Published At
Categories with 技术
comments powered by Disqus