理解SaltStack(5) – 状态系统

本文介绍salt的状态系统是如何工作的。
salt状态系统是在远程执行模块之后开发的,如你所想,salt状态系统是建立在远程执行模块之上的。salt状态模块除了一个重要的区别,其它的与远程执行非常类似。区别就是状态模块包含用于查看系统是否已处于正确状态的逻辑。事实上,逻辑确认后,状态模块仅仅是调用远程执行模块来执行任务的。

状态系统流程

状态系统与远程执行状态之间最主要的区别是状态系统内的流程控制。Salt提供了特殊的指令,可以定义依赖关系,重用代码,失败分支,控制流以及变量和模板。

理解SaltStack(4) – 远程执行

本文介绍salt远程执行系统是如何工作的。
salt一开始就是设计成为一个远程执行工具的,salt中其它子系统对远程执行使用非常频繁。

  • salt命令设计能跨系统和跨平台工作。根据目标平台情况salt ‘*’ pkg.install git命令使用yum,apt,pacman或salt的windows包仓库安装git软件。一个命令支持多个系统。
  • salt命令以一致的数据结构返回结果。这样使得测试结果和存储结果到数据库变得容易。
  • 由于接收命令是异步的,所有的目标系统能同时执行一个任务。
  • salt使用数百个python模块库完成远程管理,并且你可以添加自己的模块(或最好贡献你的模块到项目!)。任何能通过Python,shell命令或者任何其它接口访问的程序或服务都可以封装一个salt执行模块来执行任务。
  • 远程执行系统通过salt命令行来访问。让我们来尝试执行一个简单的命令,然后通过salt系统来跟踪它:

    1. salt ‘*’ test.rand_sleep 120

    基于我们对salt通信系统的了解,下面是这个命令的一些底层行为:

  • 1.此命令通过publisher端口发送到所有已连接的minions。
  • 2.所有minon检查此命令,评估自身与命令带的target字段是否匹配以此来决定是否应该执行这个命令。
  • 3.目标系统执行命令并返回结果给request server。
  • 我们来深入了解,当在minon执行命令时发生了什么。首先每个命令分到一个单独的工作线程,所以salt minion能同时执行多个任务。
    那么在minion谁来执行test.rand_sleep 120命令?当然是salt执行模块!
    所有用来管理系统的命令都由salt执行模块来提供。这些模块就是在salt中做实际的工作的,并且你只要用一次后就大概知道它们如何工作了。
    当salt minion收到一个命令,找到正确的模块(在这个示例中是test模块),然后调用相关的函数(rand_sleep)及其参数(120)。
    运维自动化

    理解SaltStack(3) – 通信与安全

    本节介绍Salt通信模型以及认证和安全性的基本概述。

    架构模型

    salt使用server-agent通信模型,(可以作为独立的单台服务器管理工具,也能无代理通过SSH工作)。这个服务器组件称为salt master,代理称为salt minion。
    运维自动化
    salt master负责发送命令给salt minons,然后聚合显示这些命令的结果。单个salt master能管理数千个系统。

    通信模型

    Salt使用发布-订阅模式与受管系统通信。连接由salt minion发起,意味着你不需要在那些系统上监听任何端口来接收请求(从而减少攻击的可能性)。salt master使用4505和4506端口,必须向minion开放接收请求。
    运维自动化

  • Publisher: (4505端口)所有的salt minions与publisher端口建立持久连接。通过此端口在所有的连接上异步发送命令,这使得能够在大量的系统上同时执行命令。
  • Request Server:(4506端口) salt minions连接request server,当需要时发送结果给salt master和安全地请求文件,minion特定的数据值(称为salt pillar)。salt master和salt minion之间的连接是1:1的,且不是异步。
  • SALT MINION认证

    当minion首次启动时,通过网络搜索名称为salt的系统(不过这很容易更改为一个IP或者其它的主机名)。当发现后,minion发起一个握手然后发送它的公钥给salt master。
    运维自动化
    此次连接发起后,salt minion的公钥就存储在了服务器上,然后必须在salt master上执行salt-key命令接受这个minion(或者通过一些自动机制)。当salt minion的公钥被接受时,salt master才会提供解码消息所需的安全密钥(意味着在minion的key还没被接受时,minion不会运行任何命令)。
    minion的key被接受后,salt master给minion返回公钥和AES key,用来加密和解密由master发送的消息。AES key使用minion发送过来的公钥来加密,因为AES key只能由minion解密。

    安全通信

    salt master和salt minion接下来之间的通信都是使用轮换的AES key来加密。AES加密密钥使用TLS的显式初始化向量和CBC块链接算法。

    轮换的安全密钥

    轮换的AES密钥用来加密由salt master发送给salt minion的作业和加密与salt master文件服务器的连接。每次salt master重启和每次salt minion的密钥被删除都会使用salt-key命令来重新生成一个新的密钥。
    当新密码生成后,所有的salt minions必须重新发起认证请求来接收更新的AES密钥。这就使得AES的更新不会中断minion的连接。

    加密通信信道

    Salt master和Salt minion之间的发布通信使用轮换AES密钥加密。Salt master和Salt minion之间的直接通信使用唯一AES密钥来加密每个会话。
    例如,发布作业使用轮换AES密钥来加密,然后minion特定的数据(如salt pillar)使用唯一的AES密钥加密。

    用户访问控制

    在一个命令发送给minions之前,salt对Publiser ACL执行一些内部的检查以确保用户有权限执行当前的命令。如果用户被授权对指定的目标运行指定的命令,则发送命令。否则返回错误。

    理解SaltStack(2) – 插件

    没有涉及salt插件的讨论那所有关于salt方法的讨论都是不完整的。理解插件和salt的可插拔架构往往就像发现新大陆的感觉,把salt研究者变成salt的福音传道者。
    基本的解释是:salt的核心框架提供了高速通信和事件总线。
    此框架连接并验证受管系统,并为这些系统提供发送通知的方法。
    在这个核心框架上层,Salt的其余功能暴露为一组松散耦合的可插入子系统。

    可插拔的子系统

    salt包含超过20个的可插拔子系统,但大多数用户只对用于直接管理系统的少数感兴趣。下表包含Salt中一些更常见的子系统的列表:
    运维自动化

    “可插拔是什么意思”
    Salt没有定义一个内置的方式来执行任何子系统的任务,每个子系统仅仅是把它的工作委托给插件。salt为每个系统提供一系列的插件,不过更改一个插件在大多数情况下跟更新一个配置文件那样的简单。这种可插拔性使salt非常灵活。

    为了说明,下图显示了几个常见的子系统以及每个子系统最常见的插件。
    运维自动化
    此图表只显示了一些可用的子系统和插件,但应该能给你对salt一般架构有一个初步了解。

    作业运行期间的子系统

    当一个作业运行时,几个salt子系统被调用用来处理作业。下面的图表显示一个经典的状态运行或远程执行作业的子系统流程:
    运维自动化

    插件?听起来像讨论salt模块!
    在salt中,插件就是Python中的模块,既然每个插件就是一个Python模块,大多数时候,他们被简单地称为模块,或更准确地,Salt子系统模块(Salt auth模块,Salt文件服务器模块等)。只要你明白每个Salt模块都是一个扩展Salt中许多子系统之一的插件,你就会很好地理解这种关系。

    在每一步中,子系统委托它的工作给配置的插件。例如,在第7步的job returner插件可能是30个插件中的一个,包含MySQL,redis或者根本没有配置的(在第4步后job returner插件也可以直接在受管系统上运行)。
    在每一步中,有许多可用的插件用于完成一个任务,从而可以产生数百种可能的salt配置和工作流。

    伸缩性

    伸缩性使salt成为一个非常强大和可定制的工具,不过当你在学习这个工具时使得很难回答一些标准的问题。
    为了有趣些,我们采取“技术上正确”的方法,并回答几个关于Salt的常见问题:

  • 你如何开始salt作业?- 从任何可以调用Python,REST API,命令行或使用salt内置调度程序的接口
  • salt如何格式化结果? – YAML,JSON,纯文本,python数据结构和其它一些格式,你可以在任何时候使用单个参数来更改格式。
  • Salt使用什么格式来配置声明? – 根据你的使用情况来从15个支持的格式中选择一个,你还可以选择模板语言。格式是基于每个文件指定的,因此你可以同时使用多个格式。
  • 结果保存在哪里? – 你想存储的任何地方,你有30个选择。
  • 除了让你非常讨厌的对话,以这种方式回答这些问题确实说了一些关于salt方法管理的事情。你了解你的基础设施,在目前复杂的环境中,没有做任何事情最好的方式。
    没有必要为这些事情烦恼,salt为大多数用户设置了出色的默认值。主要是,当你什么时候需要伸缩性,它就在那里。

    salt组件

    有了salt的可插拔子系统的新知识,希望你开始明白,salt组件实际上是salt中的可插拔子系统,具有相应的插件。Salt grains? Salt pillar? Salt runners?所有可插拔子系统都很容易扩展。

    虚拟模块

    我们在这里已经讨论了很多,但是还有一个我们需要讨论的模块。还记得早些时候我们解释了salt如何抽象操作系统的底层细节吗?salt实现这种抽象的一种方式是使用虚拟模块。
    一些管理任务在不同的操作系统之间非常的不一样,在编写插件时,它们之间能使用的重复代码很少。
    例如,Debian系统上的包管理使用一个名为aptpkg的执行模块完成。在Redhat上,它使用一个名为yumpkg的执行模块完成(原因很明显)。如果你一直使用Salt,你会知道salt调用pkg远程执行模块进行包管理,它可以在所有操作系统上使用。
    为了启用这种类型的抽象,Salt使用虚拟模块名称加载这些类型的模块。aptpkg模块包含的说明基本上说“如果你是Debian系统,请将此模块加载为pkg。 否则,不要加载这个!类似的代码存在于对Redhat或CentOS的检查决定使用yumpkg中。这样可以存在多个模块来执行相同的任务,但只加载了一个虚拟名称。
    在阅读模块文档时,请记住这一点,因为你经常需要阅读非虚拟模块的文档以了解其行为。你可以在Salt模块中搜索__virtualname__,以找到Salt在加载该模块时使用的名称。
    下一篇文章我们讨论salt的通信。

    理解SaltStack(1) – 设计思想

    你可以通过观察saltstack的行为来了解它是如何工作的。那就是说,很多事情发生在底层你很难注意到,就像数据文件在控制台传输。此系列文章说明saltstack是如何工作的,saltstack的子系统,以及saltstack模块化架构如何使用和扩展saltstack来管理你的整个基础架构。
    在我们了解saltstack的特定组件之前,有必要了解关于SaltStack如何处理基础设施管理的方方面面。

    实时通信

    所有的salt minions都是同时接收到命令的。那意味着更新10或10000个系统所花的时间非常相近,并且能够在数秒钟内查询数千个系统。saltstack获取关于你基础设施的信息方法是实时查询的,而不是依赖数据库。

    各司其职

    salt minions只做属于它们自己的工作。Salt master发送的是一组轻量级的指令,基本上是包含”如果你是一个带有这些属性的minion:运行这些带参数的命令”。当接收到命令时,由salt minions判断是否与属性匹配。每个salt minion已经有需要存储在本地的所有命令,所以命令能够被执行和其结果很快地返回给salt master。salt master不需要为minion做任何工作,因为它能自己完成,常常能完成得更好。

    高性能和可扩展性

    Saltstack设计用于高性能和可扩展性。saltstack的通信系统在salt master与minions之间使用ZeroMQ或原始TCP建立一条持久的数据通道,给予saltstack相对于竞争方案相当大的性能优势。消息使用MessagePack进行高效序列化。在内部,salt使用Python Tornado作为一个异步网络库,而且使用了多线程和并发这些前沿的技术来进一步优化salt性能。
    用户在生产环境中的单台master管理超过10000台minions并不是不常见,目前所知有越过35000台minions由单台salt master管理!salt已经证明了其在真实环境中的速度和可扩展性。

    规范化一切

    规范化是saltstack跨平台管理功能的关键。不管你的目标机器是Linux, Windows, MacOS, FreeBSD, Solaris, AIX,物理硬件,云主机或容器,salt命令和状态都运行一致。salt抽象每个操作系统,硬件类型和系统工具的详细信息以便你能正确地管理你的基础设施。
    规范化一切还包括返回:salt命令返回以一致的数据结构的结果以方便解析和存储。

    管理一切

    salt几乎都能运行在安装有Python的所有设备。对于不支持Python的那些设备,你可以使用minion代理系统。这意味着能够被salt管理的唯一条件是支持任意的网络协议(甚至是你自己写的协议)。salt命令被发送到minion代理服务器,它将salt调用转换为本地协议,然后发送到设备。解析从设备返回的数据,然后放入数据结构并返回。

    自动化一切

    salt的事件驱动基础设施不仅让你能够自动化初始系统配置,也让你能够自动化扩展,修复和完成持续管理。salt用户自动部署和维护复杂的分布式网络应用程序和数据库,自定义应用程序,文件,用户帐户,标准包,云资源等。

    可选编程

    你不需要学习编程语言就能够使用salt的所有功能。salt的远程执行能力是CLI命令,状态系统使用YAML来描述系统的所需配置。
    你仍然可以采取”基础设施即代码”的方法 – salt有许多工具来支持这点,包括强制的必要系统与命令式和声明性执行。Salt只是帮助你不需要编写Python或Ruby代码来描述你的基础设施。

    模块化系统

    一些管理工具认为它们是可扩展的,因为它们能够运行外部脚本。在saltstack中,一切都是可扩展性的。下一篇文章会介绍,甚至是底层的通信协议都是可互换的。salt有超过20个可扩展的子系统,意味着salt能够做的事件,你也可以自定义它怎样完成任务。
    salt能够快速适应新的技术和管理新的应用,你永远都不会被别人的决定所困扰,管理你的基础设施哪一个方法最好。

    插件

    在下一篇文章,我们将介绍salt插件,以及它为什么对salt至关重要。

    SaltStack源码解析 — salt ‘*’ test.ping执行过程

    前言

     

    本文我们来学习salt ‘*’ test.ping命令实现的整个过程,涉及的组件比较多,将有助于更进一步了解SaltStack的运行机制。

     

    总体概述

     

    salt ‘*’ test.ping涉及的组件比较多,包括Master Req Server,Master Publisher,Minion,Master EventPubliser等,现在概要地介绍下整个实现流程:

    • 1、在salt-master机器执行salt ‘*’ test.ping命令;
    • 2、salt向Master Req Server发送带publish命令的消息;
    • 3、Master Req Server收到消息后向publish_pull.ipc push消息;
    • 4、Master Publisher向Minion Publish消息;
    • 5、Minion收到消息后启动一个新进程来执行消息中fun指定的函数;
    • 6、函数执行完成后,返回结果给Master Req Server;
    • 7、Master Req Server把结果push给Master EventPublisher;
    • 8、这时因为salt客户端订阅了Master EventPublisher,将收到返回结果,之后直接输出到终端。整个流程结束。

     

    活动图

     

    为了更清楚了解整个流程,下面是活动图:
    源码解析

     

    salt ‘*’ test.ping函数调用图

     

    源码解析

     

    Master Req Server处理salt test.ping消息函数调用图

     

    源码解析

     

    Minion处理Master Pub消息函数调用图

     

    源码解析

     

    Master Req Server处理Minion数据返回函数调用图

     

    源码解析

    SaltStack源码解析 — Master与Minion认证过程

    前言

     

    在Minion进程启动的时候,先会连接Master的Req Server请求认证,直到认证成功才会继续。下面我们分析其认证过程。

     

    总体概述

     

    • 1、完成Minion进程启动前,Minon向Master Req Server发送cmd为_auth的payload消息;
    • 2、Master Req Server收到Minion的消息后,使用_auth方法执行认证处理;
    • 3、开始对key文件作如下判断,如果key在minions_rejected目录,则拒绝连接;如果key在minions目录,验证pub key是否相等,如果不相等,加入到minions_denied;如果key不在minions_pre目录,则把key写入到minions_pre目录;如果minions_pre不存在,如果pub key验证不通过,加入到minions_denied目录。

     

    minion认证请求过程活动图

     

    源码解析

     

    minion发送认证请求函数调用图

     

    源码解析

     

    master处理minion验证请求函数调用图

     

    源码解析

    SaltStack源码解析 — salt-minion启动过程

    功能介绍

     

    salt-minion负责接收salt-master的消息,执行相应的指令。

     

    环境介绍

     

    • 系统:CentOS-7
    • python版本:2.7.5
    • saltstack版本:2015.5.2 (Lithium)

     

    场景描述

     

    本节分析salt-minion启动过程,我们使用如下命令启动salt-minion:

    1. /usr/bin/salt-minion -d

     

    总体分析

     

    salt-minion启动过程总体分析如下:
    1、使用parsers.MinionOptionParser类解析命令行参数及配置文件,此类继承了MasterOptionParser类,与salt-master解析过程差不多;
    2、加载必要的模块,如grains,pillar;
    3、开始连接salt-master的Req Server,评估与master的验证状态,如果master没有把minion的key加入信任列表,minion则循环验证直到验证通过;
    4、发送消息通过master,minion已启动;
    5、订阅salt-master pub服务器。

     

    详细分析

     

    函数调用流程图

     

    源码解析

     

    核心类功能介绍

     

    类关系图

    源码解析

    MinionOptionParser类

    MinionOptionParser类继承了MasterOptionParser,覆盖了MasterOptionParser的setup_config方法,改为由之前的master配置文件为minion配置文件。MasterOptionParser的讲解可以参考SaltStack源码解析 — salt-master启动过程

     

    Minion类

    这个应该算是比较重要的类了,包括了与master通信的所有方法。比如_do_socket_recv,负责接收master pub信息;_do_event_poll,负责处理事件;authenticate负责处理与master的验证。

    SaltStack源码解析 — salt-master启动过程

    环境介绍

     

    我们使用如下环境来分析SaltStack源码:

    • 系统:CentOS-7
    • python版本:2.7.5
    • saltstack版本:2015.5.2 (Lithium)

    我们使用如下方法来安装salt-master:

    1. rpm -Uvh http://mirrors.opencas.cn/epel/7/x86_64/e/epel-release-7-5.noarch.rpm
    2. yum install salt-master

     

    场景描述

     

    本节分析salt-master启动过程,我们使用如下命令启动salt-master:

    1. /usr/bin/salt-master -d

     

    前置阅读

     

     

    总体分析

     

    salt-master的启动过程可简单分为两块,一是解析配置文件和命令行参数,二是启动所需进程。
    对于解析命令行参数,主要使用到python标准模块optparse,解析master配置文件使用yaml模块。
    主要过程为:
    1、导入salt.syspaths作为命令行参数默认值,导入salt.config作为master配置文件默认值;
    2、ConfigDirMixIn,LogLevelMixIn,RunUserMixin等几个类使用optparse的add_option注册命令行选项;
    3、调用parse_args函数,解析命令行参数,解析master配置文件;
    4、调用self.master.start(),注册sigusr1和sigusr2信号,分别用来输出堆栈和profile信息;
    5、接着启动所需进程,如maintenance进程,publisher进程,master event进程等。

     

    详细分析

     

    函数调用流程图

     

    源码解析

     

    核心类功能介绍

     

    类关系图

    图片源码解析

    MasterOptionParser类

    此类主要用来解析命令行参数和yaml配置文件。继承了python标准optparse.OptionParser类,以前这六个类ConfigDirMixIn,LogLevelMixIn,RunUserMixin,DaemonMixIn,PidfileMixin,SaltfileMixIn分别用来注册配置文件路径,日志等级,守护进程,pid文件路径,saltfile路径等命令行选项。重写了optparse.OptionPaser的parse_args方法,添加对master yaml配置文件的解析。

     

    Maintenance进程

    Maintenance进程是用来做master的常规维护工作,如维护定时任务.

     

    Publisher Server

    绑定了默认的4505 zmq pub端口和publish_pull.ipc pull类型ipc,只要向publish_pull.ipc push数据,凡是subcribe 4505 publisher的client都将收到数据,具体此server什么作用还没有看.

     

    EventPublisher Server

    绑定了master_event_pub.ipc pub和master_event_pull.ipc pull,只要向master_event_pull.ipc push数据,订阅master_event_pub.ipc的client将收到消息.

     

    ReqServer Server

    启动了多个Mworker进程,每个进程连接workers.ipc REP,再启用了zmq_device,绑定tcp port 4506 ROUTER和workers.ipc DEALER,这样只要向4506 发送REQ数据,将会负载均衡到Mworker进程,Mworker进程收到请求后执行_handle_payload函数,也就是执行相应的模块.