最近看了劉天斯大哥的文章《構建一個高可用及自動發現docker基礎架構》,以爲高大上,他的架構基於etcd+confd+docker+haproxy構建的。至於優點,劉天斯大哥已經說的很清楚。python
我這裏想說的是我本身基於saltstack+docker+haproxy構建的架構,全部操做都只要在salt-master上執行便可。nginx
架構說明:管理員在salt-master端使用python程序啓動容器,向redis註冊信息,包括容器名字、IP、端口等。master端會根據這個信息實時生成pillar數據,再根據相應的states文件,就能按期更新haproxy配置和reload服務。redis
流程:管理員在master端經過python程序遠程啓動容器,並將信息註冊到redis,master開啓一個crontab,根據pillar數據和states按期維護haproxy配置並reload。
docker
服務部署shell
接入層 是基於CentOS 6.2搭建。bash
存儲層 是基於CentOS 6.5搭建。架構
應用層 是基於Ubuntu 13.04搭建。frontend
角色 | IP | 服務 |
接入層 | 192.168.79.51 |
salt-minion haproxy |
存儲層 | 192.168.79.55 | salt-master redis |
應用層 | 192.168.79.44 | salt-minion docker |
關於服務的安裝能夠查看官網安裝,這裏再也不描述。tcp
79.55ide
/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-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()[0] 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'][0]['HostPort'] name = info['Name'][1:] 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(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 <p_w_picpath name>:<version>' % sys.argv[0] print ' %s start <container name or id>' % sys.argv[0] print ' %s stop <container name or id>\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 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[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: jinja reload_haproxy: service.running: - name: haproxy - enable: True - reload: True - watch: - file: create_conf
pillar數據
haproxy.sls
#!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'][key] = conn.get(key) return haproxy
top.sls
base: '*': # 根據具體狀況修改 - haproxy
咱們能夠打開http://192.168.79.51/admin-status監控變化
直接打開http://192.168.79.51/ 能夠看到信息
參考地址