随着上线的服务器数量增多,如何批量有效的管理各个节点服务器正常运作是每个运维人员需要解决的难题。
什么是 saltstack
你要是 naive 地问:部署服务器,有什么好难的?不就写个脚本,再 one by one 地 ssh 这些服务器跑一遍吗?
服务器少还好办,几台、几十台一般人尚可承受但,再不济多配几个运维(貌似无意间黑了一下运维,嘻嘻)嘛~
但,假如你有成百上千台服务器需要部署,你会怎么做?想象一下你每次 one by one 地登陆这些服务器,在这些服务器中执行同样的命令并且编辑同一个配置文件,这他妈完全是重复性操作啊,人呐,重复性劳动做多了难免会犯错,要是稍微不留意手一抖配错了咋办?即使侥幸部署成功,将来需要更改配置,所有的线上环境都要同步变更,你再让我 one by one 地操作这些服务器?!
我的天呐~我疯了吗!
技术人的自我修养之一:如果一条命令重复了两次,你就要交给机器去做。
那么,问题来了:
怎么样通过一个命令一次完成所有服务器的部署操作?
在这种情况下,一些批量部署的工具应运而生,比如 puppet,saltstack,chef 等等……
saltstack 是使用 python 编写的开源自动化部署与管理工具,它取 Puppet 和 Chef 二者之所长整合之,拥有良好的扩展性以及优秀的执行效率,配置简单,跨平台,适合大规模批量管理服务器。
saltstack 原理
Saltstack 基于 C/S 架构,服务端 master 和客户端 minions。minion 与 master 之间通过 ZeroMQ 消息队列通信,使用了 ZeroMq 的 发布-订阅
模式。。
master 监听 4505
和 4506
端口:
- 4505 对应的是 ZMQ 的 PUB system,用来发送消息
- 4506 对应的是 ZMQ 的 REP system,是来接受消息
minion
查看自身的 ID:
vdna@debian:~$ cat /etc/salt/minion_id
foo.domain.com
minion
需配置 /etc/salt/minion
中 master
的地址,上线后与 master
端联系,把自己的 pub key
发过去,。
14 # Set the location of the salt master server. If the master server cannot be
15 # resolved, then the minion will fail to start.
16 master: 192.168.10.52
这时 master
端通过 salt-key -L
命令就会看到 minion
的 minion_id
:
hxz@pc0170:/srv$ salt-key -L
Accepted Keys:
Denied Keys:
Unaccepted Keys:
foo.domain.com
Rejected Keys:
注意:
安全起见,在接受 minion 之前,master 和 minion 的公钥必须互相验证。
在 master 端运行 salt-key -F master
:
hxz@pc0170:/srv$ salt-key -F master
Password:
Local Keys:
master.pem: 00:cc:4f:6c:8e:63:4e:c3:66:33:e3:a9:28:01:6c:82
master.pub: eb:7e:e1:5b:a8:f2:93:68:7c:17:aa:3e:fa:3a:53:e9
然后在 minion 端将输出来的 master.pub
值设为 /etc/salt/minion
中的 maste_finger。
486 # Fingerprint of the master public key to double verify the master is valid,
487 # the master fingerprint can be found by running "salt-key -F master" on the
488 # salt master.
489 master_finger: 'eb:7e:e1:5b:a8:f2:93:68:7c:17:aa:3e:fa:3a:53:e9'
在 master 端, 运行 salt-key -f minion-id
查看对应 minion 的公钥:
salt-key -f foo.domain.com
Unaccepted Keys:
foo.domain.com: 39:f9:e4:8a:aa:74:8d:52:1a:ec:92:03:82:09:c8:f9
在 minion 端,运行 salt-call key.finger --local
查看自身的公钥:
salt-call key.finger --local
local:
39:f9:e4:8a:aa:74:8d:52:1a:ec:92:03:82:09:c8:f9
如果它们匹配的话,那么 master 可以通过运行 salt-key -a foo.domain.com
放心地接受这个 minion。
hxz@pc0170:/srv$ salt-key -a foo.domain.com
The following keys are going to be accepted:
Unaccepted Keys:
foo.domain.com
Proceed? [n/Y] y
Key for minion webserver_qa accepted.
好啦,master 和 minion 彼此都对上眼了,现在 master
可以发送任何指令让 minion
执行了,salt
有很多可执行模块,master
下发任务到匹配的 minion
上去,minion
执行模块函数,并返回结果。
举个栗子
salt '*' test.ping
具体步骤如下:
-
salt
命令,将test.ping
命令从salt.client.LocalClient.cmd_cli
发布到master
,获取一个Jodid
,根据Jodid
获取命令执行结果。 -
master
接收到命令后,将要执行的命令发送给客户端minion
。 -
minion
从消息总线上接收到要处理的命令,交给minion._handle_aes
处理。 -
minion._handle_aes
发起一个本地线程调用test
模块执行 ping 命令(不是那个 ICMPping
命令,只是为了检测 minion 是否有响应)。线程执行完后,调用minion._return_pub
方法,将执行结果通过消息总线返回给master
。 -
master
接收到客户端返回的结果,调用master._handle_aes
方法,将结果写到文件中。 -
salt.client.LocalClient.cmd_cli
通过轮询获取Job
执行结果,将结果输出到终端。
hxz@pc0170:/srv$ salt "*" test.ping
foo.domain.com:
True
salt
salt 是最常用的一个命令,用法:
Usage: salt [options] '' [arguments]
以 salt '*' test.ping
为例:
- '*' (这两个引号不能少,很蛋疼的)代表的是 target,是指在哪些 minion 上操作
- test 是一个执行模块
- ping 是执行模块下面的函数
关于 salt 有哪些可执行模块,模块下面有哪些函数,可以通过 sys.doc
命令查看帮助:
salt "*" sys.doc ##查看所有执行模块的doc
salt "*" sys.doc test ##查看test模块的帮助
salt "*" sys.doc test.ping ##查看test.ping函数的帮助
实用命令
cmd
模块包含了许多和命令行相关的函数,比如 cmd.run 和 cmd.re_run
salt '*' cmd.run 'ls -l /etc'
pkg
模块会自动地将本地系统的包管理器映射到 salt 中,这意味着 pkg.install vim
将自动地在 Red Hat
系统中调用 yum
,在Debian
系统中调用apt-get
,在Osx
系统中调用 brew
安装 vim
。
salt '*' pkg.install vim
network.interfaces
方法会列出 minion 中所有的网络接口,包括 IP 地址、子网掩码、MAC 地址等:
salt '*' network.interfaces
salt-call
目前为止,介绍的大部分 master 端命令都是 salt,但有时为了查找、定位问题,使用 salt-call 直接登陆到 minion 是非常实用的,你可以查看当你在 master 端执行命令后 minion 端具体的 log 信息(其中有些信息你在 master 端是无法看到的)。更多关于 salt-call 的信息可以参考here
Grains
salt 通过系统调用的方式来收集 minion 端本机的数据信息,包括操作系统、CPU、内存等信息。它同样可以包含静态数据集,这使得 minions 可以方便的进行分组、管理。
通常的做法是将 grains 分配给 minions 并指定每个 minion 的角色。这些静态 grains 可以在 minon 的配置文件或通过 grains.setval 方法来设置。
Target
salt 有多种方式来指定哪些 minion 来执行 master 分发的命令,默认采用 minion_id *
匹配模式,比如:现有多个 minons 其 minion_id 分别为 larry1
, larry2
, curly1
和 curly2
, larry*
将会匹配到 larry1
和 larry2
, *1
将会匹配到 larry1
和 curly1
。
其他的匹配方式:
- 正则匹配:利用正则表达式
- Grains:利用 Grains 数据,参考:�here
- Pillar:利用 Pillar 数据,参考:�here
- IP:利用 IP地址、子网、区段等信息
- Compound:在多个目标中建立逻辑关系,参考here
- Nodegroup:参考here
Salt States
salt 中的配置管理模块, 下面这段是官方介绍的 state 总诀,我就不翻译了,保持原汁原味~
Salt states are based on data modeling and build on a low level data structure that is used to execute each state function. Then more logical layers are built on top of each other.
The high layers of the state system which this tutorial will cover consists of everything that needs to be known to use states, the two high layers covered here are the sls layer and the highest layer highstate.
Understanding the layers of data management in the State System will help with understanding states, but they never need to be used. Just as understanding how a compiler functions assists when learning a programming language, understanding what is going on under the hood of a configuration management system will also prove to be a valuable asset.
第一个 sls
state 系统是建立在 SLS
规则上面,salt 的文件服务器上的 sls
文件中定义了这些要应用的规则。下面来创建一个简单的 SLS
文件,在 /srv/salt
文件夹下创建一个 vim.sls
文件,下面的语句确保当启用这个 state
配置时 vim
已经在目标 minion
安装好。
/srv/sat/vim.sls
:
vim:
pkg.installed
现在,应用这个 SLS 配置方案
,在 minions 上安装 vim
:
salt '*' state.apply vim
这条命令将触发 state 系统去执行这个 vim
配置方案。为了让这个 vim 方案更完善,可以加一个 vimrc
配置文件:
/srv/salt/vim.sls
:
vim:
pkg.installed: []
/etc/vimrc:
file.managed:
- source: salt://vimrc
- mode: 644
- user: root
- group: root
现在,master 端需要将 vimrc
复制到 /srv/salt/vimrc
,在 salt 中,所有的都是文件,因此不需考虑路径重定向问题。这个 vimrc 文件和 vim.sls 都在 /srv/salt/vim.sls
文件夹下面,同样执行上面那条命令,所有的 minions 除了会安装 vim 外,还会将 vimrc
文件拷贝到 /etc/vimrc
。
Adding Some Depth
很明显,只在 sls 文件服务器的根目录下维护这些 SLS 配置方案,很难扩展到大规模的部署场景,这就是为什么需要目录层次结构。让我们来配置一个 nginx 部署方案,首先创建一个 nginx 子目录,并在里面新建 init.sls 文件。
/srv/salt/nginx/init.sls
:
nginx:
pkg.installed: []
service.running:
- require:
- pkg: nginx
这里引入了几个 SLS 规则中的新概念。
首先,service.running
声明语句确保 nginx 服务是运行的。
当然,nginx 服务运行前当然要先安装 nginx 软件,因此,require 语句为二者建立了依赖关系,require 确保被依赖的组件成功安装。
提示:
require
属于requisites
选项族,它是一个功能强大的 state 组件,更多信息参考 here
可以看到,在 sls
根目录下面可以有 nginx 子目录,同样,vim 的配置也可以再灵活点,将 vim.sls
和 vimrc
移动动到 edit
子目录下面,
/srv/salt/edit/vim.sls
:
vim:
pkg.installed
/etc/vimrc:
file.managed:
- source: salt://edit/vimrc
- mode: 644
- user: root
- group: root
只有 vimrc
文件的 source
目录稍微改动了点,现在 vim
配置方案引用名变成 edit.vim
因为 vim.sls
在根目录的 edit
子目录下面。除了 vim
配置文件,edit
子目录还可以包含 emacs
、nano
等其他编辑器等配置信息。
Next Reading
到这里,对 saltstack 算是有个初步的认识和应用了,但这只是 saltstack 里面九牛一毛,下一步要研究的是:
- Salt States
- Pillar