欢迎光临
我们一直在努力

Docker Workflow(四):服务发现与负载均衡

【编者的话】作者讲述了如何将服务发现(Consul.io与Consul-Template)与负载均衡(Nginx)相结合,实现灵活的配置和自动化重载,降低运维难度。当你还执着于给容器分配固定IP这件事上时,也许服务发现才是正道。

这是关于我们如何在IIIEPE的生产环境中使用Docker的系列文章的最后一部分。如果你还没看过第一(译文)、第二(译文)和第三(译文)部分,请先前往阅读再继续。本文中,我将讨论如何配置服务发现和负载均衡的。
服务发现

市面上有不少服务发现方案,不过我们只测试过etcd和Consul.io。Etcd是CoreOS的一部分,虽然你可以脱离CoreOS使用它,但你很快就会发现你需要学习的不仅仅是etcd。Consul.io使用非常简单,通过Docker运行,并且拥有一个不错的生态系统。

在细说之前,如果你不知道什么是服务发现,我得说明一下,它与负载均衡无关,只是一款知晓运行在基础设施上的容器当前状态的软件。也就是说,服务发现跟你如何发送信息给它无关。

与其它服务发现工具一样,Consul.io解决了一个问题,它会存储应用的IP、端口和状态。要将应用注册到Consul.io里(正确的说法是服务),我们使用了Registrator。一旦Consul.io感知到应用,就需要做点什么,在我们的案例中,要重新载入负载均衡配置,因此我们使用了Consul-Template。

因为Consul.io和Registrator都运行在Docker容器里,实现起来比我们想象的要简单得多。

对于Consul-Template,最困难的部分是弄明白模板的语法。
负载均衡

我们使用Nginx作为负载均衡器,因为我们已使用多年,知道如何配置它,而像HAProxy这样的方案只会给整个工作流增加复杂度。因为这是所有事情的最后一块,我们选择了简单的方式来完成它。最终,我们想用HAProxy取代Nginx,不过这得再等几个星期。

在一个正常的负载均衡场景中,你会这样配置Nginx:

upstream myapp {
ip_hash;
server 10.10.10.10:14001 fail_timeout=0;
keepalive 64;
}

server {
listen 80;
server_name example.com;
location / {
proxy_pass          http://myapp;
}
}

当你想在upstream块里动态分配一系列的IP和端口时,问题就出现了。使用consul-template,我们创建了一个模板文件/etc/nginx/templates/template,每个使用该负载均衡器处理的应用都会有一个区块:

upstream myapp {
ip_hash;
{{range service "myapp"}}
server {{.Address}}:{{.Port}} fail_timeout=0;
{{end}}
keepalive 64;
}

server {
listen 80;
server_name example.com;
location / {
proxy_pass          http://myapp;
}
}

对于使用SSL的网站,模板会长一点:

# this part handles the list of IPs and ports
upstream myapp {
ip_hash;
{{range service "myapp"}}
server {{.Address}}:{{.Port}} fail_timeout=0;
{{end}}
keepalive 64;
}

# this section handles requests to port 80, which we'll redirect to the port 445
server {
    listen                          80;
    server_name                     example.com;
    return 301 https://$host$request_uri;
}

server {
    listen                          443 ssl spdy;
    server_name                     example.com;
    keepalive_timeout 75 75;

    ssl                             on;
    ssl_certificate                 /etc/nginx/cert/path_to_cert.crt;
    ssl_certificate_key             /etc/nginx/cert/path_to_key.key;
    ssl_session_cache               builtin:1000 shared:SSL:10m;
    ssl_protocols                   TLSv1 TLSv1.1 TLSv1.2;
    ssl_ciphers                     HIGH:!aNULL:!eNULL:!EXPORT:!CAMELLIA:!DES:!MD5:!PSK:!RC4;
    ssl_prefer_server_ciphers       on;

    add_header                      Strict-Transport-Security max-age=31536000;

    location / {
            proxy_pass              http://myapp;
            proxy_set_header        Host $host;
            proxy_set_header        X-Forwarded-Proto $scheme;
            proxy_set_header        X-Real-IP $remote_addr;
            proxy_set_header        X-Forwarded-For $proxy_add_x_forwarded_for;
            proxy_connect_timeout   150;
            proxy_send_timeout      100;
            proxy_read_timeout      90;
            proxy_buffers           4 32k;
            client_max_body_size    500m;
            client_body_buffer_size 128k;
            proxy_redirect          http:// https://;
    }
}

每次Consul-Template运行时,它会向Consul.io查询“myapp”的服务,并将发现的每个容器的IP和端口添加到upstream块中。

因为Consul.io和Consul-Template需要在服务器重启时启动,我们创建了一个Upstart作业来处理:

description    "Consul Template"
author        "Luis Elizondo"

start on filesystem or runlevel [2345]
stop on shutdown

script
echo $$ > /var/run/consul-template.pid
exec consul-template \
    -consul IP_OF_CONSUL:PORT_OF_CONSUL \
    -template "/etc/nginx/templates/template:/etc/nginx/sites-enabled/default:service nginx restart"
end script

pre-start script
echo "[`date`] Consul Template Starting" >> /var/log/consul-template.log
end script

pre-stop script
rm /var/run/consul-template.pid
echo "[`date`] Consul Template Stoping" >> /var/log/consul-template.log
end script

Consul.io也一样:
description    "Consul"
author        "Luis Elizondo"

start on filesystem or runlevel [2345]
stop on shutdown

script
echo $$ > /var/run/consul.pid
exec docker start consul
end script

pre-start script
echo "[`date`] Consul Starting" >> /var/log/consul.log
end script

pre-stop script
rm /var/run/consul.pid
exec docker stop consul
echo "[`date`] Consul Stoping" >> /var/log/consul.log
end script

Registrator也需要,不过Registrator不是运行在LB上的,而是在每个web节点上:
description    "Registrator"
author        "Luis Elizondo"

start on filesystem or runlevel [2345]
stop on shutdown

script
echo $$ > /var/run/registrator.pid
exec docker start registrator
end script

pre-start script
echo "[`date`] Registrator Starting" >> /var/log/registrator.log
end script

pre-stop script
rm /var/run/registrator.pid
exec docker stop registrator
echo "[`date`] Registrator Stoping" >> /var/log/registrator.log

在2014年11月我们开始这趟旅程之前,我们找不到可以采纳或适应我们条件的完整工作流的足够信息,这也是我在此与大家分享的主要动机。作为完成这件事的二人小组成员之一,我意识到我们的工作流还远远不够完善,随着时间的推移,可能会出现我们未预料到的情况。现在我们有很多想改进的事情,迁移到HAProxy(不针对Nginx)是其中这一。不过,我们的工作流和基础设施是以帮助我们完成工作的方式来配置的(我的主要职责是作为开发人员,不是系统管理员),而不是把我们的存在复杂化。

测试、安装和实现新的工作流,然后迁移所有应用总共花费了我们2个半月时间,但这是值得的。在迁移之前,我们使用Digital Ocean来预演大多数的问题和情况,这对我们而言是个很棒的方案,因为它非常便宜(我们花了大概5美元),这么做让我们可以将每一步都记录下来。

原文:http://dockerone.com/article/283

未经允许不得转载:SRE空间 » Docker Workflow(四):服务发现与负载均衡

分享到:更多 ()

评论 抢沙发

评论前必须登录!

 

oracle