实验环境:
物理机执行: iptables -t nat -I POSTROUTING -s 172.25.254.0/24 -j MASQUERADE
让server1和server2可以上网。
server1 :172.25.254.1 master端
server2 : 172.25.254.2 minion端
server3 : 172.25.254.3 minion端
Salt同样引入了更加细致化的领域控制系统来远程执行,使得系统成为目标不止可以通过主机名,还可以通过系统属性。
Salt 和ansible 最大的区别在于salt是具有客户端的,而 ansible 没有,salt 直接获取root权限进行访问,
我们可以去saltstack官网下载,也可以去阿里云中下载:
mirrors.aliyun.com
yum install https://mirrors.aliyun.com/saltstack/yum/redhat/salt-repo-latest-2.el7.noarch.rpm
执行这条命令会生成yum源:
[root@server1 images]# cd /etc/yum.repos.d/
[root@server1 yum.repos.d]# ls
redhat.repo salt-latest.repo westos.repo
# 生成这个仓库
[root@server1 yum.repos.d]# cat salt-latest.repo
[salt-latest]
name=SaltStack Latest Release Channel for RHEL/Centos $releasever
baseurl=https://repo.saltstack.com/yum/redhat/7/$basearch/latest
failovermethod=priority
enabled=1
gpgcheck=1
gpgkey=file:///etc/pki/rpm-gpg/saltstack-signing-key
## 我们把里面的路径改为指向阿里云,这样会更快一些。
[root@server1 yum.repos.d]# sed -i "s/repo.saltstack.com/mirrors.aliyun.com\/saltstack/g" /etc/yum.repos.d/salt-latest.repo
[root@server1 yum.repos.d]# cat salt-latest.repo
baseurl=https://mirrors.aliyun.com/saltstack/yum/redhat/7/$basearch/latest
# 这个
[root@server1 yum.repos.d]# yum repolist
Loaded plugins: langpacks, product-id, search-disabled-repos, subscription-
: manager
This system is not registered to Red Hat Subscription Management. You can use subscription-manager to register.
repo id repo name status
HighAvailability westos.repoHighAvailability 51
salt-latest/x86_64 SaltStack Latest Release Channel for RHEL/Centos 7Serv 83
##可以列出,说明没问题
然后我们在server2中也做同样的yum源的配置
master端设置:(server1)
• # yum install -y salt-master #安装master端
• # systemctl enable salt-master #设置master自启动
• # systemctl start salt-master #启动master服务
[root@server1 ~]# yum install -y lsof # 可以用来查看打开的端口
[root@server1 ~]# lsof -i :4505 # 消息队列
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
salt-mast 3562 root 15u IPv4 33242 0t0 TCP *:4505 (LISTEN)
[root@server1 ~]# lsof -i :4506 # 接收请求
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
salt-mast 3569 root 23u IPv4 33287 0t0 TCP *:4506 (LISTEN)
# 此时server2还没有连接
minion端配置:
• # yum install -y salt-minion #安装minion端
• # vim /etc/salt/minion
master: 172.25.0.1 #设置master主机的ip,注意冒号后有空格
• # systemctl enable salt-minion
• # systemctl start salt-minion
[root@server1 ~]# lsof -i :4505
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
salt-mast 3562 root 15u IPv4 33242 0t0 TCP *:4505 (LISTEN)
## 4505端口没有变
[root@server1 ~]# lsof -i :4506
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
salt-mast 3569 root 23u IPv4 33287 0t0 TCP *:4506 (LISTEN)
salt-mast 3569 root 30u IPv4 37746 0t0 TCP server1:4506->server2:57622 (ESTABLISHED)
## server2 向 server1 发起了一个请求,这时我我们的master端需要通过key去允许,才可以建立连接,
相当于证书的颁发
-A 允许所有,可以看出server2就到了接受的keys 里面去了。
这里我们要注意
[root@server2 salt]# cat minion_id
server2 这个为文件里面记录了主机名,salt会始终会去文件中的名字,当我们更改了主机名时,要及时的去这个文件中更改,或者删除文件,重启minion端
[root@server1 ~]# lsof -i :4505
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
salt-mast 3562 root 15u IPv4 33242 0t0 TCP *:4505 (LISTEN)
salt-mast 3562 root 17u IPv4 38484 0t0 TCP server1:4505->server2:36732 (ESTABLISHED)
## 这是我们的主服务就和server2 建立了长连接了。这样当server1发布新东西时,这时所有minion端就可以接收到
[root@server1 ~]# lsof -i :4506
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
salt-mast 3569 root 23u IPv4 33287 0t0 TCP *:4506 (LISTEN)
查看更详尽的进程信息:
[root@server1 ~]# yum install -y python-setproctitle.x86_64 # 安装这个包
[root@server1 ~]# systemctl restart salt-master.service # 重启salt
[root@server1 ~]# ps ax # 查看
5983 ? Ss 0:00 /usr/bin/python /usr/bin/salt-master ProcessManager
5990 ? S 0:00 /usr/bin/python /usr/bin/salt-master MultiprocessingLoggingQueue
5997 ? Sl 0:00 /usr/bin/python /usr/bin/salt-master ZeroMQPubServerChannel # 消息队列
6000 ? S 0:00 /usr/bin/python /usr/bin/salt-master EventPublisher
6001 ? S 0:00 /usr/bin/python /usr/bin/salt-master Maintenance
6002 ? S 0:00 /usr/bin/python /usr/bin/salt-master ReqServer_ProcessManager # 请求响应
6003 ? Sl 0:00 /usr/bin/python /usr/bin/salt-master MWorkerQueue # 维护队列
6004 ? R 0:00 /usr/bin/python /usr/bin/salt-master MWorker-0
6005 ? R 0:00 /usr/bin/python /usr/bin/salt-master MWorker-1
6006 ? R 0:00 /usr/bin/python /usr/bin/salt-master MWorker-2
6007 ? R 0:00 /usr/bin/python /usr/bin/salt-master MWorker-3
6008 ? Sl 0:00 /usr/bin/python /usr/bin/salt-master FileserverUpdate
6019 ? R 0:00 /usr/bin/python /usr/bin/salt-master MWorker-4
master 端测试与minion端的连接:
这里 * 代表当先目录下的所有文件,所以我们要加上 ‘’ 来让他代表slat里面的所有key(用salt-key -L 可以列出的)。
也可以直接指定key。
这时我们就可以使用远程命令了,而且我们是超户哦:
[root@server1 ~]# salt server2 cmd.run df
server2:
Filesystem 1K-blocks Used Available Use% Mounted on
/dev/mapper/rhel-root 17811456 1249308 16562148 8% /
devtmpfs 495420 0 495420 0% /dev
tmpfs 507512 80 507432 1% /dev/shm
tmpfs 507512 13220 494292 3% /run
tmpfs 507512 0 507512 0% /sys/fs/cgroup
/dev/sda1 1038336 135224 903112 14% /boot
tmpfs 101504 0 101504 0% /run/user/0
[root@server1 ~]# salt server2 cmd.run pwd
server2:
/root
[root@server1 ~]# salt server2 cmd.run 'touch /tmp/file'
server2:
[root@server2 ~]# ls /tmp/file
/tmp/file
Salt命令由三个主要部分构成:
salt '' [arguments]
目标 函数 内容
Targect:
target: 指定哪些minion, 默认的规则是使用glob匹配minion id.
[root@server1 ~]# salt server? test.ping # 使用通配符
server2:
True
[root@server1 ~]# salt server[1-3] test.ping
server2:
True
[root@server1 ~]# salt '*' test.ping
server2:
True
[root@server1 ~]# salt 'server2' test.ping
server2:
True
[root@server1 ~]# salt 'server2,server3' test.ping
No minions matched the target. No command was sent, no jid was assigned.
ERROR: No return received
[root@server1 ~]# salt -L 'server2,server3' test.ping # 使用列表
server2:
True
server3:
Minion did not return. [No response]
ERROR: Minions returned with non-zero exit code
[root@server1 ~]# salt -E 'server[1-3]' test.ping # 使用正则表达式
server2:
True
Function:
funcation是module提供的功能,Salt内置了大量有效的functions.(其实就是python的各种模块)
## http://docs.saltstack.cn/ 查看中文手册
[root@server1 ~]# salt '*' cmd.run 'uname -a' # 远程执行
server2:
Linux server2 3.10.0-957.el7.x86_64 #1 SMP Thu Oct 4 20:48:51 UTC 2018 x86_64 x86_64 x86_64 GNU/Linux
[root@server1 ~]# salt 'server2' sys.doc pkg #查看模块文档
arguments通过空格来界定参数:
salt '*' pkg.remove
salt '*' pkg.remove ,,
salt '*' pkg.remove pkgs='["foo", "bar"]'
这样就很简单的完成了远程安装。命令游4505端口推送,下面的带颜色的结果由4506端口接收的。
我们还可以去:
http://docs.saltstack.cn/ref/modules/all/index.html
查看salt内置的执行模块列表,这里面的使用方式是写文件时的用法,和命令行不太相同。
salt的数据都会保存在/var/cache/salt 目录中,(ansible保存在 /tmp 中)
[root@server2 salt]# pwd
/var/cache/salt
[root@server2 salt]# tree .
.
`-- minion
|-- extmods
`-- proc
3 directories, 0 files
当系统自带的模块不够时,我们就可以去自己编写。
默认的文件目录为:
[root@server1 ~]# vim /etc/salt/master
#
#file_roots:
# base:
# - /srv/salt # 在这里
#
[root@server1 ~]# mkdir /srv/salt # 这里就是salt的base目录,所有的数据都定位到这里,ansible指定的是当前目录。
[root@server1 ~]# mkdir /srv/salt/_modules # 这里是模块固定存放目录,
[root@server1 _modules]# vim mydisk.py # 编写文件
def df():
return __salt__['cmd.run']('df -h')
[root@server1 _modules]# salt server2 saltutil.sync_modules # 同步到server2
server2:
- modules.mydisk
在server2中查看:
[root@server2 salt]# tree .
.
`-- minion
|-- extmods
| `-- modules
| `-- mydisk.py
|-- files
| `-- base # 这个base就是/srv/salt
| `-- _modules
| `-- mydisk.py # 文件就通不过来了
|-- module_refresh
`-- proc
## 可以看出文件缓存到了server2中的 /var/cache/salt 目录中
然后我们就可以调用了:
[root@server1 salt]# salt server2 mydisk.df # 调用我们刚才写的mydisk模块的df方法。
server2:
Filesystem Size Used Avail Use% Mounted on
/dev/mapper/rhel-root 17G 1.2G 16G 8% /
devtmpfs 484M 0 484M 0% /dev
tmpfs 496M 100K 496M 1% /dev/shm
tmpfs 496M 13M 483M 3% /run
tmpfs 496M 0 496M 0% /sys/fs/cgroup
/dev/sda1 1014M 133M 882M 14% /boot
tmpfs 100M 0 100M 0% /run/user/0
sls文件的写法有两种方式;
vim apache.sls
[root@server1 salt]# cat apache.sls
httpd:
pkg.installed (这种是写到了一起)
[root@server1 salt]# cat apache.sls
httpd: # 声明(这里是软件包的声明)
pkg: # 状态声明(模块)
- installed # 函数声明
[root@server1 salt]# salt server2 state.sls apache # 指定主机执行
这时在server2上它会先把sls文件推送过来,再去执行安装。
[root@server2 salt]# tree .
.
`-- minion
|-- extmods
| `-- modules
| |-- mydisk.py
| `-- mydisk.pyc
|-- files
| `-- base
| |-- apache.sls # 推送过来了
| `-- _modules
| `-- mydisk.py
|-- module_refresh
`-- proc
`-- 20200608051500237034
当我们需要安装多个包时:
web:
pkg.installed:
- pkgs:
- httpd # 这里指定包,可以接多个
- php
推送过去:
[root@server1 salt]# salt server2 state.sls apache
在server2中查看日志:
它再安装的时后连依赖性也安装了。这时候如果我们在删除的时后就不会卸载到那些依赖性,因为salt只会把状态调整到 installed ,中间的过程可能会多样,所以就造成了这种结果。这不是一种还原机制。
apache/init.sls
就是apache
.当我们的sls文件越写越多时,为了方便,我们会在base目录创建目录,将一个属性 sls文件全部放到里面:
[root@server1 salt]# mkdir apache
[root@server1 salt]# mv apache.sls apache/installed.sls
[root@server1 salt]# ls apache/ # 就好比ansibe中的角色一样
installed.sls
[root@server1 salt]# salt server2 state.sls apache.installed # 这时的推送是这样的,用 . 分隔
这样有时会出现弊端,那我们还有另一种方式:
[root@server1 apache]# mv installed.sls init.sls # init.sls 入口文件,每次都会先访问这个文件
[root@server1 apache]# cd # 进入根目录
[root@server1 ~]# salt server2 state.sls apache # 也可以进行推送了,不必进入base的目录
server2: #注意这里只写apache,init.sls引导文件就代表apache
----------
ID: web
Function: pkg.installed
Result: True
Comment: All specified packages are already installed
Started: 14:12:36.650803
Duration: 555.309 ms
Changes:
Summary for server2
------------
Succeeded: 1
Failed: 0
------------
Total states run: 1
Total run time: 555.309 ms
我们可以把其它的sls文件,用include 写入到 int.sls 文件中
我们现在用init.sls开启httpd:
[root@server1 salt]# cat apache/init.sls
web:
pkg.installed:
- pkgs:
- httpd
- php
service.running:
- name: httpd
[root@server1 salt]# salt server2 state.sls apache
[root@server1 salt]# cat apache/init.sls
web:
pkg.installed:
- pkgs:
- httpd
- php
service.running:
- name: httpd
- enable: True # 加上开机自启
[root@server1 salt]# salt server2 state.sls apache
[root@server2 salt]# systemctl is-enabled httpd
enabled
[root@server2 salt]# tree
.
`-- minion
|-- accumulator
|-- extmods
| `-- modules
| |-- mydisk.py
| `-- mydisk.pyc
|-- files
| `-- base
| |-- apache
| | |-- init.sls # 这里
| | `-- installed.sls
| |-- apache.sls
| `-- _modules
| `-- mydisk.py
|-- highstate.cache.p
|-- module_refresh
|-- pkg_refresh
|-- proc
`-- sls.p
配置文件:
[root@server1 salt]# cat apache/init.sls
web:
pkg.installed:
- pkgs:
- httpd
- php
file.managed:
- source: salt://apache/files/httpd.conf #源地址,指/srv/salt/apache/files/httpd.conf
- name: /etc/httpd/conf/httpd.conf # 目的地地址
service.running:
- name: httpd
- enable: True
[root@server1 salt]# cd apache/
[root@server1 apache]# mkdir files # 创建对应目录
[root@server1 apache]# scp server2:/etc/httpd/conf/httpd.conf ./files # 拷贝一个文件过来
root@server2's password:
httpd.conf 100% 11KB 5.6MB/s 00:00
[root@server1 apache]# vim httpd.conf
我们将端口改为8080 端口.以示区别。
server2的配置文件已经更改为8080端口了。但是此时的netstat 端口还是80端口,所以我们
web:
pkg.installed:
- pkgs:
- httpd
- php
file.managed:
- source: salt://apache/files/httpd.conf
- name: /etc/httpd/conf/httpd.conf
service.running:
- name: httpd
- enable: True
- watch:
- file: web
用 watch 监控web声明,这里应注意,每个声明底下的模块只能使用一次,不然就会混乱,比如web地下只能有一个file模块,如果想再加的话,就再写一个声明
[root@server1 salt]# salt server2 state.sls apache
[root@server2 salt]# netstat -tnlp
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name
tcp 0 0 0.0.0.0:22 0.0.0.0:* LISTEN 3055/sshd
tcp 0 0 127.0.0.1:25 0.0.0.0:* LISTEN 3149/master
tcp6 0 0 :::8080 :::* LISTEN 14806/httpd #就变成8080端口了
tcp6 0 0 :::22 :::* LISTEN 3055/sshd
tcp6 0 0 ::1:25 :::* LISTEN 3149/master
我们还可以这么写:
web:
pkg.installed:
- pkgs:
- httpd
- php
service.running:
- name: httpd
- enable: True
- watch:
- file: /etc/httpd/conf/httpd.conf
/etc/httpd/conf/httpd.conf: # name替换为声明
file.managed: # 将file独立出来
- source: salt://apache/files/httpd.conf
开启server3,做和server2相同的配置:
[root@server3 packages]# yum install -y salt-minion.noarch 下载开启服务,enable。
[root@server3 packages]# vim /etc/salt/minion # 设置master
[root@server1 salt]# salt-key -L
Accepted Keys:
server2
Denied Keys:
Unaccepted Keys:
server3
Rejected Keys:
[root@server1 salt]# salt-key -A
The following keys are going to be accepted:
Unaccepted Keys:
server3
Proceed? [n/Y] Y
Key for minion server3 accepted.
[root@server1 salt]# salt-key -L
Accepted Keys:
server2
server3
Denied Keys:
Unaccepted Keys:
Rejected Keys:
[root@server1 salt]# lsof -i :4505
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
/usr/bin/ 5997 root 15u IPv4 40208 0t0 TCP *:4505 (LISTEN)
/usr/bin/ 5997 root 17u IPv4 42437 0t0 TCP server1:4505->server2:36740 (ESTABLISHED)
/usr/bin/ 5997 root 23u IPv4 89914 0t0 TCP server1:4505->server3:37524 (ESTABLISHED)
[root@server1 salt]# mkdir nginx
[root@server1 salt]# cd nginx
[root@server1 nginx]# vim init.sls
nginx-install: # 安装依赖性
pkg.installed:
- pkgs:
- openssl-devel
- pcre-devel
- gcc
file.managed: # 源码包推送过去
- name: /mnt/nginx-1.17.10.tar.gz
- source: salt://nginx/files/nginx-1.17.10.tar.gz
cmd.run: # 编译安装
- name: cd /mnt/ && tar zxf nginx-1.17.10.tar.gz && cd nginx-1.17.10 && sed -i 's/CFLAGS="$CFLAGS -g"/#CFLAGS="$CFLAGS -g"/g' auto/cc/gcc && ./configure --prefix=/usr/local/nginx --with-http_ssl_module &> /dev/null && make &> /dev/null && make install &> /dev/null
- creates: /usr/local/nginx # cmd会重复执行编译安装,这个参数会检测路径是否存在,若存在,就不再编译安装了
nginx-service:
file.managed: #推送文件
- name: /usr/lib/systemd/system/nginx.service
- source: salt://nginx/files/nginx.service
service.running: # 启动服务
- name: nginx
[root@server1 nginx]# mkdir files
[root@server1 nginx]# cd files/
[root@server1 files]# ls
nginx-1.17.10.tar.gz nginx.service # 脚本文件和源码包
[root@server1 files]# cat nginx.service
[Unit]
Description=The NGINX HTTP and reverse proxy server
After=syslog.target network-online.target remote-fs.target nss-lookup.target
Wants=network-online.target
[Service]
Type=forking
PIDFile=/usr/local/nginx/logs/nginx.pid
ExecStartPre=/usr/local/nginx/sbin/nginx -t
ExecStart=/usr/local/nginx/sbin/nginx
ExecReload=/usr/local/nginx/sbin/nginx -s reload
ExecStop=/bin/kill -s QUIT $MAINPID
PrivateTmp=true
[Install]
WantedBy=multi-user.target
[root@server1 nginx]# salt server3 state.sls nginx
[root@server3 sbin]# ps ax # 启动起来了
6868 ? Ss 0:00 nginx: master process ./nginx
6869 ? S 0:00 nginx: worker process
加入配置文件:
nginx-install:
pkg.installed:
- pkgs:
- openssl-devel
- pcre-devel
- gcc
file.managed:
- name: /mnt/nginx-1.17.10.tar.gz
- source: salt://nginx/files/nginx-1.17.10.tar.gz
cmd.run:
- name: cd /mnt/ && tar zxf nginx-1.17.10.tar.gz && cd nginx-1.17.10 && sed -i 's/CFLAGS="$CFLAGS -g"/#CFLAGS="$CFLAGS -g"/g' auto/cc/gcc && ./configure --prefix=/usr/local/nginx --with-http_ssl_module &> /dev/null && make &> /dev/null && make install &> /dev/null
- creates: /usr/local/nginx
/usr/local/nginx/conf/nginx.conf: # 拷贝配置文件过去
file.managed:
- source: salt://nginx/files/nginx.conf
nginx-service:
file.managed:
- name: /usr/lib/systemd/system/nginx.service
- source: salt://nginx/files/nginx.service
service.running:
- name: nginx
- enable: True # 自启
- reload: True # 重新加载
- watch: # 监控
- file: /usr/local/nginx/conf/nginx.conf
[root@server1 files]# vim nginx.conf
worker_processes 2; # 设置worker 两个
[root@server1 files]# salt server3 state.sls nginx
[root@server3 sbin]# ps ax
6895 ? Ss 0:00 nginx: master process /usr/local/nginx/sbin/nginx
6898 ? S 0:00 [kworker/u2:0]
6913 ? S 0:00 [kworker/0:2]
6916 ? R 0:00 [kworker/0:0]
6978 ? S 0:00 nginx: worker process
6979 ? S 0:00 nginx: worker process # 就有两个worker进程了
在这里我们举例使用一下include:
[root@server1 nginx]# cat init.sls
nginx-install:
pkg.installed:
- pkgs:
- openssl-devel
- pcre-devel
- gcc
file.managed:
- name: /mnt/nginx-1.17.10.tar.gz
- source: salt://nginx/files/nginx-1.17.10.tar.gz
cmd.run:
- name: cd /mnt/ ...
- creates: /usr/local/nginx
include: # 这就是include的使用方式,默认只读取接口文件,将另一个文件放入到这个接口文件中,就可以使用了
- nginx.service # nginx 目录下的 service 文件
[root@server1 nginx]# cat service.sls # 这个文件放的是从init.sls中截取的文件内容
/usr/local/nginx/conf/nginx.conf:
file.managed:
...
[root@server1 nginx]# salt server3 state.sls nginx # 推送
server3:
----------
ID: /usr/local/nginx/conf/nginx.conf
Function: file.managed
Result: True
Comment: File /usr/local/nginx/conf/nginx.conf is in the correct state
Started: 11:04:36.407291
Duration: 45.936 ms
Changes:
----------
ID: nginx-service
Function: file.managed
Name: /usr/lib/systemd/system/nginx.service
我们发现会优先执行include的内容
我们进入base目录(/srv/salt),创建top.sls文件
[root@server1 salt]# vim top.sls
[root@server1 salt]# cat top.sls
base:
'server2':
- apache # 在server2上执行apache的sls文件
'server3':
- nginx # 在server3上执行 nginx 的sls文件
说明了对于名为base的环境,server2将应用名为apache的状态文件。server3将应用名为nginx的状态文件。
Salt将在/srv/salt(base,在master的配置文件中设定)目录中查找apache.sls或init.sls。
这种高级状态文件的推送方式为:
[root@server1 salt]# salt '*' state.highstate
server2:
ID: web
Function: service.running
Name: httpd
Result: True
Comment: The service httpd is already running
Summary for server2
------------
Succeeded: 3
Failed: 0
------------
server3:
----------
ID: nginx-service
Function: service.running
Name: nginx
Result: True
Comment: The service nginx is already running
Summary for server3
------------
Succeeded: 6
Failed: 0
------------
而且只会把状态不同的进行变更。
grains和pillar的区别在于:
像上面的操作,我们在推送的时后会把数据缓存到minion端的 /var/cache/salt/ 中,使用pillar方式就不会。
信息查询:
用于查询minion端的IP、FQDN等信息。
## 默认可用的grains:salt '*' grains.ls
[root@server1 salt]# salt server2 grains.ls
server2:
- SSDs
- biosreleasedate
- biosversion
- cpu_flags
- cpu_model
- cpuarch
- cwd
- disks
- dns
- domain
- fqdn
- fqdn_ip4
## 查看每一项的值:
[root@server1 salt]# salt server3 grains.items
Red Hat
master:
172.25.254.1
mdadm:
mem_total:
991
nodename:
server3
## 取单项的值:
[root@server1 salt]# salt server3 grains.item ipv4 # 不是 items 了
server3:
----------
ipv4:
- 127.0.0.1
- 172.25.254.3
这些grains,我们可以在minion端的配置文件去静态指定
grains:
roles: apache ##指定这个键值对
# - webserver 列表的方式可以通过短杠指定
# - memcache
# deployment: datacenter4
# cabinet: 13
# cab_u: 14-15
[root@server2 minion.d]# systemctl restart salt-minion.service
#重启salt-minion,否则数据不会更新
[root@server1 salt]# salt server2 grains.item roles
server2:
----------
roles: # 然后就可以看到了。
apache
我们还可以去etc/salt/grains中定义:
[root@server3 files]# vim /etc/salt/grains
[root@server3 files]# cat /etc/salt/grains
roles: nginx
[root@server1 salt]# salt server3 saltutil.sync_grains #同步数据
server3:
[root@server1 salt]# salt server3 grains.item roles # 就可以查看了,这种方式不用重启服务
server3:
----------
roles:
nginx
还可以通过编写模块的方式;
[root@server1 salt]# mkdir /srv/salt/_grains # 在salt-master端创建_grains目录
[root@server1 salt]# cd _grains/
[root@server1 _grains]# vim my_grain.py
[root@server1 _grains]# cat my_grain.py
def my_grain():
grains = {}
grains['salt'] = 'stack'
grains['hello'] = 'world'
return grains
[root@server1 _grains]# salt '*' saltutil.sync_grains # 同步到所有结点
server2:
- grains.my_grain
server3:
- grains.my_grain
[root@server1 _grains]# salt 'server2' grains.item hello
server2:
----------
hello:
world
[root@server1 _grains]# salt 'server3' grains.item salt
server3:
----------
salt:
stack
[root@server2 salt]# tree .
.
`-- minion
|-- accumulator
|-- extmods
| |-- grains
| | |-- my_grain.py
| | `-- my_grain.pyc
| `-- modules
| |-- mydisk.py
| `-- mydisk.pyc
|-- files
| `-- base
| |-- apache
| | |-- files
| | | `-- httpd.conf
| | |-- init.sls
| | `-- installed.sls
| |-- apache.sls
| |-- _grains
| | `-- my_grain.py # 同步过来了
grains匹配运用:
[root@server1 _grains]# salt -G roles:apache cmd.run hostname
server2: #这里是server2中的角色
server2
-G 通过grains来匹配目标,只要目标有roles是 apache 的就执行 hostname
[root@server1 _grains]# salt -G roles:apache cmd.run hostname
server2:
server2
[root@server1 _grains]# salt -G roles:nginx cmd.run hostname
server3:
server3
[root@server1 _grains]# salt -G hello:world cmd.run hostname
server2:
server2
server3:
server3
在top文件中匹配:
[root@server1 salt]# vim top.sls
[root@server1 salt]# cat top.sls
base:
'roles:apache':
- match: grain # 通过grain匹配roles是apache的主机,相当于标签,方便了对很多台主机进行操作
- apache
'roles:nginx':
- match: grain
- nginx
[root@server1 salt]# salt '*' state.highstate # 高级推送
数据不能存放到/srv/salt上,因为这个目录里的数据都推推送到minion端。
定义pillar基础目录:
[root@server1 salt]# vim /etc/salt/master
我们可以在这里进行指定,也可以采用默认,我们采用默认。
[root@server1 salt]# mkdir /srv/pillar
[root@server1 salt]# vim packages.sls
{% if grains['fqdn'] == 'server3' %} # 如果主机名是server3
package: nginx # 是这个对印关系
{% elif grains['fqdn'] == 'server2' %} # 如果
package: httpd
{% endif %}
[root@server1 pillar]# vim top.sls # 编写top文件
[root@server1 pillar]# cat top.sls
base:
'*':
- packages
这时我们就可以查看了,因为是动态的,所以不需要刷新或重启
[root@server1 pillar]# salt '*' pillar.items
server3:
----------
package:
nginx # 获取到了
server2:
----------
package:
httpd
[root@server1 pillar]# salt '*' pillar.item package #但是我们单独查看的时候
server3:
----------
package:
server2:
----------
package: # 就访问不到了
[root@server1 pillar]# salt '*' saltutil.refresh_pillar # 刷新
server2:
True
server3:
True
[root@server1 pillar]# salt '*' pillar.item package
server2:
----------
package:
httpd
server3:
----------
package:
nginx # 就能访问了
pillar的数据匹配:
[root@server1 pillar]# salt -I package:nginx cmd.run hostname
server3:
server3
## -I 表示用 pillar 的方式查询 package 对应 nginx 的主机执行 hostname
state系统中使用:
[root@server1 salt]# cd apache/
[root@server1 apache]# ls
files init.sls
[root@server1 apache]# vim init.sls
web:
pkg.installed:
- pkgs:
- {{ pillar['package'] }} 这里本来是 name:httpd,现在在pillar中获取
- php
。。。
[root@server1 apache]# salt '*' state.highstate # 高级推送没问题
[root@server1 apache]# salt server2 state.sls apache # 指定推送也没有问题
[root@server1 apache]# salt server3 state.sls apache # 推送给server3时就会报错,因为3上装的nginx
# 匹配nginx:
[root@server1 nginx]# ls
files init.sls
[root@server1 nginx]# vim init.sls
service.running:
- name: {{ pillar['package'] }} # 用pillar去获取nginx
- enable: True
- reload: True
- watch:
- file: /usr/local/nginx/conf/nginx.conf
[root@server1 nginx]# salt server3 state.sls nginx # 推送没有问题
Jinja最基本的用法是使用控制结构包装条件:
[root@server1 salt]# ls
apache _grains _modules nginx top.sls
[root@server1 salt]# vim test.sls
/mnt/testfile:
file.append:
{% if grains['fqdn'] == 'server2' %}
- text: server2
{% elif grains['fqdn'] == 'server3' %} # 通过grains 获取
- text: server3
{% endif %}
[root@server1 salt]# salt '*' state.sls test # 推送
在server2个serve'r3中查看;
[root@server3 salt]# cat /mnt/testfile
server3
[root@server2 salt]# cat /mnt/testfile
server2
Jinja在普通文件的使用:
[root@server1 salt]# cd apache/
[root@server1 apache]# ls
files init.sls
[root@server1 apache]# vim init.sls
web:
pkg.installed:
- pkgs:
- {{ pillar['package'] }}
- php
service.running:
- name: httpd
- enable: True
- watch:
- file: /etc/httpd/conf/httpd.conf
/etc/httpd/conf/httpd.conf:
file.managed:
- source: salt://apache/files/httpd.conf
- template: jinja # 使用jinja模板
- context: # 直接更改
bind: 172.25.254.2
[root@server1 apache]# vim files/httpd.conf # 在配置文件中更改
Listen {{ bind }}:80 # 监听server2的80端口。
[root@server1 apache]# salt server2 state.sls apache # 推送
server2:
ID: /etc/httpd/conf/httpd.conf
Function: file.managed
Result: True
Comment: File /etc/httpd/conf/httpd.conf updated
Started: 23:13:33.279187
Duration: 32.654 ms
Changes:
----------
diff:
---
+++
@@ -39,7 +39,7 @@
# prevent Apache from glomming onto all bound IP addresses.
#
#Listen 12.34.56.78:80
-Listen 8080
+Listen 172.25.254.2:80 # 更改了
我们这里还可以用pillar直接进行调用:
[root@server1 apache]# cd /srv/pillar/
[root@server1 pillar]# ls
packages.sls top.sls
[root@server1 pillar]# vim packages.sls
{% if grains['fqdn'] == 'server3' %}
package: nginx
{% elif grains['fqdn'] == 'server2' %}
package: httpd
port: 8080
{% endif %}
[root@server1 pillar]# cd ../salt/apache/files/
[root@server1 files]# vim httpd.conf
Listen {{ bind }}:{{ pillar['port'] }} # 更改如这行,使用jinja模板才可以调用pillar
[root@server1 files]# salt server2 state.sls apache
#Listen 12.34.56.78:80
-Listen 172.25.254.2:80
+Listen 172.25.254.2:8080 # 更改了
引用变量:
[root@server1 files]# vim httpd.conf
[root@server1 files]# salt server2 state.sls apache # 推送也成功了
在state文件中引用:
[root@server1 files]# vim httpd.conf
[root@server1 files]# vim ../init.sls
[root@server1 files]# cat ../init.sls
...
/etc/httpd/conf/httpd.conf:
file.managed:
- source: salt://apache/files/httpd.conf
- template: jinja
- context:
bind: {{ grains['ipv4'][-1] }} # 直接在这里引用
port: {{ pillar['port'] }}
引用变量文件:
[root@server1 salt]# vim lib.sls # 建立文件
[root@server1 salt]# cat lib.sls
{%set port = 8000 %}
[root@server1 salt]# vim apache/files/httpd.conf
root@server1 salt]# cat apache/init.sls
...
/etc/httpd/conf/httpd.conf:
file.managed:
- source: salt://apache/files/httpd.conf
- template: jinja
- context:
bind: {{ grains['ipv4'][-1] }}
port: {{ pillar['port'] }} # sls 文件也有port变量
要注意这两个port 是不同的,下面这个是pillar指定的,而上面时变量文件指定的
[root@server1 salt]# cat lib.sls
{%set port = 8000 %} # 变量文件指定8000端口
[root@server1 salt]# cat ../pillar/packages.sls
{% if grains['fqdn'] == 'server3' %}
package: nginx
{% elif grains['fqdn'] == 'server2' %}
package: httpd
port: 8080 # pillar指定8080多口
{% endif %}
[root@server1 salt]# pwd
/srv/salt
那幺到底谁生效哪?这就是优先级的问题,因为lib.sls文件是最后导进去的,所以这个会生效
推送测试:
[root@server1 salt]# salt server2 state.sls apache
是8000端口吧!
而且这时文件在传送过去的时候删除了第一行,因为我们的apache不识别这种格式:
[root@server2 salt]# vim /etc/httpd/conf/httpd.conf
[root@server2 salt]# vim /var/cache/salt/minion/files/base/apache/files/httpd.conf
我们让server2做master,server3做backup。
[root@server1 salt]# mkdir keepalived
[root@server1 salt]# mkdir files
[root@server1 salt]# cd keepalived/files/
[root@server1 files]# scp server2:/etc/keepalived/keepalived.conf . #拷贝一份配置文件,可以先装上keepalived复制一份配置文件在删除。
[root@server1 files]# vim keepalived.conf
global_defs {
notification_email {
root@localhost
}
notification_email_from keepalived@localhost
smtp_server 127.0.0.1
smtp_connect_timeout 30
router_id LVS_DEVEL
vrrp_skip_check_adv_addr
# vrrp_strict # 注释掉这个
vrrp_garp_interval 0
vrrp_gna_interval 0
}
vrrp_instance VI_1 {
state {{ STATE }} # 我们改为引用变量
interface eth0
virtual_router_id 51
priority {{ PRI}} # 变量
advert_int 1
authentication {
auth_type PASS
auth_pass 1111
}
virtual_ipaddress {
172.25.254.100 #
}
}
然后用pillar指定变量:
[root@server1 keepalived]# vim /srv/pillar/packages.sls
{% if grains['fqdn'] == 'server3' %}
package: nginx
state: BACKUP # server3 成为备用结点
pri: 50
{% elif grains['fqdn'] == 'server2' %}
package: httpd
port: 8080
state: MASTER # serer2做主节点
pri: 100
{% endif %}
[root@server1 files]# cd ..
[root@server1 keepalived]# vim init.sls # 建立引导文件
[root@server1 keepalived]# cat init.sls
kp-install: # 安装(可以先注释掉下面,让先安装,复制一个配置文件过来,后面接上面的scp那条命令)
pkg.installed:
- pkgs:
- keepalived
file.managed: # 配置文件(上面获取到的)
- name: /etc/keepalived/keepalived.conf
- source: salt://keepalived/files/keepalived.conf
- template: jinja
- context:
STATE: {{ pillar['state'] }} # 调用变量
PRI: {{ pillar['pri'] }}
service.running: # 启动服务
- name: keepalived
- enable: True
- reload: True
- watch:
- file: kp-install
测试推送:
[root@server1 keepalived]# salt '*' state.sls keepalived
# server2中查看
[root@server2 ~]# cat /etc/keepalived/keepalived.conf
。。。
vrrp_instance VI_1 {
state MASTER # master结点
interface eth0
virtual_router_id 51
priority 100 # 优先级100
[root@server2 ~]# ip a
2: ens3: mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
inet 172.25.254.100/32 scope global ens3 # 虚拟IP
# server3中查看;
[root@server3 ~]# cat /etc/keepalived/keepalived.conf
...
vrrp_instance VI_1 {
state BACKUP # 备用结点
interface ens3
virtual_router_id 51
priority 50 # 优先级50
现在我们去编写top文件,去高级推送:
[root@server1 salt]# vim top.sls
[root@server1 salt]# cd /srv/salt/
[root@server1 salt]# vim top.sls
base:
'server2': # server2开启apache和高可用
- apache
- keepalived
'server3':
- nginx # 开启nginx和高可用
- keepalived
然后去掉apache目录的的init.sls和配置文件的监听地址,只留下监听端口,这样才能通过访问VIP访问。
这里都去掉了bind哪一行,只剩下了port。
然后高级推送:
[root@server1 salt]# salt '*' state.highstate
[root@server1 salt]# curl 172.25.254.100
Test Page for the Apache HTTP Server on Red Hat Enterprise Linux