前言:

  此博文主要以介绍salt配置管理理论为主,关于一些项目的实战将在后续的博文中展开。


Salt配置管理系统介绍

   salt的配置管理系统与远程执行都是salt的核心功能,关于远程执行更多的介绍请参考上一篇博文SaltStack远程执行常用模块使用》。这里我将介绍salt的另一个核心功能,配置管理系统,通过配置管理系统我们可以完成服服器的个性化配置文件管理,复杂的一些应用部署,比如LAMP源码部署,根据系统版本初始化系统配置等更多的功能。

  salt配置管理系统依赖于state状态管理,而我们管理需要state状态文件,这些文件必须以 .sls 结尾,需要由我们自己来编写。此文件格式与YAML语法格式相同,并且还可以使用Jinja(Python的模块引擎),通过它我们可以完成一些个性化配置等功能,本文后面将会对YAML,Jinja,还有一点特殊的状态文件以及Salt环境作一些介绍。


环境介绍


  环境里面主要就是存放我们的一些状态文件,配置文件等,我们的这些文件可以是生产环境 (Prod),或者开发环境(Dev)等,当然我们可以按我们的服务器种类,来分或者其它方法分,最主要是适用。我们安装好服务端(Salt-master)后默认有一个基础环境(Base),下面我们来自定义我们的环境。

修改服务端配置文件:/etc/salt/master

#在配置文件最后加入以下内容,可以在配置文件里查找“file_roots:”关键字,找到相关例子和说明
file_roots:
  base:
    - /srv/salt/base
  test:
    - /srv/salt/test

以上配置文件我们定义了2个环境,分别为base,test,其中base环境为必须有的,且名称不可更改,其它我们可以自定义,接来下我们需要创建我们的目录,然后重启服务端服务

mkdir /srv/salt/{base,test}
systemctl restart salt-master

YAML语法介绍


  关于yaml语法在salt客户端配置文件,服务端配置文件和state状态文件都是采用此讲法结构,所我们很有必要撑握此语法的使用。此语法有以下几个要点

  1. 缩进:缩进必须两个空格,不可以使用tab,主要用来表示层级关系

  2. 冒号:只要是以冒号结尾的行的下一行必须缩进两个空格,相当于Python里面的key-value。当然如果我们的key只有一个值的话我们可以写成一行,中间空一格即可。如果我们的key的值为一个列表,那么就需要另起一行,并且缩进两个空格以 - 开头

  3. 短横线:如上一条所说,一个短模线就相当于一个列表里面的一个元素,我们可以有多个元素。并且短模线的后面必须要有一个空格

例如,我们可以将服务端配置文件里面的file_roots改成如下配置:

file_roots:
  base: /srv/salt/base
  test:
    - /srv/salt/test1
    - /srv/salt/test2

将以上内容转换为我们Python的字典如下:

{'file_roots': {'test': ['/srv/salt/test1', '/srv/salt/test2'], 'base': '/srv/salt/base'}}
#我们可以使用python的yaml模块(pyyaml包)进行yaml和dict之间的转换测试

top.sls介绍


  此文件文件名固定为top.sls,用来定义环境的总入口配置文件,当使用以下命令的时候就会调用

