docker深入2-使用registrator和consul-template自动注册和变更服务

2016/6/23


一、示例
测试环境基于文档:docker深入2-熟悉v1.11和找不同.txt

    host-n35                        host-n36
-----------------------------------------------------
                                    conf
                                    consul-tempalte
----------------------------------------
webapp(container)       ------      webapp(container) 
----------------------------------------
registrator_35          ------      registrator_36
consul-node1            ------      consul-node2
-----------------------------------------------------

二、配置
1、配置 consul 集群
调整防火墙:
firewall-cmd --zone=public --add-port=8300-8302/tcp
firewall-cmd --zone=public --add-port=8301-8302/udp
firewall-cmd --zone=public --add-port=8400/tcp
firewall-cmd --zone=public --add-port=8500/tcp
firewall-cmd --zone=public --add-port=53/tcp
firewall-cmd --zone=public --add-port=53/udp

持久:
firewall-cmd --zone=public --add-port=2375/tcp --permanent
firewall-cmd --zone=public --add-port=4000/tcp --permanent
firewall-cmd --zone=public --add-port=8300-8302/tcp --permanent
firewall-cmd --zone=public --add-port=8301-8302/udp --permanent
firewall-cmd --zone=public --add-port=8400/tcp --permanent
firewall-cmd --zone=public --add-port=8500/tcp --permanent
firewall-cmd --zone=public --add-port=53/tcp --permanent
firewall-cmd --zone=public --add-port=53/udp --permanent

注1:如下配置简化了 IP 映射的细节,直接使用 0.0.0.0 来提供服务。
注2:cunsul 的 service 要使用 dns 来提供域名解析,这样 registrator 才能顺利的注册服务到 consul 上来。
【n35】
docker run -d --restart=always -v /data/docker/consul:/data \
-p 8300:8300 \
-p 8301:8301 \
-p 8301:8301/udp \
-p 8302:8302 \
-p 8302:8302/udp \
-p 8400:8400 \
-p 8500:8500 \
-p 53:53 \
-p 53:53/udp \
--name=consul-node1 progrium/consul -server -advertise 10.111.222.35 -bootstrap-expect 2

【n36】
docker run -d --restart=always -v /data/docker/consul:/data \
-p 8300:8300 \
-p 8301:8301 \
-p 8301:8301/udp \
-p 8302:8302 \
-p 8302:8302/udp \
-p 8400:8400 \
-p 8500:8500 \
-p 53:53 \
-p 53:53/udp \
--name=consul-node2 progrium/consul -server -advertise 10.111.222.36 -join 10.111.222.35

【查看 n35 日志】
[Jack@n35 ~]$ docker logs -f consul-node1
    2016/05/23 08:58:58 [INFO] serf: EventMemberJoin: 0db39e28b326 10.111.222.36
    2016/05/23 08:58:58 [INFO] consul: adding server 0db39e28b326 (Addr: 10.111.222.36:8300) (DC: dc1)
    2016/05/23 08:58:58 [INFO] consul: Attempting bootstrap with nodes: [10.111.222.35:8300 10.111.222.36:8300]
    2016/05/23 08:58:58 [WARN] raft: Heartbeat timeout reached, starting election
    2016/05/23 08:58:58 [INFO] raft: Node at 10.111.222.35:8300 [Candidate] entering Candidate state
    2016/05/23 08:58:58 [WARN] raft: Remote peer 10.111.222.36:8300 does not have local node 10.111.222.35:8300 as a peer
    2016/05/23 08:58:58 [INFO] raft: Election won. Tally: 2
    2016/05/23 08:58:58 [INFO] raft: Node at 10.111.222.35:8300 [Leader] entering Leader state
    2016/05/23 08:58:58 [INFO] consul: cluster leadership acquired
    2016/05/23 08:58:58 [INFO] consul: New leader elected: be67d37cbf68
    2016/05/23 08:58:58 [INFO] raft: pipelining replication to peer 10.111.222.36:8300
    2016/05/23 08:58:58 [INFO] consul: member 'be67d37cbf68' joined, marking health alive
    2016/05/23 08:58:58 [INFO] consul: member '0db39e28b326' joined, marking health alive

    
