自动化运维-【配置管理工具】

自动化运维工具php

运维目标有三个阶段,第一是追求稳定性,第二是追求标准化,第三是追求自动化。对于第三阶段来讲,什么是运维自动化呢?简单地讲,运维自动化就是将平常重复性工做按照事先设定好的规则,在必定时间范围内自动化运行,而不须要人工参与。接下来简单介绍经常使用运维自动化工具。html

  同类自动化工具GitHub关注程度node

同类的自动化运维工具 Watch(关注) Star(点赞) Fork(复制) Contributors(贡献者)
Ansible 1387 17716 5356 1428
Saltstack 530 6678 3002 1520
Puppet 463 4044 1678 425
Chef 383 4333 1806 464
Fabric 379 7334 1235 116

  技术特性比较python

名称 Puppet SaltStack Ansible
开发语言 Ruby Python Python
客户端 无(也是缺点,机器太多的时候会变慢,串行)
二次开发 不支持 支持 支持
通讯验证
同窗加密 标准SSL协议 AES加密 OpenSSH
平台支持 AIX,BSD,HP-UX,Linux,Mac OS X,Solaris,Windows BSD,Linux,Mac OS X,Solaris,Windows AIX,BSD,HP-UX,Linux,Mac OS X,Solaris
配置文件格式 Ruby语法格式 YAML YAML
Web UI 提供 提供 提供(商业版本)
命令执行 不支持(配置模块可实现) 支持 支持

  优缺点对比mysql

名称 优点 劣势 成本
Puppet 模块由Ruby或Ruby子集编写
push命令能够便可触发变动
Web界面生成处理报表、资源清单、实时节点管理
代理运行端进行详细、深刻的报告和对节点进行配置
相对其余工具较复杂,需学习Puppet的DSL或Ruby
安装过程缺乏错误校验和产生错误报表
开源软件免费
SaltStack企业版每一年内个节点花费约¥100
Saltstack 状态文件可用简单YAML配置模块或复杂的Python/PyDSL脚本
与客户端能够基于SSH或在被管节点安装代理
Web界面可看到运行的工做、minion状态、事件日志、可在客户端执行命令
扩展能力极强
Web界面像毒药竞争产品不稳定与相对不完善
缺少生成深度报告的能力
开源软件免费
SaltStack企业版每一年内个节点花费约¥150,随着数量增长相应的会有折扣
Ansible 模块能够用任何语言开发
备管节点不须要安装代理软件
有Web管理界面、可配置用户、组、资源清单和执行Playbook
安装、运行极其简单
对备管理节点为Windows有待增强
Web管理界面是内置的Ansible的一部分
需导入资源清单
执行效率较低
开源版本免费
Ansible Tower小于10台被管理节点免费
超过10太后没年每台需支付¥100~$250的支持服务费用

 

 

1.Fabriclinux

Fabric 是一个用 Python 编写的命令行工具库,它能够帮助系统管理员高效地执行某些任务,好比经过 SSH 到多台机器上执行某些命令,远程布署应用等。ios

1.1.安装nginx

yum -y install python-devel 安装python-devel
wget https://bootstrap.pypa.io/get-pip.py & python get-pip.py安装pip
pip install fabric 安装fabric
fab 测试
View Code

1.2.例子web

#!/usr/bin/env python
# coding: utf-8

"""
 查看本地与远程主机信息
 
 
 经常使用API搜索
 local 执行本地命令, local('unamr -a')
 lcd 切换本地目录, lcd('/home')
 cd 切换远程目录, cd('/var/log')
 run 执行远程命令, run('free -m')
 sudo sudo方式执行远程命令, sudo('service httpd reload')
 put 上传本地文件到远程主机, put('/home/1.txt', '/data/1.txt')
 get 从远程主机下载文件到本地, get('/home/1.txt', '/data/1.txt')
 prompt 获取用户输入信息, prompt('please input user password: ')
 confirm 获取提示信息确认, confirm('Tests failed.Continue(Y/N)? ')
 reboot 重启远程主机, reboot()
 @runs_once 函数装饰符, 标识的函数只会执行一次, 不受多台主机影响
 
"""

from fabric.api import *

env.user = 'root'
env.hosts = ['192.168.1.7', '192.168.1.8']
env.password = '456852.com'

@runs_once #查看本地系统信息, 当有多台主机时,只运行一台
def local_task(): #本地任务函数
 local('uname -a')

def remote_task():
 with cd('/var/log'): #with 的做用是让后面的表达式的语句继承当前状态, 实现 'cd /var/log && ls -l'
  run('ls -l')
使用方法
#!/usr/bin/python
# -*- coding:utf-8 -*-

from fabric.api import *

# 设置服务器登陆参数
env.roledefs = {
    # 操做一致的放一组,一组执行同一个操做
    'servers1':['root@linux2:22',],
    # 第二组
    'servers2':['root@linux3:22',]
}

# 本机操做
def localtask():
    local('/usr/local/nginx/nginx')

# servers1服务器组操做
@roles('servers1')
def task1():
    run('/usr/local/tomcat/bin/startup.sh')

# servers2 服务器组操做
@roles('servers2')
def task2():
    run('/usr/local/tomcat/bin/startup.sh')

# 执行任务
def doworks():
    execute(localtask)
    execute(task1)
    execute(task2)
