Pillar:皮勒的那些事儿

话说这 salt 里面的术语都起得特立独行,State 之所以叫 State ,我绕了半天才搞懂原来它是指期望达到的某种 状态,关于 State ,前面发了四篇文章,终于算是入门了。

今天,我来开始撸一撸 salt 中的另一个核心概念:Pillar
关于 Pillar 的更详细文档,请参考 这里

Pillar 是存储于 master 上面并发送给相关 minions 的一些树形结构数据:

注意:初学者很容易混淆 GrainsPillar。你只需记住,Grains 是跟 minion 自身相关的静态数据,比如硬件、系统信息;Pillar 是由 master 生成并分发给 minion 的信息。

Pillar 主要可以保存下面几类数据:

  • 高敏感度数据

比如密钥、密码之类。通过 Pillar 传输的数据可以确保只有部分相关的 minion 能收到(你总不希望 minoion A 收到 minion B 的 mysql 登陆密码吧)。

  • minion 的配置信息

可以在 Pillar 中配置 minion 的可执行模块、statesreturners

  • 变量

Pillar 中可以定义用于给 minion 分配角色、组别等变量,之后,它们就能在 sls 的模版语句中访问了。

  • 其他数据

Pillar 还可以包含其他任意键值对格式的数据。

因此,可以说 PillarSalt 系统中最重要的组件之一,怪不得老外给它取名叫 Pillar 呢,字面意思是“核心的,支柱”,看来它在 salt 系统里面的威望也很高啊。

皮勒有多重要呢,这么说吧,我们这厢经常唱红歌:“没有共产党就没有新中国”,套用到 salt 中,那就是:“没有 皮勒就没有盐”。

设置 Pillar

默认情况下, pillar 已经在 salt 中运行,跟 State 类似,Pillar 也是由一个 top.sl 和一组 sls 文件构成,默认的根目录是 /srv/pillar,你需要手动创建这个目录。

首先新建一个 top 文件:

/srv/pillar/top.sls:

1
2
3
base:
'*':
- data

这个 top 文件会搜集 data.sls 里面的数据给所有的 minion:

/srv/pillar/data.sls:

1
info: some data

为了让刚才新建的 pillar 生效,运行如下命令,通知 minionsmaster 上获取对应的 pillar 数据:

1
salt '*' saltutil.refresh_pillar

查看最新的 pillar:

1
salt '*' pillar.items

更复杂点的 Pillar

不像 State 语法那么严谨,pillar 可以设置任意列表或字典型数据:

/srv/pillar/users/init.sls:

1
2
3
4
5
users:
thatch: 1000
shouse: 1001
utahdave: 1002
redbeard: 1003

注:pillar 同样遵守和 State 文件一样的约定,users/init.sls 可以用 users 引用。

/srv/pillar/top.sls:

1
2
3
4
base:
'*':
- data
- users

现在,在 state 文件中使用这些 pillar 数据:

/srv/salt/users/init.sls:

1
2
3
4
5
{% for user, uid in pillar.get('users', {}).items() %}
{{user}}:
user.present:
- uid: {{uid}}
{% endfor %}

Pillar 作为 State 参数

所有的 Pillar (包括 Grains)信息在执行 State 之前就已经初始化完毕,Pillar 数据可以在 State 文件中使用来为不同的 minion 定制不同的行为。

一个简单示例:在 Pillar 中为不同的 Linux 发行版设置不同的 Apache 安装包名。

/srv/pillar/pkg/init.sls:

1
2
3
4
5
6
7
8
9
10
11
pkgs:
{% if grains['os_family'] == 'RedHat' %}
apache: httpd
vim: vim-enhanced
{% elif grains['os_family'] == 'Debian' %}
apache: apache2
vim: vim
{% elif grains['os'] == 'Arch' %}
apache: apache
vim: vim
{% endif %}

把这个新的 pkg 应用到 top 文件:

/srv/pillar/top.sls:

1
2
3
4
5
base:
'*':
- data
- users
- pkg

minions 根据自身的系统信息找到其对应的 pillar 数据,因此 state 文件可以安全地实现参数化控制。

/srv/salt/apache/init.sls:

1
2
3
apache:
pkg.installed:
- name: {{ salt['pillar.get']('pkgs:apache', 'httpd') }}

这里,某个 pillar 值在 minion 中未定义的话,可以提供一个默认值,如:上面最后一行的 httpd

Pillar 使 state 可扩展

Pillar 的设计初衷之一就是让 sls 简单可扩展,不必每次都重新编译。

比如,这样一个 state 文件:

/srv/salt/edit/vim.sls:

1
2
3
4
5
6
7
8
9
10
11
vim:
pkg.installed: []

/etc/vimrc:
file.managed:
- source: salt://edit/vimrc
- mode: 644
- user: root
- group: root
- require:
- pkg: vim

通过 pillar,可以很容易将它改造成一个更加灵活可扩展的 state

/srv/salt/edit/vim.sls:

1
2
3
4
5
6
7
8
9
10
11
12
vim:
pkg.installed:
- name: {{ pillar['pkgs']['vim'] }}

/etc/vimrc:
file.managed:
- source: {{ pillar['vimrc'] }}
- mode: 644
- user: root
- group: root
- require:
- pkg: vim

可以看到,通过 pillarvimrc 的路径可以根据需要来配置,而不必硬编码到 state 文件:

/srv/pillar/edit/vim.sls:

1
2
3
4
5
6
7
{% if grains['id'].startswith('dev') %}
vimrc: salt://edit/dev_vimrc
{% elif grains['id'].startswith('qa') %}
vimrc: salt://edit/qa_vimrc
{% else %}
vimrc: salt://edit/vimrc
{% endif %}

命令行传递 PILLAR 参数

Pillar 数据可以通过命令行执行:

1
2
salt '*' state.apply pillar='{"foo": "bar"}'
salt '*' state.apply my_sls_file pillar='{"hello": "world"}'

注:如果某个 keyminion 中已经存在,且 pillar 参数中也含有该 key 值,那么以命令行参数值为准。

姿势总结

这几天,谈的主题都是 salt,从宏观地介绍到具体 statepillar 等细节,很惭愧,有些东西翻译得不到位,信、达、雅三重境界只勉勉强强能称得上 ,如有谬误之处,还请读者不吝指正。

彦祖老师 wechat