saltstack

SaltStack 运维通关手册–SaltStack State 框架

配置和启用 Salt State Tree

Salt State 系统的核心是 SLS 或 Salt State 文件。 SLS 表示系统应处于的状态,并设置为使用一种简单的格式包含此数据。 这通常称为配置管理。
States 状态存储在 master 上的文本文件中,并通过 master 文件服务器按需传送到 minions。 状态文件的集合即构成 State Tree。
要在 Salt 中开始使用集中式的状态系统,必须首先设置 Salt File Server。 编辑 master 配置文件(file_roots)并添加以下内容:

file_roots:
  base:
    - /etc/salt/srv/salt/base

重启 salt-master

pkill salt-master
salt-master -d

准备 top file 文件
我们之前在 master 上配置的 file_roots 目录下(如果没有配置,默认为 /srv/salt)创建了一个名为 top.sls 的文件,现在修改这个文件。
修改文件: /etc/salt/srv/salt/base/top.sls

base:
  "*":
    - webserver

top file 文件被划分为多个不同的环境(稍后讨论)。默认环境是 base。 在 base 环境下,定义了一系列 minion 匹配映射关系; 现在只需简单的指定为所有主机 *。
创建一个 sls 文件,路径 /etc/salt/srv/salt/base/webserver.sls

nginx:
  pkg:
    - installed

第一行称为 ID 声明,可以是一个任意标识符。 在上面的这种情况下,它定义了要安装的包的名称。
第二行称为 state 声明,它定义了我们正在使用哪些 Salt States。 在此示例中,我们使用 pkg state 来确保安装了给定的包。
第三行称为 Function 声明,它定义了在 pkg state 模块中要调用的函数。
Salt 会将文件以指定的渲染器进行渲染格式化数据,默认为 Jinja2 模板中使用 YAML。
接下来,让我们运行我们创建的状态文件。 在 master 服务器上打开终端并运行:

salt '*' state.apply

www.sublimetext.com:
----------
          ID: nginx
    Function: pkg.installed
      Result: True
     Comment: Package nginx is already installed
     Started: 22:57:25.504406
    Duration: 65.675 ms
     Changes:

Summary for www.sublimetext.com
------------
Succeeded: 1
Failed:    0
------------
Total states run:     1
Total run time:  65.765 ms

我们的 Master 指示所有目标 minions 运行 state.apply。 在没有任何 SLS 目标的情况下执行此功能时,minion 将下载 top file 文件并尝试匹配其中的表达式。 当 minion 与表达式匹配时,将为其列出的模块下载、编译和执行。
在没有指定任何 SLS 文件名称的情况下调用 state.apply 的效果相当于运行 state.highstate
在指定了 SLS 文件名称的情况下调用的 state.apply 将运行 state.sls

命令执行完成后,minion 将报告所有采取的行动和做的所有更改的摘要。
state 文件目录结构规则
如上面的示例中,SLS 文件 webserver.sls 简称为 webserver。 在 top.sls 或 Include 声明中引用时,SLS 文件的命名空间遵循一些简单的规则:
.sls 的后缀被丢弃了 (也就是说 webserver.sls 变成了 webserver)。

子目录被做了更好的组织,其中:
每个子目录在 Salt 状态和命令行中用点(遵循 Python 导入模型)表示。 文件系统上的 webserver/dev.sls,在 Salt 中称为 webserver.dev。由于斜杠表示为点,因此 SLS 文件不能在名称中包含点(SLS 文件后缀的点除外)。 你将无法正确匹配 SLS 文件 webserver_1.0.sls,因为 webserver_1.0 将与目录 /webserver_1/0.sls 匹配
子目录中名为 init.sls 的文件将通过目录的路径引用。 因此,webserver/init.sls 称作 webserver。
如果 webserver.sls 和 webserver/init.sls 都存在,webserver/init.sls 将被忽略,webserver.sls 将被作为合法的 webserver 使用。
更复杂的 STATES、REQUISITES
require 关键字用以进行 state 依赖,表明多个 state 直接的依存关系。编辑 /etc/salt/srv/salt/base/webserver.sls 文件:

nginx:
  pkg.installed: [] # 安装 nginx 软件包

  file.absent:  # 删除影响 service 模块的文件
    - names:
      - /etc/init/nginx.conf
      - /etc/nginx/conf.d/default.conf

/etc/nginx/nginx.conf:
  file.managed:
    - source: salt://webserver/nginx.conf
    - require:
      - pkg: nginx

nginx service:
  service.running:
    - name: nginx
    - watch:
      - file: /etc/nginx/nginx.conf
      - file: /etc/nginx/conf.d/default.conf
    - require:
      - pkg: nginx

/var/www/index.html:
  file:
    - managed
    - source: salt://webserver/index.html
    - require:
      - pkg: nginx

/var/www/index.html 是一个 ID 声明,在实例中同样作为 file state 的目标位置存在。
file 表示该示例使用 Salt 的 file state。
managed 表示使用 managed function 将从 master 服务器下载文件并将其安装在指定的位置。
absent 表示使用 absent function 来删除指定的文件。
source 作为 managed 函数的参数传递进去。
watch 表示监听某个任务,当任务状态为 Changes 时,会操作重启 nginx。
require 表示这个 state 任务依赖别的 state 任务。
pkg 作为 一个 require 依赖,指向了一个 state 和一个 ID,及我们声明的 pkg 安装 nginx 部分,该声明告诉 Salt 在安装 nginx 服务之前不要安装 HTML 文件。

创建目录 /etc/salt/srv/salt/base/webserver/,然后创建 source 源文件 index.html,输入如下内容:

<p>Hello,SaltStack</p>

编辑 Nginx 主配置文件 /etc/salt/srv/salt/base/webserver/nginx.conf:

user  nginx;
worker_processes  1;

error_log  /var/log/nginx/error.log warn;
pid        /var/run/nginx.pid;


events {
    worker_connections  1024;
}