View Code
#!/bin/bash
# -*- coding: utf-8 -*-
import paramiko,os,time,shutil
from fabric.api import *
from fabric.colors import *

env.user = 'root'
env.hosts = ['192.168.10.241','192.168.10.242','192.168.10.243','192.168.10.244','192.168.10.245']
env.passwords = {
        'root@192.168.10.241:22':'p3mtk',
        'root@192.168.10.242:22':'VU6w3',
        'root@192.168.10.243:22':'1uP1P',
        'root@192.168.10.244:22':'6tznM7',
        'root@192.168.10.245:22':'4DXkv5',
}
os.system("""rm -r -f pid_test.log""")
os.system("""date>> /home/post/serverpid/pid.log""")
os.system("""date>> /home/post/serverpid/pid_test.log""")
os.system("""echo ================================================================================>> /home/post/serverpid/pid.log""")
os.system("""echo ================================================================================>> /home/post/serverpid/pid_test.log""")

#@runs_once
#def clear_log():
#    local("""echo ''>>/home/post/serverpid/pid_test.log""")
def test():
    local("""echo ''>>/home/post/serverpid/pid_test.log""")
    with settings(hide('running','stdout', 'stderr','warnings','everything')):
                h2 = "ps -ef|grep home/lcs/web/tomcat-job/bin/bootstrap|grep -v grep|awk '{print $2}'" #192.168.10.245
                h3 = "ps -ef|grep robot|grep -v grep|awk '{print $2}'"  #192.168.10.241,192.168.10.242,192.168.10.243
                h4 = "ps -ef|grep mysql|grep -v grep|awk '{print $2}'"  #192.168.10.245
                h5 = "ps -ef|grep redis|grep -v grep|awk '{print $2}'"  #192.168.10.245
                h6 = "ps -ef|grep zookeeper|grep -v grep|awk '{print $2}'"  #192.168.10.241,192.168.10.242,192.168.10.243
                h7 = "ps -ef|grep IPProxy.py|grep -v grep|awk '{print $2}'" #192.168.10.244

                if env.host == '192.168.10.245':
                        result_245_tomcat = run(h2)
                        result_245_redis = run(h4)
                        result_245_mysql = run(h5)
                        if (result_245_tomcat == "") or (result_245_mysql == "") or (result_245_redis == ""):
                                local("""echo '%s'' %s' 执行失败,PID为‘%s’>>/home/post/serverpid/pid.log"""%(env.host,h2,result_245_tomcat))
                                local("""echo '%s'' %s' 执行失败,PID为‘%s’>>/home/post/serverpid/pid.log"""%(env.host,h4,result_245_mysql))
                                local("""echo '%s'' %s' 执行失败,PID为‘%s’>>/home/post/serverpid/pid.log"""%(env.host,h5,result_245_redis))
                                local("""echo '%s'' %s' 执行失败,PID为‘%s’>>/home/post/serverpid/pid_test.log"""%(env.host,h2,result_245_tomcat))
                                local("""echo '%s'' %s' 执行失败,PID为‘%s’>>/home/post/serverpid/pid_test.log"""%(env.host,h4,result_245_mysql))
                                local("""echo '%s'' %s' 执行失败,PID为‘%s’>>/home/post/serverpid/pid_test.log"""%(env.host,h5,result_245_redis))

                        else:
                                local("""echo '%s'' %s' 执行成功,PID为‘%s’>>/home/post/serverpid/pid.log"""%(env.host,h2,result_245_tomcat))
                                local("""echo '%s'' %s' 执行成功,PID为‘%s’>>/home/post/serverpid/pid.log"""%(env.host,h4,result_245_mysql))
                                local("""echo '%s'' %s' 执行成功,PID为‘%s’>>/home/post/serverpid/pid.log"""%(env.host,h5,result_245_redis))
                                local("""echo '%s'' %s' 执行成功,PID为‘%s’>>/home/post/serverpid/pid_test.log"""%(env.host,h2,result_245_tomcat))
                                local("""echo '%s'' %s' 执行成功,PID为‘%s’>>/home/post/serverpid/pid_test.log"""%(env.host,h4,result_245_mysql))
                                local("""echo '%s'' %s' 执行成功,PID为‘%s’>>/home/post/serverpid/pid_test.log"""%(env.host,h5,result_245_redis))
                               #print yellow("%s 执行成功...") %env.host
                elif env.host == '192.168.10.244':
                        result_244_ipproxy = run(h7)
                        if (result_244_ipproxy == ""):
                                local("""echo '%s'' %s' 执行失败,PID为空>>/home/post/serverpid/pid.log"""%(env.host,h7))
                                local("""echo '%s'' %s' 执行失败,PID为空>>/home/post/serverpid/pid_test.log"""%(env.host,h7))
                                #abort(red("错误..."))
                        else:
                                local("""echo '%s'' %s' 执行成功>>/home/post/serverpid/pid.log"""%(env.host,h7))
                                local("""echo '%s'' %s' 执行成功>>/home/post/serverpid/pid_test.log"""%(env.host,h7))
                                #print yellow("%s 执行成功...") %env.host
                else:
                        result_robot = run(h3)
                        result_zookeeper = run(h6)
                        if result_robot.strip('\n') == '':
                                local("""echo '%s'' %s' 执行失败,PID为空>>/home/post/serverpid/pid.log"""%(env.host,h3))
                local("""echo '%s'' %s' 执行失败,PID为空>>/home/post/serverpid/pid_test.log"""%(env.host,h3))
                        elif result_zookeeper.strip('\n') =='':
                                local("""echo '%s'' %s' 执行失败,PID为空>>/home/post/serverpid/pid.log"""%(env.host,h6))
                                local("""echo '%s'' %s' 执行失败,PID为空>>/home/post/serverpid/pid_test.log"""%(env.host,h6))
                        else:
                                local("""echo '%s'' %s' 执行成功>>/home/post/serverpid/pid.log"""%(env.host,h3))
                                local("""echo '%s'' %s' 执行成功>>/home/post/serverpid/pid.log"""%(env.host,h6))
                                local("""echo '%s'' %s' 执行成功>>/home/post/serverpid/pid_test.log"""%(env.host,h3))
                                local("""echo '%s'' %s' 执行成功>>/home/post/serverpid/pid_test.log"""%(env.host,h6))
                #print yellow("%s 执行成功...") %env.host
