saltstack與docker結合構建高可用和自動發現服務

最近看了劉天斯大哥的文章《構建一個高可用及自動發現docker基礎架構》,覺得高大上,他的架構基於etcd+confd+docker+haproxy構建的。至於優勢,劉天斯大哥已經說的很清楚。

我這裏想說的是我自己基於saltstack+docker+haproxy構建的架構,所有操作都只要在salt-master上執行即可。


架構說明:管理員在salt-master端使用python程序啓動容器,向redis註冊信息,包括容器名字、IP、端口等。master端會根據這個信息實時生成pillar數據,再根據相應的states文件,就能定期更新haproxy配置和reload服務。

wKioL1RkEJDzz3RSAAJB57_heVk103.jpg

流程:管理員在master端通過python程序遠程啓動容器,並將信息註冊到redis,master開啓一個crontab,根據pillar數據和states定期維護haproxy配置並reload。

wKioL1RkEXuDfXkTAADRkE_gu34447.jpg


服務部署

接入層 是基於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目錄下。

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(image):
        container_id = cli.create_container(image=image)
        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 <image 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監控變化

wKioL1RkINXiP2yBAAGTSbxq8do782.jpg


直接打開http://192.168.79.51/ 可以看到信息

wKioL1RkIVfzwkLVAAE2gnyjWXY419.jpg


參考地址

http://blog.liuts.com/post/242/

http://www.saltstack.com/


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章