http {
    include       /etc/nginx/mime.types;
    default_type  application/octet-stream;

    log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                      '$status $body_bytes_sent "$http_referer" '
                      '"$http_user_agent" "$http_x_forwarded_for"';

    access_log  /var/log/nginx/access.log  main;

    sendfile        on;
    #tcp_nopush     on;

    keepalive_timeout  65;

    #gzip  on;
    server {
        listen       80;
        location / {
            root   /var/www;
            index  index.html index.htm;
        }
    }
    include /etc/nginx/conf.d/*.conf;
}

执行命令 salt ‘*’ state.apply webserver

image.png

测试是否正常访问 http 服务

curl http://127.0.0.1

 

image.png

模板、包含和扩展
在处理复杂业务逻辑时,SLS 模块可能需要编程逻辑或内联执行。 这是通过模块模板实现的。 使用的默认模块模板系统是 Jinja2,这可以通过更改 master 配置中的 renderer 值来配置。
测试文件 /etc/salt/srv/salt/base/test_temp.sls 

{% for usr in 'moe','larry','curly' %}
{{ usr }}:
  group:
    - present
  user:
    - present
    - groups:
      - {{ usr }}
    - require:
      - group: {{ usr }}
{% endfor %}

示例中,我们使用 for 循环遍历一个列表,分别调用 group 和 user 模块创建对应的组和用户。
sls 文件写法遵循 yaml 和 jinjia2 语法即可。
执行 salt ‘*’ state.apply test_temp

image.png

查看任务是否确实完成。

cat /etc/group | tail -3

 

image.png

在 SLS 模块中使用环境变量
测试文件 /etc/salt/srv/salt/base/test_env_var.sls 

{% set myenvvar = salt['environ.get']('MYENVVAR') %}
{% if myenvvar %}

创建一个从环境变量获取内容的文件:
  file.managed:
    - name: /tmp/hello
    - contents: {{ salt['environ.get']('MYENVVAR') }}

{% else %}

Fail - 没有指定环境输入:
  test.fail_without_changes

{% endif %}

进入目录 /etc/salt/srv/salt/base/,然后执行命令 MYENVVAR=”world” salt-call state.template test_env_var

image.png

如果不执行环境变量,salt-call state.template test_env_var

image.png

在 SLS 模块中使用 grains
测试文件 /etc/salt/srv/salt/base/test_grains.sls 

echo 服务器ID:{{ grains.id }}: cmd.run

salt '*' state.apply test_grains

 

image.png

在模板中调用 Salt 模块的方法
由 minion 加载的所有 Salt 模块都可在模板系统中使用。 这允许在目标系统上实时收集数据。 它还允许从 sls 模块中轻松运行 shell 命令。
测试示例 /etc/salt/srv/salt/base/test_salt_mod.sls: 

调用 Salt module:
  cmd.run:
    - name: echo "Salt State 调用 module {{ salt['network.hw_addr']('eth0') }}"

示例中,我们只想 cmd.run 模块,但传入参数中调用了 network.hw_addr 获取 eth0 的 mac 地址。
执行 salt ‘*’ state.apply test_salt_mod

image.png

include 导入其他文件中的任务
新建目录 /etc/salt/srv/salt/base/python
创建文件 /etc/salt/srv/salt/base/python/python-libs.sls 

python-dateutil: pkg.installed

调用 pkg.installed 安装 python-dateutil 软件
创建文件 /etc/salt/srv/salt/base/python/django.sls

include:
  - python.python-libs

django:
  pip.installed:
    - require:
        - pkg: python-dateutil

示例中,我们通过 include 包含了 python/python-libs.sls 声明的任务,并通过 require 依赖了它。
include 的方法与 python 导入模块类似,忽略 .sls 后缀,并通过 . 作为连接符
执行 salt ‘*’ state.apply python.django

image.png

extend 用来修改已经定义的任务
我们可以使用 Extend 修改以前的声明。
首先创建目录 /etc/salt/srv/salt/base/web/,然后定义一个 nginx 安装的 state 文件 /etc/salt/srv/salt/base/web/nginx.sls 

nginx:
  pkg.installed: []
  file.absent:
  - name: /etc/init/nginx.conf

定义一个推送 nginx 文件,扩展 nginx 重启的 state 文件 /etc/salt/srv/salt/base/web/web.sls

include:
  - web.nginx

extend:
  nginx:
    service:
      - running
      - watch:
          - file: nginx_config

nginx_config:
  file.managed:
    - source: salt://fileroot/nginx/a.conf
    - name: /etc/nginx/conf.d/a.conf

新建存放 nginx 配置文件的目录,mkdir -p /etc/salt/srv/salt/base/fileroot/nginx/
新建 nginx 配置文件 touch /etc/salt/srv/salt/base/fileroot/nginx/a.conf
执行 state 文件

salt '*' state.apply web.web

 

image.png

我们可以看到 nginx 执行了重启操作。
开发自定义的 State 模块
在使用状态模块之前,必须将其分发给各 minions。 可以通过将它们放入 salt://_states/ 中来完成。 然后可以通过运行 saltutil.sync_states 或 saltutil.sync_all 将它们手动分发给 minions。 或者,在运行 highstate 状态时,自定义状态类型将自动同步。
注意:使用文件名中携带连字符的状态模块会导致 !pyobjects 例程出现问题。 请坚持使用下划线的最佳做法。
任何已与 minions 同步的自定义状态(与 Salt 的默认状态集中的名称之一相同的)将替换具有相同名称的默认状态。 请注意,状态模块的名称根据其文件名默认为同一个(即 foo.py 变为状态模块 foo ),但是可以使用 virtual 函数覆盖其名称。
自定义 state 模块遵循的步骤
设置返回数据字典并执行任何必要的输入验证(类型检查,寻找互斥参数的使用等)。
检查是否需要进行更改。 最好通过附带的执行模块中的信息收集功能来完成此操作。 该状态应该能够使用该函数的返回值来判断该 minion 是否已经处于所需状态。
如果步骤 2 发现 minion 已经处于所需状态,则立即退出,并返回 True 结果,而无需进行任何更改。
如果步骤 2 发现确实需要进行更改,请检查状态是否在测试模式下运行(即使用 test=True)。 如果是这样,则退出并返回值为 None 的结果、相关注释和(如有可能)将进行哪些更改的描述。
执行所需的更改。 应该再次使用附带的执行模块中的函数来完成此操作。 如果该函数的结果足以告诉您是否发生了错误,则可以退出并返回 False 结果和相关注释以说明发生了什么。
再次从步骤 2 执行相同的检查,以确认 minion 是否处于所需状态。 就像在第 2 步中一样,此函数应该能够通过其返回数据来告诉您是否需要进行更改。
设置返回数据并返回。
自定义 state 调用 salt 组件
状态模块可以使用 __salt__ 调用 salt 执行模块。 使用 __grains__ 调用 salt 数据。 使用 __states__ 调用 salt state 模块。 类似 ret = __states__[‘file.managed’](name=’/tmp/myfile’, source=’salt://myfile’)
自定义 state 返回数据
name:与传递给状态的 name 参数值相同。
changes:一个描述变更的字典。 每个被更改的事物都应该是一个键,其值则作为另一个字典,其中包含旧/新值的键称为 old 和 new。
result: 取值为三个值之一。 如果操作成功,则为 True;否则为 False;如果状态以测试模式运行,则为 None,即 test=True;如果状态未以测试模式运行,则将进行更改。
自定义 state 模块示例
自定义执行模块文件:/etc/salt/srv/salt/base/_modules/my_custom_module.py: 

import random
def current_state(*k, **kw):
    return random.choice([True, False])

def change_state(*k, **kw):
    return random.choice([True, False])

创建目录 /etc/salt/srv/salt/base/_states/,然后添加自定义 state 模块文件:/etc/salt/srv/salt/base/_states/custom_state.py

import salt.exceptions

def enforce_custom_thing(name, foo, bar=True):
    '''
    定义一个 state 状态

    这个状态模块做一个定制的事情。它调用执行模块
    `my_custom_module` 来检查当前系统并执行任何
    需要更改。

    name
        The thing to do something to
    foo
        一个请求参数
    bar : True
        一个带默认值的参数
    '''
    ret = {
        'name': name,
        'changes': {},
        'result': False,
        'comment': '',
        }

    # 做基本的数据确认,参数核对.
    if bar == True and foo.startswith('Foo'):
        raise salt.exceptions.SaltInvocationError(
            'Argument "foo" cannot start with "Foo" if argument "bar" is True.')

    # 核对当前的系统状态,是否需要做修改
    current_state = __salt__['my_custom_module.current_state'](name)

    if current_state == foo:
        ret['result'] = True
        ret['comment'] = 'System already in the correct state'
        return ret

    # 如果我们运行在 `test=true` 状态下, 将不做任何更改.
    if __opts__['test'] == True:
        ret['comment'] = 'The state of "{0}" will be changed.'.format(name)
        ret['changes'] = {
            'old': current_state,
            'new': 'Description, diff, whatever of the new state',
        }

        #  如果运行在 test 模式,返回 `None`
        ret['result'] = None

        return ret

    # 最后,执行修改并返回结果
    new_state = __salt__['my_custom_module.change_state'](name, foo)

    ret['comment'] = 'The state of "{0}" was changed!'.format(name)

    ret['changes'] = {
        'old': current_state,
        'new': new_state,
    }

    ret['result'] = True

    return ret

调用自定义 state 模块文件:/etc/salt/srv/salt/base/call_custom_state.sls

测试自定义 state 模块:
  custom_state:
    - enforce_custom_thing      # 调用自定义 state 模块中的函数
    - name: a_value
    - foo: Foo
    - bar: False

执行:

salt '*' saltutil.sync_all
salt '*' state.apply call_custom_state
image.png

作者:Jachin111
链接:https://www.jianshu.com/p/ecf22d0184bf
来源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

salt-api使用

启用salt-api 服务

这里简单的说明下,SaltStack官方支持三种REST API,分别是rest_cherry; rest_tonado和rest_wsgi, 本文选择使用rest_cherry模块来实现SaltStack的HTTP API。

配置salt-API服务

yum -y install salt-api
useradd -M -s /sbin/nologin saltapi
echo "saltapi" | passwd saltapi --stdin
vim /etc/salt/master
external_auth:
  pam:
    saltapi:
      - .*
      - '@wheel'
      - '@runner'

rest_cherrypy:
  port: 8000
  disable_ssl: Ture
  
  systemctl restart salt-master 
  systemctl restart salt-api 

使用CURL测试salt-API接口

第一步登录获得token,后续的命令使用token直接执行。

curl  -sk http://192.168.56.11:8000/login -H 'Accept: application/x-yaml' -d username='saltapi' -d password='saltapi' -d eauth='pam'

return:
- eauth: pam
  expire: 1522883646.381435
  perms:
  - .*
  - '@wheel'
  - '@runner'
  start: 1522840446.381431
  token: 86e323effd30bed7b2cdbcf4e70744048bbc25ca
  user: saltapi

第二步执行如下命令:salt 'linux-node2' test.ping

curl -sk http://192.168.56.11:8000/ -H 'Accept: application/json' -H 'X-Auth-Token: 86e323effd30bed7b2cdbcf4e70744048bbc25ca' -d client='local' -d tgt='linux-node2' -d fun='test.ping'  | python -mjson.tool  
{
    "return": [
        {
            "linux-node2": true
        }
    ]
}

执行带参数的命令:salt 'linux-node2' cmd.run 'free -m'

curl -sk http://192.168.56.11:8000/ -H 'Accept: application/json' -H 'X-Auth-Token: 86e323effd30bed7b2cdbcf4e70744048bbc25ca' -d client='local' -d tgt='linux-node2' -d fun='cmd.run' -d arg='whoami' | python -mjson.tool
{
    "return": [
        {
            "linux-node2": "root"
        }
    ]
}

salt API /run 接口

运行绕过正常会话处理的命令除此之外,该URL与根URL(/)相同。

curl -sk http://192.168.56.11:8000/run \
    -H 'Accept: application/x-yaml' \
    -H 'Content-type: application/json' \
    -d '[{
        "client": "local",
        "tgt": "linux-node2",
        "fun": "test.ping",
        "username": "saltapi",
        "password": "saltapi",
        "eauth": "pam"
    }]' 
return:
- linux-node2: true

使用python 实现如下命令

salt 'linux-node2' cmd.run 'free -m'
import requests

url='http://192.168.56.11:8000/login'
username = 'saltapi'
password = 'saltapi'

data = {'username': username,'password': password,'eauth': 'pam'}
headers = {'Accept': 'application/json','Content-Type': 'application/x-www-form-urlencoded'}
login_req = requests.post(url=url, headers=headers, data=data)
js = login_req.json()
token = js['return'][0].get('token')
print(token)


cmd_headers = {'Accept': 'application/json','Content-type': 'application/x-www-form-urlencoded', 'X-Auth-Token': token}
cmd_data = {'client': 'local', 'tgt': 'linux-node2', 'fun': 'cmd.run', 'arg': 'free -m '}
urls = 'http://192.168.56.11:8000'
req = requests.post(urls,headers=cmd_headers,data=cmd_data)
print(req.status_code)

if req.status_code == 200:
	print(req.json())

执行结果如下:

ab5d9ea0f428367c79f8eaf3dc62d39b1c45b4c9
200
{'return': [{'linux-node2': '              total        used        free      shared  buff/cache   available\nMem:            979         607          76          49         295         172\nSwap:             0           0           0'}]}

使用python编写过程中遇到的问题:

  • curl 请求时,默认会增加Content-type': 'application/x-www-form-urlencoded 的头部,所以在request请求头中也需要加入。

使用saltstack的sls功能

sls文件编写

[root@vm01 ~]# vim /etc/salt/master
#在master配置文件中添加以下内容
file_roots:
base:
– /srv/salt

[root@vm01 ~]# mkdir -p /srv/salt
[root@vm01 ~]# cd /srv/salt/
[root@vm01 salt]# pwd
/srv/salt
[root@vm01 salt]# vim top.sls
base:
‘*’:
– httpd

[root@vm01 salt]# vim httpd.sls
httpd:
pkg:
– installed

[root@vm01 salt]#
[root@vm01 salt]# salt ‘*’ service.available httpd
vm02:
False
[root@vm01 salt]#
[root@vm01 salt]# salt ‘*’ state.highstate -v
Executing job with jid 20160412203923856918
——————————————-

vm02:
———-
ID: httpd
Function: pkg.installed
Result: True
Comment: The following packages were installed/updated: httpd
Started: 20:39:25.356652
Duration: 46945.068 ms
Changes:
———-
httpd:
———-
new:
2.2.15-47.el6.centos.4
old:

Summary
————
Succeeded: 1 (changed=1)
Failed: 0
————
Total states run: 1
[root@vm01 salt]#
[root@vm01 salt]# salt ‘*’ service.available httpd
vm02:
True
[root@vm01 salt]#

#minion端查看httpd是否已经安装成功
[root@vm02 ~]# rpm -q httpd
httpd-2.2.15-47.el6.centos.4.x86_64
[root@vm02 ~]#
#ok,已经安装成功了,就这么简单。

SaltStack使用salt-ssh模式

1.salt-ssh 是 0.17.0 新引入的一个功能,不需要minion对客户端进行管理,也不需要master。

2.salt-ssh 支持salt大部分的功能:如 grains、modules、state 等

3.salt-ssh 没有使用ZeroMQ的通信架构,执行是串行模式

类似 paramiko、pssh、ansible 这类的工具

Roster使用

salt-ssh需要一个名单系统来确定哪些执行目标,Salt的0.17.0版本中salt-ssh引入roster系统

roster系统编译成了一个数据结构,包含了targets,这些targets是一个目标系统主机列表和或如连接到这些targets

配置文件如下
复制代码
# target的信息
    host:        # 远端主机的ip地址或者dns域名
    user:        # 登录的用户
    passwd:      # 用户密码,如果不使用此选项,则默认使用秘钥方式
# 可选的部分
    port:        #ssh端口
    sudo:        #可以通过sudo
    tty:         # 如果设置了sudo,设置这个参数为true
    priv:        # ssh秘钥的文件路径
    timeout:     # 当建立链接时等待响应时间的秒数
    minion_opts: # minion的位置路径
    thin_dir:    # target系统的存储目录,默认是/tmp/salt-<hash>
    cmd_umask:   # 使用salt-call命令的umask值
复制代码

安装配置

一,安装salt-ssh
[root@linux-node1 ~]# yum install salt-ssh
二,修改roster文件,配置要管理的机器
复制代码
[root@linux-node1 ~]# tail -11  /etc/salt/roster 
linux-node1.example.com:
  host: 192.168.56.11
  user: root
  passwd: 123456
  port: 22

linux-node2.example.com:
  host: 192.168.56.12
  user: root
  passwd: 123456
  port: 22
复制代码
三,进行管理测试
[root@linux-node1 ~]# salt-ssh '*' test.ping -i
linux-node1.example.com:
    True
linux-node2.example.com:
    True
四,salt-ssh命令用法
复制代码
-r, –raw, –raw-shell # 直接使用shell命令
–priv #指定SSH私有密钥文件
–roster #定义使用哪个roster系统,如果定义了一个后端数据库,扫描方式,或者用户自定义的的roster系统,默认的就是/etc/salt/roster文件
–roster-file #指定roster文件
–refresh, –refresh-cache #刷新cache,如果target的grains改变会自动刷新
–max-procs #指定进程数,默认为25
-i, –ignore-host-keys #当ssh连接时,忽略keys
–passwd #指定默认密码
–key-deploy #配置keys 设置这个参数对于所有minions用来部署ssh-key认证,
 这个参和–passwd结合起来使用会使初始化部署很快很方便。当调用master模块时,并加上参数 –key-deploy 即可在minions生成keys,下次开始就不使用密码
复制代码
五,salt-ssh执行状态模块
 salt-ssh ‘*’ state.sls web.lamp

总结

1.salt-ssh 是在salt基础上打了一个python包上传到客户端的默认tmp目录下

在客户端上面解压并执行返回结果,最后删除tmp上传的临时文件

2.salt-minion方法是salt-mater先执行语法验证,验证通过后发送到minion

minion收到Msater的状态文件默认保存在/var/cache/salt/minion

注意:也有时候salt-master语法验证通过,在minion上可能因为环境问题会执行失败

3.salt-ssh和salt-minion可以共存,salt-minion不依赖于ssh服务

 

salt之pillar组件

pillar也是salt最重要的组件之一,其作用是定义与被控主机相关的任何数据,定义好的数据可以被其他组件使用,如模板、state、API等。在pillar中定义的数据与不同业务特征的被控主机相关联,这样不同被控主机只能看到自己匹配的数据,因此pillar安全性很高,适用于一些比较敏感的数据,这也是区别于grains最关键的一点,如定义不同业务组主机的用户id、组id、读写权限、程序包等信息,定义的规范是采用Python字典形式,即键/值,最上层的键一般为主机的id或组名称。

pillar的定义:

1、主配置文件定义

salt默认将主控端配置文件中的所有数据都定义到pillar中,而且对所有被控主机开放,可通过修改/etc/salt/master配置中的pillar_opts: True或False来定义是否开户或禁用这项功能,修改后执行salt ‘*’ pillar.data来观察效果。

2、SLS文件定义

pillar支持在slsy文件中定义数据,格式须符合YAML规范,与salt和state组件十分相似,两者文件的配置格式、入口文件top.sls都是一致的。

(1)定义pillar的主目录

修改主配置文件/etc/salt/master的pillar_roots参数,定义pillar的主目录

同时创建pillar目录,执行命令: install -d /srv/pillar

(2)定义入口文件top.sls

入口文件的作用一般是定义pillar的数据覆盖被控主机的有效域范围,”*” 代表任意主机,其中包括了一个data.sls文件,

/srv/pillar/top.sls

base:

‘*’:

– data

/srv/pillar/data.sls

appname: website

flow:

maxconn: 30000

maxmem: 6G

(3)校验pillar

通过 salt ‘myhost’ pillar.data appname flow 命令可以看到多出了上面定义的 data.sls数据项。如果结果不符合预期,可以尝试刷新被控机pillar数据,

运行 salt ‘myhost’ saltutil.refresh_pillar 即可刷新

 

3、pillar的使用

完成pillar配置后,接下来我们可以在state、模板文件中引用,模板格式为 “{{ pillar变量 }}” ,例如:

{{ pillar[‘appname’] }} (一级字典)

{{ pillar[‘flow’][‘maxconn’] }} (二级字典) 或 {{ salt[‘pillar.get’](‘flow: maxconn’),{} }}

 

Python API格式如下:

pillar[‘flow’][‘maxconn’]

pillar.get(‘flow:appname’,{})

 

结合grains处理数据的差异性—-示例:

3.1 创建pillar目录和top.sls文件

1
2
3
4
5
 # mkdir /srv/pillar
 # vi /srv/pillar/top.sls
 base:
   '*':
 - ip

3.2 先通过pillar获取minion主机IP

1
2
 # vi /srv/pillar/ip.sls
 ip: {{ grains['ipv4'][1] }}

#写完后,执行sls命令,可以看到已经获取到IP

1
2
3
4
5
6
7
8
9
 # salt '*' pillar.item ip
 host2:
     ----------
     ip:
         192.168.18.213
 host1:
     ----------
     ip:
         192.168.18.212

 

 

 

 

既然grains与pillar类似,就说下区别:

1.grains是minion每次加载时获取本地系统信息数据,是静态的,固定的,而pillar是动态加载数据,随时变化的,比grains更灵活。

2.grains数据存储在minion本地,pillar存储在master

 

Using salt-ssh to install Salt

In recent articles I covered how I’ve built a Continuous Delivery pipeline for my blog. These articles talk about using Docker to build a container for my blog, using Travis CI to test and build that container, and finally using a Masterless SaltStack configuration to deploy the blog. Once setup, this pipeline enables me to publish new posts by simply managing them within a GitHub repository.

The nice thing about this setup is that not only are blog posts managed hands-free. All of the servers that host my blog are managed hands-free. That means required packages, services and configurations are all deployed with the same Masterless SaltStack configuration used for the blog application deployment.

The only thing that isn’t hands-free about this setup, is installing and configuring the initial SaltStack Minion agent. That is, until today. In this article I am going to cover how to use salt-ssh, SaltStack’s SSH functionality to install and configure the salt-minion package on a new server.

How salt-ssh works

A typical SaltStack deployment consists of a Master server running the salt-master process, and one or more Minion servers running the salt-minion process. The salt-minion service will initiate communication with the salt-master service over a ZeroMQ connection and the Master distributes desired states to the Minion.

With this typical setup, you must first have a salt-master service installed and configured, and every server that you wish to manage with Salt must have the salt-minion service installed and configured. The salt-ssh package however, changes that.

salt-ssh is designed to provide SaltStack with the ability to manage servers in an agent-less fashion. What that means is, salt-ssh gives you the ability to manage a server, without having to install and configure the salt-minion package.

Why use salt-ssh instead of the salt-minion agent?

Why would anyone not want to install the salt-minion package? Well, there are a lot of possible reasons. One reason that comes to mind is that some systems are so performance oriented that there may be a desire to avoid performance degradation by running an agent. While salt-minion doesn’t normally use a lot of resources, it uses some and that some may be too much for certain environments.

Another reason may be due to network restrictions, for example if the Minions are in a DMZ segment of a network you may want to use salt-ssh from the master so that connections are only going from the master to the minion and never the minion to the master like the traditional setup.

For today’s article, the reasoning behind using salt-ssh is that I wish to automate the installation and configuration of the salt-minion service on new servers. These servers will not have the salt-minion package installed by default and I wanted to automate the initial installation of Salt.

Getting started with salt-ssh

Before we can start using salt-ssh to setup our new server we will first need to setup a Master server where we can call salt-ssh from. For my environment I will be using a virtual machine running on my local laptop as the Salt Master. Since we are using salt-ssh there is no need for the Minions to connect to this Master which makes running it from a laptop a simple solution.

Installing SaltStack

On this Salt Master, we will need to install both the salt-master and the salt-ssh packages. Like previous articles we will be following SaltStack’s official guide for installing Salt on Ubuntu systems.

Setup Apt

The official install guide for Ubuntu uses the Apt package manager to install SaltStack. In order to install these packages with Apt we will need to setup the SaltStack repository. We will do so using the add-apt-repository command.

$ sudo add-apt-repository ppa:saltstack/salt
     Salt, the remote execution and configuration management tool.
     More info: https://launchpad.net/~saltstack/+archive/ubuntu/salt
    Press [ENTER] to continue or ctrl-c to cancel adding it

    gpg: keyring `/tmp/tmpvi1b21hk/secring.gpg' created
    gpg: keyring `/tmp/tmpvi1b21hk/pubring.gpg' created
    gpg: requesting key 0E27C0A6 from hkp server keyserver.ubuntu.com
    gpg: /tmp/tmpvi1b21hk/trustdb.gpg: trustdb created
    gpg: key 0E27C0A6: public key "Launchpad PPA for Salt Stack" imported
    gpg: Total number processed: 1
    gpg:               imported: 1  (RSA: 1)
    OK

Once the Apt repository has been added we will need to refresh Apt’s package cache with the apt-get update command.

$ sudo apt-get update
Get:1 http://security.ubuntu.com trusty-security InRelease [65.9 kB]
Ign http://ppa.launchpad.net trusty InRelease                                  
Ign http://archive.ubuntu.com trusty InRelease                                 
Get:2 http://archive.ubuntu.com trusty-updates InRelease [65.9 kB]
Get:3 http://ppa.launchpad.net trusty Release.gpg [316 B]                      
Get:4 http://ppa.launchpad.net trusty Release [15.1 kB]                        
Get:5 http://security.ubuntu.com trusty-security/main Sources [118 kB]         
Fetched 10.9 MB in 7s (1,528 kB/s)                                             
Reading package lists... Done

This update command causes Apt to look through it’s known package repositories and refresh a local inventory of available packages.

Installing the salt-master and salt-ssh packages

Now that we have SaltStack’s Apt repository configured we can proceed with installing the required Salt packages. We will do this with the apt-get install command specifying the two packages we wish to install.

$ sudo apt-get install salt-master salt-ssh
Reading package lists... Done
Building dependency tree       
Reading state information... Done
The following extra packages will be installed:
  git git-man liberror-perl libpgm-5.1-0 libzmq3 python-async python-croniter
  python-dateutil python-git python-gitdb python-jinja2 python-m2crypto
  python-markupsafe python-msgpack python-smmap python-zmq salt-common
Suggested packages:
  git-daemon-run git-daemon-sysvinit git-doc git-el git-email git-gui gitk
  gitweb git-arch git-bzr git-cvs git-mediawiki git-svn python-jinja2-doc
  salt-doc python-mako
The following NEW packages will be installed:
  git git-man liberror-perl libpgm-5.1-0 libzmq3 python-async python-croniter
  python-dateutil python-git python-gitdb python-jinja2 python-m2crypto
  python-markupsafe python-msgpack python-smmap python-zmq salt-common
  salt-master salt-ssh
0 upgraded, 19 newly installed, 0 to remove and 189 not upgraded.
Need to get 7,069 kB of archives.
After this operation, 38.7 MB of additional disk space will be used.
Do you want to continue? [Y/n] Y

In addition to the salt-ssh and salt-master packages Apt will install any dependencies that these packages require. With these packages installed, we can now move on to configuring our Salt master.

Configuring salt-ssh to connect to our target minion

Before we can start using salt-ssh to manage our new minion server we will first need to tell salt-ssh how to connect to that server. We will do this by editing the /etc/salt/roster file.

$ sudo vi /etc/salt/roster

With a traditional SaltStack setup the minion agents would initiate the first connection to the Salt master. This first connection is the way the master service identifies new minion servers. With salt-ssh there is no process for Salt to automatically identify new minion servers. This is where the /etc/salt/roster file comes into the picture, as this file used as an inventory of minions for salt-ssh.

As with other configuration files in Salt, the roster file is a YAML formatted file which makes it fairly straight forwarder to understand. The information required to specify a new minion is also pretty straight forward.

blr1-001:
  host: 10.0.0.2
  user: root

The above information is fairly minimal, the basic definition is a Target name blr1-001, a Hostname or IP address specified by host and then the Username specified by user.

The target name is used when running the salt-ssh command to specify what minion we wish to target. The host key is used by salt-ssh to define where to connect to, and the user key is used to define who to connect as.

In the example above I specified to use the root user. It is possible to use salt-ssh with a non-root user by simply adding sudo: True to the minion entry.

Testing connectivity to our minion

With the minion now defined within the /etc/salt/roster file we should now be able to connect to our minion with salt-ssh. We can test this out by executing a test.ping task against this target with salt-ssh.

$ sudo salt-ssh 'blr1-001' --priv=/home/vagrant/.ssh/id_rsa test.ping
blr1-001:
    ----------
    retcode:
        254
    stderr:
    stdout:
        The host key needs to be accepted, to auto accept run salt-ssh with the -i flag:
        The authenticity of host '10.0.0.2 (10.0.0.2)' can't be established.
        ECDSA key fingerprint is 2c:34:0a:51:a2:bb:88:cc:3b:86:25:bc:b8:d0:b3:d0.
        Are you sure you want to continue connecting (yes/no)?

The salt-ssh command above has a similar syntax to the standard salt command called with a typical Master/Minion setup; the format is salt-ssh <target> <task>. In this case our target was blr1-001 the same name we defined earlier and our task was test.ping.

You may also notice that I passed the --priv flag followed by a path to my SSH private key. This flag is used to specify an SSH key to use when connecting to the minion server. By default, salt-ssh will use SaltStack’s internal SSH key, which means if you wish to use an alternative key you will need to specify the key with the --priv flag.

In many cases it’s perfectly fine to use SaltStack’s internal SSH key, in my case the SSH public key has already been distributed which means I do not want to use Salt’s internal SSH key.

Bypassing Host Key Validation

If we look at the output of the salt-ssh command executed earlier, we can see that the command was not successful. The reason for this is because this master server has not accepted the host key from the new minion server. We can get around this issue by specifying the -i flag when running salt-ssh.

$ sudo salt-ssh 'blr1-001' --priv /home/vagrant/.ssh/id_rsa -i test.ping
blr1-001:
    True

The -i flag tells salt-ssh to ignore host key checks from SSH. We can see from the above salt-ssh execution, when the -i flag is used, everything works as expected.

Specifying a password

In the salt-ssh commands above we used an SSH key for authentication with the Minion server. This worked because prior to setting up Salt, I deployed the public SSH key to the minion server we are connecting with. If we didn’t want to use SSH keys for authentication with the Salt Minion for whatever reason, we could also use password based authentication by specifying the password within the roster file.

$ sudo vi /etc/salt/roster

To add a password for authentication, simply add the passwd key within the target servers specification.

blr1-001:
  host: 10.0.0.2
  user: root
  passwd: example

With the above definition salt-ssh will now connect to our minion by establishing an SSH connection to 10.0.0.2 and login to this system as the root user with the password of example. With a password defined, we can rerun our test.ping this time with the --priv flag omitted.

$ sudo salt-ssh 'blr1-001' -i test.ping
blr1-001:
    True

Now that a test.ping has returned correctly we can move on to our next step of defining the Salt states to install and configure the salt-minion package.

Using Salt to install Salt

In the Master-less Salt Minions article I had two GitHub repositories setup with various Salt state files. One repository contains salt state files that can be used to setup a generic base system, and the other contains custom state files used to setup the environment running this blog.

Breaking down the minion state

Within this second repository is a salt state file that installs and configures the salt-minion service. Let’s take a quick look at this state to understand how the salt-minion package is being installed.

salt-minion:
  pkgrepo:
    - managed
    - humanname: SaltStack Repo
    - name: deb http://repo.saltstack.com/apt/ubuntu/14.04/amd64/latest {{ grains['lsb_distrib_codename'] }} main
    - dist: {{ grains['lsb_distrib_codename'] }}
    - key_url: https://repo.saltstack.com/apt/ubuntu/14.04/amd64/latest/SALTSTACK-GPG-KEY.pub
  pkg:
    - latest
  service:
    - dead
    - enable: False

/etc/salt/minion.d/masterless.conf:
  file.managed:
    - source: salt://salt/config/etc/salt/minion.d/masterless.conf

/etc/cron.d/salt-standalone:
  file.managed:
    - source: salt://salt/config/etc/cron.d/salt-standalone

In the above state we can see that the Salt Apt repository is being added with the pkgrep module. The salt-minion package is being installed with the pkg module and the salt-minion service is being disabled by the service module.

We can also see that two files /etc/salt/minion.d/masterless.conf and /etc/cron.d/salt-standalone are being deployed. For this article, we will use this state as is to perform the initial salt-minion installation and configuration.

Setting up the master

As with the previous article we will use both of these repositories to setup our minion server. We will get started by first using git to clone these repositories into a directory within /srv/salt.

For the first repository, we will clone the contents into a base directory.

$ sudo git clone https://github.com/madflojo/salt-base.git /srv/salt/base
Cloning into '/srv/salt/base'...
remote: Counting objects: 54, done.
remote: Total 54 (delta 0), reused 0 (delta 0), pack-reused 54
Unpacking objects: 100% (54/54), done.
Checking connectivity... done.

The second repository we will clone into /srv/salt/bencane.

$ sudo git clone https://github.com/madflojo/blog-salt.git /srv/salt/bencane
Cloning into '/srv/salt/bencane'...
remote: Counting objects: 46, done.
remote: Total 46 (delta 0), reused 0 (delta 0), pack-reused 46
Unpacking objects: 100% (46/46), done.
Checking connectivity... done.

With all of the salt states now on our local system we can configure Salt to use these state files. To do this we will need to edit the /etc/salt/master configuration file.

$ sudo vi /etc/salt/master

Within the master file the file_roots configuration parameter is used to define where Salt’s state files are located on the master. Since we have two different locations for the two sets of state files we will specify them individually as their own item underneath file_roots.

file_roots:
  base:
    - /srv/salt/base
  bencane:
    - /srv/salt/bencane

With the above defined, we can now use our Salt states to setup a new minion server. To do this we will once again run salt-ssh but this time specifying the state.highstate task.

$ sudo salt-ssh 'blr1-001' -i state.highstate
----------
          ID: salt-minion
    Function: pkgrepo.managed
        Name: deb http://repo.saltstack.com/apt/ubuntu/14.04/amd64/latest trusty main
      Result: True
     Comment: Configured package repo 'deb http://repo.saltstack.com/apt/ubuntu/14.04/amd64/latest trusty main'
     Started: 21:18:54.462571
    Duration: 20440.965 ms
     Changes:   
              ----------
              repo:
                  deb http://repo.saltstack.com/apt/ubuntu/14.04/amd64/latest trusty main
----------
          ID: salt-minion
    Function: pkg.latest
      Result: True
     Comment: The following packages were successfully installed/upgraded: salt-minion
     Started: 21:19:14.903859
    Duration: 16889.713 ms
     Changes:   
              ----------
              dctrl-tools:
                  ----------
                  new:
                      2.23ubuntu1
                  old:
              salt-minion:
                  ----------
                  new:
                      2016.3.1+ds-1
                  old:
----------
          ID: salt-minion
    Function: service.dead
      Result: True
     Comment: Service salt-minion has been disabled, and is dead
     Started: 21:19:32.488449
    Duration: 133.722 ms
     Changes:   
              ----------
              salt-minion:
                  True
----------
          ID: /etc/salt/minion.d/masterless.conf
    Function: file.managed
      Result: True
     Comment: File /etc/salt/minion.d/masterless.conf updated
     Started: 21:19:32.626328
    Duration: 11.762 ms
     Changes:   
              ----------
              diff:
                  New file
              mode:
                  0644
----------
          ID: /etc/cron.d/salt-standalone
    Function: file.managed
      Result: True
     Comment: File /etc/cron.d/salt-standalone updated
     Started: 21:19:32.638297
    Duration: 4.049 ms
     Changes:   
              ----------
              diff:
                  New file
              mode:
                  0644

Summary
-------------
Succeeded: 37 (changed=23)
Failed:     0
-------------
Total states run:     37

From the results of the state.highstate task, we can see that 37 Salt states were verified and 23 of those resulted in changes being made. We can also see from the output of the command above that our salt-ssh execution just resulted in the installation and configuration of the salt-minion package.

If we wanted to verify that this is true even further we can use the cmd.run Salt module to execute the dpkg --list command.

$ sudo salt-ssh 'blr1-001' -i cmd.run "dpkg --list | grep salt"
blr1-001:
    ii  salt-common                        2016.3.1+ds-1                    all          shared libraries that salt requires for all packages
    ii  salt-minion                        2016.3.1+ds-1                    all          client package for salt, the distributed remote execution system

Summary

With the above, we can see that we were successfully able to install the salt-minion agent to a remote system via salt-ssh. While this may seem like quite a bit of work to setup for a single minion. The ability to install Salt with salt-ssh can be very useful when you are setting up multiple minions, as this same methodology works whether you’re installing Salt on 1 or 1,000 minions.

ansible vs saltstack速度测试

salt vs ansible
管理的机器数1500

time salt "*"  cmd.run "hostname"
real    0m3.983s
user    0m3.582s
sys     0m0.252s

time  salt '*' test.ping
real    0m3.856s
user    0m3.454s
sys     0m0.242s

time ansible ... -m ping
real    3m44.632s
user    2m9.356s
sys     1m25.901s

time ansible ... -m shell -a "hostname"
real    1m35.808s
user    1m50.635s
sys     1m26.378s


 

saltstack高效运维

salt介绍

saltstack是由thomas Hatch于2011年创建的一个开源项目,设计初衷是为了实现一个快速的远程执行系统。

salt强大吗

系统管理员日常会进行大量的重复性操作,例如安装软件,修改配置文件,创建用户,批量执行命令等等。如果主机数量庞大,单靠人工维护实在让人难以忍受。

早期运维人员会根据自己的生产环境来写特定脚本完成大量重复性工作,这些脚本复杂且难以维护。系统管理员面临的问题主要是1、系统配置管理,2、远程执行命令,因此诞生了很多开源软件,系统维护方面有fabric、puppet、chef、ansible、saltstack等,这些软件擅长维护系统状态或方便的对大量主机进行批量的命令执行。

salt灵活性强大,可以进行大规模部署,也能进行小规模的系统部署。salt的设计架构适用于任意数量的服务器,从少量本地网络系统到跨越数个数据中心,拓扑架构都是c/s模型,配置简单。

不管是几台、几百台、几千台服务器,都可以使用salt在一个中心节点上进行管控,灵活定位任意服务器子集来运行命令。

Salt是python编写的,支持用户通过python自定义功能模块,也提供了大量的python API接口,用户可以根据需要进行简单快速的扩展。

saltstack的运行方式

  • Local  本地运行,交付管理
  • Master/Minion   <<<   常用方式
  • Salt SSH   不需要客户端

salt部署基本架构

在安装salt之前,先理解salt架构中各个角色,主要区分是salt-master和salt-minion,顾名思义master是中心控制系统,minion是被管理的客户端。

salt架构中的一种就是master > minion。

在远程执行系统中,salt用python通过函数调用完成任务。

运行salt依赖包

复制代码
复制代码
python
zeromq
pyzmp
pycrypto
msgpack-python
yaml
jinja2
复制代码
复制代码

解决依赖包最简单的办法就是用安装包管理器,yum工具

服务器环境准备

服务器环境 centos7(master) centos7(master)
ip地址 192.168.178.131 192.168.178.132
身份 master slave
软件包 salt-master salt-minion

修改虚拟机ip地址为静态地址,并且确保可上网

 master网卡配置
 slave网卡配置
 dns配置文件
 /etc/hosts

 

关闭服务器安全策略

 关闭安全策略

安装saltstack

salt软件包需要epel源的支持,那么下载

EPEL的全称叫 Extra Packages for Enterprise Linux 。EPEL是由 Fedora 社区打造,为 RHEL 及衍生发行版如 CentOS、Scientific Linux 等提供高质量软件包的项目。装上了 EPEL之后,就相当于添加了一个第三方源。

wget -O /etc/yum.repos.d/CentOS-Base.repo http://mirrors.aliyun.com/repo/Centos-7.repo
wget -O /etc/yum.repos.d/epel.repo http://mirrors.aliyun.com/repo/epel-7.repo
yum clean all #清空缓存
yum makecache #生成yum缓存

安装好epel源就可以开始安装salt了

查看salt包
yum list salt

安装salt-master
yum install salt-master -y
安装salt-minion
yum install salt-minion -y

salt端口

安装好salt之后开始配置,salt-master默认监听两个端口:

4505   publish_port 提供远程命令发送功能
4506   ret_port     提供认证,文件服务,结果收集等功能
确保客户端可以通信服务器的此2个端口,保证防火墙允许端口通过。因此在测试环境直接关闭防火墙。

配置文件

salt-master的配置文件是/etc/salt/master
salt-minion的配置文件是/etc/salt/minion
配置文件中包含了大量可调整的参数,这些参数控制master和minion各个方面

配置salt-master

 常用配置解析

超哥的salt-master文件

复制代码
复制代码
[root@master ~]# grep -v ^# /etc/salt/master|grep -v ^$
interface: 0.0.0.0  #绑定到本地的0.0.0.0地址
publish_port: 4505  #管理端口,命令发送
user: root      #运行salt进程的用户
worker_threads: 5  #salt运行线程数,线程越多处理速度越快,不要超过cpu个数
ret_port: 4506  #执行结果返回端口
pidfile: /var/run/salt-master.pid #pid文件位置
log_file: /var/log/salt/master  #日志文件地址

#自动接收minion的key
auto_accept: False
复制代码
复制代码

复制代码
# minion的识别ID,可以是IP,域名,或是可以通过DNS解析的字符串
id: slave
 
# salt运行的用户权限
user: root
 
# master的识别ID,可以是IP,域名,或是可以通过DNS解析的字符串
master : master
 
# master通信端口
master_port: 4506
 
# 备份模式,minion是本地备份,当进行文件管理时的文件备份模式
backup_mode: minion
 
# 执行salt-call时候的输出方式
output: nested
 
# minion等待master接受认证的时间
acceptance_wait_time: 10
 
# 失败重连次数,0表示无限次,非零会不断尝试到设置值后停止尝试
acceptance_wait_time_max: 0
 
# 重新认证延迟时间,可以避免因为master的key改变导致minion需要重新认证的syn风暴
random_reauth_delay: 60
 
# 日志文件位置
log_file: /var/logs/salt_minion.log
复制代码

超哥的satl-minion文件

复制代码
复制代码
[root@slave ~]# grep -v ^# /etc/salt/minion|grep -v ^$
master: master
master_port: 4506
user: root
id: slave
acceptance_wait_time: 10
log_file: /var/log/salt/minion
复制代码
复制代码

 启动salt-master和salt-minion

复制代码
复制代码
systemctl start salt-minion
systemctl start salt-master

#检查salt状态
systemctl status salt-minion
systemctl status salt-master
复制代码
复制代码

在master上接收minion秘钥

在minion启动后连接master会请求master为其签发证书,等待证书签发完成后,master可以信任minion,并且minion和master之间的通信是加密的。

在salt-master执行

salt-key命令用于管理mionion秘钥

复制代码
复制代码
[root@master ~]# salt-key -L
Accepted Keys:
Denied Keys:
Unaccepted Keys:
slave    #此时已经出现slave
Rejected Keys:
复制代码
复制代码

此时slave已经出现在unaccepted keys中,说明minion已经和master联系,并且master已经获取了minion的公钥,等待下一步指令。

检查master和minion的秘钥匹配

在master上执行

[root@master ~]# salt-key -f slave
Unaccepted Keys:
slave:  0a:b9:97:b5:9a:65:b8:49:a1:50:a5:6a:66:ce:33:ea

然后可以在minion上获取minion的秘钥

[root@slave ~]# salt-call --local key.finger
local:
    0a:b9:97:b5:9a:65:b8:49:a1:50:a5:6a:66:ce:33:ea

因此可确认秘钥匹配,在master上接收秘钥

复制代码
复制代码
[root@master ~]# salt-key -a slave
The following keys are going to be accepted:
Unaccepted Keys:
slave
Proceed? [n/Y] y
Key for minion slave accepted.
复制代码
复制代码

确认接收秘钥后,检验minion秘钥是否被接收

复制代码
复制代码
[root@master ~]# salt-key -L
Accepted Keys:
slave
Denied Keys:
Unaccepted Keys:
Rejected Keys:
复制代码
复制代码

秘钥接收完成后,就可以执行第一条salt啦

salt-key

只有Master接受了Minion Key后,才能进行管理。具体的认证命令为salt-key常用的有如下命令。

复制代码
复制代码
[root@linux-node1 ~]# salt-key -L
Accepted Keys:  #已经接受的key
Denied Keys:    #拒绝的key
Unaccepted Keys:#未加入的key
Rejected Keys:#吊销的key

#常用参数
-L  #查看KEY状态
-A  #允许所有
-D  #删除所有
-a  #认证指定的key
-d  #删除指定的key
-r  #注销掉指定key(该状态为未被认证)

#在master端/etc/salt/master配置
auto_accept: True   #如果对Minion信任,可以配置master自动接受请求
复制代码
复制代码

salt-key的使用

复制代码
复制代码
#列出当前所有的key
[root@salt0-master ~]# salt-key 
Accepted Keys:
salt1-minion.example.com
salt2-minion.example.com
salt3-minion.example.com
salt4-minion.example.com
Denied Keys:
Unaccepted Keys:
Rejected Keys:

#添加指定minion的key
[root@salt0-master ~]# salt-key  -a salt1-minion.example.com -y
#添加所有minion的key
[root@salt0-master ~]# salt-key  -A  -y

#删除指定的key
[root@salt0-master ~]# salt-key -d salt1-minion.example.com -y
#删除所有的key
[root@salt0-master ~]# salt-key -D -y
复制代码
复制代码

 

 

 

日常命令参数

首先知道master和minion都安装了什么文件,然后才知道怎么操作

master端

rpm -ql salt-master
复制代码
复制代码
/etc/salt/master      # salt master主配置文件
/usr/bin/salt           #salt master 核心操作命令
/usr/bin/salt-cp       #salt 文件传输命令
/usr/bin/salt-key    #salt证书管理
/usr/bin/salt-master    #salt master 服务命令
/usr/bin/salt-run          #salt master runner命令
复制代码
复制代码

slave端

[root@slave  ~]$rpm -ql salt-minion
/etc/salt/minion     #minion配置文件
/usr/bin/salt-call    #拉取命令
/usr/bin/salt-minion   #minion服务命令
/usr/lib/systemd/system/salt-minion.service   #minion启动脚本

第一条salt命令

复制代码
复制代码
[root@master ~]# salt '*' test.ping
slave:
    True

# salt 是一个命令 
# * 表示目标主机, 在这里代表所有目标主机 
# test.ping是salt远程执行的一个模块下面的方法。
复制代码
复制代码

这是条很简单的探测minion主机存活命令,也是远程执行命令,我们通过master发送消息给”*”所有的minion,并且告诉他们运行salt内置的命令(也是python模块中的一个函数),返回true表示slave机器监控存活。

 

test模块实际上还有许多其他的函数

 test其他函数

测试下test.echo

[root@master 192.168.199.155 ~]$salt '*' test.echo 'chaoge nb666'
slave:
    chaoge nb666

test.fib生成斐波那契数列

菲波那切数列定义是第0项是0,第1项是1,数列从第3项开始,每一项等于前两项之和。

复制代码
复制代码
[root@master 192.168.199.155 ~]$salt '*' test.fib 50
slave:
    |_
      - 0
      - 1
      - 1
      - 2
      - 3
      - 5
      - 8
      - 13
      - 21
      - 34
    - 1.09672546387e-05
复制代码
复制代码

小结

此前在机器上安装了salt minion和salt master,进行了最简单的连接,然后master接受了minion的秘钥,运行了第一条test.ping命令

salt命令组成结构

在命令行输入的命令都是     执行模块

等到命令写入到文件中,             就叫做状态模块

salt --help #即可查看salt帮助

[root@master 192.168.199.155 ~]$salt –help
Usage: salt [options] ‘<target>’ <function> [arguments]

salt命令 参数 目标 salt模块的函数 远程执行的参数

完整的五部分命令

复制代码
复制代码
#--summary参数显示salt命令的概要
[root@master 192.168.199.155 ~]$salt --summary '*' cmd.run 'hostname'
slave:
    slave


-------------------------------------------
Summary
-------------------------------------------
# of Minions Targeted: 1
# of Minions Returned: 1
# of Minions Did Not Return: 0
-------------------------------------------
复制代码
复制代码

列出所有salt的sys模块

#与系统交互的sys模块
[root@master 192.168.11.72 ~]$salt 'slave' sys.list_modules

远程执行命令模块

cmd是超级模块,所有shell命令都能执行

复制代码
复制代码
[root@master 192.168.11.72 ~]$salt 'slave' cmd.run 'ps -ef|grep python'
slave:
    root        905      1  0 07:31 ?        00:00:02 /usr/bin/python -Es /usr/sbin/tuned -l -P
    root       3843      1  0 11:05 ?        00:00:00 /usr/bin/python /usr/bin/salt-minion
    root       3846   3843  0 11:05 ?        00:00:01 /usr/bin/python /usr/bin/salt-minion
    root       4031      1  0 11:31 ?        00:00:00 /usr/bin/python /usr/bin/salt-minion
    root       4032   4031  0 11:31 ?        00:00:00 /bin/sh -c ps -ef|grep python
    root       4034   4032  0 11:31 ?        00:00:00 grep python
复制代码
复制代码

 

 

远程安装nginx

复制代码
复制代码
#在minion上安装nginx
[root@master 192.168.11.72 ~]$salt 'slave' pkg.install "nginx"
#卸载minion上的nginx
[root@master 192.168.11.72 ~]$salt 'slave' pkg.remove "nginx"
#检查pkg包的版本
[root@master 192.168.11.72 ~]$salt 'slave' pkg.version "nginx"
复制代码
复制代码

远程管理服务模块

管理服务是系统管理员的重要任务,通过salt管理minion服务会很简单,使用service模块

复制代码
复制代码
[root@master 192.168.11.72 ~]$salt 'slave' service.start "nginx"
slave:
    True
[root@master 192.168.11.72 ~]$salt 'slave' service.status "nginx"
slave:
    True
[root@master 192.168.11.72 ~]$salt 'slave' service.stop "nginx"
slave:
    True
复制代码
复制代码

与标准的Linux命令一样,salt的命令一样用法

–out控制salt命令结果输出的格式

JSON

复制代码
复制代码
[root@master 192.168.199.155 ~]$salt --out=json '*' cmd.run_all 'hostname'
{
    "slave": {
        "pid": 2268,
        "retcode": 0,
        "stderr": "",
        "stdout": "slave"
    }
}
复制代码
复制代码

YAML

复制代码
复制代码
[root@master 192.168.199.155 ~]$salt --out=yaml '*' cmd.run_all 'hostname'
slave:
  pid: 2289
  retcode: 0
  stderr: ''
  stdout: slave
复制代码
复制代码

YAML讲解

复制代码
复制代码
在学习saltstack过程中,第一要点就是States编写技巧,简称SLS文件。这个文件遵循YAML语法。初学者看这玩意很容易懵逼,来,超哥拯救你学习YAML语法
json xml yaml 数据序列化格式
yaml容易被解析,应用于配置文件

salt的配置文件是yaml配置文件,不能用tab
saltstack,k8s,ansible都用的yaml格式配置文件


语法规则
    大小写敏感
    使用缩进表示层级关系   
    缩进时禁止tab键,只能空格
    缩进的空格数不重要,相同层级的元素左侧对其即可
    # 表示注释行
yaml支持的数据结构
    对象: 键值对,也称作映射 mapping 哈希hashes 字典 dict    冒号表示 key: value   key冒号后必须有
    数组: 一组按次序排列的值,又称为序列sequence 列表list     短横线  - list1
    纯量: 单个不可再分的值

对象:键值对
yaml
    first_key:
      second_key:second_value

python
    {
        'first_key':{
            'second_key':'second_value',
        }
    }
复制代码
复制代码

 

YAML是YAML Ain't Markup Language的首字母缩写,YAML的语法简单,
结构体通过空格展示
项目使用 '-' 代表
键值对通过 ':' 分割
YAML语法遵循固定的缩进风格,表示数据层级结构关系,saltstack需要每个缩进级别由2个空格组成,禁止用tabs!!!
复制代码
复制代码
Python中的字典是简单的键值对,go语言中称作哈希表map
字典的key通过冒号分割

key在YAML中表现形式是一个冒号结果的字符串
my_key: my_value
转化到python语法中,上述命令为
{'my_key':'my_value'}

value还可以通过缩进和key关联,四个空格!!
my_key:
    my_value 
转化为python语法同样的
{'my_key':'my_value'}

YAML语法中字典是可以嵌套的
one_dict_key:
    two_dict_key:value_dict
转化为python语法

{
‘one_dict_key’:{
‘two_dict_key’:’value_dict’
}
}

复制代码
复制代码
复制代码
复制代码
短横杠
YAML语法表示列表,使用一个横杠加一个空格
多个项使用同样的缩进级别作为同一个列表的部分
- list_value_one
- list_value_two
- list_value_three
列表可以作为一个键值对的value,例如一次性要安装多个软件
my_dict:
  - l1
  - l2
  - l3
转化为python代码理解就是

{
‘my_dict’:[‘l1′,’l2’,;l3]
}

复制代码
复制代码

 目标定位字符串

之前的salt命令我们都是使用 salt ‘*’控制所有minion,并且我们只有一个“slave”,但是生产环境的服务器很可能是成千上百的minion,因此需要灵活地定位所需的服务器并且执行远程命令。

 

1.全局匹配
[root@master 192.168.11.72 ~]$salt '*' test.ping
slave:
    True
复制代码
复制代码
Linux通配符
*               代表任意字符,或空字符串
?               代表一个字符,不可以为空
[a-z] [0-9]     代表任何一个小写字母

[root@master 192.168.11.72 ~]$salt 'slav?' test.ping
slave:
    True

[root@master 192.168.11.72 ~]$salt '[a-z]lave' test.ping
slave:
    True            
salt海支持python的re正则表达式
复制代码
复制代码

state模块定义主机状态

之前执行的远程命令,都是一个过程式的,类似一段shell或者python脚本执行,执行一次触发一次相同的功能。

那么大量的minion上运行远程命令就必须使用salt提供的“状态管理”了,状态是对minion的一种描述和定义,运维不需要关心部署是如何完成的,只需要描述minion需要达到什么状态。

接下来通过state模块部署nginx

master端

复制代码
复制代码
vim /etc/salt/master 
#打开注释,写入以下,必须严格遵循语法,空格
file_roots:
  base:
    - /srv/salt/base
 dev:
   - /srv/salt/dev
 test:
   - /srv/salt/test
 prod:
   - / srv/salt/prod

#此步骤在master和minion都需要执行,都需要文件夹,和nginx.sls文件
[root@master  ~]$mkdir -p /srv/salt/{base,dev,test,prod}

[root@slave   ~]$mkdir -p /srv/salt/{base,dev,test,prod}

复制代码
复制代码
复制代码
复制代码
#这个nginx.sls状态文件,在master和minion上都得有
[root@master /srv/salt/base]$cat nginx.sls
nginx-install:
  pkg.installed:
    - name: nginx

nginx-service:
  service.running:
    - name: nginx
    - enable: True
复制代码
复制代码
解释下nginx.sls描述文件
sls配置文件都遵循YAML语言描述
第一条命令使用了pkg.install安装命令,相对于运行了yum install,而此时state模块会判断nginx是否安装了,如果没有安装就进行安装,安装了就什么都不做。
状态描述都会遵循这个原则,只有检测到真实状态和所需状态不一就会执行此功能,这种性质叫做幂等性。

此时用state模块部署nginx软件,通过我们编写的nginx.sls描述性配置文件,命令行调用state模块的sls函数。

#启动命令,此时slave已经安装且存活了nginx,进行状态管理
[root@master  /srv/salt/base]$salt 'slave' state.sls nginx

可以去slave测试关闭nginx,删除nginx,重新执行命令,一样可以安装启动nginx

通过master检查slave的nginx状态

复制代码
复制代码
[root@master 192.168.199.155 /srv/salt/base]$salt 'slave' cmd.run 'ps -ef|grep nginx'
slave:
    root       8543      1  0 Sep14 ?        00:00:00 nginx: master process /usr/sbin/nginx
    nginx      8544   8543  0 Sep14 ?        00:00:00 nginx: worker process
    root       8592   8591  0 00:03 ?        00:00:00 /bin/sh -c ps -ef|grep nginx
    root       8594   8592  0 00:03 ?        00:00:00 /bin/sh -c ps -ef|grep nginx
复制代码
复制代码

Salt采集静态信息之Grains

如果你入职了,你的老板让你收集公司300台服务器的相关硬件信息,你是一台台登录呢?还是选择用salt收集呢?又或者用python的salt-api写脚本呢

复制代码
复制代码
Grains 是saltstack组件中非常重要之一,在配置部署时候回经常使用,Grains记录minion的静态信息,比如常用属性,CPU、内存、磁盘、网络信息等。
Minions的Grains信息是Minion启动时采集汇报给Master的
Grains是以 key  value形式存储的数据库,可以看做Host的元数据(metadata)
Grains保存着收集到的客户端的详细信息
如果slave机器数据变化,grains就过期了
在生产环境中需要自定义Grains,可以通过
Minion配置文件
Grains相关模块定义
Python脚本定义

salt 'slave' sys.doc grains#查看grains的命令用法
复制代码
复制代码

Grains

复制代码
复制代码
Grains人为是描述minion本身固有的静态属性数据,列出主机所有Grains数据

[root@master 192.168.11.72 ~]$salt ‘slave’ grains.items
slave:
———-
SSDs:
biosreleasedate:
05/19/2017
biosversion:
6.00

信息过长,已经省略

salt ‘slave’ grains.ls  #列出所有grains方法

复制代码
复制代码

检索某些数据

复制代码
复制代码
[root@master 192.168.11.72 ~]$salt 'slave' grains.item os id host
slave:
    ----------
    host:
        slave
    id:
        slave
    os:
        CentOS
复制代码
复制代码

利用Grains静态信息定位主机

超哥以前公司有100+的redhat操作系统,80+的centos,在不知道salt之前很是懵逼。。

除了系统的不同,还有不同的系统版本,redhat6.x centos6.x..

复制代码
复制代码
两种写法:
salt '*' grains.item key1 key2 key3
salt '*' -G

#定位Cenots的机器
[root@master 192.168.11.72 ~]$salt -G 'os:CentOS' test.ping
slave:
    True
#定位操作系统系统是7系列的机器

[root@master 192.168.11.72 ~]$salt -G ‘osrelease:7*’ test.ping
slave:
True

#找出ip地址

salt ‘*’ grains.item fqdn_ip4

复制代码
复制代码

因此用grains.items列出所有的数据匹配主机,以及根据单一信息定位数据,Grains还可以自定义来满足不同的需求。

自定义设置Grains数据

复制代码
复制代码
#设置数据
[root@master 192.168.11.72 ~]$salt 'slave' grains.setval cpu_num 8
slave:
    ----------
    cpu_num:
        8
#查询数据
[root@master 192.168.11.72 ~]$salt 'slave' grains.item cpu_num
slave:
    ----------
    cpu_num:
        8
复制代码
复制代码

在master端设置Grains静态数据,原理会将此数据添加到minion服务器的配置文件的/etc/salt/grains

[root@slave 192.168.11.71 ~]$cat /etc/salt/grains
cpu_num: 8

对于复杂的数据结构,可以添加灵活的JSON语法

复制代码
复制代码
[root@master 192.168.11.72 ~]$salt 'slave' grains.setval cpu_info '["Intel","Xeon","10"]'
slave:
    ----------
    cpu_info:
        - Intel
        - Xeon
        - 10
[root@master 192.168.11.72 ~]$salt 'slave' grains.item cpu_info
slave:
    ----------
    cpu_info:
        - Intel
        - Xeon
        - 10
复制代码
复制代码

此时可以检查minion服务器上的grains文件

复制代码
复制代码
[root@slave 192.168.11.71 ~]$cat /etc/salt/grains
cpu_info:
- Intel
- Xeon
- '10'
cpu_num: 8
复制代码
复制代码

因此Grains数据写入配置文件后,重启salt-minion服务,数据也不会丢失

想要删除可以通过grains.delval命令删除,或者去minion的配置文件删除配置一样完成操作(或者删除文件)

复制代码
复制代码
1.方法一,清空值
[root@master 192.168.11.72 ~]$salt 'slave' grains.delval cpu_info
slave:
    None
[root@master 192.168.11.72 ~]$salt 'slave' grains.delval cpu_num
slave:
    None

2.方法二 删除minion的grains配置文件,重启服务

[root@slave 192.168.11.71 ~]$rm -rf /etc/salt/grains
[root@slave 192.168.11.71 ~]$!sys
systemctl restart salt-minion

检查结果删除成功
复制代码
复制代码

 数据管理中心之Pillar组件

Pillar也是saltstack组件中非常重要的组件之一,称作数据管理中心,经常配合states在大规模的配置管理中使用。

Pillar是动态的,存储在master端,提供和给minion端

Pillar在SaltStack中主要的作用是存储和定义配置管理中需要的一些数据,比如软件版本号,用户账号密码等,保证敏感数据不被其他minion看到

存储格式与Grains类似,都是YAML格式

在master配置文件中有一段Pillar settings选项专门定义Pillar的参数

 

cat /etc/salt/master  
#此配置代表pillar的工作根目录,在/srv/pillar下,然后可以新建sls文件
#pillar_roots:
#  base:
#    - /srv/pillar

默认pillar的工作目录在/srv/pillar目录下,执行如下代码

复制代码
复制代码
mkdir -p /srv/pillar
#指定环境,标记,引用packages.sls和services.sls
vim /srv/pillar/top.sls
base:
  '*':
      - packages
      - services
vim /srv/pillar/packages.sls
nginx:
    packages-name: nginx
    version: 1.12.2

vim /srv/pillar/packages.sls
nginx:
    port: 80
    user: root

复制代码
复制代码

检查我们设置的pillar值

复制代码
复制代码
[root@master 192.168.199.155 /srv/pillar]$salt '*' pillar.item nginx
slave:
    ----------
    nginx:
        ----------
        packages-name:
            nginx
        port:
            80
        user:
            root
        version:
            1.12.2
复制代码
复制代码

Pillar与Grains对比

pillar与Grains对比

类型     数据采集方式   应用场景                   定义位置
Grains   静态         minion启动时收集  数据查询  目标选择  配置管理   minion
Pillar   动态         master进行自定义  目标选择  配置管理  敏感数据   master

Python API调用SaltStack

SaltStack本身提供salt(usr/bin/salt)来交互管理,但是去服务器上敲命令肯定不是一个长远之计,这时候python就体现了nb的功能。

Python API就是给Python提供的API使用,需要在SaltStack master上运行

实例代码

复制代码
复制代码
[root@master  ~]$python
Python 2.7.5 (default, Jul 13 2018, 13:06:57)
[GCC 4.8.5 20150623 (Red Hat 4.8.5-28)] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import salt.client
>>> local = salt.client.LocalClient()  #<salt.client.LocalClient object at 0x7f886dbdd850>
>>> local.cmd('*','cmd.run',['hostname'])#向所有minion发送命令
{'slave': 'slave'}
复制代码
复制代码

因此python API就是提供了向saltstack发送命令的入口。

通过API获取saltstack的配置文件

获取master配置文件

>>> import salt.config #导入salt配置模块
>>> m_opts=salt.config.client_config('/etc/salt/master') #读取salt配置文件,得到一个字典数据

获取minion配置文件

复制代码
复制代码
Python 2.7.5 (default, Jul 13 2018, 13:06:57)
[GCC 4.8.5 20150623 (Red Hat 4.8.5-28)] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import salt.client
>>> salt.config.minion_config('/etc/salt/minion') #读取minion配置文件,得到字典数据,通过字典方法可以查看信息
复制代码
复制代码

Python API介绍

复制代码
复制代码
/usr/bin/salt默认使用的接口是LocalClient,该接口只能在salt master上使用
[root@master  ~]$python
Python 2.7.5 (default, Jul 13 2018, 13:06:57)
[GCC 4.8.5 20150623 (Red Hat 4.8.5-28)] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import salt.client
>>> local = salt.client.LocalClient()  #<salt.client.LocalClient object at 0x7f886dbdd850>
>>> local.cmd('*','cmd.run',['hostname'])#向所有minion发送命令
{'slave': 'slave'}
复制代码
复制代码

逐条返回结果,local.cmd_iter()

复制代码
复制代码
>>> ret=local.cmd_iter('*','test.ping')
>>> ret
<generator object cmd_iter at 0x7f886d455c80>
>>> for i in ret:
...     print i
...
{'slave': {'retcode': 0, 'ret': True}}
复制代码
复制代码

菲波那切数列

>>> local.cmd('*','test.fib',[10])
{'slave': [[0, 1, 1, 2, 3, 5, 8], 2.1457672119140625e-06]}

检查minion服务器信息

>>> local.cmd('*','cmd.run',['hostname'])
{'slave': 'slave'}
>>> local.cmd('*','cmd.run',['ifconfig'])
>>> local.cmd('*','cmd.run',['crontab -l'])
>>> local.cmd('*','cmd.run',['df -h'])

启停minion的服务,如nginx

复制代码
复制代码
>>> local.cmd('*','service.stop',['nginx'])
{'slave': True}
>>> local.cmd('*','service.status',['nginx'])
{'slave': False}
>>> local.cmd('*','service.start',['nginx'])
{'slave': True}
复制代码
复制代码