def go():
    test()
View Code
alarm_msg = local(zabbix_off,capture=True)
说明:capture=True参数默认值是False,表示输出到终端)

调用:fab -f test.py remote_task
帮助:fab --help
注意

 

2.Paramikoredis

  paramiko模块,基于SSH用于链接远程服务器并执行相关操做。使用该模块能够对远程服务器进行命令或文件操做,值得一说的是,fabric和ansible内部的远程管理就是使用的paramiko来现实。

2.1.安装paramiko

pip3 install paramiko

2.2.使用paramiko

  sshclient

import paramiko
   
# 建立SSH对象
ssh = paramiko.SSHClient()
# 容许链接不在know_hosts文件中的主机
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
# 链接服务器
ssh.connect(hostname='c1.salt.com', port=22, username='wupeiqi', password='123')
   
# 执行命令
stdin, stdout, stderr = ssh.exec_command('ls')
# 获取命令结果
result = stdout.read()
   
# 关闭链接
ssh.close()
基于用户名密码链接远程主机
import paramiko
  
private_key = paramiko.RSAKey.from_private_key_file('/home/auto/.ssh/id_rsa')
  
# 建立SSH对象
ssh = paramiko.SSHClient()
# 容许链接不在know_hosts文件中的主机
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
# 链接服务器
ssh.connect(hostname='c1.salt.com', port=22, username='wupeiqi', key=private_key)
  
# 执行命令
stdin, stdout, stderr = ssh.exec_command('df')
# 获取命令结果
result = stdout.read()
  
# 关闭链接
ssh.close()
基于公钥链接远程主机

  sshcilent是传统的链接服务器、执行命令、关闭的一个操做,有时候须要登陆上服务器执行多个操做,好比执行命令、上传/下载文件,方法1则没法实现,能够经过以下方式来操做

# 实例化一个transport对象
trans = paramiko.Transport(('192.168.2.129', 22))
# 创建链接
trans.connect(username='super', password='super')

# 将sshclient的对象的transport指定为以上的trans
ssh = paramiko.SSHClient()
ssh._transport = trans
# 执行命令,和传统方法同样
stdin, stdout, stderr = ssh.exec_command('df -hl')
print(stdout.read().decode())

# 关闭链接
trans.close()
--------------------- 
做者:songfreeman 
来源:CSDN 
原文:https://blog.csdn.net/songfreeman/article/details/50920767 
版权声明:本文为博主原创文章,转载请附上博文连接!
基于transport的用户名密码登陆
# 指定本地的RSA私钥文件,若是创建密钥对时设置的有密码,password为设定的密码,如无不用指定password参数
pkey = paramiko.RSAKey.from_private_key_file('/home/super/.ssh/id_rsa', password='12345')
# 创建链接
trans = paramiko.Transport(('192.168.2.129', 22))
trans.connect(username='super', pkey=pkey)

# 将sshclient的对象的transport指定为以上的trans
ssh = paramiko.SSHClient()
ssh._transport = trans

# 执行命令,和传统方法同样
stdin, stdout, stderr = ssh.exec_command('df -hl')
print(stdout.read().decode())

# 关闭链接
trans.close()
--------------------- 
做者:songfreeman 
来源:CSDN 
原文:https://blog.csdn.net/songfreeman/article/details/50920767 
版权声明:本文为博主原创文章,转载请附上博文连接!
基于transport的秘钥登陆

  sftpclient

import paramiko
  
transport = paramiko.Transport(('hostname',22))
transport.connect(username='wupeiqi',password='123')
  
sftp = paramiko.SFTPClient.from_transport(transport)
# 将location.py 上传至服务器 /tmp/test.py
sftp.put('/tmp/location.py', '/tmp/test.py')
# 将remove_path 下载到本地 local_path
sftp.get('remove_path', 'local_path')
  
transport.close()
基于用户名密码上传
import paramiko
  
private_key = paramiko.RSAKey.from_private_key_file('/home/auto/.ssh/id_rsa')
  
transport = paramiko.Transport(('hostname', 22))
transport.connect(username='wupeiqi', pkey=private_key )
  
sftp = paramiko.SFTPClient.from_transport(transport)
# 将location.py 上传至服务器 /tmp/test.py
sftp.put('/tmp/location.py', '/tmp/test.py')
# 将remove_path 下载到本地 local_path
sftp.get('remove_path', 'local_path')
  
