Saltstack中ZeroMQ那點事

基本簡介python

前置閱讀bash

環境說明網絡

Salt中的ZeroMQ patterns架構

Salt Master異步

Salt Minionsocket

Salttcp

總結ide

基本簡介ui

Salt 底層網絡架構採用 ZeroMQ 進行實現(2014.1及以前版本, 從2014.7起, Salt新增 RAET ), 官方手冊 有簡短描述. 那麼今天就一窺在Salt內部使用了哪些 ZeroMQ pattern? 各個組件間又是如何協做的哪?加密


前置閱讀

0MQ - The Guide: Sockets and Patterns

環境說明

CentOS6.4

Salt 2014.1.10 ,默認配置

Salt中的ZeroMQ patterns

Salt Master

Salt Master爲Salt中心管控節點. 爲Salt環境提供命令下發, 文件, 結果收集等服務.


在Master啓動時, 首先啓動名爲 ReqServer , ReqServer在初始化 時, 當即建立以下ZeroMQ patterns:


clients:

ZeroMQ pattern: zmq.ROUTER

listen地址: tcp://0.0.0.0:4506

listen方式: bind

做用: Salt Master Ret接口, 支持認證(auth), 文件服務, 結果收集等功能

workers:

ZeroMQ pattern: zmq.DEALER

listen地址: ipc:///var/run/salt/master/workers.ipc

listen方式: bind

做用: Salt Master任務處理進程接口

同時clients與workers, 創建了一個 zeromq.device :


zmq.device(zmq.QUEUE, self.clients, self.workers)

經過zmq.device, 實現了clients接收到請求後, 轉發到workers進程接口上進行處理


接下來, Master會啓動 Publisher , 當即建立了以下ZeroMQ patterns:


pub:

ZeroMQ pattern: zmq.PUB

listen地址: tcp://0.0.0.0:4505

listen方式: bind

做用: Salt Master pub接口, 提供遠程執行命令發送功能

pull:

ZeroMQ pattern: zmq.PULL

listen地址: ipc:///var/run/salt/master/publish_pull.ipc

listen方式: bind

做用: Salt Master遠程執行命令pull接口

pull接口在接收到數據後, 會將數據從pub接口上進行發送:


package = pull_sock.recv()

pub_sock.send(package)

接下來, Master啓動 EventPublisher, 以實現Event BUS, 建立了以下ZeroMQ patterns:


epub:

ZeroMQ pattern: zmq.PUB

listen地址: ipc:///var/run/salt/master/master_event_pub.ipc

listen方式: bind

做用: Salt Master event pub接口, 以方便其餘或第三方應用訂閱event bus上的event

epull:

ZeroMQ pattern: zmq.PULL

listen地址: ipc:///var/run/salt/master/master_event_pull.ipc

listen方式: bind

做用: Salt Master event pull接口

同時epull接口在收到包時, 會將數據在pub接口上進行發送:


package = self.epull_sock.recv()

self.epub_sock.send(package)

在啓動EventPublisher以後, Salt Master會繼續啓動Halite, Reactor系統, 該部分暫不描述. 隨後, Salt會啓動多個Work進程(默認是5, 在規模較大的環境中, 建議增長配置文件中的 worker_threads 數目來增長該類進程)來進行任務處理, 每一個Worker進程會建立以下ZeroMQ patterns:


socket

ZeroMQ pattern: zmq.REP

listen地址: ipc:///var/run/salt/master/workers.ipc

listen方式: connect

做用: Salt Master任務處理進程, 處理驗證Minion, 獲取Master配置, Mine, pillar, fileserver文件獲取, minion event fire到master的event接口, 收集minions的返回結果等任務

Salt Minion

Salt Minion爲Salt環境操做節點, 遠程命令從Master發送過來後, 會在該主機上進行執行並將結果返回給Master.


Salt Minion 在啓動時從配置文件中獲取Master的地址, 若是爲域名, 則進行解析. 解析完畢後, 會鏈接Master的Ret接口進行key認證. 認證經過, 會獲取到master的 publish_port , 這就是爲何在Minion的配置文件中只須要指定Minion的 ret_port (對應minion配置文件中的master_port) 便可.


在獲取到master的publish_port(默認爲4505)以後, 會創建minion本地的Event接口:


epub:

ZeroMQ pattern: zmq.PUB

listen地址: ipc:///var/run/salt/minion/minion_event_{id_hash}_pub.ipc

listen方式: bind

做用: Salt Minion event pub接口, 以便其餘或第三方應用經過該event bus獲取event信息

epull:

ZeroMQ pattern: zmq.PULL

listen地址: ipc:///var/run/salt/minion/minion_event_{id_hash}_pull.ipc

listen方式: bind

做用: Salt Minion event pull接口

epull接口在接收到數據後, 會檢查是否須要處理, 若是須要處理, 則進行執行. 隨後將該數據包傳送到epub接口:


    # Check the event system

    if socks.get(self.epull_sock) == zmq.POLLIN:

        package = self.epull_sock.recv(zmq.NOBLOCK)

        log.debug("Handling event %r", package)

        try:

            if package.startswith('module_refresh'):

                self.module_refresh()

            elif package.startswith('pillar_refresh'):

                self.pillar_refresh()

            elif package.startswith('grains_refresh'):

                if self.grains_cache != self.opts['grains']:

                    self.pillar_refresh()

                    self.grains_cache = self.opts['grains']

                 elif package.startswith('fire_master'):

                     tag, data = salt.utils.event.MinionEvent.unpack(package)

                     log.debug("Forwarding master event tag={tag}".format(tag=data['tag']))

                     self._fire_master(data['data'], data['tag'], data['events'], data['pretag'])


            self.epub_sock.send(package)

        except Exception:

            log.debug("Exception while handling events", exc_info=True)

