配置pillar,在 pillar目录下添加自定义模块
[root@server1 srv]# cat pillar/kp.sls
{% if grains['fqdn'] == 'server2' %}
state: Master
vrid: 51
pri: 100
{% elif grains['fqdn'] == 'server3' %}
state: BACKUP
vrid: 51
pri: 50
{% endif %}
[root@server1 srv]# cat pillar/top.sls
base:
'*':
- pkgs
- kp
编写keepalived脚本
创建目录keepalived
mkdir /etc/salt/keeplived
主配文件模板:
[root@server1 keepalived]# cat keepalived.conf
! Configuration File for keepalived
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 {{ VRID }}
priority {{ PRI }}
advert_int 1
authentication {
auth_type PASS
auth_pass 1111
}
virtual_ipaddress {
172.25.3.100/24
}
安装脚本:
[root@server1 keepalived]# cat init.sls
kp-install:
pkg.installed:
- name: keepalived
file.managed:
- name: /etc/keepalived/keepalived.conf
- source: salt://keepalived/keepalived.conf
- template: jinja
- context:
STATE: {{ pillar['state'] }}
VRID: {{ pillar['vrid' ]}}
PRI: {{ pillar['pri'] }}
service.running:
- name: keepalived
- reload: true
- watch:
- file: kp-install
highstate脚本:
[root@server1 salt]# cat top.sls
base:
'roles:apache':
- match: grain
- apache
- keepalived
'roles:nginx':
- match: grain
- nginx.service
- keepalived
执行
salt '*' saltutil.sync_grains
salt '*' state.highstate
查看ip
ip addr show
测试高可用
[root@server2 ~]# systemctl stop keepalived.service
[root@server2 ~]# systemctl start keepalived.service
[root@server2 ~]# netstat -antlp
关闭server2上keepalived
systemctl stop keepalived.service
ip a
访问vip,发现切换到server3默认发布页面:
启动server2上keepalived,发现master再次切入至server2
systemctl start keepalived.service
job下数据默认存放24小时
server1/2安装 MySQL-python
yum install -y MySQL-python.x86_64
server1 安装mysql,并安全初始化
mysql_secure_installation
导入数据备份:
vim salt.sql
mysql -pwestos < salt.sql
CREATE DATABASE `salt`
DEFAULT CHARACTER SET utf8
DEFAULT COLLATE utf8_general_ci;
USE `salt`;
--
-- Table structure for table `jids`
--
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;
--
-- Table structure for table `salt_returns`
--
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;
--
-- Table structure for table `salt_events`
--
DROP TABLE IF EXISTS `salt_events`;
CREATE TABLE `salt_events` (
`id` BIGINT NOT NULL AUTO_INCREMENT,
`tag` varchar(255) NOT NULL,
`data` mediumtext NOT NULL,
`alter_time` TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
`master_id` varchar(255) NOT NULL,
PRIMARY KEY (`id`),
KEY `tag` (`tag`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
登入数据库,授权用户网络访问
mysql -pwestos
grant all on salt.* to salt@'%' identified by 'salt'; #授权用户网络访问
server2 配置minion
vim minion
return: mysql
mysql.host: '172.25.3.1'
mysql.user: 'salt'
mysql.pass: 'salt'
mysql.db: 'salt'
mysql.port: 3306
systemctl restart salt-minion.service
测试:
salt server2 my_disk.df
mysql -pwestos
use salt
select * from salt_returns\G;
查看结果:
*************************** 1. row ***************************
fun: saltutil.find_job
jid: 20210718032447080204
return: {}
id: server2
success: 1
full_ret: {"fun_args": ["20210718032442068396"], "jid": "20210718032447080204", "return": {}, "retcode": 0, "success": true, "fun": "saltutil.find_job", "id": "server2"}
alter_time: 2021-07-17 23:24:55
被动式:无需配置minion也可以被收集
server1配置master:
vim master
master_job_cache: mysql
mysql.host: 'localhost'
mysql.user: 'salt'
mysql.pass: 'salt'
mysql.db: 'salt'
mysql.port: 3306
systemctl restart salt-master.service
授权本地用户:
mysql -pwestos
grant all on salt.* to salt@localhost identified by 'salt';
测试:
salt '*' my_disk.df --return mysql
查看
select * from salt_returns\G;
获取到server3信息
alter_time: 2021-07-17 23:32:28
*************************** 4. row ***************************
fun: my_disk.df
jid: 20210718033228414731
return: "Filesystem Size Used Avail Use% Mounted on\n/dev/mapper/rhel-root 27G 1.3G 26G 5% /\ndevtmpfs 988M 0 988M 0% /dev\ntmpfs 1000M 140K 1000M 1% /dev/shm\ntmpfs 1000M 8.6M 991M 1% /run\ntmpfs 1000M 0 1000M 0% /sys/fs/cgroup\n/dev/vda1 1014M 132M 883M 14% /boot\ntmpfs 200M 0 200M 0% /run/user/0"
id: server3
success: 1
full_ret: {"fun_args": [], "jid": "20210718033228414731", "return": "Filesystem Size Used Avail Use% Mounted on\n/dev/mapper/rhel-root 27G 1.3G 26G 5% /\ndevtmpfs 988M 0 988M 0% /dev\ntmpfs 1000M 140K 1000M 1% /dev/shm\ntmpfs 1000M 8.6M 991M 1% /run\ntmpfs 1000M 0 1000M 0% /sys/fs/cgroup\n/dev/vda1 1014M 132M 883M 14% /boot\ntmpfs 200M 0 200M 0% /run/user/0", "retcode": 0, "success": true, "cmd": "_return", "_stamp": "2021-07-18T03:32:28.691707", "fun": "my_disk.df", "id": "server3"}
alter_time: 2021-07-17 23:32:28
安装salt-ssh:
yum install -y salt-ssh
vim roster
server3:
host: 172.25.3.3
user: root
passwd: westos
salt-ssh '*' test.ping
server4
yum install -y salt-master
vim master
order_masters: True
server1
yum install -y salt-syndic
vim master
syndic_master: 172.25.3.4
启动服务:
systemctl restart salt-master.service
systemctl start salt-syndic.service
注册主机:
salt-key -L
salt-key -A
测试:
cd /etc/salt/
salt '*' my_disk.df
安装salt-api
yum install -y slat-api
编辑认证及调用配置文件:
[root@server1 ~]# cd /etc/salt/master.d/
[root@server1 master.d]# cat api.conf
rest_cherrypy:
port: 8000
ssl_crt: /etc/pki/tls/certs/localhost.crt
ssl_key: /etc/pki/tls/private/localhost.key
[root@server1 master.d]# cat auth.conf
external_auth:
pam:
saltapi:
- .*
- '@wheel'
- '@runner'
- '@jobs'
cd /etc/salt/master.d/
vim auth.conf
vim api.conf
创建saltapi用户
useradd saltapi
echo westos |passwd --stdin saltapi
生成密钥
cd /etc/pki/tls/private/
openssl genrsa 1024 > localhost.key
生成认证文件
cd /etc/pki/tls/certs/
[root@server1 certs]# make testcert
umask 77 ; \
/usr/bin/openssl req -utf8 -new -key /etc/pki/tls/private/localhost.key -x509 -days 365 -out /etc/pki/tls/certs/localhost.crt
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) [XX]:cn
State or Province Name (full name) []:shannxi
Locality Name (eg, city) [Default City]:xian
Organization Name (eg, company) [Default Company Ltd]:westos
Organizational Unit Name (eg, section) []:linux
Common Name (eg, your name or your server's hostname) []:server1
Email Address []:[email protected]
查看认证文件及密钥
[root@server1 master.d]# ll /etc/pki/tls/private/localhost.key
-rw-r--r-- 1 root root 887 Jul 18 03:18 /etc/pki/tls/private/localhost.key
[root@server1 master.d]# ll /etc/pki/tls/certs/localhost.crt
-rw------- 1 root root 1038 Jul 18 03:19 /etc/pki/tls/certs/localhost.crt
启动服务:
systemctl restart salt-master.service
systemctl start salt-api.service
获取token认证码
curl -sSk https://172.25.3.1:8000/login -H 'Accept: application/x-yaml' -d username=saltapi -d password=westos -d eauth=pam
认证玛内容
return:
- eauth: pam
expire: 1626636538.547457
perms:
- .*
- '@wheel'
- '@runner'
- '@jobs'
start: 1626593338.547456
token: fd2a30e454581056e12493c7ada7c7d97f7b9a3d
user: saltapi
调用api接口:
curl -sSk https://172.25.3.1:8000 -H 'Accept: application/x-yaml' -H 'X-Auth-Token: fd2a30e454581056e12493c7ada7c7d97f7b9a3d' -d username=saltapi -d password=westos -d client=local -d tgt='*' -d fun=test.ping
return:
- server2: true
server3: true
执行saltapi.py
:
[root@server1 ~]# python saltapi.py
([u'server2', u'server3'], [])
[root@server1 ~]# cat saltapi.py
# -*- coding: utf-8 -*-
import urllib2,urllib
import time
import ssl
ssl._create_default_https_context = ssl._create_unverified_context
try:
import json
except ImportError:
import simplejson as json
class SaltAPI(object):
__token_id = ''
def __init__(self,url,username,password):
self.__url = url.rstrip('/')
self.__user = username
self.__password = password
def token_id(self):
''' user login and get token id '''
params = {'eauth': 'pam', 'username': self.__user, 'password': self.__password}
encode = urllib.urlencode(params)
obj = urllib.unquote(encode)
content = self.postRequest(obj,prefix='/login')
try:
self.__token_id = content['return'][0]['token']
except KeyError:
raise KeyError
def postRequest(self,obj,prefix='/'):
url = self.__url + prefix
headers = {'X-Auth-Token' : self.__token_id}
req = urllib2.Request(url, obj, headers)
opener = urllib2.urlopen(req)
content = json.loads(opener.read())
return content
def list_all_key(self):
params = {'client': 'wheel', 'fun': 'key.list_all'}
obj = urllib.urlencode(params)
self.token_id()
content = self.postRequest(obj)
minions = content['return'][0]['data']['return']['minions']
minions_pre = content['return'][0]['data']['return']['minions_pre']
return minions,minions_pre
def delete_key(self,node_name):
params = {'client': 'wheel', 'fun': 'key.delete', 'match': node_name}
obj = urllib.urlencode(params)
self.token_id()
content = self.postRequest(obj)
ret = content['return'][0]['data']['success']
return ret
def accept_key(self,node_name):
params = {'client': 'wheel', 'fun': 'key.accept', 'match': node_name}
obj = urllib.urlencode(params)
self.token_id()
content = self.postRequest(obj)
ret = content['return'][0]['data']['success']
return ret
def remote_noarg_execution(self,tgt,fun):
''' Execute commands without parameters '''
params = {'client': 'local', 'tgt': tgt, 'fun': fun}
obj = urllib.urlencode(params)
self.token_id()
content = self.postRequest(obj)
ret = content['return'][0][tgt]
return ret
def remote_execution(self,tgt,fun,arg):
''' Command execution with parameters '''
params = {'client': 'local', 'tgt': tgt, 'fun': fun, 'arg': arg}
obj = urllib.urlencode(params)
self.token_id()
content = self.postRequest(obj)
ret = content['return'][0][tgt]
return ret
def target_remote_execution(self,tgt,fun,arg):
''' Use targeting for remote execution '''
params = {'client': 'local', 'tgt': tgt, 'fun': fun, 'arg': arg, 'expr_form': 'nodegroup'}
obj = urllib.urlencode(params)
self.token_id()
content = self.postRequest(obj)
jid = content['return'][0]['jid']
return jid
def deploy(self,tgt,arg):
''' Module deployment '''
params = {'client': 'local', 'tgt': tgt, 'fun': 'state.sls', 'arg': arg}
obj = urllib.urlencode(params)
self.token_id()
content = self.postRequest(obj)
return content
def async_deploy(self,tgt,arg):
''' Asynchronously send a command to connected minions '''
params = {'client': 'local_async', 'tgt': tgt, 'fun': 'state.sls', 'arg': arg}
obj = urllib.urlencode(params)
self.token_id()
content = self.postRequest(obj)
jid = content['return'][0]['jid']
return jid
def target_deploy(self,tgt,arg):
''' Based on the node group forms deployment '''
params = {'client': 'local_async', 'tgt': tgt, 'fun': 'state.sls', 'arg': arg, 'expr_form': 'nodegroup'}
obj = urllib.urlencode(params)
self.token_id()
content = self.postRequest(obj)
jid = content['return'][0]['jid']
return jid
def main():
sapi = SaltAPI(url='https://172.25.3.1:8000',username='saltapi',password='westos')
sapi.token_id()
print sapi.list_all_key()
#sapi.delete_key('test-01')
#sapi.accept_key('test-01')
#sapi.deploy('*','httpd.apache')
#print sapi.remote_noarg_execution('test-01','grains.items')
if __name__ == '__main__':
main()
执行结果: