SaltStack 一日游

随着上线的服务器数量增多,如何批量有效的管理各个节点服务器正常运作是每个运维人员需要解决的难题。

什么是 saltstack

你要是 naive 地问:部署服务器,有什么好难的?不就写个脚本,再 one by one 地 ssh 这些服务器跑一遍吗?

服务器少还好办,几台、几十台一般人尚可承受但,再不济多配几个运维(貌似无意间黑了一下运维,嘻嘻)嘛~

但,假如你有成百上千台服务器需要部署,你会怎么做?想象一下你每次 one by one 地登陆这些服务器,在这些服务器中执行同样的命令并且编辑同一个配置文件,这他妈完全是重复性操作啊,人呐,重复性劳动做多了难免会犯错,要是稍微不留意手一抖配错了咋办?即使侥幸部署成功,将来需要更改配置,所有的线上环境都要同步变更,你再让我 one by one 地操作这些服务器?!

我的天呐~我疯了吗!

《SaltStack 一日游》

技术人的自我修养之一:如果一条命令重复了两次,你就要交给机器去做。

那么,问题来了:

怎么样通过一个命令一次完成所有服务器的部署操作?

在这种情况下,一些批量部署的工具应运而生,比如 puppet,saltstack,chef 等等……

saltstack 是使用 python 编写的开源自动化部署与管理工具,它取 Puppet 和 Chef 二者之所长整合之,拥有良好的扩展性以及优秀的执行效率,配置简单,跨平台,适合大规模批量管理服务器。

saltstack 原理

Saltstack 基于 C/S 架构,服务端 master 和客户端 minions。minion 与 master 之间通过 ZeroMQ 消息队列通信,使用了 ZeroMq 的 发布-订阅模式。。

master 监听 45054506 端口:

  • 4505 对应的是 ZMQ 的 PUB system,用来发送消息
  • 4506 对应的是 ZMQ 的 REP system,是来接受消息

minion 查看自身的 ID:

vdna@debian:~$ cat /etc/salt/minion_id
foo.domain.com

minion 需配置 /etc/salt/minionmaster 的地址,上线后与 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 命令就会看到 minionminion_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 命令(不是那个 ICMP ping 命令,只是为了检测 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] '<target>' <function> [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.runcmd.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, curly1curly2, larry* 将会匹配到 larry1larry2, *1将会匹配到 larry1curly1

其他的匹配方式:

  • 正则匹配:利用正则表达式
  • 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.slsvimrc 移动动到 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 子目录还可以包含 emacsnano 等其他编辑器等配置信息。

Next Reading

到这里,对 saltstack 算是有个初步的认识和应用了,但这只是 saltstack 里面九牛一毛,下一步要研究的是:

  • Salt States
  • Pillar

《SaltStack 一日游》

    原文作者:hxzqlh
    原文地址: https://www.jianshu.com/p/8f8ebc920643
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