salt [TARGET] state.highstate <ENV>(state模块的highstate方法)时就会自动调用对应环境的top.sls,那么如果不使用state.highstate,而使用salt [TARGETstate.sls [State_File] <ENV>可以指定执行某一个状态文件,这样就不需要调用top.sls这个总入口文件了。如果不指定环境,那么默认调用base环境的状态文件。上面我们讲过所有state状态文件(以.sls结尾)都是使用yaml格式,下面我们看一个例子:

base:           #第一行为环境的名称,与file_roots保持一致,如果是test环境那就这里就是test
  '*':         #指定主机,可以使用所有的target,如通配符,regex,grain,pillar,nodegroups等 
    - init.init_env #要执行的状态文件,以环境根目录开始,父目录与子目录用点分隔,非常像Python的模块调用
  'os:CentOS':
    - match:grain  #指定要使用的target
    - httpd_install

可能你看完这小节感觉不是特别理解,比如什么是target,为什么这样调用state状态文件,state.highstate又是什么意思。关于什么是target,参考另一篇博文《Salt之target介绍》,那么关于剩下的问题我将在本博文后面以一个小例子来让大家明白


init.sls介绍


  关于此文件用得不是特别广范,但还是需要给大家介绍我们来看一个例子,先来看看我们的目录结构,这里test环境根目录下面的jdk目录结构。主要用来安装使用源码安装jdk7

jdk/
├── 7                     #根据安装的版本来划分目录,我们还可以安装jdk8等
│   ├── files               #用于存放文件的目录
│   │   ├── jdk-7u79-linux-x64.gz   #源码包
│   │   └── jdk.sh           #环境变量配置文件
│   ├── init.sls              #占且称之为目录初始化状态文件
│   └── install.sls            #安装状态文件
└── 8
    ├── files
    │   ├── jdk-8u102-linux-x64.tar.gz
    │   └── jdk.sh
    └── install.sls

再看看我们init.sls文件的内容

include:              #特殊模块,用于包含其它模块
  - jdk.7.install        #被包含模块的路径,以环境根目录开始

从上面我们可以看出为什么我们jdk8的没有init.sls,这个文件有一个特殊的作用,那可有可无,下面我们将以安装jdk8和jdk7来演示为什么可有可无

安装jdk7

salt "*node1" state.sls jdk.7 saltenv=test

上面的命令我们安装jdk7我们使用的是state.sls,所以我们后面要跟模块的名称,模块名称需要从环境根目录开始,到最终我们使用的模块。但上面我们使用的是jdk.7,而7是一个目录,并不是state状态文件,所以这时候我们的init.sls就起到了这样一个作用,当最后所指的状态文件为一个目录时,那么系统会自动找到该目录下面的init.sls状态文件,而此文件我们包含了我们安装jdk所需要的模块,最后通过此文件来执行,如果该目录下面也没有init.sls那么就会直接报错,找不到可执行的状态文件。saltenv=test表示指定环境为test环境

安装jdk8

salt "*node1" state.sls jdk.8.install saltenv=test test=True

从上面的目录结构我们可以看出jdk/8/这个目录下面并没有init.sls,所以这时候我们需要最终指定一个状态文件,test=True表示不直接执行,而先测试执行过程,确认执行过程正确后再取消此选项真正的执行

注:上面所讲的方法不仅可以用于salt命令行,同样试用于state状态文件之间的引用


Jinja介绍


  我们前面的博文中已经讲过salt是完全基于Python开发的自动化运维配置管理工具,Jinja是基于Python的模板引擎,我们可以通过使用jinja模板在state状态配置文件里面实现条件判断,循环,变量引用等一些功能。比如我们要部署Nginx+keepalived负载均衡,那么我们就可以通过jinja的条件判断来实现区分master和slave,又或者我们需要指定Nginx配置文件,但配置文件里面的参数都不固定我们可以通过变量来解决。所以jinja在salt的应用非常的多,很广泛,如果使用得好的话,可以让你的项目可读性,执行效率更高,更加的高大上,更能体能salt自动化的功效,我们首先介绍下几种jinja的语法:

变量

条件判断

下面将以使用salt管理客户端DNS配置文件为例来演示变量和条件判断的使用

cd /srv/salt/test        #进入我们的测试环境根目录
mkdir files           #新建一个存放文件的目录
touch files/resolv.conf     #创建DNS模板文件
touch nameserver.sls       #创建状态配置文件
#resolv.conf文件内容如下

dns manager:                   #任务的ID
  file.managed:                 #状态管理模块file的managed方法,用来管理文件
    - name: /etc/resolv.conf        #每个模块方法都有一个 -name 属性,此属性可写在ID处,代表ID,如果这样的话这里就需要再写 -name属性
    - source: salt://files/resolv.conf   #源文件
    - user: root              #定义属主
    - group: root              #定义属组
    - mode: 644               #定义权限
    - template: jinja            #标记此状态文件为jinja,否则将视为普通状态文件调用
{% if grains['fqdn'] == "kubernetes-node1" %}    #第一个条件
      DNS_SERVER: 192.168.1.10           #第一个条件为真执行的动作,定义变量
{% elif grains['fqdn'] == "kubernetes-node2" %}   #第二个条件
      DNS_SERVER: 192.168.1.11           #第二个条件为真执行的动作,定义变量
{% endif %}                                        #条件结束,不管是多分支还是单分支都必须要有结束

#nameserver.sls文件内容如下

# Generated by NetworkManager
nameserver {{ DNS_SERVER }}        #引用变量

执行命令:

salt "*" state.sls nameserver saltenv=test

当执行完成命令后我们fqdn名称为kubernetes-node1的DNS将设置为192.168.1.10而kubernetes-node2的DNS将设置为192.168.1.11

扩展:在jinja里面的变量我们还可以引用pillar和salt命令执行的结果,方法如下

{{ salt['network.hw_addr']('eth0') }}

{{ pillar['apache']['PORT'] }}


循环

关于循环如果后续有时间将以实现反向代理(Nginx/HAProxy)动态添加后端服务器为例展示


最后:本博文内容不多,主要是以后面实战为主,欢迎大家收藏,关注我的博客,后续有时间会陆续补上一些实战的项目配置