Saltstack是一个具备puppet与func功能为一身的集中化管理平台,saltstack基于python实现,功能十分强大,各模块融合度及复用性极高,官方极力推荐作为云计算平台的基础架构。可以轻松维护成千上万台服务器. 相对于同类型的其他平台, 例如Ruby下的Chef, 以及大家比较熟知的puppet, Salt的优势在于他的配置更加简单, 运行效率更高, 自带的模块更加丰富, 以及API是全python语法对于我们搞运维的同学来说相对比较易读, 所以笔者认为是一个大家值得去学习的自动化部署平台.
本文将帮助大家了解如何快速部署一个Salt平台.
大家如果想了解更多地相关知识, 可以去访问salt的官方文档 (中文版需VPN)
https://docs.saltstack.com/en/latest/topics/index.html
http://docs.saltstack.cn/zh_CN/latest/
SaltStack implementation
安装环境:
System: Centos 6.3
Salt master: salt-master.example.com
Salt minion: salt-client01.example.com
一. 环境部署及安装
1. 关闭iptables和SELINUX
# service iptables stop
# setenforce 0
# vi /etc/sysconfig/selinux
... SELINUX=disabled ...
2. 安装第三方yum源
# rpm -Uvh http://ftp.linux.ncsu.edu/pub/epel/6/i386/epel-release-6-8.noarch.rpm
3. 更新系统证书模块和python到最新版本
# yum upgrade ca-certificates --disablerepo=epel -y
# yum update python -y
4. 在服务器端(Salt master)安装Salt-master
# yum install salt-master -y
5. 在客户端(Salt minion)安装Salt-minion
# yum install salt-minion -y
二. 初始配置
[Salt minion side]
1. 在客户端添加服务端地址从而提交申请
# vi /etc/salt/minion
... # Set the location of the salt master server, if the master server cannot be # resolved, then the minion will fail to start. master: salt-master.example.com ...
# /etc/init.d/salt-minion restart
[Salt master side]
2. 检查客户端申请
# salt-key list
Accepted Keys: Denied Keys: Unaccepted Keys: salt-client01.example.com Rejected Keys:
3. 获准申请
# salt-key -a salt-client01.example.com
The following keys are going to be accepted: Unaccepted Keys: salt-client01.example.com Proceed? [n/Y] y Key for minion salt-client01.example.com accepted.
这里服务端与客户端的连接配置基本完成.
三. 模块介绍
这里我们可以通过此命令列出Salt常用的模块, 接下来我将介绍一些常用模块的使用方法
# salt '*' sys.list_modules
salt-client01.example.com: - acl - aliases - alternatives - archive - artifactory - at - blockdev - bridge - btrfs - buildout - cloud - cmd …
1. cmd module
1). 执行远程客户端CLI
# salt '*' cmd.run 'hostname'
salt-client01.example.com: salt-client01.example.com
2). 将脚本推送到客户端(目录位置: /var/cache/salt/minion/files/base/test.sh) 并远程去执行该脚本
# cd /src/salt
# echo 'hostname' > test.sh
# salt '*' cmd.script salt://test.sh
salt-client01.example.com: ---------- pid: 3028 retcode: 0 stderr: stdout: salt-client01.example.com
2. cp module
1). GET_FILE方法
Tip: Salt默认的文件根文件目录为/src/salt, 所以我们可以将我们需要推送的文件放到此目录, 从而可以使用salt自带的协议去传送.
这里cp.get_file方法是将具体master端的文件推送到客户端具体目录
[Salt master side]
# mkdir -p /srv/salt && cd /srv/salt
# echo "test" > test.txt
# salt '*' cp.get_file salt://test.txt /root/test.txt makedirs=True
salt-client01.example.com: /root/test.txt
若传送的文件很大, 而服务器的硬件资源又很充裕, 我们可以通过他的压缩=>传输=>解压的方法提高我们的文件传输速率(这里1到9表示压缩文件的比率)
# salt '*' cp.get_file salt://test.txt /root/test.txt gzip=5
2). GET_DIR方法
这里cp.get_dir 方法是将具体master端的目录及子目录文件推送到客户端
# mkdir -p /srv/salt/test_folder && cd /srv/salt/test_folder
# touch test_file0{1,2,3}
# salt '*' cp.get_dir salt://test_folder /root
salt-client01.example.com: - /root/test_folder/test_file01 - /root/test_folder/test_file02 - /root/test_folder/test_file03
压缩传送
# salt '*' cp.get_dir salt://test_folder /root gzip=5 template=jinja
3). GET_URL方法
下载具体的URL文件到客户端
# salt '*' cp.get_url http://www.showerlee.com ~/index.html
salt-client01.example.com: /root/index.html
3. cron module
1). 查看客户端计划任务列表
# salt '*' cron.raw_cron root
salt-client01.example.com: * * * * 0 /bin/sh ~/test.sh
2). 添加一个计划任务
# salt '*' cron.set_job root '*' '*' '*' '*' 1 /usr/local/weekly
salt-client01.example.com: new
# salt '*' cron.raw_cron root
salt-client01.example.com: * * * * 0 /bin/sh ~/test.sh # Lines below here are managed by Salt, do not edit * * * * 1 /usr/local/weekly
3). 删除一个计划任务
# salt '*' cron.rm_job root /usr/local/weekly salt-client01.example.com: removed
4. dnsutil module
1). 添加一个HOST记录
# salt '*' dnsutil.hosts_append /etc/hosts 127.0.0.1 salt-client01
salt-client01.example.com: The following line was added to /etc/hosts: 127.0.0.1 salt-client01
2). 删除一个HOST记录
# salt '*' dnsutil.hosts_remove /etc/hosts salt-client01
==============================
salt-client01.example.com:
None
==================================
5. file module
1). 获取客户端文件md5值
# salt '*' file.get_sum /etc/passwd md5
==============================
salt-client01.example.com:
17d14d55b712bd36a735b66dd708c177
==================================
2). 检查该文件是否匹配给定的md5值, 匹配则返回Ture
# salt '*' file.check_hash /etc/passwd md5:17d14d55b712bd36a735b66dd708c177
==============================
salt-client01.example.com:
True
==================================
3). 更新客户端文件属主及属组
# salt '*' file.chown ~/test.txt nobody nobody
==============================
salt-client01.example.com:
None
==================================
4). 调用客户端cp命令
# salt '*' file.copy ~/test.txt ~/test1.txt
==============================
salt-client01.example.com:
True
==================================
5). 查看客户端文件是否存在
# salt '*' file.directory_exists /etc
==============================
salt-client01.example.com:
True
==================================
6). 获取客户端文件的详细属性
# salt '*' file.stats /etc/passwd
==============================
salt-client01.example.com:
----------
atime:
1442470687.07
ctime:
1396603826.1
gid:
0
group:
root
inode:
277879
mode:
0644
mtime:
1396603826.1
size:
1560
target:
/etc/passwd
type:
file
uid:
0
user:
root
==================================
7). 获取客户端文件权限
# salt '*' file.get_mode /etc/passwd
==============================
salt-client01.example.com:
0644
==================================
8). 更改客户端文件权限
# salt '*' file.set_mode ~/test.txt 0777
==============================
salt-client01.example.com:
0777
==================================
9). 创建客户端目录
# salt '*' file.mkdir ~/test_dir
==============================
salt-client01.example.com:
None
==================================
10). 替换客户端文件内容字符串.
# salt '*' file.sed /etc/httpd/conf/httpd.conf 'LogLevel warn' 'LogLevel info'
==============================
salt-client01.example.com:
----------
pid:
3666
retcode:
0
stderr:
stdout:
==================================
11). 添加客户端文件字符串
# salt '*' file.append ~/test.conf "maxclient 100"
==============================
salt-client01.example.com:
Wrote 1 lines to "/root/test.conf"
==================================
12). 删除客户端文件
# salt '*' file.remove ~/test1.txt
==============================
salt-client01.example.com:
True
==================================
6. network module
1). 调用dig, ping, traceroute命令并返回结果.
# salt '*' network.dig http://www.showerlee.com
# salt '*' network.ping http://www.showerlee.com ;
# salt '*' network.traceroute http://www.showerlee.com
7. pkg package module
这里本例使用的是CentOS系统, 则这里调用的是yum包管理安装, 若为Ubuntu Salt会调用apt-get.
1). 安装PHP到客户端
# salt '*' pkg.install php
2). 删除客户端PHP
# salt '*' pkg.remove php
3). 更新客户端所有yum包
# salt '*' pkg.upgrade
8. service module
1). 开启或关闭httpd服务系统启动(可以理解调用chkconfig命令)
# salt '*' service.enable httpd
# salt '*' service.disable httpd
2). 调用service命令(reload, restart, start, stop, status)执行相关服务操作
# salt '*' service.reload httpd
# salt '*' service.restart httpd
# salt '*' service.start httpd
# salt '*' service.stop httpd
# salt '*' service.status httpd
9. grains module
1). 返回匹配给定内核版本的主机
# salt -G 'kernelrelease:2.6.32-279.el6.x86_64' cmd.run 'uname -a'
2). 获取所有客户端grain模块相关信息
# salt '*' grains.ls
3). 获取客户端系统名
# salt '*' grains.item os
============================
salt-client01.example.com:
----------
os:
CentOS
================================
4). 获取客户端系统相关信息
# salt '*' grains.items
============================
salt-client01.example.com:
----------
SSDs:
biosreleasedate:
12/01/2006
biosversion:
VirtualBox
cpu_flags:
- fpu
- vme
- de
- pse
- tsc
- msr
- pae
- mce
- cx8
- apic
- mtrr
- pge
- mca
- cmov
- pat
- pse36
- clflush
- mmx
- fxsr
- sse
- sse2
- syscall
- nx
- rdtscp
- lm
- constant_tsc
- up
- rep_good
- pni
- monitor
- ssse3
- lahf_lm
cpu_model:
Intel(R) Core(TM) i7-4750HQ CPU @ 2.00GHz
cpuarch:
x86_64
domain:
example.com
fqdn:
salt-client01.example.com
fqdn_ip4:
- 10.110.16.251
fqdn_ip6:
gpus:
|_
----------
model:
VirtualBox Graphics Adapter
vendor:
unknown
host:
salt-client01
hwaddr_interfaces:
----------
eth0:
08:00:27:cd:54:79
lo:
00:00:00:00:00:00
id:
salt-client01.example.com
init:
upstart
ip4_interfaces:
----------
eth0:
- 10.110.16.251
lo:
- 127.0.0.1
ip6_interfaces:
----------
eth0:
- fe80::a00:27ff:fecd:5479
lo:
- ::1
ip_interfaces:
----------
eth0:
- 10.110.16.251
- fe80::a00:27ff:fecd:5479
lo:
- 127.0.0.1
- ::1
ipv4:
- 10.110.16.251
- 127.0.0.1
ipv6:
- ::1
- fe80::a00:27ff:fecd:5479
kernel:
Linux
kernelrelease:
2.6.32-279.el6.x86_64
locale_info:
----------
defaultencoding:
unknown
defaultlanguage:
unknown
detectedencoding:
ANSI_X3.4-1968
localhost:
salt-client01.example.com
lsb_distrib_codename:
Final
lsb_distrib_id:
CentOS
lsb_distrib_release:
6.3
machine_id:
1307a6546720f165db6c202900000006
manufacturer:
innotek GmbH
master:
salt-master.example.com
mdadm:
mem_total:
996
nodename:
salt-client01.example.com
num_cpus:
1
num_gpus:
1
os:
CentOS
os_family:
RedHat
osarch:
x86_64
oscodename:
Final
osfinger:
CentOS-6
osfullname:
CentOS
osmajorrelease:
6
osrelease:
6.3
osrelease_info:
- 6
- 3
path:
/sbin:/usr/sbin:/bin:/usr/bin
productname:
VirtualBox
ps:
ps -efH
pythonexecutable:
/usr/bin/python2.6
pythonpath:
- /usr/bin
- /usr/lib64/python26.zip
- /usr/lib64/python2.6
- /usr/lib64/python2.6/plat-linux2
- /usr/lib64/python2.6/lib-tk
- /usr/lib64/python2.6/lib-old
- /usr/lib64/python2.6/lib-dynload
- /usr/lib64/python2.6/site-packages
- /usr/lib64/python2.6/site-packages/gtk-2.0
- /usr/lib/python2.6/site-packages
pythonversion:
- 2
- 6
- 6
- final
- 0
saltpath:
/usr/lib/python2.6/site-packages/salt
saltversion:
2015.5.5
saltversioninfo:
- 2015
- 5
- 5
- 0
selinux:
----------
enabled:
False
enforced:
Disabled
serialnumber:
0
server_id:
1640489673
shell:
/bin/bash
virtual:
VirtualBox
zmqversion:
3.2.5
=============================
四. pillar介绍
Pillar是Saltstack最重要的组件之一, 其作用是定义与被控主机端相关的任何配置, 使其可以随时被模板, state, API等调用, 他的规范采用Python字典形式, 简单来说可以理解为他是一个字典形式的参数列表, 大家随后写的部署脚本等都可以从这里调用数据, 而不需要在具体的脚本里将数据写死, 提高脚本的复用性.
1). 获取当前pillar配置信息
# vi /etc/salt/master
======================
替换pillar_opts 参数为True.
==========================
# salt '*' pillar.data
=====================
...
==========================
2). SLS文件定义
pillar定义的配置参数会保存在sls文件中, 格式需符合YAML规范, 我们常规会配置一个top.sls的入口文件, 用来定义pillar数据的覆盖被控主机的有效范围.
a. 首先在master主配置文件中定义pillar主目录
# vi /etc/salt/master
添加:
=====================
pillar_roots:
base:
- /srv/pillar
========================
b. 定义入口文件top.sls
Tip: "*" 代表任意主机, - data代表该同级目录包含一个apache.sls文件
# vi /srv/sillar/top.sls
====================
base:
'*':
- apache
==========================
c. 定义具体的apache参数文件
# vi /srv/sillar/apache.sls
======================
appname: website
flow:
maxconn: 30000
maxmem: 6G
==========================
d. 校验以上定义好的pillar
通过查看"salt-client01.example.com"主机的pillar数据,我们可以看到apache数据项, 原因是我们定义top.sls时使用了"*"涵盖了所有主机
如果返回结果为空我们尝试刷新被控主机数据后查看最终配置结果.
# salt '*' saltutil.refresh_pillar
# salt '*' pillar.data appname flow
=====================
salt-client01.example.com:
----------
appname:
website
flow:
----------
maxconn:
30000
maxem:
6G
==========================
这里返回的是我们定义好的appname和flow参数对应的值.
e.pillar的使用
完成pilar配置后, 我们可以在state, 模板文件中引用配置好的参数字典
例如:
一维字典: {{ pillar['appname'] }}
二维字典: {{ pillar['flow']['maxconn'] }}
我们也可以根据配置项过滤出匹配该参数的主机, 使用任意方法来让其返回相应的系统信息.
这里通过 -I 参数过滤出该主机并查看该主机的连通状态.
# salt -I 'appname:website' test.ping
=====================
salt-client01.example.com:
True
=========================
五. state介绍.
state是saltstack最核心的功能, 它通过预先定制好的sls(salt state file)文件, 类似于chef的cookbook对被控主机进行状态管理, 支持常见的pkg, file, network, service, user模块调用, 更多模块可以参考官方文档: http://docs.saltstack.com/ref/states/all/index.html
1). state定义
state的定义是通过sls文件进行描述的, 支持YAML语法, 定义规则如下
==========================
$ID:
$State:
- $state: state
=============================
$ID 表示具体操作的对象, $State表示具体操作的使用的模块, - $state state表示对具体具体模块方法的调用.
例如:
====================
apache: # state名称
pkg: # 使用pkg状态对象
- installed # 执行installed方法
service: # 使用service管理系统守护进程
- running # 执行查看running方法查看是否服务正常安装,未安装则需安装并运行
- require: # 确保apache只有在安装后, 才会启动.
- pkg: apache
==========================
上述代码检查apache软件包是否安装, 如未安装将通过yum或者api进行安装, 并最终检查apache服务是否处于运行状态.
六. pillar和state的集成配置实现将apache部署到客户端
1). 配置pillar
# vi /srv/pillar/top.sls
==========================
base:
'*':
- apache
==============================
b. 通过检查客户端系统, 判断具体的apache服务名
# mkdir -p /srv/pillar/apache
# vi /srv/pillar/apache/init.sls
=========================
pkgs:
{% if grains['os_family'] == 'Debian' %}
apache: apache2
{% elif grains['os_family'] == 'Redhat' %}
apache: httpd
{% elif grains['os'] == 'CentOS' %}
apache: httpd
{% endif %}
==============================
c. 测试pillar数据返回结果
# salt '*' pillar.data pkgs
=========================
salt-client01.example.com:
----------
pkgs:
----------
apache:
httpd
==============================
结果返回CentOS下apache服务名httpd, 说明配置已生效.
d. 配置 state
# vi /srv/salt/top.sls
=========================
base:
'*':
- apache
=============================
# mkdir /srv/salt/apache
# vi /srv/salt/apache/init.sls
这里可以看到通过python字典来调用pillar已配置参数.
=========================
pkg:
- installed
- name: {{ pillar['pkgs']['apache']}}
service.running:
- name: {{ pillar['pkgs']['apache']}}
- require:
- pkg: {{ pillar['pkgs']['apache']}}
=============================
e. 执行state
这里将执行最终的配置, 远程部署apache客户端.
# salt '*' state.highstate
=========================
salt-client01.example.com:
----------
ID: apache
Function: pkg.installed
Name: httpd
Result: True
Comment: The following packages were installed/updated: httpd
Started: 04:35:34.311058
Duration: 58831.849 ms
Changes:
----------
httpd:
----------
new:
2.2.15-47.el6.centos
old:
----------
ID: apache
Function: service.running
Name: httpd
Result: True
Comment: Started Service httpd
Started: 04:36:33.148020
Duration: 192.294 ms
Changes:
----------
httpd:
True
Summary
------------
Succeeded: 2 (changed=2)
Failed: 0
------------
Total states run: 2
=============================
部署完毕...