saltstack与docker结合构建高可用和自动发现服务
最近看了刘天斯大哥的文章《构建一个高可用及自动发现docker基础架构》,觉得高大上,他的架构基于etcd+confd+docker+haproxy构建的。至于优势,刘天斯大哥已经说的很清楚。我这里想说的是我自己基于saltstack+docker+haproxy构建的架构,所有操作都只要在salt-master上执行即可。
架构说明:管理员在salt-master端使用python程序启动容器,向redis注册信息,包括容器名字、IP、端口等。master端会根据这个信息实时生成pillar数据,再根据相应的states文件,就能定期更新haproxy配置和reload服务。
流程:管理员在master端通过python程序远程启动容器,并将信息注册到redis,master开启一个crontab,根据pillar数据和states定期维护haproxy配置并reload。
服务部署
接入层 是基于CentOS 6.2搭建。
存储层 是基于CentOS 6.5搭建。
应用层 是基于Ubuntu 13.04搭建。
角色IP服务
接入层192.168.79.51
salt-minion haproxy
存储层192.168.79.55salt-master redis
应用层192.168.79.44salt-minion docker
关于服务的安装可以查看官网安装,这里不再描述。
79.55
/srv/salt/haproxy目录有三个文件:docker_nginx_manage.py、haproxy.cfg、haproxy.sls。
/srv/pillar目录有两个文件:haproxy.sls、top.sls。
操作步骤
将docker_nginx_manage.py统一同步到应用主机/opt/bin目录下。
1
salt -L '192.168.79.44,' cp.get_file salt://haproxy/docker_nginx_manage.py /opt/bin/docker_nginx_manage.py, 这里可以定义一个应用组,使用-N参数
刷新下pillar
1
salt '*' saltutil.refresh_pillar
添加crontab
1
*/1 * * * * /usr/bin/salt-L '192.168.79.51,' state.sls haproxy.haproxy &>/dev/null &
启动一个容器
1
salt '192.168.79.44' cmd.run 'python /opt/bin/docker_nginx_manage.py run nginx'
一分钟后会执行crontab任务,修改haproxy并reload。
docker_nginx_manage.py代码
我这里只是测试,代码写的比较简单,实际情况需要考虑异常、容器名字唯一等情况。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
#!/usr/bin/env python
# coding:utf-8
import sys
import docker
import redis
import subprocess
import re
cli = docker.Client(base_url='unix://var/run/docker.sock')
conn = redis.StrictRedis(host='192.168.79.55', port=2001)# 根据实际情况修改
def delete_redis(key):
conn.delete(key)
def insert_redis(key,value):
conn.set(key,value)
def get_ip():
out = subprocess.Popen(
'/sbin/ip addr show eth0',
shell=True,
close_fds=True,
stdout=subprocess.PIPE,
stderr=subprocess.STDOUT).communicate()
info = re.compile(r'inet\s*(.*?)/\d+\s*brd\s*').search(out)
ip = info.group(1)
return ip
def get_info(container):
info = cli.inspect_container(container)
ip = get_ip()
port = info['NetworkSettings']['Ports']['80/tcp']['HostPort']
name = info['Name']
return name,ip+':'+port
def stop_container(container):
name,value = get_info(container)
cli.stop(container)
delete_redis(name)
def start_container(container):
cli.start(container,publish_all_ports=True)
name,value = get_info(container)
insert_redis(name,value)
def create_container(image):
container_id = cli.create_container(image=image)
start_container(container_id)
def check_args():
if len(sys.argv) != 3 or sys.argv not in ['run','start','stop']:
print '\nUsage: %s run <image name>:<version>' % sys.argv
print ' %s start <container name or id>'% sys.argv
print ' %s stop <container name or id>\n' % sys.argv
sys.exit(1)
def main():
check_args()
if sys.argv == 'run':
create_container(sys.argv)
elif sys.argv == 'stop':
stop_container(sys.argv)
elif sys.argv == 'start':
start_container(sys.argv)
else:
check_args()
if __name__ == "__main__":
main()
haproxy.cfg模版配置
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
global
log 127.0.0.1 local3
maxconn 5000
uid 99
gid 99
daemon
defaults
log 127.0.0.1 local3
mode http
option dontlognull
retries 3
option redispatch
maxconn 2000
timeout connect5000
timeout client 50000
timeout server 50000
listen frontend 0.0.0.0:80
mode http
balance roundrobin
maxconn 2000
option forwardfor
{% for i in pillar.haproxy -%}
server {{i}} {{pillar.haproxy}} check inter 5000 fall 1 rise 2
{% endfor -%}
stats enable
stats uri /admin-status
stats auth admin:123456
stats admin if TRUE
haproxy.sls文件
1
2
3
4
5
6
7
8
9
10
11
12
13
14
create_conf:
file.managed:
- name: /etc/haproxy/haproxy.cfg
- source: salt://haproxy/haproxy.cfg
- template: jinja
reload_haproxy:
service.running:
- name: haproxy
- enable: True
- reload: True
- watch:
- file: create_conf
pillar数据
haproxy.sls
1
2
3
4
5
6
7
8
9
10
11
12
13
14
#!py
import redis
def run():
haproxy = {}
haproxy['haproxy'] = {}
conn = redis.StrictRedis(host='192.168.79.55', port=2001)
keys = conn.keys('*')
keys.sort()
for key in keys:
haproxy['haproxy'] = conn.get(key)
return haproxy
top.sls
1
2
3
base:
'*': # 根据具体情况修改
- haproxy
我们可以打开http://192.168.79.51/admin-status监控变化
直接打开http://192.168.79.51/ 可以看到信息
参考地址
http://www.iyunv.com/thread-29341-1-1.html
http://www.saltstack.com/
页:
[1]