文章目录
ssh
saltssh简介
基本定义
- salt-ssh是通过ssh协议执行命令进行管理服务器,不需要在服务器端安装minion客户端,如果有安装minion也可以调用minion模块,salt-ssh有点类似ansible无客户端基与ssh协议进行管理服务器,通过
roser(/etc/salt/roser)配置文件
。
应用场景
- 主要作用是不需要安装minion,只要ssh协议开放,即可远程执行命令,可用作拿到一批新机器,批量配置时使用,也可以直接通过salt-ssh不安装minion进行管理。
- salt ssh系统并不完全取代salt的通信系统。它只是简单的基于ssh协议不在依赖于ZeroMQ和salt-minion,但是由于salt ssh完全是基于ssh协议的,所以在进行远程行,
ssh的执行效率要远远低于ZeroMQ
- 创建roster系统是因为salt-ssh需要依赖这个名单来确定哪些系统如何连接并且执行。
- 因为这个roster系统属于“热插拔”类型,它可以增强附着在任何现有的系统中来收集关于哪些服务器目前可用以及可以使用salt-ssh来连接的信息
注意:此实验环境中不用装minion,不需要开启master和minion。
server2(minion)
- 关闭minion服务,方便我们观察实验现象。
[root@server2 ~]# systemctl stop salt-minion #停止 查看实验现象
server1(master)
- 安装salt-ssh。
[root@server1 2019]# yum install salt-ssh -y
- 编辑配置文件,添加要ssh连接的主机:
[root@server1 2019]# cd /etc/salt/
[root@server1 salt]# vim roster
server2:
host: 172.25.11.2
user: root #要ssh连接的用户和密码
passwd: redhat
测试
- 配置成功后直接测试,可以看到ping的结果为true。
[root@server1 salt]# salt-ssh '*' test.ping
- 查看server2的分区
[root@server1 salt]# salt-ssh server2 -r 'df' #查看server2的分区
- 查看server2的主机名。
[root@server1 salt]# salt-ssh server2 -r 'hostname'
API
- saltsatck本身就提供了一套算完整的api,使用 CherryPy 来实现 restful 的 api,供外部的程序调用。
- 官网说明: https://docs.saltstack.com/en/latest/ref/netapi/all/salt.netapi.rest_cherrypy.html
server2(minion)
- 在server2上将刚才关闭的服务再次打开。
[root@server2 ~]# systemctl start salt-minion #将关闭的服务再次打开
server1(master)
- 在server1安装salt-api。
[root@server1 salt]# yum install salt-api -y
- 在
/etc/pki/tls/private/
目录下生成key。
[root@server1 salt]# cd /etc/pki/tls/
[root@server1 tls]# cd private/
[root@server1 private]# openssl genrsa 2048 > localhost.key #生成key
[root@server1 private]# cat localhost.key #查看已经生成
- 在
/etc/pki/tls/certs
目录下生成证书,因为在这个目录下面有makefile文件,该文件里面有生成证书的相应方式,使用钥匙生成证书
[root@server1 private]# cd ..
[root@server1 tls]# cd certs/
[root@server1 certs]# make testcert #生成证书
- 在server1上
/etc/salt
下查看master
文件里面有相应的api模块文件的目录及其文件命名格式,api模版文件要在master.d
目录下且以.conf结尾。
[root@server1 ~]# vim /etc/salt/master #里写了命名格式以及文件路径
12 #default_include: master.d/*.conf
- 按照官网的格式,在
/etc/salt/master.d
目录下编辑api的配置文件添加证书及其钥匙。 - 官网:
https://docs.saltstack.com/en/latest/topics/eauth/index.html#acl-eauth
[root@server1 certs]# vim /etc/salt/master.d/api.conf #所以按要求新建这个文件
rest_cherrypy:
port: 8000 #开启端口
ssl_crt: /etc/pki/tls/certs/localhost.crt
ssl_key: /etc/pki/tls/private/localhost.key
- 要保证api文件里的证书和私钥的路径是正确的。
[root@server1 certs]# ll /etc/pki/tls/certs/localhost.crt #上面的证书和钥匙可以在系统中查到
[root@server1 certs]# ll /etc/pki/tls/private/localhost.key
- 同样的,在
/etc/salt/master.d
目录下新建认证文件,按照官网的格式写。
[root@server1 master.d]# vim /etc/salt/master.d/auth.conf #认证文件
external_auth:
pam:
saltdev: #用户名
- '.*'
- '@wheel' #允许所有的wheel模块
- '@runner'
- '@jobs'
- 添加用户saltdev,修改密码为saltdev。
[root@server1 master.d]# useradd saltdev #添加上面文件里写的saltdev用户,修改他的密码为saltdev,跟官网保持一致
[root@server1 master.d]# passwd saltdev
- 开启salt-api服务,重启salt-master服务,并查看端口8000有没有成功开启。
[root@server1 ~]# systemctl restart salt-master
[root@server1 ~]# systemctl start salt-api
[root@server1 ~]# netstat -antlp #查看8000端口已开启
- 登陆,获取token。
[root@server1 ~]# curl -sSk https://localhost:8000/login \ #登陆,获取token
> -H 'Accept: application/x-yaml' \
> -d username=saltdev \
> -d password=saltdev \
> -d eauth=pam
- 利用刚才的token,执行test.ping命令,检测所有的minion端。
#利用刚才的token,执行test.ping命令,检测所有的minion端。
[root@server1 ~]# curl -sSk https://localhost:8000 -H 'Accept: application/x-yaml' -H 'X-Auth-Token:b4d2689c7630149c88c29408d174022dd92765bb' \
> -d client=local \
> -d tgt='*' \ #目标是*
> -d fun=test.ping
Python OMT
- github官网可以找到别人写好的文件学习学习。
打印该master节点下的所有获得key的minion
[root@server1 ~]# vim saltapi.py #写一个python脚本
import urllib2,urllib
import time
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://localhost:8000',username='saltdev',password='saltdev') #修改这一行的3个参数 注意是https
#sapi.token_id()
print sapi.list_all_key() #取消注释 打印
#sapi.delete_key('test-01')
#sapi.accept_key('test-01')
#sapi.deploy('test-01','nginx')
#print sapi.remote_noarg_execution('test-01','grains.items')
if __name__ == '__main__':
main()
- 修改了2处。
- 执行此脚本,可以看到执行结果。
[root@server1 ~]# python saltapi.py
打印出server2和server3
- 列出所有的允许的key。
[root@server1 ~]# salt-key -L
开启server2的httpd服务
- 再次修改.py文件 开启server2的apache服务。
- 注意:必须确保在base目录下
(/srv/salt)
有相应的sls安装及其启动服务install.sls
或service.sls
的文件 - 修改前 先查看进程:
ps ax
,可以看到此时httpd服务未开启。
- 修改文件并执行。
[root@server1 ~]# vim saltapi.py
[root@server1 ~]# python saltapi.py
- server2再查看进程,开启httpd服务了
ps ax
开启server3的nginx服务
- 注意:必须确保在base目录下
(/srv/salt)
有相应的sls安装及其启动服务install.sls
或service.sls
的文件 - 开启server3的nginx,编辑py文件并执行。
[root@server1 ~]# vim saltapi.py
[root@server1 ~]# python saltapi.py
- 在server3查看进程
ps ax
,nginx成功开启。
注意:有可能server3开启了httpd,关闭apache,再执行一次python脚本然后再查看nginx的进程。