transport.close()
基于秘钥进行上传

3.demo

#!/usr/bin/env python
# -*- coding:utf-8 -*-
import paramiko
import uuid

class SSHConnection(object):

    def __init__(self, host='172.16.103.191', port=22, username='wupeiqi',pwd='123'):
        self.host = host
        self.port = port
        self.username = username
        self.pwd = pwd
        self.__k = None

    def create_file(self):
        file_name = str(uuid.uuid4())
        with open(file_name,'w') as f:
            f.write('sb')
        return file_name

    def run(self):
        self.connect()
        self.upload('/home/wupeiqi/tttttttttttt.py')
        self.rename('/home/wupeiqi/tttttttttttt.py', '/home/wupeiqi/ooooooooo.py)
        self.close()

    def connect(self):
        transport = paramiko.Transport((self.host,self.port))
        transport.connect(username=self.username,password=self.pwd)
        self.__transport = transport

    def close(self):

        self.__transport.close()

    def upload(self,target_path):
        # 链接,上传
        file_name = self.create_file()

        sftp = paramiko.SFTPClient.from_transport(self.__transport)
        # 将location.py 上传至服务器 /tmp/test.py
        sftp.put(file_name, target_path)

    def rename(self, old_path, new_path):

        ssh = paramiko.SSHClient()
        ssh._transport = self.__transport
        # 执行命令
        cmd = "mv %s %s" % (old_path, new_path,)
        stdin, stdout, stderr = ssh.exec_command(cmd)
        # 获取命令结果
        result = stdout.read()

    def cmd(self, command):
        ssh = paramiko.SSHClient()
        ssh._transport = self.__transport
        # 执行命令
        stdin, stdout, stderr = ssh.exec_command(command)
        # 获取命令结果
        result = stdout.read()
        return result
        


ha = SSHConnection()
ha.run()
demo

4.实现输入命令立马返回结果的功能 

以上操做都是基本的链接,若是咱们想实现一个相似xshell工具的功能,登陆之后能够输入命令回车后就返回结果:

import paramiko
import os
import select
import sys

# 创建一个socket
trans = paramiko.Transport(('192.168.2.129', 22))
# 启动一个客户端
trans.start_client()

# 若是使用rsa密钥登陆的话
'''
default_key_file = os.path.join(os.environ['HOME'], '.ssh', 'id_rsa')
prikey = paramiko.RSAKey.from_private_key_file(default_key_file)
trans.auth_publickey(username='super', key=prikey)
'''
# 若是使用用户名和密码登陆
trans.auth_password(username='super', password='super')
# 打开一个通道
channel = trans.open_session()
# 获取终端
channel.get_pty()
# 激活终端,这样就能够登陆到终端了,就和咱们用相似于xshell登陆系统同样
channel.invoke_shell()
# 下面就能够执行你全部的操做,用select实现
# 对输入终端sys.stdin和 通道进行监控,
# 当用户在终端输入命令后,将命令交给channel通道,这个时候sys.stdin就发生变化,select就能够感知
# channel的发送命令、获取结果过程其实就是一个socket的发送和接受信息的过程
while True:
    readlist, writelist, errlist = select.select([channel, sys.stdin,], [], [])
    # 若是是用户输入命令了,sys.stdin发生变化
    if sys.stdin in readlist:
        # 获取输入的内容
        input_cmd = sys.stdin.read(1)
        # 将命令发送给服务器
        channel.sendall(input_cmd)

    # 服务器返回告终果,channel通道接受到结果,发生变化 select感知到
    if channel in readlist:
        # 获取结果
        result = channel.recv(1024)
        # 断开链接后退出
        if len(result) == 0:
            print("\r\n**** EOF **** \r\n")
            break
        # 输出到屏幕
        sys.stdout.write(result.decode())
        sys.stdout.flush()

# 关闭通道
channel.close()
# 关闭连接
trans.close()
--------------------- 
做者:songfreeman 
来源:CSDN 
原文:https://blog.csdn.net/songfreeman/article/details/50920767 
版权声明:本文为博主原创文章,转载请附上博文连接!
View Code

5.支持tab命令补全

import paramiko
import os
import select
import sys
import tty
import termios

'''
实现一个xshell登陆系统的效果,登陆到系统就不断输入命令同时返回结果
支持自动补全,直接调用服务器终端

'''
# 创建一个socket
trans = paramiko.Transport(('192.168.2.129', 22))
# 启动一个客户端
trans.start_client()

# 若是使用rsa密钥登陆的话
'''
default_key_file = os.path.join(os.environ['HOME'], '.ssh', 'id_rsa')
prikey = paramiko.RSAKey.from_private_key_file(default_key_file)
trans.auth_publickey(username='super', key=prikey)
'''
# 若是使用用户名和密码登陆
trans.auth_password(username='super', password='super')
# 打开一个通道
channel = trans.open_session()
# 获取终端
channel.get_pty()
# 激活终端,这样就能够登陆到终端了,就和咱们用相似于xshell登陆系统同样
channel.invoke_shell()

# 获取原操做终端属性
oldtty = termios.tcgetattr(sys.stdin)
try:
    # 将如今的操做终端属性设置为服务器上的原生终端属性,能够支持tab了
    tty.setraw(sys.stdin)
    channel.settimeout(0)

    while True:
        readlist, writelist, errlist = select.select([channel, sys.stdin,], [], [])
        # 若是是用户输入命令了,sys.stdin发生变化
        if sys.stdin in readlist:
            # 获取输入的内容,输入一个字符发送1个字符
            input_cmd = sys.stdin.read(1)
            # 将命令发送给服务器
            channel.sendall(input_cmd)

        # 服务器返回告终果,channel通道接受到结果,发生变化 select感知到
        if channel in readlist:
            # 获取结果
            result = channel.recv(1024)
            # 断开链接后退出
            if len(result) == 0:
                print("\r\n**** EOF **** \r\n")
                break
            # 输出到屏幕
            sys.stdout.write(result.decode())
            sys.stdout.flush()
finally:
    # 执行完后将如今的终端属性恢复为原操做终端属性
    termios.tcsetattr(sys.stdin, termios.TCSADRAIN, oldtty)

# 关闭通道
channel.close()
# 关闭连接
trans.close()
--------------------- 
做者:songfreeman 
来源:CSDN 
原文:https://blog.csdn.net/songfreeman/article/details/50920767 
版权声明:本文为博主原创文章,转载请附上博文连接!
View Code

 

3.Saltstack

Salt,一种全新的基础设施管理方式,部署轻松,在几分钟内可运行起来,扩展性好,很容易管理上万台服务器,速度够快,服务器之间秒级通信。 SaltStack是使用Python语言开发,同时提供Rest API方便二次开发以及和其它平台进行集成。
Salt底层采用动态的链接总线, 使其能够用于远程执行(最先是作远程执行), 配置管理(状态管理),云管理(salt-cloud)和事件驱动等等。
详细介绍  官方文档  saltstack原理

1.安装配置

1.关闭防火墙和selinux
中止: systemctl disable firewalld
禁用: systemctl stop firewalld

vi /etc/selinux/config
将SELINUX=enforcing改成SELINUX=disabled

2.修改master和minion的host(也能够不修改)
192.168.10.231 node1    #master 和minion
192.168.10.232 node2    #minion

3.master和minion添加阿里源
wget -O /etc/yum.repos.d/epel.repo http://mirrors.aliyun.com/repo/epel-7.repo
或者使用saltstack源
sudo yum install -y https://repo.saltstack.com/yum/redhat/salt-repo-latest-2.el7.noarch.rpm

4.安装saltstack
服务器安装:yum -y install salt-master salt-minion       #master服务器端既安装master服务也安装minion服务
客户端安装:yum -y install salt-minion                   #minion服务器只安装minion服务

5.启动master和minion

systemctl enable /usr/lib/systemd/system/salt-master.service
systemctl start salt-master

systemctl enable /usr/lib/systemd/system/salt-minion.service
systemctl start salt-minion

6.配置
服务器配置:配置文件在/etc/salt下 注意:masterhe和minion的配置文件多一个空格都会报错(注意:服务器端的配置能够不用写,只配置minion端就ok)
[root@node1 ~]# grep -vE "^$|#" /etc/salt/master
interface: 192.168.10.231

客户端配置:
[root@node2 ~]# grep -vE "^$|#" /etc/salt/minion
master: 192.168.10.231          #修改为master的ip,写域名也能够,若是有内部dns的话
id: node2                       #能够修改成ip地址,这样就必须以ip地址为惟一性。通常不修改

2.master和minion的公钥交互过程

1.首先咱们来看minion服务器的配置文件
minion服务器 [root@node2 salt]# tree
/etc/salt/ . ├── cloud ├── cloud.conf.d ├── cloud.deploy.d ├── cloud.maps.d ├── cloud.profiles.d ├── cloud.providers.d ├── master ├── master.d ├── minion ├── minion.d ├── minion_id #很是重要 ├── pki │   ├── master │   └── minion │   ├── minion.pem #公钥 │   └── minion.pub #私钥 ├── proxy ├── proxy.d └── roster 咱们在上一步已经将minion的配置文件中的id改为主机名。再看id参数的解释时候发现,若是id不设置,minion服务器会获取一个socket.getfqdn()的fqdn的名称,放置在minion_id文件里面,若是刚开始没设置id参数,后来设置的话,须要将minion_id文件删除,至关于删除魂缓存,而后从新启动。 在通常的游戏公司会将id设置成ip地址,来确保惟一性。 pki目录是minion在第一次启动以后生成的机器公钥和私钥,nminion将本身的公钥(minion.pem)发送给matser,先放在master的/etc/salt/pki/minions_pre下,而且以minion配置文件中的id命名(相似:linux-node1.example.com,其中linux-node1是你机器的主机名称) 2.其次查看master服务器的配置文件 master服务器 [root@node1 pki]# tree /etc/salt/pki/ #存放minion服务器发送过来的公钥的目录 . ├── master │   ├── master.pem │   ├── master.pub │   ├── minions #活动的 │   ├── minions_autosign #注册的 │   ├── minions_denied #不容许的 │   ├── minions_pre #存放minio服务器发送过来的公钥 │   │   ├── node1 │   │   └── node2 │   └── minions_rejected #拒绝的 └── minion ├── minion.pem └── minion.pub master在第一次启动的时候会建立master文件夹,里面有如上文件夹,在minion服务器将公钥发过来以后,master要进行认证。使用salt-key命令来认证,其中salt-key -a(容许一个) node* 是支持通配符的,salt-key -A(容许全部) 不支持通配符 [root@node1 master]# salt-key -a node* ,输入y确认 Accepted Keys: #容许的minion Denied Keys: #不容许的minion Unaccepted Keys: #未认证的minion node1 node2 Rejected Keys: #拒绝的minion 3.接下来,看minion服务器的配置文件发生了什么变化 minion服务器 [root@node2 salt]# tree . ├── cloud ├── cloud.conf.d ├── cloud.deploy.d ├── cloud.maps.d ├── cloud.profiles.d ├── cloud.providers.d ├── master ├── master.d ├── minion ├── minion_id #很是重要 ├── minion.d │   └── _schedule.conf ├── pki │   ├── master │   └── minion │   ├── minion_master.pub #master的服务器的公钥 │   ├── minion.pem │   └── minion.pub ├── proxy ├── proxy.d └── roster 咱们能看到/etc/salt/pki/minion目录下多了一个minion_master.pub文件,这个是在刚才master服务器认证命令执行以后,matser发给minion服务器的公钥,这样双方就能够通讯了
4.接下来,看master服务器配置文件发生了什么变化 matser服务器 [root@node1 pki]# tree
/etc/salt/pki . ├── master │   ├── master.pem │   ├── master.pub │   ├── minions │   │   ├── node1 │   │   └── node2 │   ├── minions_autosign │   ├── minions_denied │   ├── minions_pre │   └── minions_rejected └── minion ├── minion_master.pub ├── minion.pem └── minion.pub 7 directories, 7 files 咱们能够看到,minions_pre下的公钥转移到了minions,而且,minion本身的minion_master.pub公钥也放到了对应目录, master只能管理/etc/salt/pki/master/minions目录里面的机器,这就是master和minion的验证步骤,很是安全,其中传输过程是经过AES算法来加密的


注意:若是想更改minion配置文件里面的id该如何作那?
  1.将要修改的minion服务器从master同一列表里面删除,使用salt-key -d id名
  2.在minion服务器上将minion服务停掉
  3.删除minion服务器/etc/salt/pki目录
  4.删掉/etc/salt/目录下的minion_id文件
  5.在配置文件里面修改minion的id
  6.从新启动,在master上从新添加minion
 

接下来咱们查看salt-master安装了那些文件,方便咱们了解saltsatck的往后操做
master上:
  [root@centos7-node1 ~]# rpm -ql salt-master
  /etc/salt/master #salt-master的配hi文件爱你
  /usr/bin/salt #salt-master操做的核心命令
  /usr/bin/salt-cp #salt文件传输命令
  /usr/bin/salt-key #salt证书管理命令
  /usr/bin/salt-master #salt master 服务命令
  /usr/bin/salt-run #saltmaster runner 命令
  /usr/bin/salt-unity
  /usr/lib/systemd/system/salt-master.service #salt-master服务启动脚本
  /usr/share/man/man1/salt-cp.1.gz
  /usr/share/man/man1/salt-key.1.gz
  /usr/share/man/man1/salt-master.1.gz
  /usr/share/man/man1/salt-run.1.gz
  /usr/share/man/man1/salt-unity.1.gz
  /usr/share/man/man7/salt.7.gz
minion:
[root@centos7-node2 salt]# rpm -ql salt-minion
  /etc/salt/minion #minion服务器配置文件
  /usr/bin/salt-call #minion salt-call命令
  /usr/bin/salt-minion #salt minion服务命令
  /usr/lib/systemd/system/salt-minion.service #minion服务启动脚本
  /usr/share/man/man1/salt-call.1.gz
  /usr/share/man/man1/salt-minion.1.gz

master配置文件中重要的参数:
  
max_open_files :能够根据master将minion的数量进行适当的调整
  timeout:能够根据master和minion的网络状态调整
  auto_accpet和autosign_file :在大规模部署minion的时候设置自动签证
  master_tops和全部以external开头的参数:是saltstack与外部系统进行整合相关配置参数

 3.学习saltstack的命令

第一个salt命令,检查通讯是否正常
  salt(命令) '*'(匹配目标) test.ping(test模块里面的ping函数,注意:这里面的ping不是icmp的那个ping命令)
  [root@node1 pki]# salt '*' test.ping   node2:    True   node1:    True   [root@node1 pki]#
第二个salt命令。也能够叫超级命令
[root@node1 pki]# salt \* cmd.run 'id'
node2:
uid=0(root) gid=0(root) groups=0(root)
node1:
uid=0(root) gid=0(root) groups=0(root)
[root@node1 pki]#

3.1 salt命令附加

salt -h
usage: salt [options] '<target>' <function> [arguments]

options:操做参数 state:salt中的配置管理系统 target:salt中的管理对象或者叫操做目标参数(服务器)   
-E:正则匹配 --pcre   -L:列表匹配 --list   -G:grains匹配 --grain   -N:组匹配 --nodegroup   -R:范围匹配 --range   -C:综合匹配,指的多个条件匹配 --compound   —I:pillar值匹配 --pillar   —S:minion网段匹配 --ipcidr

4.master和minion通讯

在saltstack中使用了zeromq队列来出来master和minion之间的并发执行命令
[root@node1 pki]# lsof -ni:4505
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
salt-mast 7791 root 16u IPv4 5889405 0t0 TCP *:4505 (LISTEN)
salt-mast 7791 root 18u IPv4 5924298 0t0 TCP 192.168.10.231:4505->192.168.10.232:49386 (ESTABLISHED)
salt-mast 7791 root 19u IPv4 5925223 0t0 TCP 192.168.10.231:4505->192.168.10.231:42746 (ESTABLISHED)
salt-mini 9629 root 21u IPv4 5923723 0t0 TCP 192.168.10.231:42746->192.168.10.231:4505 (ESTABLISHED)
[root@node1 pki]#
能够看到master全部的命令都经过监听4505端口,来进行并行(zeromq)处理命令,处理结果经过matser的4506端口来接受

 5.salt配置管理

默认saltstack配置管理的配置文件的格式为yaml,类型xml标记语言
数据结构能够用相似大纲的缩排方式呈现,结构经过缩进来表示,连续的项目经过减号“-”来表示,map结构里面的key/value对用冒号“:”来分隔。样例以下:
house:
  family:
    name: Doe
    parents:
      - John
      - Jane
    children:
      - Paul
      - Mark
      - Simone
  address:
    number: 34
    street: Main Street
    city: Nowheretown
    zipcode: 12345
-短横线表明列表
缩进是两个空格,

5.1配置管理
saltstack自带一个文件“File Server settings“设置的小系统,经过设置它,来告诉saltstack来读取配置文件
打开master的配置文件,找到first_root,打开注释(若是只有一个,那么base是必须存在的,开发,运维,测试可使用不一样的文件,就能够按照下面的来建立)
file_roots:
base:
- /srv/salt/base
建立目录: mkdir -p /srv/salt/base/web(最后的文件起什么名字均可以,只是为了和想配置其余服务区分开,若是你要配置mysql,就能够再建立mysql)
从新启动master:systemctl restart master
进入/srv/salt/base/web目录下,建立配置文件(配置文件的后缀名称必须以.sls结尾)
vim apache.sls,进行编辑
apache-install: #在配置文件中顶格写,个人理解是id,就是给你要安装的软件起个名字,用来区分配置文件中其余要安装的软件
pkg.installed: #在配置文件两个空格后开始写,pkg是一个模块,installed是模块中的一个安装方法,pgk的模块会匹配你的操做系统而后使用各个系统的安装方法
- name: sysstat #在配置文件中四个空格后开始写,https是要安装的服务名称
apache-service:
service.running: #service是一个状态模块,running是模块中的一个running性方法
- name: httpd #要运行的服务名称,启动的时候service也会去判断系统,而后使用系统的启动方法
- enable: True #enable是开机自启
注意:必定不要用tab键,和空格数量要确认好

确认配置:
  1.master中的
File Server settings的配置是
file_roots:
base:
- /srv/salt/base
dev:
- /srv/salt/dev
test:
- /srv/salt/test
prod:
- /srv/salt/prod
  2.肯定文件路径
  
[root@node1 salt]# ll /srv/salt/base/web
  total 4
  -rw-r--r-- 1 root root 54 Nov 29 05:25 apache.sls
  3.肯定内容是否按照yaml标准来执行编写的

肯定执行结果:
salt 'node2' state.sls web.apache saltenv=prod
  #salt是命令
  #‘node2’是在什么主机上执行
  #stata.sls是远程执行命令
  #web.apache是在
/srv/salt/base/下web目录里面的apache
  #saltenv=prod是默认在这个base目录下执行,若是要在
/srv/salt/prod目录下执行的话,要加上该句

  [root@node1 salt]# salt 'node2' state.sls web.apache
  node2:
  ----------
  ID: apache-install
  Function: pkg.installed
  Name: sysstat
  Result: True
  Comment: All specified packages are already installed
  Started: 05:56:09.247803
  Duration: 1505.008 ms
  Changes:

  Summary for node2
  ------------
  Succeeded: 1
  Failed: 0
  ------------
  Total states run: 1
  Total run time: 1.505 s
  [root@node1 salt]# 

5.2top.sls,能体现saltstack的自动化,能指定minion具体作什么
必须写在base目录下,而且文件名字必须为top.sls
vim top.sls
base:
'node1': #表明全部机器
- web.apache #表明使用top.sls执行web目录下的apache.sls,可是要注意,不加.sls后缀名

执行salt '*' state.highstate
[root@node1 base]# salt '*' state.highstate
node2:
----------
ID: states
Function: no.None
Result: False
Comment: No Top file or master_tops data matches found.
Changes:
Summary for node2------------
Succeeded: 0
Failed: 1
------------
Total states run: 1
Total run time: 0.000 ms
node1:
----------
ID: sysstat-install
Function: pkg.installed
Name: sysstat
Result: True
Comment: The following packages were installed/updated: sysstat
Started: 06:21:18.206403
Duration: 9034.407 ms
Changes:
---------
sysstat:
----------
new:
10.1.5-13.el7
old:
Summary for node1
------------
Succeeded: 1 (changed=1)
Failed: 0
------------
Total states run: 1
Total run time: 9.034 s

能够看到node1执行成功,而node2没有执行成功,缘由是:
  base目录下的top.sls里面要执行的主机写的是'node1',而不是*,虽然
salt '*' state.highstate 高级命令里面指定了‘*’,这只是通知全部的主机将要执行什么操做,可是收到消息的主机能够不执行,觉得你饿在top.sls配置里只是指定了‘node1’须要安装
salt '*' state.highstate test=True 是用做测试可是不执行  很重要的参数

  6.saltstack组件(数据存储系统)

(saltstack技术入门与实战:2.2)

Grains
  存放着salt minion启动时收集到的信息,运行的过程当中不收集,相对来讲是静态的信息,能够用做收集资产管理,作自动化信息查询
Grains的应用场景
  Grains能够在state系统中使用,用于配置管理模块。
  Grains能够在target中使用,再用来匹配minion,好比匹配操做系统,使用-G选项。
  Grains能够用于信息查询,Grains保存着收集到的客户端的详细信息。

收集自定义的Grains信息
  经过minion配置文件
  经过grains相关模块定义
  经过python脚本定义

查看grains命令
  salt 'node2' sys.doc grains 查看全部grains的详细用法

命令详解
  1.列出minion可用的Grains名称
    Available grains can be listed by using the 'grains.ls' module
    salt 'node1' grains.ls
  2.列出Grains详细数据
    Grains data can be listed by using the 'grains.items' module(超级详细)
    salt 'saltstack-node1*' grains.items
    只显示item 里的os值,注意item后面没有s
    salt '*' grains.item os
  3.获取指定的Grains信息
    salt 'node1*' grains.get ip4_interfaces
  4.在指定的机器上执行操做
    
salt -G 'os:CentOS' cmd.run 'uptime'

自定义grains
  1.经过top.sls来自定义
  
[root@node1 base]# cat /srv/salt/base/top.sls
  base:
   'os:CentOS':
   - match: grain
   - web.apache
  这个top.sls的意思就是,经过grains来匹配出全部的os等于CentOS的机器,并执行web目录下的apache.sls
  执行top.sls :salt '*' state.highstate
  说的简单一点就是在top.sls里面经过grains进行匹配
  
  2.编辑/etc/salt/grains在里面进行自定义
   这种配置方式有个优势,能够把自定义的grains抽取出来,把配置写好后,再批量分发给不一样的minion端,这样就能够统一自定义的grains,并且配置还特别简单。
salt '*' saltutil.sync_grains #刷新
  验证命令:
   #注意写法!test表明测试环境。
  [root@saltstack-node1 ~]# vim /etc/salt/grains
   cloud: openstack
  roles:
   - nginx
   - php
  env: test
  #配置完成后,必需要重启minion服务,或者执行:  salt 'saltstack-node1*' grains.get cloud
  salt 'saltstack-node1*' grains.get roles
  salt 'saltstack-node1*' grains.get env
  3.能够在/etc/salt/minion的配置文件里面那些,可是这样写比较混乱,不建议这样写

Pillar
能够给指定的minion定义其须要的数据,只有指定的人才能看其数据,通常存放比较重要的数据,觉得你饿pillar比较安全,通常在master上设置
定义pillar
  其实pillar与配置管理的F
ile Server settings的配置很像
  打开vim /etc/salt/master,搜索pillar_roots,去掉注释
  pillar_roots:
base:
- /srv/pillar/base
   prod:
   - /srv/pillar/prod
  建立
/srv/pillar/prod和/srv/pillar/base目录,mkdir -p /srv/pillar/{base,prod}
  从新启动master,systemctl restart salt-master

  文章

7.saltstack的api

import salt.client
local = salt.client.LocalClient()
result = local.cmd('c2.salt.com', 'cmd.run', ['ifconfig'])


saltstack api 参数详解 参数详解2 参数详解3 参数详解4 参数详解5
  
client : 模块,python处理salt-api的主要模块,‘client interfaces <netapi-clients>’
local : 使用‘LocalClient <salt.client.LocalClient>’ 发送命令给受控主机,等价于saltstack命令行中的'salt'命令
local_async : 和local不一样之处在于,这个模块是用于异步操做的,即在master端执行命令后返回的是一个jobid,任务放在后台运行,经过产看jobid的结果来获取命令的执行结果。
runner : 使用'RunnerClient<salt.runner.RunnerClient>' 调用salt-master上的runner模块,等价于saltstack命令行中的'salt-run'命令
runner_async : 异步执行runner模块
wheel : 使用'WheelClient<salt.wheel.WheelClient>', 调用salt-master上的wheel模块,wheel模块没有在命令行端等价的模块,但它一般管理主机资源,好比文件状态,pillar文件,salt配置文件,以及关键模块<salt.wheel.key>功能相似于命令行中的salt-key。
wheel_async : 异步执行wheel模块
备注:通常状况下local模块,须要tgt和arg(数组),kwarg(字典),由于这些值将被发送到minions并用于执行所请求的函数。而runner和wheel都是直接应用于master,不须要这些参数。
tgt : minions
fun : 函数
arg : 参数
expr_form : tgt的匹配规则
'glob' - Bash glob completion - Default
'pcre' - Perl style regular expression
'list' - Python list of hosts
'grain' - Match based on a grain comparison
'grain_pcre' - Grain comparison with a regex
'pillar' - Pillar data comparison
'nodegroup' - Match on nodegroup
'range' - Use a Range server for matching
'compound' - Pass a compound match string

 

 

 

 

啦啦啦啦

相关文章
相关标签/搜索