【查看 n36 日志】
[Jack@n36 ~]$ docker logs -f consul-node2
    2016/05/23 08:58:58 [INFO] consul: adding server be67d37cbf68 (Addr: 10.111.222.35:8300) (DC: dc1)
    2016/05/23 08:58:58 [INFO] consul: New leader elected: be67d37cbf68

    
    
2、配置 registrator 来注册 docker container 的信息到上述 consul 集群中。
【n35】
docker run -d --restart=always -v /var/run/docker.sock:/tmp/docker.sock --name registrator_35 gliderlabs/registrator consul://10.111.222.35:8500

【n36】
docker run -d --restart=always -v /var/run/docker.sock:/tmp/docker.sock --name registrator_36 gliderlabs/registrator consul://10.111.222.36:8500

【查看 n35 日志】
[Jack@n35 ~]$ docker logs -f registrator_35
2016/05/23 09:05:08 Starting registrator v7 ...
2016/05/23 09:05:08 Using consul adapter: consul://10.111.222.35:8500
2016/05/23 09:05:08 Connecting to backend (0/0)
2016/05/23 09:05:08 consul: current leader  10.111.222.35:8300
2016/05/23 09:05:08 Listening for Docker events ...
2016/05/23 09:05:08 Syncing services on 3 containers
2016/05/23 09:05:08 ignored: 205155915c61 no published ports
2016/05/23 09:05:08 added: be67d37cbf68 205155915c61:consul-node1:53
2016/05/23 09:05:08 added: be67d37cbf68 205155915c61:consul-node1:8300
2016/05/23 09:05:08 added: be67d37cbf68 205155915c61:consul-node1:53:udp
2016/05/23 09:05:08 added: be67d37cbf68 205155915c61:consul-node1:8302
2016/05/23 09:05:08 added: be67d37cbf68 205155915c61:consul-node1:8302:udp
2016/05/23 09:05:08 added: be67d37cbf68 205155915c61:consul-node1:8400
2016/05/23 09:05:08 added: be67d37cbf68 205155915c61:consul-node1:8500
2016/05/23 09:05:08 added: be67d37cbf68 205155915c61:consul-node1:8301:udp
2016/05/23 09:05:08 added: be67d37cbf68 205155915c61:consul-node1:8301
2016/05/23 09:05:08 added: 312c4fdb40d0 205155915c61:reg4work:5000

【查看 n36 日志】
[Jack@n36 ~]$ docker logs -f registrator_36
2016/05/23 09:05:23 Starting registrator v7 ...
2016/05/23 09:05:23 Using consul adapter: consul://10.111.222.36:8500
2016/05/23 09:05:23 Connecting to backend (0/0)
2016/05/23 09:05:23 consul: current leader  10.111.222.35:8300
2016/05/23 09:05:23 Listening for Docker events ...
2016/05/23 09:05:23 Syncing services on 2 containers
2016/05/23 09:05:23 ignored: 1f61c2d2bcf9 no published ports
2016/05/23 09:05:23 added: 0db39e28b326 1f61c2d2bcf9:consul-node2:8302:udp
2016/05/23 09:05:24 added: 0db39e28b326 1f61c2d2bcf9:consul-node2:8500
2016/05/23 09:05:24 added: 0db39e28b326 1f61c2d2bcf9:consul-node2:8301
2016/05/23 09:05:24 added: 0db39e28b326 1f61c2d2bcf9:consul-node2:53:udp
2016/05/23 09:05:24 added: 0db39e28b326 1f61c2d2bcf9:consul-node2:8300
2016/05/23 09:05:24 added: 0db39e28b326 1f61c2d2bcf9:consul-node2:8301:udp
2016/05/23 09:05:24 added: 0db39e28b326 1f61c2d2bcf9:consul-node2:8302
2016/05/23 09:05:24 added: 0db39e28b326 1f61c2d2bcf9:consul-node2:53
2016/05/23 09:05:24 added: 0db39e28b326 1f61c2d2bcf9:consul-node2:8400