在event接口創建完畢後, 會創建以下ZeroMQ pattern:


socket:

ZeroMQ pattern: zmq.SUB

listen地址: "tcp:/":tcp://{master_ip}:4505

listen方式: connect

做用: 訂閱來自Master pub接口的任務

因爲遠程執行命令的發送, 是經過ZeroMQ PUB/SUB pattern進行創建的, 即當master下發操做指令時, 全部的minion都可以接收到, 而後minion會檢查本機是否target match, 若是match, 則進行執行.執行完畢後, 會經過 SREQ 發送到Master的Ret接口, 期間會建立以下ZeroMQ pattern:


socket:

ZeroMQ pattern: zmq.REQ

listen地址: "tcp:/":tcp://{master_ip}:4506

listen方式: connect

做用: 將執行結果發送給Master

更多關於Minion如何來執行任務, 請訪問: http://devopstarter.info/yuan-ma-jie-du-saltstackyun-xing-ji-zhi-zhi-job-runtime/


Salt

Salt Master與Salt Minion創建了對應的ZeroMQ pattern, 那麼當一個遠程執行指令下發下去, 其數據流向是怎麼個流程哪? 以執行test.ping爲例:


1. 在master端bash下, 執行:


salt '*' test.ping

其對應的 python執行 是:


client = salt.cli.SaltCMD()

client.run()

在內部, 又是調用:


local = salt.client.LocalClient()

cmd_fun = local.cmd_cli()

for full_ret in cmd_func(kwargs):

    ret, out = self._format_ret(full_ret)

    self._output_ret(ret, out)

2. 在 LocalClient 對象初始化時, 會建立用於對發送的數據進行序列化的 Serial 對象, 及 MasterEvent 對象. MasterEvent對象會建立以下ZeroMQ pattern:


sub:

ZeroMQ pattern: zmq.SUB

listen地址: ipc:///var/run/salt/master/master_event_pub.ipc

listen方式: connect

做用: 用於訂閱來自於Master event pub接口的數據

3. cmd_cli 在執行時, 會首先經過 run_job 將操做指令封裝成以下內容:</p>


{'tgt_type': 'glob', 'jid': '', 'key': 'LCkViTMgqKBqb5ooG8kznznztLYPsWR1xdTYnAz9udkU9/Lla32yDvUmVKLPaUNSMtbWdBoQPIs=', 'tgt': '*', 'arg': [], 'fun': 'test.ping', 'kwargs': {'show_timeout': False}, 'cmd': 'publish', 'ret': '', 'user': 'root'}

將發送到本地master的Ret接口, 期間會建立以下ZeroMQ pattern:


socket:

ZeroMQ pattern: zmq.REQ

listen地址: tcp://127.0.0.1:4506

listen方式: connect

做用: 將封裝後的指令發送到Master Ret接口

4. Master Ret接口接收到3中發送的數據後, 會經過chminions.check_minions獲取本次須要哪些minions執行, 併產生jid, 而後在master event接口上進行fire_event操做, 以後對數據使用master私鑰(master.pem)進行簽名, 而後建立以下ZeroMQ pattern:


pub_socket:

ZeroMQ pattern: zmq.PUSH

listen地址: ipc:///var/run/salt/master/publish_pull.ipc

listen方式: connect

做用: 將指令傳送到Master Pull接口

Master Pull接口接收到數據後, 會迅速的在Master Pub接口上發送將以前收到的數據


同時將jid及minions封裝後的結果返回給3, 3中cmd_cli獲取到數據後, 調用 get_cli_event_returns ,監聽Master端的Event bus, 過濾出本次任務jid所對應的event, 用來獲取執行結果


5. 此時Minion經過PUB/SUB, 便可收到來自於Master Pub接口的消息. Minion接收到消息後, 會首先經過本地的master pub_key(minion_master.pub)進行解密, 已確保消息來自於Master. 解密完成後, 本地進行target匹配, 若是匹配上, 表示須要執行, 派生出一個新的進程進行執行. 反之則直接忽略.


6. Minion執行完畢後, 會經過 _return_pub 將封裝後的結果經過AES加密發送到Master的Ret接口.


7. Master Ret接收到6中發送的數據後, 會進行AES解密, 而後經過 _return, 首先將解密後的數據在本地event接口上進行fire_event, 並將結果存儲在master本地.


8. 因爲7中進行fire_event, 此時4中的get_cli_event_returns便可捕捉到, 因爲採用迭代器, 每一個收到的結果均能立刻顯示出來, 一旦捕獲到的minions的結果大於等於以前得到的minions數目, 即表示全部minions均已返回結果, 退出.


總結

Salt利用ZeroMQ靈活高效的patterns, 使Salt網絡拓撲變得很是靈活高效. 利用PUB/SUB, 實現了高效的遠程執行指令下發機制; 利用ROUTER/REQ, 實現認證及異步的遠程執行結果返回; 利用DEALER/REP, 實現多進程任務處理機制; 利用PULL/PUB, 實現Event BUS, 使其餘或第三方應用能夠快速的使用PUB/SUB接收到Event BUS上的消息.


I love Salt, I love ZeroMQ!


Powered by Redmine ? 2006-2014 Jean-Philippe Lang 

相關文章
相關標籤/搜索