最近看了刘天斯大哥的文章,觉得高大上,他的架构基于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.55 salt-master redis
应用层 192.168.79.44 salt-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目录下。

salt -L '192.168.79.44,' cp.get_file salt://haproxy/docker_nginx_manage.py /opt/bin/docker_nginx_manage.py, 这里可以定义一个应用组,使用-N参数

刷新下pillar

salt '*' saltutil.refresh_pillar

添加crontab

*/1 * * * * /usr/bin/salt  -L '192.168.79.51,' state.sls haproxy.haproxy &>/dev/null &

启动一个容器

salt '192.168.79.44' cmd.run 'python /opt/bin/docker_nginx_manage.py run nginx'

一分钟后会执行crontab任务,修改haproxy并reload。

docker_nginx_manage.py代码

我这里只是测试,代码写的比较简单,实际情况需要考虑异常、容器名字唯一等情况。

#!/usr/bin/env python# coding:utf-8import sysimport dockerimport redisimport subprocessimport recli = 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()[0]        info = re.compile(r'inet\s*(.*?)/\d+\s*brd\s*').search(out)        ip = info.group(1)        return ipdef get_info(container):        info = cli.inspect_container(container)        ip = get_ip()        port = info['NetworkSettings']['Ports']['80/tcp'][0]['HostPort']        name = info['Name'][1:]        return name,ip+':'+portdef 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(p_w_picpath):        container_id = cli.create_container(p_w_picpath=p_w_picpath)        start_container(container_id)def check_args():        if len(sys.argv) != 3 or sys.argv[1] not in ['run','start','stop']:                print '\nUsage: %s run 
:
' % sys.argv[0]                print ' %s start 
'  % sys.argv[0]                print ' %s stop 
\n'       % sys.argv[0]                sys.exit(1)def main():        check_args()        if sys.argv[1] == 'run':                create_container(sys.argv[2])        elif sys.argv[1] == 'stop':                stop_container(sys.argv[2])        elif sys.argv[1] == 'start':                start_container(sys.argv[2])        else:                check_args()if __name__ == "__main__":        main()

haproxy.cfg模版配置

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 connect  5000          timeout client 50000          timeout server 50000listen frontend 0.0.0.0:80          mode http          balance roundrobin          maxconn 2000          option forwardfor        {% for i in pillar.haproxy -%}         server `i` {
{pillar.haproxy[i]}} check inter 5000 fall 1 rise 2        {% endfor -%}        stats enable          stats uri /admin-status          stats auth admin:123456          stats admin if TRUE

haproxy.sls文件

create_conf:  file.managed:    - name: /etc/haproxy/haproxy.cfg    - source: salt://haproxy/haproxy.cfg    - template: jinjareload_haproxy:  service.running:    - name: haproxy    - enable: True    - reload: True    - watch:      - file: create_conf

pillar数据

haproxy.sls

#!pyimport redisdef 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'][key] = conn.get(key)        return haproxy

top.sls

base:  '*':   # 根据具体情况修改    - haproxy

我们可以打开

直接打开/ 可以看到信息

参考地址