分别在 2 个 host 上启动 1 个 container,观察是否自动被注册到 consul 中:
[Jack@n36 ~]$ docker run -d -P --name z001 training/webapp python app.py
66ef0c6ce19b6c33e13d772ada5504732c032046bb9cd2410ec48545111aa140
[Jack@n35 ~]$ docker run -d -P --name z002 training/webapp python app.py 
7fde646e0c29370ff1375f4692f4dc64c14eda490997d736cb2cc2a0712ce039

再次查看日志:
【查看 n35 日志】
2016/05/23 09:09:11 added: 7fde646e0c29 205155915c61:z002:5000
【查看 n36 日志】
2016/05/23 09:08:38 added: 66ef0c6ce19b 1f61c2d2bcf9:z001:5000


通过 API 来查看 webapp 的内容:
[Jack@n36 ~]$ curl -s 10.111.222.35:8500/v1/catalog/service/webapp |python -mjson.tool
[
    {
        "Address": "10.111.222.36",
        "Node": "0db39e28b326",
        "ServiceAddress": "",
        "ServiceID": "1f61c2d2bcf9:z001:5000",
        "ServiceName": "webapp",
        "ServicePort": 32774,
        "ServiceTags": null
    },
    {
        "Address": "10.111.222.35",
        "Node": "be67d37cbf68",
        "ServiceAddress": "",
        "ServiceID": "205155915c61:z002:5000",
        "ServiceName": "webapp",
        "ServicePort": 32768,
        "ServiceTags": null
    }
]

3、使用 consul-template
目的:在一台测试机上安装 consul-template 来从 consul 获取数据,更新本地的某个配置文件。
从下述页面选择一个版本:
https://releases.hashicorp.com/consul-template/

注3:将 n36 充当测试机。

[root@n36 ~] curl https://releases.hashicorp.com/consul-template/0.14.0/consul-template_0.14.0_linux_amd64.zip -o consul-template.zip && unzip consul-template.zip && mv ./consul-template /usr/bin/

生成一个简易的模版来测试:
[Jack@n36 ~]$ echo -e '{{range service "webapp"}}\nserver ``.`Address`:``.`Port``end`' > /tmp/consul.ctmpl
[Jack@n36 ~]$ cat /tmp/consul.ctmpl
{{range service "webapp"}}
server ``.`Address`:``.`Port``end`

启动 consul-template 来看看模版生成的内容是啥:
[Jack@n36 ~]$ consul-template -consul 10.111.222.35:8500 -template "/tmp/consul.ctmpl:/tmp/consul.result" -once
结果如下:
[Jack@n36 ~]$ cat /tmp/consul.result

server 10.111.222.36:32774
server 10.111.222.35:32768

如上所示,符合预期。

测试请求是否正常:
[Jack@n36 ~]$ curl 10.111.222.36:32774
Hello world![Jack@n36 ~]$ 
[Jack@n36 ~]$ curl 10.111.222.35:32768
Hello world![Jack@n36 ~]$ 
[Jack@n36 ~]$


4、移除 webapp 后观察变化
[Jack@n35 ~]$ docker rm -f z002
z002
【查看 n35 日志】
[Jack@n35 ~]$ docker logs -f registrator_35
2016/05/23 09:53:23 removed: 7fde646e0c29 205155915c61:z002:5000

[Jack@n35 ~]$ docker logs -f consul-node1
    2016/05/23 09:53:23 [INFO] agent: Deregistered service '205155915c61:z002:5000'

符合预期。









三、疑惑
Q1、consul 服务注意事项?
A:
-bootstrap-expect 3:表明需要有3个节点,才能启动集群。
-bootstrap:单个节点使用这个标记来立即启动服务,而不是用来等待集群的创建。
-advertise:来申明 consul 使用哪个 IP 来提供服务。
-join:指定第一个 consul 服务的 IP 来加入集群。

