自動化運維-【配置管理工具】

自動化運維工具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

 

 

 

 

啦啦啦啦

相關文章
相關標籤/搜索