saltstack
Saltstack概述
Salt一种全新的基础设施管理方式,部署轻松,在几分钟内可运行起来,扩展性好,很容易管理上万台服务器,速度够快,服务器之间秒级通讯。
salt底层采用动态的连接总线, 使其可以用于编配, 远程执行, 配置管理等等.
参考中文文档:http://docs.saltstack.cn/zh_CN/latest/topics/tutorials/starting_states.html
参考英文文档:https://docs.saltstack.com/en/latest/
Saltstack运行模式:
- Local
- Master/Minion
- Salt SSH
Saltstack三大功能:
- 远程执行(执行远程命令)
- 配置管理(状态管理)
- 云管理
Saltstack部署环境准备:
1、主机名要固定统一
[root@linux-node1 ~]# cat /etc/hosts 127.0.0.1 localhost localhost.localdomain localhost4 localhost4.localdomain4 ::1 localhost localhost.localdomain localhost6 localhost6.localdomain6 10.0.0.7 linux-node1.example.com linux-node1 10.0.0.8 linux-node2.example.com linux-node2 [root@linux-node1 ~]# cat /etc/sysconfig/network NETWORKING=yes HOSTNAME=linux-node1.example.com
而且能够ping通
要想实现自动化运维,首先要满足PPT原则(流程、人员、工具技术)
Saltstack准备环境
两台Centos6.6,10.0.0.7做master,10.0.0.8做minion
1、安装epel和salt组件
# 安装epel源 [root@linux-node1 ~]# rpm -ivh http://mirrors.aliyun.com/epel/epel-release-latest-6.noarch.rpm # 服务端安装master [root@linux-node1 ~]# yum -y install salt-master # 为了做实验,在服务端也安装下客户端 [root@linux-node1 ~]# yum -y install salt-minion # 客户端安装minion [root@linux-node2 ~]# yum -y install salt-minion # 设置开机启动 [root@linux-node1 ~]# chkconfig salt-master on [root@linux-node1 ~]# chkconfig salt-minion on
设置完成后,可以先讲master启动。然后修改配置文件,需要告诉minion端master是谁。
2、启动master服务
[root@linux-node1 ~]# /etc/init.d/salt-master start Starting salt-master daemon: [确定]
3、修改两台客户端的配置文件
[root@linux-node1 ~]# egrep "master: 10.0.0.7|#id" /etc/salt/minion master: 10.0.0.7 #id:
master:master的IP地址
id:默认通过python的方法socket.getfqdn()去获取fqdn名。所以要求设置好主机名并能解析。也可以使用IP地址,看业务需求。
4、启动minion客户端。
[root@linux-node1 ~]# /etc/init.d/salt-minion start Starting salt-minion daemon: [确定] [root@linux-node2 ~]# /etc/init.d/salt-minion start Starting salt-minion daemon: [确定]
5、minion端的认证
# minion启动的时候会创建KEY [root@linux-node1 /]# ll /etc/salt/pki/minion/ 总用量 8 -r-------- 1 root root 1679 12月 28 23:04 minion.pem -rw-r--r-- 1 root root 451 12月 28 23:04 minion.pub # master启动的时候会创建KEY [root@linux-node1 /]# ll /etc/salt/pki/master/ 总用量 28 -r-------- 1 root root 1679 12月 28 22:54 master.pem -rw-r--r-- 1 root root 451 12月 28 22:54 master.pub # 等待同意的Key [root@linux-node1 /]# ll /etc/salt/pki/master/minions_pre/ 总用量 8 -rw-r--r-- 1 root root 451 12月 28 23:04 linux-node1.example.com -rw-r--r-- 1 root root 451 12月 28 23:03 linux-node2.example.com # 查看需要同意的Key [root@linux-node1 /]# salt-key Accepted Keys: Denied Keys: Unaccepted Keys: linux-node1.example.com linux-node2.example.com Rejected Keys: # 执行同意操作 -A 全部同意 [root@linux-node1 /]# salt-key -A The following keys are going to be accepted: Unaccepted Keys: linux-node1.example.com linux-node2.example.com Proceed? [n/Y] y Key for minion linux-node1.example.com accepted. Key for minion linux-node2.example.com accepted. # -a 匹配的同意,可以使用*通配符 [root@linux-node1 /]# salt-key -a linux*
# 通过认证的主机位置会发生改变,原本在minion_pre下面
[root@linux-node1 /]# tree /etc/salt/pki/master/
/etc/salt/pki/master/
├── master.pem
├── master.pub
├── minions
│ ├── linux-node1.example.com
│ └── linux-node2.example.com
├── minions_autosign
├── minions_denied
├── minions_pre
└── minions_rejected
其实上面的master下面的minion中的两个主机名命名的文件是minion端的公钥(你要是不信自己打开see),同时在master认证通过的时候,master也偷偷的把他的公钥放到了minion端一份。用事实说话,在minion端上查看。
[root@linux-node2 ~]# ll /etc/salt/pki/minion/ 总用量 12 -rw-r--r-- 1 root root 451 12月 28 23:11 minion_master.pub -r-------- 1 root root 1675 12月 28 23:03 minion.pem -rw-r--r-- 1 root root 451 12月 28 23:03 minion.pub
6:salt-key命令
[root@linux-node1 /]# salt-key --help Actions: -l ARG, --list=ARG List the public keys. The args "pre", "un", and "unaccepted" will list unaccepted/unsigned keys. "acc" or "accepted" will list accepted/signed keys. "rej" or "rejected" will list rejected keys. "den" or "denied" will list denied keys. Finally, "all" will list all keys. -L, --list-all List all public keys. (Deprecated: use "--list all") -a ACCEPT, --accept=ACCEPT Accept the specified public key (use --include-all to match rejected keys in addition to pending keys). Globs are supported. -A, --accept-all Accept all pending keys -r REJECT, --reject=REJECT Reject the specified public key (use --include-all to match accepted keys in addition to pending keys). Globs are supported. -R, --reject-all Reject all pending keys --include-all Include non-pending keys when accepting/rejecting -p PRINT, --print=PRINT Print the specified public key -P, --print-all Print all public keys -d DELETE, --delete=DELETE Delete the specified key. Globs are supported. -D, --delete-all Delete all keys
Saltstack远程执行
salt命令 ‘client’ 模块.方法 ‘参数’
[root@linux-node1 /]# salt '*' test.ping linux-node1.example.com: True linux-node2.example.com: True [root@linux-node1 /]# salt '*' cmd.run 'w' linux-node2.example.com: 23:32:17 up 51 min, 1 user, load average: 0.00, 0.00, 0.00 USER TTY FROM LOGIN@ IDLE JCPU PCPU WHAT root pts/0 10.0.0.1 22:41 7:39 0.06s 0.06s -bash linux-node1.example.com: 23:32:17 up 53 min, 2 users, load average: 0.00, 0.00, 0.00 USER TTY FROM LOGIN@ IDLE JCPU PCPU WHAT root pts/0 10.0.0.1 22:40 0.00s 0.85s 0.67s /usr/bin/python root pts/1 10.0.0.1 22:56 35:04 0.00s 0.00s -bash
Saltstack配置管理
1、修改master的配置文件
# 开启base环境 [root@linux-node1 /]# vim /etc/salt/master 416:file_roots: 417: base: 418: - /srv/salt # 创建目录 [root@linux-node1 /]# mkdir /srv/salt # 只要改动配置文件就要重启 [root@linux-node1 /]# /etc/init.d/salt-master restart Stopping salt-master daemon: [确定] Starting salt-master daemon: [确定]
2:写一个apache的安装sls
[root@linux-node1 salt]# cd /srv/salt/ [root@linux-node1 salt]# cat /srv/salt/apache.sls apache-install: pkg.installed: - names: - httpd - httpd-devel apache-service: service.running: - name: httpd - enable: True - reload: True # 在所有minion端,执行state模块下的sls方法,运行apache这个状态 [root@linux-node1 salt]# salt '*' state.sls apache
# 检查是否安装成功
[root@linux-node1 salt]# lsof -i:80
apache-install: #ID声明,声明是干什么用的
pkg.installed: #PKG是一个软件包状态模块,installed是其中的方法
- names: #表明要装的包的名字,因为是装多个包
- httpd
- httpd-devel
[root@linux-node1 master]# salt '*' state.sls apache
#使用salt对所有的机器使用state这个模块下的sls方法来执行apache这个状态模块
#如果使用的分目录的方式,执行的方法是:salt '*' state.sls init.apache
3、使用高级状态
要有一个入口文件默认是top.sls,不建议修改,且必须放在base环境目录下。
# top文件,入口文件 [root@linux-node1 salt]# cat /srv/salt/top.sls base: '*.example.com': - apache # 使用高级状态执行 [root@linux-node1 salt]# salt '*' state.highstate
Saltstack数据系统
Grains and Pillar
Grains里面收集了minion启动时候的所有系统信息,存储在minion端。静态数据,只有重启的时候才重新收集。
在minion设置
应用场景:
1、信息查询
# 查看grains的key [root@linux-node1 salt]# salt 'linux-node1*' grains.ls # 查看grains的所有信息 [root@linux-node1 salt]# salt 'linux-node1*' grains.items # 查询某个的信息 [root@linux-node1 salt]# salt 'linux-node1*' grains.get fqdn linux-node1.example.com: linux-node1.example.com [root@linux-node1 salt]# salt 'linux-node1*' grains.get os linux-node1.example.com: CentOS
2、主机匹配
# 使用granis来匹配主机 -G 参数, [root@linux-node1 salt]# salt -G os:CentOS cmd.run 'uptime' linux-node2.example.com: 00:28:03 up 1:46, 1 user, load average: 0.00, 0.00, 0.00 linux-node1.example.com: 00:28:03 up 1:48, 2 users, load average: 0.00, 0.00, 0.00 # 编辑minion配置文件,自定义设置角色,我添加一个cgt [root@linux-node1 ~]# vim /etc/salt/minion 82 grains: 83 roles: 84 - webserver 85 - memcache 86 - cgt # 修改配置文件需要重启服务 [root@linux-node1 ~]# /etc/init.d/salt-minion restart Stopping salt-minion daemon: [确定] Starting salt-minion daemon: [确定] # 对角色有cgt的机器进行操作 [root@linux-node1 salt]# salt -G roles:cgt cmd.run 'uptime' linux-node1.example.com: 00:32:41 up 1:53, 2 users, load average: 0.06, 0.02, 0.00
如果你觉得写在配置文件中不方便,可以写在他的一个默认文件中
[root@linux-node1 ~]# vim /etc/salt/grains web:nginx
3、在top.sls中匹配使用
[root@linux-node1 salt]# cat /srv/salt/top.sls base: 'os:CentOS': - match: grain - apache [root@linux-node1 salt]# salt '*' state.highstate
Pillar:给minion指定它想要的数据。
在master端设置的
1、修改配置文件
# 在服务端开启pillar [root@linux-node1 ~]# vim /etc/salt/master 529 pillar_roots: 530 base: 531 - /srv/pillar 552 pillar_opts: False [root@linux-node1 ~]# mkdir /srv/pillar [root@linux-node1 ~]# /etc/init.d/salt-master restart Stopping salt-master daemon: [确定] Starting salt-master daemon: [确定]
2、编写pillar中的文件
# 编写一个apache.sls 这是pillar中的,与前面的salt下的文件没有任何的关系 [root@linux-node1 ~]# cat /srv/pillar/apache.sls {%if grains['os'] == 'CentOS' %} apache: httpd {% elif grains['os'] == 'Debian' %} apache: apache2 {% endif %} # 告诉pillar下面哪些主机可以来使用apache.sls文件,这是所有主机* [root@linux-node1 ~]# cat /srv/pillar/top.sls base: '*': - apache
3、执行pillar
因为都是centos是系统,所以获取的都是httpd
[root@linux-node1 ~]# salt '*' pillar.items linux-node2.example.com: ---------- apache: httpd linux-node1.example.com: ---------- apache: httpd
4、用来定位主机
# 对apache:httpd的minion执行命令 [root@linux-node1 ~]# salt -I 'apache:httpd' test.ping No minions matched the target. No command was sent, no jid was assigned. ERROR: No return received # 刷新pillar,grains是需要重启minion端,pillar是需要刷新 [root@linux-node1 ~]# salt '*' saltutil.refresh_pillar linux-node2.example.com: True linux-node1.example.com: True [root@linux-node1 ~]# salt -I 'apache:httpd' test.ping linux-node2.example.com: True linux-node1.example.com: True
Grains和Pillar的区别
远程执行
- 目标(Targeting)
- 模块(Module)
- 返回(Returnners)
Targeting目标
1、Globbing and regex
匹配minions 通过通配符和正则表达式,与minion ID有关系。
2、Grains
用来匹配minion的grains,是指那些关于minion主机的静态信息,比如OS,软件版本,虚拟化,CPU,内存等等。
3、Pillar
通过用户定义的变量匹配minion主机
4、Subnet/IP Address
通过子网或IP地址匹配minion主机(当前仅支持IPV4)。
5、Compound matching
把上面的全部匹配器组合为一个表达式。
6、Node groups
在master配置文件中静态定义minion组,使用:ref:复合 <targeting-compound> 匹配语法。
7、Batching execution
一些命令集在匹配上的minions时只需要执行一次。
Modules模块
Salt 模块是远程执行的基础。它提供了一系列的功能,比如安装包,重启一个服务,运行名称命令,传输文件等等。
用户权限的限制
# 设置用户名:larry,和可以执行的命令 [root@linux-node1 ~]# vim /etc/salt/master 245 client_acl: 246 larry: 247 - test.ping 248 - network.* # 更改权限 [root@linux-node1 sudoers.d]# chmod 755 /var/cache/salt /var/cache/salt/master /var/cache/salt/master/jobs /var/run/salt /var/run/salt/master # 重启服务 [root@linux-node1 sudoers.d]# /etc/init.d/salt-master restart # 切换到larry用户执行 [larry@linux-node1 ~]$ salt '*' test.ping linux-node2.example.com: True linux-node1.example.com: True [larry@linux-node1 ~]$ salt '*' cmd.run 'uptime' Failed to authenticate!
Returners
Salt返回接收器(returner)允许把minion的响应保存在各种数据存储或不同的位置,甚至把响应内容显示在命令行。Returner可以用来扩展Salt,和新的、定制的接口和支持新的数据库进行通信。
以mysql的返回为例
# 安装数据库 [root@linux-node1 ~]# yum -y install mysql-server # 安装依赖包 [root@linux-node1 ~]# yum -y install python-mysqldb # 启动数据库 [root@linux-node1 ~]# /etc/init.d/mysqld start
# 客户端安装MySQL-python
[root@linux-node1 ~]# yum -y install MySQL-python
创建相应的表
CREATE DATABASE `salt` DEFAULT CHARACTER SET utf8 DEFAULT COLLATE utf8_general_ci; USE `salt`; DROP TABLE IF EXISTS `jids`; CREATE TABLE `jids` ( `jid` varchar(255) NOT NULL, `load` mediumtext NOT NULL, UNIQUE KEY `jid` (`jid`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; DROP TABLE IF EXISTS `salt_returns`; CREATE TABLE `salt_returns` ( `fun` varchar(50) NOT NULL, `jid` varchar(255) NOT NULL, `return` mediumtext NOT NULL, `id` varchar(255) NOT NULL, `success` varchar(10) NOT NULL, `full_ret` mediumtext NOT NULL, `alter_time` TIMESTAMP DEFAULT CURRENT_TIMESTAMP, KEY `id` (`id`), KEY `jid` (`jid`), KEY `fun` (`fun`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; DROP TABLE IF EXISTS `salt_events`; CREATE TABLE `salt_events` ( `id` BIGINT NOT NULL AUTO_INCREMENT, `tag` varchar(255) NOT NULL, `data` varchar(1024) NOT NULL, `alter_time` TIMESTAMP DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (`id`), KEY `tag` (`tag`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
grant all on salt.* to salt@'10.0.0.0/255.255.255.0' identified by 'salt';
修改配置文件
此种方式是主动去Minion端获取,推荐使用。
如果不加job_cache,开启上面的return,就是被动接收。需要客户端也要修改配置文件,添加同样的内容。
[root@linux-node1 ~]# vim /etc/salt/master #return: mysql master_job_cache: mysql mysql.host: '10.0.0.7' mysql.user: 'salt' mysql.pass: 'salt' mysql.db: 'salt' mysql.port: 3306
检查是否生效
[root@linux-node1 ~]# /etc/init.d/salt-master restart [root@linux-node1 ~]# salt '*' saltutil.refresh_pillar linux-node1.example.com: True linux-node2.example.com: True [root@linux-node1 ~]# salt '*' test.ping linux-node2.example.com: True linux-node1.example.com: True # 数据库中检查有么有获取到数据(主动去minion端获取) mysql> use salt; mysql> select * from salt_returns;
配置管理
配置管理是通过远程管理来实现的。
环境配置
# 开启分别的file_roots [root@linux-node1 ~]# vim /etc/salt/master file_roots: base: - /srv/salt/base test: - /srv/salt/test prod: - /srv/salt/prod # 重新启动master [root@linux-node1 ~]# /etc/init.d/salt-master restart Stopping salt-master daemon: [确定] Starting salt-master daemon: [确定] # 创建路径 [root@linux-node1 ~]# mkdir /srv/salt/base [root@linux-node1 ~]# mkdir /srv/salt/test [root@linux-node1 ~]# mkdir /srv/salt/prod [root@linux-node1 salt]# ll /srv/salt/base/ 总用量 8 -rw-r--r-- 1 root root 171 12月 28 23:56 apache.sls -rw-r--r-- 1 root root 53 12月 29 00:49 top.sls [root@linux-node1 salt]# tree . ├── base │ ├── apache.sls │ └── top.sls ├── prod └── test
[root@linux-node1 ~]# mkdir /srv/salt/base/files
编写配置文件
[root@linux-node1 base]# vim dns.sls /etc/resolv.conf: file.managed: - source: salt://files/resolv.conf - user: root - group: root - mode: 644 [root@linux-node1 base]# cp /etc/resolv.conf /srv/salt/base/files/ [root@linux-node1 base]# cd /srv/salt/base/files/ # 做点修改,最下面加点# [root@linux-node1 files]# vim resolv.conf # Generated by NetworkManager nameserver 10.0.0.2 #########
执行状态
# 执行方式一 # 执行状态(单独执行某个状态) [root@linux-node1 files]# salt '*' state.sls dns # 到minion端查看 [root@linux-node2 ~]# cat /etc/resolv.conf # Generated by NetworkManager nameserver 10.0.0.2 ######### # 执行方式二 # 如果想使用高级状态执行,需要在top.sls中写明 [root@linux-node1 files]# vim /srv/salt/base/top.sls base: '*': - dns # 执行高级状态,从top.sls中读取,在执行 [root@linux-node1 files]# salt '*' state.highstate
salt语法:YAML
规则一:缩进
两个空格组成
不要使用tab键
规则二:冒号
他的结果是以字典的方式
以冒号结尾和路径不需要加冒号
以冒号结尾
规则三:短横线线
表示是一种列表关系(字典中的列表)
短横线后加空格
jinja模版
jinja模版的创建
# jinja模版 # 有- template: 就代表这个文件就是一个模版文件 # - defaults: 是变量列表 [root@linux-node1 base]# vim dns.sls /etc/resolv.conf: file.managed: - source: salt://files/resolv.conf - user: root - group: root - mode: 644 - template: jinja - defaults: DNS_SERVER: 10.0.0.2
jinja模版的使用
# 模板文件里面变量使用方式{{ DNS_SERVER }} [root@linux-node1 base]# vim /srv/salt/base/files/resolv.conf # Generated by NetworkManager # nameserver 10.0.0.2 nameserver {{ DNS_SERVER }} # 执行高级状态 [root@linux-node1 base]# salt '*' state.highstate # minion端查看,nameserver 自动将变量代换 [root@linux-node2 ~]# cat /etc/resolv.conf # Generated by NetworkManager # nameserver 10.0.0.2 nameserver 10.0.0.2
jinja模版中使用Grains
# 使用grains [root@linux-node1 base]# cat /srv/salt/base/files/resolv.conf # Generated by NetworkManager nameserver 10.0.0.2 # {{ grains['fqdn_ip4'] }} # minion端查看 [root@linux-node2 ~]# cat /etc/resolv.conf # Generated by NetworkManager nameserver 10.0.0.2 # ['10.0.0.8']
还可以在jinja模版中使用执行模块和Pillar
案例
设置DNS执行文件
[root@linux-node1 base]# cd /srv/salt/base/ [root@linux-node1 base]# mkdir -pv init/files # dns设置 [root@linux-node1 base]# cat /srv/salt/base/init/dns.sls /etc/resolv.conf: file.managed: - source: salt://init/files/resolv.conf - user: root - group: root - mode: 644 [root@linux-node1 base]# cp /etc/resolv.conf /srv/salt/base/init/files/
记录历史命令
格式:时间 用户 命令
[root@linux-node1 base]# cat /srv/salt/base/init/history.sls /etc/profile: file.append: - text: - export HISTTIMEFORMAT="%F %T `whoami`" [root@linux-node1 base]# tree /srv/salt/base/ /srv/salt/base/ ├── init │ ├── dns.sls │ ├── files │ │ └── resolv.conf │ └── history.sls └── top.sls
记录操作日志
写到/var/log/message
[root@linux-node1 init]# cat audit.sls /etc/bashrc: file.append: - text: - export PROMPT_COMMAND='{ msg=$(history 1 | { read x y; echo $y; });logger "[euid=$(whoami)]":$(who am i):[`pwd`]"$msg";}'
内核调优
使用salt自带的模块sysctl
[root@linux-node1 init]# cat sysctl.sls vm.swappiness: sysctl.present: - value: 0 net.ipv4.ip_local_port_range: sysctl.present: - value: 10000 65000 fs.file-max: sysctl.present: - value: 100000
#如何找呢?从/proc/sys/里面,然后后面的/用.来代替。
将初始化的sls放在一起
[root@linux-node1 init]# cat env_init.sls include: - init.dns - init.history - init.audit - init.sysctl
修改top.sls文件
base环境下init目录下的env_init.sls
[root@linux-node1 init]# cat /srv/salt/base/top.sls base: '*': - init.env_init
最终呈现结果
[root@linux-node1 base]# tree . ├── init │ ├── audit.sls │ ├── dns.sls │ ├── env_init.sls │ ├── files │ │ └── resolv.conf │ ├── history.sls │ └── sysctl.sls └── top.sls
结果检查
重新打开minion的tty窗口,分别执行history和去message下面查看,检测
状态模块:状态间关系
功能:条件判断,主要用于cmd状态模块
常用方法:
onlyif:检查的命令,近当onlyif选项指向的命令返回true时才执行
name定义的命令
unless:用于检查的命令,仅当unless选项指向的命令返回false时才执行name指向的命令
功能名称:requisites
功能:处理状态间关系
常用方法:
require #我依赖某个状态
require_in #我被某个状态依赖
watch #我关注某个状态
watch_in #我被某个状态关注