eric
作者eric·2015-04-03 15:01
系统运维工程师·某金融单位

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

字数 6387阅读 3713评论 0赞 0

【编者的话】作者讲述了如何将服务发现(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美元),这么做让我们可以将每一步都记录下来。

如果觉得我的文章对您有用,请点赞。您的支持将鼓励我继续创作!

0

添加新评论0 条评论

Ctrl+Enter 发表

作者其他文章

相关文章

相关问题

相关资料

X社区推广