使用 dig 来获取信息:
[root@n36 ~]# yum install bind-utils -y 
[Jack@n36 ~]$ curl -s 10.111.222.36:8500/v1/catalog/service/webapp |python -mjson.tool
[
    {
        "Address": "10.111.222.36",
        "Node": "8b716e39cc09",
        "ServiceAddress": "",
        "ServiceID": "6402f685c105:z001:5000",
        "ServiceName": "webapp",
        "ServicePort": 32770,
        "ServiceTags": null
    },
    {
        "Address": "10.111.222.36",
        "Node": "8b716e39cc09",
        "ServiceAddress": "",
        "ServiceID": "6402f685c105:z002:5000",
        "ServiceName": "webapp",
        "ServicePort": 32771,
        "ServiceTags": null
    },
    {
        "Address": "10.111.222.36",
        "Node": "8b716e39cc09",
        "ServiceAddress": "",
        "ServiceID": "6402f685c105:z003:5000",
        "ServiceName": "webapp",
        "ServicePort": 32772,
        "ServiceTags": null
    }
]
[Jack@n36 ~]$ dig @10.111.222.36 webapp.service.consul SRV                            

; <<>> DiG 9.9.4-RedHat-9.9.4-29.el7_2.3 <<>> @10.111.222.36 webapp.service.consul SRV
; (1 server found)
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 22230
;; flags: qr aa rd ra; QUERY: 1, ANSWER: 3, AUTHORITY: 0, ADDITIONAL: 3

;; QUESTION SECTION:
;webapp.service.consul.         IN      SRV

;; ANSWER SECTION:
webapp.service.consul.  0       IN      SRV     1 1 32772 8b716e39cc09.node.dc1.consul.
webapp.service.consul.  0       IN      SRV     1 1 32770 8b716e39cc09.node.dc1.consul.
webapp.service.consul.  0       IN      SRV     1 1 32771 8b716e39cc09.node.dc1.consul.

;; ADDITIONAL SECTION:
8b716e39cc09.node.dc1.consul. 0 IN      A       10.111.222.36
8b716e39cc09.node.dc1.consul. 0 IN      A       10.111.222.36
8b716e39cc09.node.dc1.consul. 0 IN      A       10.111.222.36

;; Query time: 2 msec
;; SERVER: 10.111.222.36#53(10.111.222.36)
;; WHEN: Thu Jun 02 16:30:43 CST 2016
;; MSG SIZE  rcvd: 378



Q2、registrator 服务注意事项?
A:在 overlay 网络下,配置 consul 集群时,DNS 端口使用哪个 IP 来提供服务? registrator 是否能检测到服务并注册成功呢?
笔者了解到以下2个方面需要注意:
1、配置 consul 时,指定了映射 53 端口到外部的IP,这个 ip 应该如何选择需要琢磨下。
2、配置 registrator 时,可以指定 docker 参数 --net,也可以指定 registrator 的参数 -internal,用途需要琢磨下。
Docker Options
--net=host	recommended	Helps Registrator get host-level IP and hostname

Registrator Options
-internal		Use exposed ports instead of published ports


Q3、consul-template 服务注意事项?
A:
-consul  指定 consul 服务的IP:PORT。
-template 指定 输入模版:输出模版:命令。
-once 表明 在命令行运行一次就退出。
-dry  表明 将结果输出到控制台,并不写入磁盘文件,且命令也不启动。



Q4、如果只有一台服务器,如何体验?
A:以【n36】为例:
1)启动一个 consul 服务
[Jack@n36 ~]$ docker run -d --restart=always -v /data/docker/consul-test:/data \
-p 8300:8300 \
-p 8301:8301 \
-p 8301:8301/udp \
-p 8302:8302 \
-p 8302:8302/udp \
-p 8400:8400 \
-p 8500:8500 \
-p 53:53 \
-p 53:53/udp \
--name=consul-test progrium/consul -server -advertise 10.111.222.36 -bootstrap


2)启动一个 registrator 服务
[Jack@n36 ~]$ docker run -d --restart=always -v /var/run/docker.sock:/tmp/docker.sock --name registrator_36 gliderlabs/registrator consul://10.111.222.36:8500


3)启动 docker 容器,registrator 将自动注册容器信息到 consul 中。
[Jack@n36 ~]$ docker run -d -P --name z001 training/webapp python app.py
[Jack@n36 ~]$ docker run -d -P --name z002 training/webapp python app.py
[Jack@n36 ~]$ docker run -d -P --name z003 training/webapp python app.py


4)查看 consul 中注册的内容
[Jack@n36 ~]$ curl -s 10.111.222.36:8500/v1/catalog/service/webapp |python -mjson.tool


