6 继续深入salt内部
6.1 salt配置
在/etc/salt
目录下通常会看到有master和minion文件,分别对应其配置。
有一些用户由于组织需要,需要将这些配置划分到更小的配置文件中。更重要的原因是Salt能够管理自身,相对于使用一个超大的配置文件来说,将它们按照需要划分到更小的、独立的、模板化的文件中更容易管理。
因此Master也会默认引入在/etc/salt/master.d/
目录(Minion对应的是 minion.d目录)中以.conf为扩展名的文件。这和很多其他服务的设计一样,使用类似的目录结构。
和Salt其他地方的配置格式一样,这些核心配置文件的格式必须是YAML格式的。
6.2 管理salt密钥
在/etc/salt
目录下有一个pki目录,下面会有master/和minion目录,分别用来存放对应的公钥和私钥。
minion上的/etc/salt/pki/minion
目录下只会有3个文件:
- minion.pem minion的RSA私钥
- minion.pub minion的RSA公钥
- minion_master.pub master的RSA公钥
master端也会将它的RSA密钥存放在/etc/salt/pki/master/
目录下(master.pem和master.pub),同时这个目录下对应还有至少三个目录:
- minoins.pre 还未被接受的minion端RSA公钥
- minions 被接受的minion端RSA公钥
- minions_rejected 被拒绝的minion端RSA公钥
6.3 salt缓存
salt同时也维护了一个缓存目录,通常在/var/cache/salt/
下。
master端任务缓存
你每天可能最常用的第一个缓存目录是jobs/录在默认配置中,该目录存储所有Master执行的任务数据。
这个目录使用hash映射(hashmap)样式存储。hash映射样式是指每条信息(本例中是任务ID或JID)通过hash算法进行运算,然后按照hash值的全部或一部分内容创建目录或目录结构。在本例中,使用分片hash模式,使用hash值的前两个字符创建父目录,子目录以切除前两个字符后的hash内容进行创建。
Salt默认使用的hash类型是MD5,算法可以通过修改 Master hash type的值进行调整:hash type: md5
minion端缓存的两个重要目录
minion端主要维护缓存两个目录:
proc目录
这个目录主要是维护当前minion正在运行的任务数据
通过给minion下发一个sleep命令操作,可以非常容易地看到这个目录salt 'salt-minion2' test.sleep 20 --async # async参数表示异步,master端会立即返回一个jid后退出
此时查看minion端:
[root@salt-minion2 minion]# find . -type f -mmin -1
./proc/20190414155119820447可以清楚看到任务文件被创建,执行完成后消失。
extendmods目录
这个目录是用于存放从master上同步到minion上的用户自定义模块,在master上的/srv/salt
创建一个_modules目录,写入如下内容:[root@salt-minion2 modules]# cat mytest.py
def ping():
return True接下来使用命令同步模块到minion:
[root@salt-master _modules]# salt 'salt-minion2' saltutil.sync_modules
salt-minion2:
- modules.mytest # 返回同步完成接下来可以在minion端extmods/modules目录下看到这个文件,同时可以在master上执行自定义方法:
[root@salt-master _modules]# salt 'salt-minion2' mytest.ping
salt-minion2:
True
6.4 事件系统
6.4.1 通用事件
在salt内部有一些非常通用的事件,一部分只应用在salt内部的子模块中,了解这些事件以及它们如何工作将会在构建反应器(Reactor)时非常有益。
salt/auth
minion会使用该事件定期完成与master的重认证,payload中包含:
- act: 指定该minion当前的状态
- id: 表示该minion的ID
- pub:指定该minion的RSA公钥
- result:指定该请求是否成功
salt/key
master端发送给minion端,告诉它密钥被ACCEPT或者REJECT的状态
- id: 指定该minion的ID
- act: 表示该minion的新状态
salt/minion//start
当salt-minion进程启动时,会在接收命令前做一些工作,一旦进程启动完毕可以处理任务时就会发送这个事件,这是一个老事件,可期待未来的版本移除。
- cmd: 用于告诉salt这是一个什么类型事件
- data: 指定salt什么时候启动
- id: 指定该minion的id
- pretag:salt内部用于产生命名空间
- tag: 事件标签的副本
salt/job//new
当创建一个新任务时,将发送该时间,包含任务的元数据,payload包含:
- arg: 指定要传递给方法的参数
- fun: 指定要调用哪个方法
- jid: 指定任务的ID
- minions: 表示需要执行该任务的minion列表
- tgt:指定该任务的target
- tgt_type: 指定该任务的target类型
- user: 指定初始化该任务的用户,如果用户使用sudo,将在用户名称前增加sudo
salt/job//ret/
一旦minion完成了任务, 它会发送一个返回数据的事件,payload包含:
- cmd: 这是另一个告诉salt这是什么类型事件的指标
- func: 类似于salt/job/
/new,指定当时调用的是哪个方法 - func_args: 类似于之前的args, 指定传递给该方法的参数
- id: 指定是哪个minion返回的数据
- jid: 指定任务ID
- retcode: 指定在处理任务时进程的返回代码
- return:指定任务所有的返回数据,跟据执行任务的不同或长或短。
- success:任务是否成功完成
salt/presence/present
只有当master配置文件中presence_events设置为True时才会有这个事件,会定期发送包含当前连接到master上的minion列表的事件。
- present:指定当前连接到master上的minion列表
salt/presence/change
只有当master配置文件中presence_events设置哪位True才有这个事件,有新的minion连接到master或从master上断开连接,会发送该事件。
- new: 指定从上次出现事件起已经连接的minion列表
- lost: 指定从上次出现的事件起已经断开连接的minion列表
6.4.2 通用云事件
salt/cloud//creating
该事件关于虚拟机创建的,payload包含:
- name: 要创建虚拟机的名字
- provider:指定要应用云供应商的名字
- profile: 指定要使用profile的配置
salt/cloud//requesting
当所有用于创建虚拟机需要的信息收集后,salt clou会从云供应商处产生一个虚拟机创建完毕的请求,payload包含:
- kwargs: 指定来自于云供应商的所有参数,使用profile,用于搜集该请求的云拓扑
salt/cloud//querying
云供应商开始处理创建一个虚拟机并返回 Salt Cloud能够用于指向的ID。然而,它井不返回 Salt Cloud Salt Cloud会等待虚拟机的IP地址变成可状态。有效装载中将包含如下数据:
- instance_id:指定云供应商需要知道的创建的虚拟机ID。它可能并不会对正的虚拟机名称或 Minion ID
salt/cloud/<vm_name>/waiting_for_ssh
当返回一个虚拟机IP地址时,并不代表虚拟机可用 Salt Cloud会等待虚拟机变成可用并且可以响应SSH连接。有效装载中将包含如下数据:
- ip_address:表示用于连接该虚拟机的主机名或IP地址。
salt/cloud/<vm_name>/deploying
虚拟机现在可以通过SSH访问(Windows WinRM)。部署(或 Windows Minion配置)会上传上去后部署脚本(或Windows安装器)会执行。有效装载中将包含如下数据。
- name:指定已经创建的虚拟机名字。
- kwargs:用于部署Salt到目标系统上的参数。它会是非常长的列表,有一些项部署脚本的内容)会非常长。
salt/cloud/<vm_name>/created
虚拟机已成功创建。这并不一定表示salt- minion进程已经可以接收连接,有可能现在还在启动阶段。此时有可能因为防火墙问题,或者其他原因导致部署脚本或 Windows安装器安装失败。如果你想等到 Minionminion/minionid> startscloud/< name>/created标签。有效装载中将包含如下数据。
- name:指定已经创建的虚拟机名字。
- provider:表示使用的供应商配置的名字。
- profile Profile配置的名字。
- instanceidMinionID不一致。
salt/cloud/<vm_name/destorying
Salt Cloud可以产生一个请求给云供应商用来销毁一个虚拟机。每个云供应商驱动都必须支持该标签。有效装载中将包含如下数据。
- name: 指定需要销毁的虚拟机名字。
salt/cloud/<vm_name>/destoryed
Salt Cloud已经销毁该虚拟机。每个云供应商驱动都必须支持该标签。有效装载中将包含女下数据。
- name: 表示刚刚完成销毁的虚拟机的名字。
6.1.3 salt API 事件
Salt API是Salt内置的API守护进程,它为取代命令行方式来控制Salt提供了REST接需要注意的是 Salt APIwebhook发送自定义事件的特性。稍后将在 Salt API部分做详细描述。
salt/netapi/
真实的URL路径依赖于salt api的配置,通常情况下会包含一个hook-to单词来表示它是个webhook,随后跟着一个斜线及任意的命令,payload:
- data: 表示用于POST给salt API URL的自定义数据。
6.5 反应器(Reactor)
salt与其他类似的系统的一个重大区别特性是,它不仅能发送事件,而且master能够基于时间中的事件来产生新的任务,为用户提供一个构件异步和自主式的系统。
6.5.1 配置反应器
反应器是master端进程,不需要直接在master端做任何配置,事实上反应器需要监听事件总线来确定它需要执行什么。一般情况下,反应器存放在/srv/reactor/
目录下。
反应器需要在master配置文件中配置,它包含标签映射以及当发现标签时应该执行的SLS文件列表,例如:
|
这是一个简单的反应器,它会等待minion完全启动并且准备接受指令时,调用highstate文件以响应。
一些注意事项:
- 在反应器系统中,事件标签会以glob通配方式进行解析,允许利用命令空间标签,基于来自特定minion事件的生成任务进行处理
- 标签(tag)和sls文件列表样式的,反应器系统中有多少需要关注的标签以及一个标签对应多少sls文件并没有什么硬性限制,但反应器是顶级声明,不能在master配置文件里配置多个反应器。
6.5.2 编写反应器
反应器默认采用YAML格式,也允许salt支持的其他格式,反应器sls文件包含三个部分:一个ID起始
,指定方法
,该方法的参数
,如下:
|
其中功能模块支持三种不同种类的方法:
- 执行模块
- runner
- wheel
使用时需要在方法名字前分别加上cmd\runner\wheel
6.5.3 调用执行模块
执行模块作为salt的基础是反应器中最长用的类型。执行模块运行在minion端,需要在salt命令中指出有哪些minion作为目标(target)需要执行。这个目标对应到反应器中是tgt
。如果不想使用默认的glob
,需要通过tgt_type
来声明目标类型。
在反应中支持如下目标类型:
- glob
- pcre
- list
- grain
- grain_pcre
- pillar
- nodegroup
- range
- compound
大多数执行模块需要指定参数列表,在反应器中可以通过arg或kwargs进行声明,arg参数包括需要传递给方法的参数列表,通过顺序来指定传递的位置。
|
kwargs参数包含一个需要传递给方法的参数名称以及对应值的字典。
|
6.5.4 调用runner模块
runner模块运行在master端,因此不需要指定运行目标(target),但是arg参数和kwarg参数依然可用,使用方法和执行模块一样:
|
6.5.5 调用wheel模块
wheel模块设计用于管理master自身,因此也不需要指定运行目标。
在wheel反应器中最常见的用法是接收或删除master上minion的key:
使用wheel反应器时需要格外小心,尤其是接收minion key的操作。
当通过python来编写反应器时要尽可能地保持简单,因为slat每次只能执行一个反应器,复杂的反应器会导致其他反应器排队等待它的返回。
6.6 编写更复杂的反应器
salt内置了丰富的模块,在反应器系统中可以实现强大的功能。接下来我们学习反应器如何使用这些模块。
发送告警
salt内置了一些模块用于对外发送告警,如smpt和http执行模块,下面我们来看一个设置简单监控的例子,它会检查minion端的磁盘使用情况,如果指定的磁盘满了,会发送一个告警。
首先看看如何建立一个监控磁盘状态的监控state
创建/srv/salt/monitor/disks.sls
文件并包含如下内容:root_device_size:
disk.status:
- name: /
- maxium: '90%'
- onfail_in:
- event: alert_admins_disk
alert_admins_disk:
event.send:
- name: alert/admins/disk接下来我们在master的配置文件中映射该事件标签给反应器以及pagerduty服务的配置:
739 reactor:
740 - alert/admins/disk:
741 - /srv/reactor/disk_alert.sls
742
743 my-pagerduty-account:
744 pagerduty.subdomain: mysubdomain
745 pagerduty.api_key: 1234567890ABCDEF1234接下来我们会创建使用pagerduty服务的事件来创建/srv/reacotr/disk_alert.sls:
1 new_instance_alert:
2 runner.pagerduty.create_event:
3 - kwarg:
4 description: "Low Disk Space: {{ id }}"
5 details: "Salt has detected low disk space on {{ id }}"
6 service_key: 01234567890ABCDEF0123456789abcde
7 profile: my-pagerduty-account此时,当salt检测到根设备使用率超过90%, 我们将会看到它产生alert_admins_disk事件。但我们看不到触发了disk_alert反应器,以及它会在pagerDuty中创建一个事件。
我们可以使用salt调度器(scheduler)
来创建自动运行这个进程,只需在minion配置中加入如下代码块:
|
配置完毕后重启minion,minion会每6分钟执行一次minion_disks.sls。
6.7 使用webhook
salt API提供一个REST接口,它能够用于接收webhook,这些webhook可以转换为事件,被反应器接收。
在我们接收webhok前,需要先进行salt API配置。
首先需要编辑master配置以使salt API能接收口webhook:
rest_chaerrypy:
port: 8080
host: 0.0.0.0
ssl_srt: /etc/pki/tls/certs/localhost.crt
ssl_key: /etc/pki/tls/certs/localhost.key
webhook_url: /hook
webhook_disable_auth: True接下来我们可以创建事件来映射来对应我们想要执行的sls文件。添加如下内容到master的配置中:
reactor:
- salt/netapi/hook/customevent
- /srv/reactor/webhook.sls
(部分内容实验有误暂时略过,待补充)
6.8 使用队列系统
队列系统是另外一个具有发送事件能力的salt组件,它可以在反应器中使用。
队列如何工作
从基本的层面上讲,队列是非常简单的,我们能够在队列中添加项目,能在稍后按照添加的顺序处理这些项目。依赖于所使用的队列模块,项目可能唯一也可能不唯一。
在我们的例子中,我们将使用默认的 sqlite 队列模块。sqlite3内置于 Python中,因此该模块可以工作在任何基础设施中。该模块将会在数据库文件不存在时自动创建数据库文件。需要注意的是, sqlite需要项目是唯一的。如果你想使用其他模块,只需要在队列命令后添加 backend sqlite中存放的队列列表,需要使用如下命令:
|
队列系统通过 runner进行管理,这意味着队列数据库只能被Master访问。当然稍后我们将看到它也用于在 Minion上管理任务。
添加项目到队列中
在通过队列处理之前,我们需要先添加一些项目到队列中,以便之后处理。现在我们将用一个叫作myqueue的队列,接下来的命令会添加一个项目到该队列中
|
也可以一次性添加多个项目
|
列出队列和队列中项目
下列命令列出队列:
|
下面命令列出队列中所有项目:
|
处理队列中项目
弹出(pop)队列中项目:
|
弹出队列中多个项目:
|
然而它并不能提供系统的自动化功能,如果想实现自动化,我们需要给反应器系统发送事件。下面的命令从队列中弹出一个项目并为它发送一个事件
|
从队列中删除项目
|
也可以用列表形式一次性删除多个项目:
|
7 用highstate复合主机状态
7.1 highstate组织多个状态配置
之前我们都是使用state.sls模块来运行状态文件,通过单一的状态文件我们可以完成诸如Apache的部署,配置文件的下发,LAMP环境安装等等。但实际的生产环境中会存在大量的主机角色,我们需要通过拆分和复用让状态文件更加模块化。同时需要能整体性组织和管理这些模块,salt为我们提供了highstate模块让我们完成这个任务。
7.2 用top.sls文件管理状态文件
top.sls也可以用来在状态系统中将不同的状态定位到不同的minion中。highstate函数正是通过top.sls文件作为入口对模块和主机进行管理的,下面首先学习用highstate函数配合top.sls文件来管理状态文件。
把lamp环境和Nginx代理状态配置文件整合:
|
编写top.sls:
|
(以下略,待补充)
7.3 状态文件的拆分复用
通过对状态文件的拆分和配置top.sls文件可以灵活地组合各种复用模块来管理minion。
(以下略,待补充)
7.4 多环境配置和管理
前面我们通过top.sls配置文件和模块的拆分已经可以对多种状态和多组minion进行同时管理了,只需要执行一条#salt state.highstate
就能完成base环境内所有minion的管理。前面的top.sls都会包含一个base:配置项,这个其实是salt配置文件中默认的环境目录,可以看一下/etc/salt/master中对应的部分:
|
file_roots这个配置项指明了我们的环境目录在哪里,salt执行对应的sls状态文件都会从默认的目录去找。一般企业都会有开发环境、测试环境和生产环境。这些环境如果都放在base目录内进行管理就会比较混乱,为了区分和便于管理,可以对不同的环境配置不同的目录:
|
重启salt-master,建立了多个环境目录后我们可以通过维护多个top.sls配置文件来管理各自的环境,也可以通过维护一个top.sls来进行管理。多个环境的top.sls在最终执行salt ‘*’ state.highstate 命令时也会合成为一个文件。
举例说明:
|
分别在file_roots: 指定目录中建立对应的状态配置模块,在/src/salt/top.sls中对所有环境的管理做统一入口,这样就可以完成不同环境的管理和隔离。
7.5 实践:keepalived + redis 高可用架构部署
文件列表如下:
|
设置master的grains,指定role、vip、redis的masterip:
|
设置slave的grains,指定role、vip、redis的masterip:
|
设置入口文件:
以list匹配的方式对两台主机应用对应的模块
|
部署Redis
安装Redis并且根据角色下发配置模板文件:
Redis安装入口文件
|
Redis软件包的安装:
|
Redis配置下发以及创建目录:
|
Redis服务启动控制:
|
部署keepalived
keepalived安装入口文件:
|
keepalived软件包的安装:
|
keepalived配置下发以及创建目录:
|
keepalived服务启动控制:
|
8 实战案例解析
8.1 LAMP环境搭建
Apache安装配置
目录结构大致如下所示:
|
apache.sls:
|
测试:
|
apache已正确安装
PHP安装
同理:
php.sls
|
MySQL安装
mysql.sls:
|
(待续)