SaltStack 最佳实践

通用规则

遵循 fomulas 的方式构造 states

Formulas 是 Salt 官方预先写好的 states,一个 Salt Formula 对应一个 Git 仓库。如果我们要直接使用,在 salt-master 加入相应配置

gitfs_remotes:
  - https://github.com/saltstack-formulas/apache-formula
  - https://github.com/saltstack-formulas/memcached-formula

这样就可以使用 salt 提供的 formula 安装这两个软件了。

我们看下 MySQL 这个 formula 的目录结构,

/srv/salt/mysql/files/         # 主要是配置文件
/srv/salt/mysql/client.sls     # 客户端安装
/srv/salt/mysql/map.jinja      # 变量定义
/srv/salt/mysql/python.sls     # python 客户端安装
/srv/salt/mysql/server.sls     # 服务端安装

/srv/salt/mysql/top.sls:

base:
  'web*':
    - mysql.client
    - mysql.python
  'db*':
    - mysql.server

这样就能清晰地看到依赖 mysql 的设备中,web* 安装客户端,db* 安装服务端。

再看另外一个 vim 的例子,

/srv/salt/vim/files/           # 主要是配置文件
/srv/salt/vim/absent.sls       # 卸载 vim
/srv/salt/vim/init.sls         # 安装 vim 并配置
/srv/salt/vim/map.jinja        # 变量定义
/srv/salt/vim/nerdtree.sls     # NERD tree 插件配置
/srv/salt/vim/pyflakes.sls     # pyflakes 插件配置
/srv/salt/vim/salt.sls         # salt 插件配置

/srv/salt/vim/top.sls:

base:
  'web*':
    - vim
    - vim.nerdtree
    - vim.pyflakes
    - vim.salt
  'db*':
    - vim.absent

我们自己写 states 时,多参考这些 formula,有现成的拿来用就行。

构造 pillars 文件

Pillars 用于存储与 minion 相关的数据(特别是需要加密的数据),在构造 pillars 时要尽量做到让使用者容易查看、修改和理解。下面看个例子,

/srv/pillar/top.sls:

base:
  '*':
    - apache
dev:
  'os:Debian':
    - match: grain
    - vim
test:
  '* and not G@os: Debian':
    - match: compound
    - emacs

注意,pillars 的 top.sls 不是用于定义变量的,而是定义不同环境下设备和具体 pillar 文件的对应关系。

比如 apache 的变量保存在相应的 apache.sls 中。

/srv/pillar/apache.sls:

apache:
  lookup:
    name: httpd
    config:
      tmpl: /etc/httpd/httpd.conf

定义变量

虽然变量可以直接在 state sls 里定义,当时通常不这么做。

/srv/salt/apache/conf.sls:

# 不推荐在这里定义变量
{% set name = 'httpd' %}
{% set tmpl = 'salt://apache/files/httpd.conf' %} 

include:
  - apache

apache_conf:
  file.managed:
    - name: {{ name }}
    - source: {{ tmpl }}
    - template: jinja
    - user: root
    - watch_in:
      - service: apache

建议定义在 pillar 里,这样可以被多个 state 共享。

/srv/pillar/apache.sls:

apache:
  lookup:
    name: httpd
    config:
      tmpl: salt://apache/files/httpd.conf

/srv/salt/apache/conf.sls:

{% from "apache/map.jinja" import apache with context %}

include:
  - apache

apache_conf:
  file.managed:
    - name: {{ salt['pillar.get']('apache:lookup:name') }}
    - source: {{ salt['pillar.get']('apache:lookup:config:tmpl') }}
    - template: jinja
    - user: root
    - watch_in:
      - service: apache

平台特定的变量写在 map.jinja 文件,跟 state 放在同一目录。

/srv/salt/apache/map.jinja:

{% set mysql = salt['grains.filter_by']({
    'Debian': {
        'name': 'apache2',
        'config': '/etc/apache2/apache.conf',
    },
    'RedHat': {
        'name': 'httpd',
        'config': '/etc/httpd/httpd.conf',
    },
    'Gentoo': {
        'name': 'apache2',
        'config': '/etc/httpd/httpd.conf',
    },
}, merge=salt['pillar.get']('apache:lookup')) %}

Pillar 数据会消耗更多 salt-master 的资源,如果 minion 众多,可能对 master 造成冲击,建议将不敏感的也不会多处引用的变量,写在 state 内部的 map.jinja 文件。

states 内部模块化

如何确保 state 模块化是 Salt 中需要理解的关键概念之一。创建 state 时,必须考虑是否可以重复使用,以及操作时有什么依赖。下面看个例子,

/srv/salt/apache/init.sls:

httpd:
  pkg:
    - installed
  service.running:
    - enable: True

/etc/httpd/httpd.conf:
  file.managed:
    - source: salt://apache/files/httpd.conf
    - template: jinja
    - watch_in:
      - service: httpd

这是个很不好的写法,httpd 直接作为 state ID,但是一个软件的包名和服务名很可能是不一样的。重构之后如下,

/srv/salt/apache/init.sls:

apache:
  pkg.installed:
    - name: httpd
  service.running:
    - name: httpd
    - enable: True

apache_conf:
  file.managed:
    - name: /etc/httpd/httpd.conf
    - source: salt://apache/files/httpd.conf
    - template: jinja
    - watch_in:
      - service: apache

进步了一些,但还存在一些问题,比如值都是静态写在 state,不能适配多平台安装。软件和配置写在同一个 state 里,不支持只需要安装软件并使用默认配置的场景。再次重构如下,

/srv/salt/apache/map.jinja:

{% set apache = salt['grains.filter_by']({
    'Debian': {
        'server': 'apache2',
        'service': 'apache2',
        'conf': '/etc/apache2/apache.conf',
    },
    'RedHat': {
        'server': 'httpd',
        'service': 'httpd',
        'conf': '/etc/httpd/httpd.conf',
    },
}, merge=salt['pillar.get']('apache:lookup')) %}

/srv/pillar/apache.sls:

apache:
  lookup:
    config:
      tmpl: salt://apache/files/httpd.conf

/srv/salt/apache/init.sls:

{% from "apache/map.jinja" import apache with context %}

apache:
  pkg.installed:
    - name: {{ apache.server }}
  service.running:
    - name: {{ apache.service }}
    - enable: True

/srv/salt/apache/conf.sls:

{% from "apache/map.jinja" import apache with context %}

include:
  - apache

apache_conf:
  file.managed:
    - name: {{ apache.conf }}
    - source: {{ salt['pillar.get']('apache:lookup:config:tmpl') }}
    - template: jinja
    - user: root
    - watch_in:
      - service: apache

这次拆分成 4 个文件,使用 pillar 和 map.jinja 定了变量,state 里动态值改成读取变量,软件和配置拆分到各自的 state。

© 2017 - 2023 · 记事本 · Theme Simpleness Powered by Hugo ·