1.keepalived模块
1saltstack安装apache
server2安装keepalived并将配置文件传给server1
[root@server2 ~]# yum install -y keepalived
[root@server2 ~]# cd /etc/keepalived/
[root@server2 keepalived]# scp keepalived.conf server1:/srv/salt/keepalived
server1
cd /srv/salt/
mkdir keepalived
cd keepalived/
vim init.sls
kp-install:
pkg.installed:
- name: keepalived
file.managed:
- name: /etc/keepalived/keepalived.conf
- source: salt://keepalived/keepalived.conf
service.running:
- name: keepalived
- reload: true
- watch:
- file: kp-install
vim 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 MASTER
interface eth0
virtual_router_id 14
priority 100
advert_int 1
authentication {
auth_type PASS
auth_pass 1111
}
virtual_ipaddress {
172.25.14.100 #VIP
}
}
server1
[root@server1 keepalived]# salt server2 state.sls keepalived
server2查看ip,出现vip 172.25.14.100
2saltstack+高可用
vim 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.14.100
}
}
[root@server1 pillar]# pwd
/srv/pillar
[root@server1 pillar]# vim kp.sls
{% if grains['fqdn'] == 'server2' %}
state: MASTER
vrid: 14
pri: 100
{% elif grains['fqdn'] == 'server3' %}
state: BACKUO
vrid: 14
pri: 50
{% endif %}
[root@server1 pillar]# vim top.sls
base:
'*':
- pkgs
- kp
[root@server1 keepalived]# pwd
/srv/salt/keepalived
[root@server1 keepalived]# vim 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
server3查看日志变为备机
[root@server1 apache]# pwd
/srv/salt/apache
[root@server1 apache]# vim init.sls
apache:
pkg.installed:
- pkgs:
- {{ pillar['package'] }}
service.running:
- name: httpd
- enable: true
- reload: true
- watch:
- file: /etc/httpd/conf/httpd.conf
/etc/httpd/conf/httpd.conf:
file.managed:
- source: salt://apache/httpd.conf
- template: jinja
- context:
http_port: {{ pillar['port'] }}
http_host: 172.25.14.100
[root@server1 salt]# pwd
/srv/salt
[root@server1 salt]# vim top.sls
base:
'roles:apache':
- match: grain
- apache
- keepalived
'roles:nginx':
- match: grain
- nginx
- keepalived
[root@server1 salt]# salt '*' state.highstate
server2添加默认发布文件
[root@server2 keepalived]# echo server2 > /var/www/html/index.html
server1访问vip
[root@server1 ~]# curl 172.25.14.100
server2
server2停掉keepalived,server1访问vip到server3
[root@server2 keepalived]# systemctl stop keepalived.service
vip出现到server3上
server2开启keepalived
[root@server2 keepalived]# systemctl start keepalived.service
server1再次访问vip,自动启用server2
2.job
server1安装mysql数据库server端
[root@server1 ~]# yum install -y MySQL-python.x86_64
[root@server1 ~]# yum install -y maridb-server
[root@server1 ~]# systemctl start mariadb.service #启动服务
[root@server1 ~]# mysql_secure_installation #安全初始化
server2
[root@server2 ~]# yum install -y MySQL-python.x86_64
查看模板
[root@server1 ~]# ls
test.sql
[root@server1 ~]# cat test.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
[root@server1 ~]# mysql -pwestos < test.sql
[root@server1 ~]# mysql -pwestos
Welcome to the MariaDB monitor. Commands end with ; or \g.
Your MariaDB connection id is 12
Server version: 5.5.60-MariaDB MariaDB Server
Copyright (c) 2000, 2018, Oracle, MariaDB Corporation Ab and others.
Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.
MariaDB [(none)]> use salt;
Reading table information for completion of table and column names
You can turn off this feature to get a quicker startup with -A
Database changed
MariaDB [salt]> show tables;
+----------------+
| Tables_in_salt |
+----------------+
| jids |
| salt_events |
| salt_returns |
+----------------+
3 rows in set (0.00 sec)
MariaDB [salt]> Bye
用户授权
[root@server1 ~]# mysql -pwestos salt
Reading table information for completion of table and column names
You can turn off this feature to get a quicker startup with -A
Welcome to the MariaDB monitor. Commands end with ; or \g.
Your MariaDB connection id is 13
Server version: 5.5.60-MariaDB MariaDB Server
Copyright (c) 2000, 2018, Oracle, MariaDB Corporation Ab and others.
Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.
MariaDB [salt]> grant all on salt.* to salt@'%' identified by 'salt';
Query OK, 0 rows affected (0.00 sec)
#授权salt用户远程操作salt.*表的所有操作
MariaDB [salt]> grant all on salt.* to salt@localhost identified by 'salt';
Query OK, 0 rows affected (0.00 sec)
#授权salt用户本地操作salt.*表的所有操作
MariaDB [salt]> Bye
server2把数据存到server1的数据库
[root@server2 ~]# vim /etc/salt/minion
return: mysql
[root@server2 ~]# systemctl restart salt-minion.service
[root@server1 ~]# salt server2 my_disk.df --return mysql
server2:
Filesystem Size Used Avail Use% Mounted on
/dev/mapper/rhel-root 17G 1.4G 16G 8% /
devtmpfs 484M 0 484M 0% /dev
tmpfs 496M 60K 496M 1% /dev/shm
tmpfs 496M 13M 483M 3% /run
tmpfs 496M 0 496M 0% /sys/fs/cgroup
/dev/vda1 1014M 132M 883M 14% /boot
tmpfs 100M 0 100M 0% /run/user/0
[root@server1 ~]# mysql -pwestos salt
Reading table information for completion of table and column names
You can turn off this feature to get a quicker startup with -A
Welcome to the MariaDB monitor. Commands end with ; or \g.
Your MariaDB connection id is 52
Server version: 5.5.60-MariaDB MariaDB Server
Copyright (c) 2000, 2018, Oracle, MariaDB Corporation Ab and others.
Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.
MariaDB [salt]> select * from salt_returns\G
server1直接配置job缓存
[root@server1 ~]# vim /etc/salt/master
master_job_cache: mysql
mysql.host: 'localhost'
mysql.user: 'salt'
mysql.pass: 'salt'
mysql.db: 'salt'
mysql.port: 3306
[root@server1 ~]# systemctl restart salt-master
[root@server1 ~]# salt '*' test.ping
server3:
True
server2:
True
server1查看数据库
[root@server1 ~]# mysql -pwestos
Welcome to the MariaDB monitor. Commands end with ; or \g.
Your MariaDB connection id is 22
Server version: 5.5.60-MariaDB MariaDB Server
Copyright (c) 2000, 2018, Oracle, MariaDB Corporation Ab and others.
Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.
MariaDB [(none)]> use salt
Reading table information for completion of table and column names
You can turn off this feature to get a quicker startup with -A
Database changed
MariaDB [salt]> show tables;
+----------------+
| Tables_in_salt |
+----------------+
| jids |
| salt_events |
| salt_returns |
+----------------+
3 rows in set (0.00 sec)
MariaDB [salt]> select * from salt_returns\G
*************************** 1. row ***************************
fun: test.ping
jid: 20210718031749923024
return: true
id: server2
success: 1
full_ret: {"fun_args": [], "jid": "20210718031749923024", "return": true, "retcode": 0, "success": true, "cmd": "_return", "_stamp": "2021-07-18T03:17:50.449626", "fun": "test.ping", "id": "server2"}
alter_time: 2021-07-18 11:17:50
*************************** 2. row ***************************
fun: test.ping
jid: 20210718031749923024
return: true
id: server3
success: 1
full_ret: {"fun_args": [], "jid": "20210718031749923024", "return": true, "retcode": 0, "success": true, "cmd": "_return", "_stamp": "2021-07-18T03:17:50.510463", "fun": "test.ping", "id": "server3"}
alter_time: 2021-07-18 11:17:50
*************************** 3. row ***************************
fun: test.ping
jid: 20210718031933619936
return: true
id: server3
success: 1
full_ret: {"fun_args": [], "jid": "20210718031933619936", "return": true, "retcode": 0, "success": true, "cmd": "_return", "_stamp": "2021-07-18T03:19:33.758337", "fun": "test.ping", "id": "server3"}
alter_time: 2021-07-18 11:19:33
*************************** 4. row ***************************
fun: test.ping
jid: 20210718031933619936
return: true
id: server2
success: 1
full_ret: {"fun_args": [], "jid": "20210718031933619936", "return": true, "retcode": 0, "success": true, "cmd": "_return", "_stamp": "2021-07-18T03:19:33.783261", "fun": "test.ping", "id": "server2"}
alter_time: 2021-07-18 11:19:33
4 rows in set (0.00 sec)
MariaDB [salt]> Bye
3.salt-ssh、salt-syndic、 salt-api配置
salt-ssh
salt-ssh可以独立运行的,不需要minion端。
设定server3无法安装salt-minion,关闭服务
[root@server3 ~]# systemctl stop salt-minion.service
server1
[root@server1 ~]# yum install -y salt-ssh
[root@server1 ~]# vim /etc/salt/roster
server3:
host: 172.25.14.3
user: root
passwd: westos
成功访问server3
[root@server1 ~]# salt-ssh '*' test.ping
server3:
True
[root@server1 ~]# salt-ssh '*' my_disk.df
server3:
Filesystem Size Used Avail Use% Mounted on
/dev/mapper/rhel-root 17G 1.4G 16G 8% /
devtmpfs 484M 0 484M 0% /dev
tmpfs 496M 0 496M 0% /dev/shm
tmpfs 496M 13M 483M 3% /run
tmpfs 496M 0 496M 0% /sys/fs/cgroup
/dev/vda1 1014M 132M 883M 14% /boot
tmpfs 100M 0 100M 0% /run/user/0
salt-syndic
syndic其实就是个代理,隔离master与minion。
Syndic必须要运行在master上,再连接到另一个topmaster上。
server4安装
[root@server4 ~]# yum install -y salt-master
[root@server4 ~]# vim /etc/salt/master
order_masters: True #作为*master
[root@server4 ~]# systemctl restart salt-master.service
server1安装
[root@server1 ~]# yum install -y salt-syndic
[root@server1 ~]# vim /etc/salt/master
syndic_master: 172.25.14.4 #指向topmaster
[root@server1 ~]# systemctl restart salt-master.service
[root@server1 ~]# systemctl start salt-syndic.service
[root@server4 ~]# salt-key -L #查看下级master的连接授权
Accepted Keys:
Denied Keys:
Unaccepted Keys:
server1
Rejected Keys:
[root@server4 ~]# salt-key -A #授权
The following keys are going to be accepted:
Unaccepted Keys:
server1
Proceed? [n/Y] Y
Key for minion server1 accepted.
测试
[root@server4 salt]# salt '*' state.sls keepalived
salt-api
SaltStack 官方提供有REST API格式的 salt-api 项目,将使Salt与第三方系统集成变得尤为简单。
server1
[root@server1 ~]# yum install -y salt-api
生成认证与密钥
[root@server1 private]# pwd
/etc/pki/tls/private
[root@server1 private]# openssl genrsa 1024
[root@server1 private]# openssl genrsa 1024 > localhost.key
[root@server1 certs]# pwd
/etc/pki/tls/certs
[root@server1 certs]# make testcert
[root@server1 master.d]# vim 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]# vim auth.conf
external_auth:
pam:
saltapi:
- .*
- '@wheel'
- '@runner'
- '@jobs'
[root@server1 master.d]# useradd saltapi #创建用户saltapi
[root@server1 master.d]# echo westos | passwd --stdin saltapi # 修改密码为westos
Changing password for user saltapi.
passwd: all authentication tokens updated successfully.
启动服务,查看端口8000
[root@server1 master.d]# systemctl restart salt-master.service
[root@server1 master.d]# systemctl start salt-api
[root@server1 master.d]# netstat -antlp | grep :8000
tcp 0 0 0.0.0.0:8000 0.0.0.0:* LISTEN 13514/salt-api
tcp 0 0 127.0.0.1:36010 127.0.0.1:8000 TIME_WAIT -
认证
[root@server1 master.d]# curl -sSk https://localhost:8000/login \
> -H 'Accept: application/x-yaml' \
> -d username=saltapi \
> -d password=westos \
> -d eauth=pam
return:
- eauth: pam
expire: 1626636315.220664
perms:
- .*
- '@wheel'
- '@runner'
- '@jobs'
start: 1626593115.220662
token: e8f2b9f6c6c05f3e6a1e6a3a92cd57aad4868547 #认证必需
user: saltapi
生成Auth-Token:
[root@server1 master.d]# curl -sSk https://172.25.14.1:8000 -H 'Accept: application/x-yaml' -H 'X-Auth-Token: e8f2b9f6c6c05f3e6a1e6a3a92cd57aad4868547' -d username=saltapi -d password=westos -d client=local -d tgt='*' -d fun=test.ping
return:
- server2: true
server3: true
拓展https://github.com/qitan/SOMS/blob/master/deploy/saltapi.py
[root@server1 ~]# vim saltapi.py
#!/usr/bin/env python
# coding: utf8
'''
@author: qitan
@contact: qqing_lai@hotmail.com
@file: saltapi.py
@time: 2017/3/30 15:29
@desc:
'''
import ssl
import urllib2, urllib
# ssl._create_default_https_context = ssl._create_unverified_context
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, context=context)
content = json.loads(opener.read())
return content
def getRequest(self,prefix='/'):
url = self.__url + prefix
headers = {'X-Auth-Token' : self.__token_id}
req = urllib2.Request(url, headers=headers)
opener = urllib2.urlopen(req, context=context)
content = json.loads(opener.read())
return content
def list_all_key(self):
'''
获取包括认证、未认证salt主机
'''
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):
'''
拒绝salt主机
'''
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):
'''
接受salt主机
'''
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 salt_runner(self,jid):
'''
通过jid获取执行结果
'''
params = {'client':'runner', 'fun':'jobs.lookup_jid', 'jid': jid}
params = {}
obj = urllib.urlencode(params)
self.token_id()
content = self.getRequest(prefix='/jobs/{}'.format(jid))
#ret = content['info'][0]['Result']
return content
def salt_running_jobs(self):
'''
获取运行中的任务
'''
params = {'client':'runner', 'fun':'jobs.active'}
obj = urllib.urlencode(params)
self.token_id()
content = self.postRequest(obj)
ret = content['return'][0]
return ret
def remote_execution(self,tgt,fun,arg,expr_form):
'''
异步执行远程命令
'''
params = {'client': 'local_async', 'tgt': tgt, 'fun': fun, 'arg': arg, 'expr_form': expr_form}
obj = urllib.urlencode(params)
self.token_id()
content = self.postRequest(obj)
jid = content['return'][0]['jid']
return jid
def remote_module(self,tgt,fun,arg,kwarg,expr_form):
'''
异步部署模块
'''
params = {'client': 'local_async', 'tgt': tgt, 'fun': fun, 'arg': arg, 'expr_form': expr_form}
#kwarg = {'SALTSRC': 'PET'}
params2 = {'arg':'pillar={}'.format(kwarg)}
arg_add = urllib.urlencode(params2)
obj = urllib.urlencode(params)
obj = obj + '&' + arg_add
self.token_id()
content = self.postRequest(obj)
jid = content['return'][0]['jid']
return jid
def remote_localexec(self,tgt,fun,arg,expr_form):
params = {'client': 'local', 'tgt': tgt, 'fun': fun, 'arg': arg, 'expr_form': expr_form}
obj = urllib.urlencode(params)
self.token_id()
content = self.postRequest(obj)
ret = content['return'][0]
return ret
def salt_state(self,tgt,arg,expr_form):
'''
sls文件
'''
params = {'client': 'local', 'tgt': tgt, 'fun': 'state.sls', 'arg': arg, 'expr_form': expr_form}
obj = urllib.urlencode(params)
self.token_id()
content = self.postRequest(obj)
ret = content['return'][0]
return ret
def project_manage(self,tgt,fun,arg1,arg2,arg3,arg4,arg5,expr_form):
'''
文件上传、备份到minion、项目管理
'''
params = {'client': 'local', 'tgt': tgt, 'fun': fun, 'arg': arg1, 'expr_form': expr_form}
# 拼接url参数
params2 = {'arg':arg2}
arg_add = urllib.urlencode(params2)
obj = urllib.urlencode(params)
obj = obj + '&' + arg_add
params3 = {'arg': arg3}
arg_add = urllib.urlencode(params3)
obj = obj + '&' + arg_add
params4 = {'arg': arg4}
arg_add = urllib.urlencode(params4)
obj = obj + '&' + arg_add
params5 = {'arg': arg5}
arg_add = urllib.urlencode(params5)
obj = obj + '&' + arg_add
self.token_id()
content = self.postRequest(obj)
ret = content['return'][0]
return ret
def file_copy(self,tgt,fun,arg1,arg2,expr_form):
'''
文件上传、备份到minion、项目管理
'''
params = {'client': 'local', 'tgt': tgt, 'fun': fun, 'arg': arg1, 'expr_form': expr_form}
# 拼接url参数
params2 = {'arg':arg2}
arg_add = urllib.urlencode(params2)
obj = urllib.urlencode(params)
obj = obj + '&' + arg_add
self.token_id()
content = self.postRequest(obj)
ret = content['return'][0]
return ret
def file_bak(self,tgt,fun,arg,expr_form):
'''
文件备份到master
'''
params = {'client': 'local', 'tgt': tgt, 'fun': fun, 'arg': arg, 'expr_form': expr_form}
obj = urllib.urlencode(params)
self.token_id()
content = self.postRequest(obj)
ret = content['return'][0]
return ret
def file_manage(self,tgt,fun,arg1,arg2,arg3,expr_form):
'''
文件回滚
'''
params = {'client': 'local', 'tgt': tgt, 'fun': fun, 'arg': arg1, 'expr_form': expr_form}
params2 = {'arg': arg2}
arg_add = urllib.urlencode(params2)
obj = urllib.urlencode(params)
obj = obj + '&' + arg_add
params3 = {'arg': arg3}
arg_add_2 = urllib.urlencode(params3)
obj = obj + '&' + arg_add_2
self.token_id()
content = self.postRequest(obj)
ret = content['return'][0]
return ret
def salt_alive(self,tgt):
'''
salt主机存活检测
'''
params = {'client': 'local', 'tgt': tgt, 'fun': 'test.ping'}
obj = urllib.urlencode(params)
self.token_id()
content = self.postRequest(obj)
ret = content['return'][0]
return ret
def remote_server_info(self,tgt,fun):
'''
获取远程主机信息
'''
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 main():
sapi = SaltAPI(url='https://172.25.14.1:8000',username='saltapi',password='westos') #根据自己的情况填写
print sapi.list_all_key()
if __name__ == '__main__':
main()
server2 apache未打开
[root@server1 ~]# vim saltapi.py
def main():
sapi = SaltAPI(url='https://172.25.14.1:8000',username='saltapi',password='westos')
#print sapi.list_all_key()
sapi.deplay('server2','apache') #开启server2apache
if __name__ == '__main__':
main()
[root@server1 ~]# python saltapi.py
查看发现server2 apache已打开