5)查看 consul-template 生成的结果
[Jack@n36 ~]$ consul-template -consul 10.111.222.36:8500 -template "/tmp/consul.ctmpl:/tmp/consul.result" -once


6)应用到 haproxy 上
[root@n36 ~]# yum install haproxy
[root@n36 ~]# cp -a /etc/haproxy/haproxy.cfg{,.ctmpl}

调整 haproxy 模版:
[root@n36 ~]# vim /etc/haproxy/haproxy.cfg.ctmpl
(略)
backend app
    balance     roundrobin
    {{range service "webapp"}}
    server app-``.`Port` ``.`Address`:``.`Port` check`end`
    

生成配置并重启服务:
[root@n36 ~]# consul-template -consul 10.111.222.36:8500 -template "/etc/haproxy/haproxy.cfg.ctmpl:/etc/haproxy/haproxy.cfg:systemctl reload haproxy.service" -once

验证配置:
[root@n36 ~]# cat /etc/haproxy/haproxy.cfg
(略)
backend app
    balance     roundrobin
    
    server app-32774 10.111.222.36:32774 check
    server app-32775 10.111.222.36:32775 check
    server app-32776 10.111.222.36:32776 check

检查 haproxy 服务的状态
[root@n36 ~]# systemctl status haproxy.service


符合预期。
注:如果 status 显示 haproxy 绑定端口失败,权限异常等问题,导致启动服务失败,则要先考虑是否启用了 selinux,很简单,按照如下操作调整设置即可验证是否受其影响。
临时关闭:setenforce 0
查看状态:sestatus 





Q5、突然发现执行大部分 docker 指令时,要等待很久才会有结果,系统的资源占用并不高,似乎是 docker 服务比较卡顿,这是为何?
A:请检查 docker 服务是否存在异常,提供一个实例如下所述。
执行命令:
[Jack@n36 ~]$ docker network ls
发现等待了半天才有回应。
使用 strace 查看:
[root@n36 ~]# time strace -p `ps -ef |grep 'docker network' |grep -v grep |awk '{print $2}'`
Process 14169 attached
futex(0x21ec290, FUTEX_WAIT, 0, NULL)   = 0
epoll_wait(5, {}, 128, 0)               = 0
select(0, NULL, NULL, NULL, {0, 100})   = 0 (Timeout)
futex(0xc820030e90, FUTEX_WAKE, 1)      = 1
futex(0x21ec290, FUTEX_WAIT, 0, NULL <unfinished ...>
+++ exited with 0 +++

real    1m11.029s
user    0m0.021s
sys     0m0.026s

果然等待了很久。

检查服务状态和系统日志:
[root@n36 ~]# systemctl status docker.service -l
[root@n36 ~]# tail -f /var/log/message

发现有节点连接失败的情况,继续查看 docker 服务的配置:
[root@n36 ~]# cat /lib/systemd/system/docker.service  |grep daemon
ExecStart=/usr/bin/docker daemon -H tcp://10.111.222.35:2375 -H unix:///var/run/docker.sock --cluster-store=consul://10.111.222.35:8500 --cluster-advertise=em2:2375 --insecure-registry 10.111.222.35:5000

consul 和 registry 服务所指向的节点 10.111.222.35 已经因为异常而下线,而 docker 服务在启动后不断的尝试连接到该节点的服务上。

尝试修正上述节点带来的影响后,重启服务。
[root@n36 ~]# systemctl daemon-reload
[root@n36 ~]# systemctl restart docker
再次执行 docker 指令,无异常。



ZYXW、参考
1、consul
https://hub.docker.com/r/progrium/consul/
https://blog.coding.net/blog/intro-consul?type=hot
http://blog.csdn.net/viewcode/article/details/45915179

2、registrator
http://gliderlabs.com/registrator/latest/user/run/

3、consul-template
https://github.com/hashicorp/consul-template
https://releases.hashicorp.com/consul-template/
https://jlordiales.me/2015/04/01/consul-template/
http://sirile.github.io/2015/07/28/scaling-with-discovery-on-docker-swarm-with-consul-registrator-and-haproxy-with-prometheus-monitoring-and-elk-log-aggregation.html

4、haproxy
http://serverfault.com/questions/654599/weird-interaction-with-systemctl-with-haproxy-on-centos-7