使用shell命令进行复杂的运维时,代码往往变得复杂难懂,而使用python脚本语言来编写运维程序,就相当于开发普通的应用一样,所以维护和扩展都比较简单,更重要的是python运维工具fabric能自动登录其他服务器进行各种操作,这种实现使用shell是很难做到的,但是使用fabric实现就很简单,所以对于程序员的日常运维部署,建议使用python编写脚本。Fabric是基于Python实现的SSH命令行工具,简化了SSH的应用程序部署及系统管理任务,它提供了系统基础的操作组件,可以通过 SSH 的方式与远程服务器进行自动化交互, 实现本地或远程shell命令,包括:命令执行、文件上传、下载及完整执行日志输出等功能。Fabric在Paramiko的基础上做了更高一层的封装,操作起来会更加简单。Fabric官网地址为:http://www.fabfile.org/

一. Fabric安装

Linux下默认有python环境,安装fabric有两种方式: 一是通过pip方式安装; 而是通过fabric源码方式安装.
一般选择pip方式安装, 安装过程如下:先安装一些依赖
[root@kevin ~]# yum install make gcc gcc-c++ python-devel python-setuptools -y安装pip
首先下载py文件:https://bootstrap.pypa.io/get-pip.py
或者百度云盘下载地址:https://pan.baidu.com/s/1o7KylCm      提取密码:eucx[root@kevin ~]# cat /etc/redhat-release
CentOS Linux release 7.5.1804 (Core) [root@kevin ~]# python -V
Python 2.7.5[root@kevin ~]# wget https://bootstrap.pypa.io/get-pip.py
[root@kevin ~]# chmod 755 get-pip.py
[root@kevin ~]# python get-pip.py
Collecting pipDownloading https://files.pythonhosted.org/packages/c2/d7/90f34cb0d83a6c5631cf71dfe64cc1054598c843a92b400e55675cc2ac37/pip-18.1-py2.py3-none-any.whl (1.3MB)100% |████████████████████████████████| 1.3MB 56kB/s
Collecting wheelDownloading https://files.pythonhosted.org/packages/ff/47/1dfa4795e24fd6f93d5d58602dd716c3f101cfd5a77cd9acbe519b44a0a9/wheel-0.32.3-py2.py3-none-any.whl
Installing collected packages: pip, wheel
Successfully installed pip-18.1 wheel-0.32.3接着使用pip安装fabric
[root@kevin ~]# pip install fabric稍等一会就安装完毕了,这时输入fab就会弹出对应的选项
[root@kevin ~]# fab --version
Fabric 2.4.0
Paramiko 2.4.2
Invoke 1.2.0[root@kevin ~]# fab --help
Usage: fab [--core-opts] task1 [--task1-opts] ... taskN [--taskN-opts]Core options:--complete                         Print tab-completion candidates for given parse remainder.--hide=STRING                      Set default value of run()'s 'hide' kwarg.--no-dedupe                        Disable task deduplication.--print-completion-script=STRING   Print the tab-completion script for your preferred shell (bash|zsh|fish).--prompt-for-login-password        Request an upfront SSH-auth password prompt.--prompt-for-passphrase            Request an upfront SSH key passphrase prompt.--prompt-for-sudo-password         Prompt user at start of session for the sudo.password config value.--write-pyc                        Enable creation of .pyc files.-c STRING, --collection=STRING     Specify collection name to load.-d, --debug                        Enable debug output.-D INT, --list-depth=INT           When listing tasks, only show the first INT levels.-e, --echo                         Echo executed commands before running.-f STRING, --config=STRING         Runtime configuration file to use.-F STRING, --list-format=STRING    Change the display format used when listing tasks. Should be one of: flat (default), nested, json.-h [STRING], --help[=STRING]       Show core or per-task help and exit.-H STRING, --hosts=STRING          Comma-separated host name(s) to execute tasks against.-i, --identity                     Path to runtime SSH identity (key) file. May be given multiple times.-l [STRING], --list[=STRING]       List available tasks, optionally limited to a namespace.-p, --pty                          Use a pty when executing shell commands.-r STRING, --search-root=STRING    Change root directory used for finding task modules.-S STRING, --ssh-config=STRING     Path to runtime SSH config file.-V, --version                      Show version and exit.-w, --warn-only                    Warn, instead of failing, when shell commands fail.=======================================================
温馨提示:
如果安装的是pip3, 则使用"pip3 install fabric3" 安装fabric
=======================================================

二. Fabric 使用

Fabric命令说明
1) fab命令格式

fab是fabric的命令行入口 命令的格式为:
# fab [options] <command>[:arg1,arg2=val2,host=foo,hosts='h1;h2',...] ...

2) fab命令常用参数

# fab --help     查看帮助常用参数
-l  显示定义好的任务函数名
-f  指定fab入口文件,默认入口文件名为fabfile.py.. 即指定fabfile文件
-g  指定网关(中转)设备,即HOST逗号分隔要操作的主机, 比如堡垒机环境,填写堡垒机IP即可.
-H  指定目标主机,多台主机用‘,’号分隔
-p  远程账号的密码,fab执行时默认使用root账户
-P  以异步并行方式运行多主机任务,默认为串行运行
-R  指定role(角色),以角色名区分不同业务组设备
-t  设置设备连接超时时间(秒)
-T  设置远程主机命令执行超时时间(秒)
-w  当命令执行失败,发出警告,而非默认中止任务。其他参数:
--set=KEY=VALUE,...     逗号分隔,设置环境变量
--shortlist             简短打印可用命令
-c PATH                 指定本地配置文件
-D                      不加载用户known_hosts文件
-i PATH                 指定私钥文件
-k                      不加载来自~/.ssh下的私钥文件
--port=PORT             指定SSH连接端口
-R ROLES                根据角色操作,逗号分隔
-s SHELL                指定新shell,默认是'/bin/bash -l -c'
--show=LEVELS           以逗号分隔的输出
--ssh-config-path=PATH  SSH配置文件路径
-T N                    设置远程命令超时时间,单位秒
-u USER                 连接远程主机用户名
-x HOSTS                以逗号分隔排除主机
-z INT                  并发进程数例1:  通过远程主机查询172.16.50.45 (该主机的root密码为123456)的主机名
[root@kevin ~]# fab -f fabtest.py -p 123456 -H 172.16.50.45 -- 'hostname'例2: 本地执行命令
[root@kevin ~]# vim fabtest.py
from fabric.api import local
def command():local('ls')[root@kevin ~]# fab -f fabtest.py command
[localhost] local: ls
fabfile.py  fabfile.pyc  tab.py  tab.pyc
Done.例3: 远程执行命令
[root@kevin ~]# vim fabtest.pyfrom fabric.api import run
def command():run('ls')[root@kevin ~]# fab -f fabtest.py -H 192.168.1.120 -u user command
[192.168.1.120] Executing task 'command'[192.168.1.120] run: ls
[192.168.1.120] Login password for 'user':
[192.168.1.120] out: access.log  a.py
[192.168.1.120] out:
Done.
Disconnecting from 192.168.1.120... done.如果在多台主机执行,只需要-H后面的IP以逗号分隔即可。例4:  给脚本函数传入位置参数
[root@kevin ~]# vim fabfile.pyfrom fabric.api import run
def hello(name="world"):print("Hello %s!" % name)[root@kevin ~]# fab -H localhost hello
[localhost] Executing task 'hello'Hello world!
Done.[root@kevin ~]# fab -H localhost hello:name=Python
[localhost] Executing task 'hello'Hello Python!
Done.例5: 主机列表组
[root@kevin ~]# vim fabfile.py
from fabric.api import run, env
env.hosts = ['root@192.168.1.120:22', 'root@192.168.1.130:22']
env.password = '123.com'env.exclude_hosts = ['root@192.168.1.120:22']   # 排除主机
def command():run('ls')[root@kevin ~]# fab command
env作用是定义fabfile全局设定,类似于变量。还有一些常用的属性:例6: 定义角色分组
[root@kevin ~]# vim install.py
from fabric.api import run, env
env.roledefs = {    'web': ['192.168.1.10', '192.168.1.20'],    'db': ['192.168.1.30', '192.168.1.40']
}
env.password = '123'@roles('web')
def task1():run('yum install httpd -y')
@roles('db')
def task2():run('yum install mysql-server -y')
def deploy():execute(task1)execute(task2)[root@kevin ~]# fab -f install.py deploy例7: 上传目录到远程主机
[root@kevin ~]# vim haha.py
from fabric.api import *
env.hosts = ['192.168.1.120']
env.user = 'user'env.password = '123.com'def task():put('/root/abc', '/home/user')run('ls -l /home/user')[root@kevin ~]# fab -f haha.py task例8: 从远程主机下载目录
[root@kevin ~]# vim heihei.py
from fabric.api import *
env.hosts = ['192.168.1.120']
env.user = 'user'env.password = '123.com'
def task():get('/home/user/b', '/opt')local('ls -l /opt')[root@kevin ~]# fab -f heihei.py task例9: 打印颜色,有助于关键地方醒目
[root@kevin ~]# vim bobo.py
from fabric.colors import *
def show():print green('Successful.')print red('Failure!')print yellow('Warning.')[root@kevin ~]# fab -f bobo.py show

3) fabfile文件的编写 (默认的文件名称为fabfile)

fab命令是结合fabfile.py文件(其他文件通过-f filename 参数来引用)来搭配使用的。fab的部分命令行参数还能通过相应的方法来代替。先来看一个小例子
[root@kevin ~]# cat fabfile.py
#!/usr/bin/env python
from fabric.api import run#定义一个任务函数,通过run方法实现远程执行"uname -s"命令
def host_type():run('uname -s')[root@kevin ~]# fab -H localhost host_type
[localhost] Executing task 'host_type'
[localhost] run: uname -s
[localhost] Login password for 'devops':
[localhost] out: Linux
[localhost] out:Done.
Disconnecting from localhost... done.其中,必须要明白的是, fab命令引用的默认文件名fabfile.py!
如果使用的是默认文件名称, 则fab执行命令中就不需要跟文件名.
如果使用非默认文件名称,比如这里不是fabfile.py, 而是host_type.py 文件, 则需要通过"-f"来指定:
[root@kevin ~]# fab -H localhost -f host_type.py host_type如果目标主机未配置密钥认证信任,将会提示输入目标主机对应账号登录密码。再来看一个小例子
[root@kevin ~]# vim fabric.py
#!/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)以上Fabric配置,实现的目的是:
简单的在本地启动nginx服务器, 在linux1和linux2上启动了tomcat服务器, 为了接受nginx服务器的代理,这里专门使用分组的方式为了适应机器比较多的集群的需要;
另外这里没有设置服务器的密码,一是为了服务器的安全;而是集群间建议设置ssh免密登录,脚本就不用设置密码了;
方法doworks执行的就是最终汇总的任务;开始执行
[root@kevin ~]# fab -f fabric.py doworks

4) fabfile全局属性 (env对象) 

fabfile之env对象的作用是定义fabfile的全局设定,支持多个属性,包含目标主机、用户名、密码、等角色.
env各属性说明如下:
evn.host:           定义目标主机,可以用IP或主机名表示,以Python的列表形式定义,如evn.hosts['192.168.56.133','192.168.56.134']。
env.exclude_hosts:  排除指定主机,如env.exclude_hosts=['192.168.56.133']。
env.user:           定义用户名,如env.user="root"。
env.port:           定义目标主机端口,默认为22,如env.port="22"。
env.password:       定义密码,如env.password='1234567'。
env.passwords:      与password功能一样,区别在于不同主机不同密码的应用场景,需要注意的是,配置passwords是需配置用户、主机、端口等信息;
env.gateway:        定义网关(中转、堡垒机)IP,如env.gateway = '192.168.56.1'。
env.deploy_release_dir:  自定义全局变量,格式:env.+"变量名称",如env.deploy_release_dir、env.age、env.sex等。
env.roledefs:       定义角色分组,比如web组与db组主机区分开来;比如
[root@kevin ~]# vim fabfile.py
..........
env.passwords = {'root@192.168.56.131:22':'1234567','root@192.168.56.132:22':'1234567','root@192.168.56.133:22':'1234567','root@192.168.56.134:22':'1234567'
}[root@kevin ~]# vim fabfile.py
..........
env.roledefs = {'webservers':['192.168.56.131','192.168.56.132','192.168.56.133'],'dbserver':['192.168.56.134','192.168.56.135']
}env.roledefs的使用方法实例:
[root@kevin ~]# vim fabfile.py
..........
env.roledefs = {'webserver':['192.168.1.21','192.168.1.22'],'dbserver':['192.168.1.25','192.168.1.26']}
#引用分组时使用python装饰器方式来进行,如:
@roles('webserver')
def webtask():run('/usr/local/nginx/sbin/nginx')@roles('webserver','dbserver')
def publictask():run('uptime')引用时使用Python修饰符的形式进行,角色修饰符下面的任务函数为其作用域,下面来看一个示例:
[root@kevin ~]# vim fabfile.py
..........
@roles('webservers')
def webtask():run('/etc/init.d/nginx start')@roles('dbservers')
def dbtask():run('/etc/init.d/mysql start')@roles('webservers','dbservers')
def pubclitasj():run('uptime')def deploy():execute(webtask)execute(dbtask)execute(pubclitask)在命令执行fab deploy就可以实现不同角色执行不同的任务函数了。

5) Fabric常用API

Fabric提供了一组简单但功能强大的fabric.api命令集,简单地调用这些API就能完成大部分应用场景需求。Fabric常用方法及说明如下:
local     执行本地命令,如:local('uname -s');
lcd       切换本地目录,如:lcd('/home');
cd        切换远程目录,如:cd('/data/logs');
run       执行远程命令,如:run('free -m');
sudo      sudo方式执行远程命令,如:sudo('/etc/init.d/httpd start');
put       传本地文件到远程主机,如:put('/home/user.info','/data/user.info');
prompt    获得用户输入信息,如:prompt('please input user password:');
confirm   获得提示信息确认,如:confirm("Tests failed. Continue[Y/N]?");
reboot    重启远程主机,如:reboot();
@task     函数修饰符,标识的函数为fab可调用的,非标记对fab不可见,纯业务逻辑;
@runs_once 函数修复符,标识的函数只会执行一次,不受多台主机影响。

6) Fabric应用示例说明 

示例一:  查看本地和远程主机信息

查看本地信息
本示例调用local()方法执行本地(主控端)命令,添加"@runs_once"修饰符保证该任务函数只执行一次。调用run()方法执行远程命令。
[root@kevin ~]# vim fabric1.1.py
#!/usr/bin/env pythonfrom fabric.api import *env.user = 'devops'
env.hosts = ['localhost']
env.password = '1234567'@runs_once              #查看本地系统信息,当有多台主机时只运行一次
def local_task():       #本地任务函数local("uname -a")通过fab命令调用local_task任务函数运行结果如下:
[root@kevin ~]# fab -f fabric1.1.py local_task
[localhost] Executing task 'local_task'
[localhost] local: uname -a
Linux devops-virtual-machine 4.15.0-20-generic #21-Ubuntu SMP Tue Apr 24 06:16:15 UTC 2018 x86_64 x86_64 x86_64 GNU/LinuxDone.查看远程主机信息
[root@kevin ~]# vim fabric1.2.py
#!/usr/bin/env pythonfrom fabric.api import *env.user = 'root'
env.hosts = ['192.168.56.11']
env.password = '1234567'def remote_task():with cd('/root'):        #"with"的作用是让后面的表达式的语句继承当前状态,实现"cd /root/ && ls -l'的效果run('ls -l')调用remote_task任务函数运行结果如下:
[root@kevin ~]# fab -f fabric1.2.py local_task
[192.168.56.11] Executing task 'remote_task'
[192.168.56.11] run: ls -l
[192.168.56.11] out: total 4
[192.168.56.11] out: -rw-------. 1 root root 1273 May 29 11:47 anaconda-ks.cfg
[192.168.56.11] out:Done.
Disconnecting from 192.168.56.11... done.如果将上面两个文件的需求, 放在一起
[root@kevin ~]# vim fabric1.py
#!/usr/bin/env python
# -*- encoding: utf-8 -*-from fabric.api import *env.user = 'root'
env.hosts = ['192.168.1.22']
env.password = '123456'@runs_once   #查看本地系统信息,当有多台主机时只运行一次
def local_task():   #本地任务函数local('uname -a')def remote_task():with cd('/var/logs'):   #with的作用是让后面的表达式语句继承当前状态,实现:cd /var/logs  && ls -l的效果run('ls -l')[root@kevin ~]# fab -f fabric1.py local_task
[root@kevin ~]# fab -f fabric1.py remote_task

示例二:动态获取远程目录列表

本示例使用"@task'修复符标志入口函数go()对外部可见,配合"@runs_once"修饰符接受用户输入,最后调用worktask()任务函数实现远程命令执行。
[root@kevin ~]# vim fabric2.py
#!/usr/bin/env pythonfrom fabric.api import *env.user = 'root'
env.hosts = ['192.168.56.11','192.168.56.12']
env.password = '1234567'@runs_once           #主机遍历过程中,只有第一台触发此函数
def input_raw():return prompt("Please input directory name:",default="/home")def worktask(dirname):run("ls -l "+dirname)@task           #限定只有go函数对fab命令可见
def go():getdirname = input_raw()worktask(getdirname)解释说明:
该示例实现了一个动态输入远程目录名称,再获取目录列表的功能,由于我们只要求输入一次,在显示所有主机上该目录的列表信息,调用一个子函数input_raw()同时配置@runs_once修复符来达到此目的。执行结果如下:
[root@kevin ~]# fab -f fabric2.py go
[192.168.56.11] Executing task 'go'
Please input directory name: [/home] /root
[192.168.56.11] run: ls -l /root
[192.168.56.11] out: total 4
[192.168.56.11] out: -rw-------. 1 root root 1273 May 29 11:47 anaconda-ks.cfg
[192.168.56.11] out:[192.168.56.12] Executing task 'go'
[192.168.56.12] run: ls -l /root
[192.168.56.12] out: total 4
[192.168.56.12] out: -rw-------. 1 root root 1273 May 29 11:59 anaconda-ks.cfg
[192.168.56.12] out:Done.
Disconnecting from 192.168.56.11... done.
Disconnecting from 192.168.56.12... done.

示例三: 网关模式文件上传与执行

本示例通过Fabric的env对象定义网关模式,即俗称的中转、堡垒机环境。定义格式为"env.gateway='192.168.56.11'",其中IP“192.168.56.11”为堡垒机IP,
再结合任务韩素实现目标主机文件上传与执行的操作。
[root@kevin ~]# vim fabric3.py
#!/usr/bin/env pythonfrom fabric.api import *
from fabric.context_managers import *
from fabric.contrib.console import confirmenv.user = 'root'
env.gateway = '192.168.56.11'                           #定义堡垒机IP,作为文件上传、执行的中转设备
env.hosts = ['192.168.56.12','192.168.56.13']env.passwords = {'root@192.168.56.11:22':'1234567',                  #堡垒机账号信息'root@192.168.56.12:22':'1234567','root@192.168.56.13:22':'1234567'
}l_pack_path = "/home/install/nginx-1.6.3.tar.gz"        #本地安装包路径
r_pack_path = "/tmp/install"                            #远程安装包路径@task
def put_task():run("mkdir -p /tmp/install")with settings(warn_only=True):result = put(l_pack_path,r_pack_path)          #上传安装包if result.failed and not confirm("put file failed, Continue[Y/N]?"):abort("Aborint file put task!")@task
def run_task():                    #执行远程命令,安装nginxwith cd(r_pack_path):run("tar -xvf nginx-1.6.3.tar.gz")with cd("nginx-1.6.3/"):                     #使用with继续继承/tmp/install目录位置状态run("./nginx_install.sh")@task
def go():       #上传、安装put_task()run_task()如下命令运行结果, 默认为串行运行
[root@kevin ~]# fab -f fabric3.py go
[192.168.56.12] Executing task 'go'
[192.168.56.12] run: mkdir -p /tmp/install
[192.168.56.12] put: /home/install/nginx-1.6.3.tar.gz -> /tmp/install/nginx-1.6.3.tar.gz
[192.168.56.12] run: tar -xvf nginx-1.6.3.tar.gz
.....
.....
.....
[192.168.56.12] out: cp conf/nginx.conf '/usr/local/nginx/conf/nginx.conf.default'
[192.168.56.12] out: test -d '/usr/local/nginx/logs'         || mkdir -p '/usr/local/nginx/logs'
[192.168.56.12] out: test -d '/usr/local/nginx/logs' ||         mkdir -p '/usr/local/nginx/logs'
[192.168.56.12] out: test -d '/usr/local/nginx/html'         || cp -R html '/usr/local/nginx'
[192.168.56.12] out: test -d '/usr/local/nginx/logs' ||         mkdir -p '/usr/local/nginx/logs'
[192.168.56.12] out: make[1]: Leaving directory `/tmp/install/nginx-1.6.3'
[192.168.56.12] out: nginx: the configuration file /usr/local/nginx/conf/nginx.conf syntax is ok
[192.168.56.12] out: nginx: configuration file /usr/local/nginx/conf/nginx.conf test is successful
[192.168.56.12] out:[192.168.56.13] Executing task 'go'
[192.168.56.13] run: mkdir -p /tmp/install
[192.168.56.13] put: /home/install/nginx-1.6.3.tar.gz -> /tmp/install/nginx-1.6.3.tar.gz
[192.168.56.13] run: tar -xvf nginx-1.6.3.tar.gz
....
....
....
[192.168.56.13] out: cp conf/nginx.conf '/usr/local/nginx/conf/nginx.conf.default'
[192.168.56.13] out: test -d '/usr/local/nginx/logs'         || mkdir -p '/usr/local/nginx/logs'
[192.168.56.13] out: test -d '/usr/local/nginx/logs' ||         mkdir -p '/usr/local/nginx/logs'
[192.168.56.13] out: test -d '/usr/local/nginx/html'         || cp -R html '/usr/local/nginx'
[192.168.56.13] out: test -d '/usr/local/nginx/logs' ||         mkdir -p '/usr/local/nginx/logs'
[192.168.56.13] out: make[1]: Leaving directory `/tmp/install/nginx-1.6.3'
[192.168.56.13] out: nginx: the configuration file /usr/local/nginx/conf/nginx.conf syntax is ok
[192.168.56.13] out: nginx: configuration file /usr/local/nginx/conf/nginx.conf test is successful
[192.168.56.13] out:Done.
Disconnecting from 192.168.56.11... done.
Disconnecting from 192.168.56.12... done.
Disconnecting from 192.168.56.13... done.再如下运行结果, 加P参数为异步并行执行结果
[root@kevin ~]# fab -Pf fabric3.py go
[192.168.56.12] Executing task 'go'
[192.168.56.13] Executing task 'go'
[192.168.56.12] run: mkdir -p /tmp/install
[192.168.56.13] run: mkdir -p /tmp/install
[192.168.56.12] put: /home/install/nginx-1.6.3.tar.gz -> /tmp/install/nginx-1.6.3.tar.gz
[192.168.56.13] put: /home/install/nginx-1.6.3.tar.gz -> /tmp/install/nginx-1.6.3.tar.gz
[192.168.56.12] run: tar -xvf nginx-1.6.3.tar.gz
....
....
....
[192.168.56.12] out: nginx-1.6.3/html/index.html
[192.168.56.12] out: nginx-1.6.3/README
[192.168.56.12] out: nginx-1.6.3/nginx_install.sh
[192.168.56.12] out: nginx-1.6.3/configure
[192.168.56.12] out:[192.168.56.12] run: ./nginx_install.sh
[192.168.56.13] run: tar -xvf nginx-1.6.3.tar.gz
[192.168.56.13] out: nginx-1.6.3/
[192.168.56.13] out: nginx-1.6.3/src/
....
....
....
[192.168.56.12] out: make[1]: Leaving directory `/tmp/install/nginx-1.6.3'
[192.168.56.12] out: nginx: the configuration file /usr/local/nginx/conf/nginx.conf syntax is ok
[192.168.56.12] out: nginx: configuration file /usr/local/nginx/conf/nginx.conf test is successful
[192.168.56.12] out:
....
....
...
[192.168.56.13] out: make[1]: Leaving directory `/tmp/install/nginx-1.6.3'
[192.168.56.13] out: nginx: the configuration file /usr/local/nginx/conf/nginx.conf syntax is ok
[192.168.56.13] out: nginx: configuration file /usr/local/nginx/conf/nginx.conf test is successful
[192.168.56.13] out:

示例四:  文件打包, 上传与校验

我们时常做一些文件包分发的工作,实施步骤一般是先压缩打包,在批量上传至目标服务器,最后做一致性校验。
本示例通过put()方法实现文件的上传,通过对比本地与远程主机文件的md5,最终实现文件一致性校验。
[root@kevin ~]# vim fabric4.py
#!/usr/bin/env pythonfrom fabric.api import *
from fabric.context_managers import *
from fabric.contrib.console import confirmenv.user = 'root'
env.hosts = ['192.168.56.12','192.168.56.13']
env.passwords = {'root@192.168.56.12:22':'1234567','root@192.168.56.13:22':'1234567',
}@runs_once
def tar_task():             #本地打包任务函数,只执行一次with lcd('/home/devops/devops'):local("tar -zcf devops.tar.gz  *")@task
def put_task():                 #上传文件任务函数run("mkdir -p /root/devops")with cd("/root/devops"):with settings(warn_only=True):                  #put(上传)出现异常时继续执行,非终止result = put("/home/devops/devops/devops.tar.gz","/root/devops/devops.tar.gz")if result.failed and not confirm("put file failed.Continue[Y/N]?"):abort("Aborting file put task!")                        #出现异常时,确认用户是否继续,(Y继续)@task
def check_task():               #校验文件任务函数with settings(warn_only=True):#本地local命令需要配置capture=True才能捕获返回值lmd5 = local("md5sum /home/devops/devops/devops.tar.gz",capture=True).split(' ')[0]rmd5 = run("md5sum /root/devops/devops.tar.gz").split(' ')[0]if lmd5 == rmd5:                #对比本地及远程文件md5信息prompt("OK")else:prompt("ERROR")@task
def go():tar_task()put_task()check_task()执行命令, 运行结果如下:(提示此程序不支持-P参数并行执行、如需并行执行,程序需要做调整). 如果只打包, 则"fab -f fabric4.py tar_task", 如果只上传, 则"fab -f fabric4.py put_task"
[root@kevin ~]# fab -f fabric4.py go
[192.168.56.12] Executing task 'go'
[localhost] local: tar -zcf devops.tar.gz  *
[192.168.56.12] run: mkdir -p /root/devops
[192.168.56.12] put: /home/devops/devops/devops.tar.gz -> /root/devops/devops.tar.gz
[localhost] local: md5sum /home/devops/devops/devops.tar.gz
[192.168.56.12] run: md5sum /root/devops/devops.tar.gz
[192.168.56.12] out: a1cf2be82647cbed0d41514bd80373de  /root/devops/devops.tar.gz
[192.168.56.12] out:OK
[192.168.56.13] Executing task 'go'
[192.168.56.13] run: mkdir -p /root/devops
[192.168.56.13] put: /home/devops/devops/devops.tar.gz -> /root/devops/devops.tar.gz
[localhost] local: md5sum /home/devops/devops/devops.tar.gz
[192.168.56.13] run: md5sum /root/devops/devops.tar.gz
[192.168.56.13] out: a1cf2be82647cbed0d41514bd80373de  /root/devops/devops.tar.gz
[192.168.56.13] out:OKDone.
Disconnecting from 192.168.56.12... done.
Disconnecting from 192.168.56.13... done.

示例五: 部署LNMP业务服务环境

本示例通过env.roledefs定义不同主机角色,在使用"@roles('webservers')"修复符绑定到对应的任务函数,实现不同角色主机的部署差异。
[root@kevin ~]# vim fabric5.py
#!/usr/bin/env pythonfrom fabric.colors import *
from fabric.api import *env.user = 'root'
env.roledefs = {'webservers':['192.168.56.11','192.168.56.12'],'dbservers':['192.168.56.13']
}env.passwords = {'root@192.168.56.11:22':'1234567','root@192.168.56.12:22':'1234567','root@192.168.56.13:22':'1234567',
}@roles('webservers')                      #使用webtask任务函数引用'webservers'角色修复符
def webtask():print(yellow('Install nginx php php-fpm...'))with settings(warn_only=True):run("yum -y install nginx")run("yum -y install php-fpm php-mysql php-mbstring php-xml php-mcrypt php-gd")run("chkconfig --levels 235 php-fpm on")run("chkconfig --levels 235 nginx on")@roles('dbservers')                       #dbtask任务函数引用'dbservers'角色修复符
def dbtask():print(yellow("Install Mysql..."))with settings(warn_only=True):run("yum -y install mysql mysql-server")run("chkconfig --levels 235 mysqld on")@roles('webservers','dbservers')           #publictask任务函数同时引用两个角色修复符
def publictask():                          #部署公共类环境,如epel、ntp等print(yellow("Install epel ntp...."))with settings(warn_only=True):run("wget -O /etc/yum.repos.d/epel.repo http://mirrors.aliyun.com/repo/epel-7.repo")run("yum -y install ntp")def deploy():execute(publictask)execute(webtask)execute(dbtask)执行命令,结果如下:
[root@kevin ~]# fab -Pf fabric5.py deploy
[192.168.56.11] Executing task 'publictask'
[192.168.56.12] Executing task 'publictask'
[192.168.56.13] Executing task 'publictask'
Install epel ntp....
[192.168.56.13] run: wget -O /etc/yum.repos.d/epel.repo http://mirrors.aliyun.com/repo/epel-7.repo
Install epel ntp....
[192.168.56.12] run: wget -O /etc/yum.repos.d/epel.repo http://mirrors.aliyun.com/repo/epel-7.repo
Install epel ntp....
[192.168.56.11] run: wget -O /etc/yum.repos.d/epel.repo http://mirrors.aliyun.com/repo/epel-7.repo
[192.168.56.12] out: --2018-06-23 20:32:30--  http://mirrors.aliyun.com/repo/epel-7.repo
[192.168.56.11] out: --2018-06-23 20:32:30--  http://mirrors.aliyun.com/repo/epel-7.repo
[192.168.56.13] out: --2018-06-23 20:32:30--  http://mirrors.aliyun.com/repo/epel-7.repo
....
[192.168.56.13] run: yum -y install ntp
[192.168.56.12] run: yum -y install ntp
[192.168.56.11] run: yum -y install ntp
....
....
....
[192.168.56.11] Executing task 'webtask'
[192.168.56.12] Executing task 'webtask'
Install nginx php php-fpm...
[192.168.56.11] run: yum -y install nginx
Install nginx php php-fpm...
[192.168.56.12] run: yum -y install nginx
....
....
....
[192.168.56.13] Executing task 'dbtask'
Install Mysql...
[192.168.56.13] run: rpm -ivh http://dev.mysql.com/get/mysql-community-release-el6-5.noarch.rpm
.....
.....
.....
[192.168.56.13] run: chkconfig --levels 235 mysqld onDone.

示例六:  分享一个生产环境代码包发布管理的配置

程序生产环境的发布是业务上线的最后一个环境,要求具备源码打包、发布、切换、回滚、版本管理等功能。
本示例实现了这一套流程功能,其中版本切换与回滚使用了Linux下的软链接实现。
[root@kevin ~]# vim fabric6.py
#!/usr/local/env pythonfrom fabric.api import *
from fabric.colors import *
from fabric.context_managers import *
from fabric.contrib.console import confirm
import timeenv.user = 'root'
env.host = ['192.168.56.12','192.168.56.13']
env.passwords = {'root@192.168.56.12:22':'1234567','root@192.168.56.13:22':'1234567',
}env.project_dev_source = '/data/dev/Lwebadmin/'              #开发服务器项目主目录
env.project_tar_source = '/data/dev/releases/'               #开发服务器项目压缩包存储目录
env.project_pack_name = 'release'                            #项目压缩包前缀,文件名为release.tar.gzenv.deploy_project_root = '/data/www/Lwebadmin/'            #项目生产环境主目录
env.deploy_release_dir = 'releases'                         #项目发布目录,位于主目录下面
env.deploy_current_dir = 'current'                          #对外服务的当前版本软链接
env.deploy_version = time.strftime("%Y%m%d")+"v2"           #版本号@runs_once
def input_versionid():                                      #获得用户输入的版本号,以便做版本回滚操作return prompt("Please input project rollback version ID:",default="")@task
@runs_once
def tar_source():                                           #打包本地项目主目录,并将压缩包存储到本地压缩包目录prompt(yellow("Creating source package...."))with lcd(env.project_dev_source):local("tar -zcf %s.tar.gz ." %(env.project_tar_source + env.project_pack_name))prompt(green("Creating source package success!"))@task
def put_package():                                          #上传任务函数prompt(yellow("Start put package...."))with settings(warn_only=True):with cd(env.deploy_project_root + env.deploy_release_dir):run("mkdir %s" %(env.deploy_version))           #创建版本目录env.deploy_full_path = env.deploy_project_root + env.deploy_release_dir + "/" + env.deploy_versionwith settings(warn_only=True):                          #上传项目压缩包至此目录result = put(env.project_tar_source + env.project_pack_name + ".tar.gz",env.deploy_full_path)if result.failed and not ("put file failed,Continue[Y/N]?"):abort("Aborting file put task!")with cd(env.deploy_full_path):                          #成功解压后删除压缩包run("tar -zxvf %s.tar.gz" %(env.project_pack_name))run("rm -rf %s.tar.gz" %(env.project_pack_name))print(green("Put & untar package success!"))@task
def make_symlink():                                         #为当前版本目录做软链接print(yellow("update current symlink"))env.deploy_full_path = env.deploy_project_root + env.deploy_release_dir + "/" + env.deploy_versionwith settings(warn_only=True):                           #删除软链接,重新创建并指定软链接源目录,新版本生效run("rm -rf %s" %(env.deploy_project_root + env.deploy_current_dir))run("ln -s %s %s" %(env.deploy_full_path,env.deploy_project_root + env.deploy_current_dir))print(green("make symlink success!"))@task
def rollback():                                             #版本回滚任务函数print(yellow("rollback project version"))versionid = input_versionid()                           #获取用户输入的回滚版本号if versionid == '':abort("Project version ID error,abort!")env.deploy_full_path = env.deploy_project_root + env.deploy_release_dir + "/" + versionidrun("rm -r %s" %(env.deploy_project_root + env.deploy_current_dir))run("ln -s %s %s" %(env.deploy_full_path,env.deploy_project_root + env.deploy_current_dir))     #删除软链接,重新创建并指定软链接源目录,新版本生效print(green("rollback sucess!"))@task
def go():               #自动化程序版本发布入口函数tar_source()put_package()make_symlink()# 需要注意: 在生产环境中将站点的根目录指向"/data/www/Lwebadmin/current",由于使用Linux软链接做切换,管理员的版本发布、回滚操作用户无感知。
[root@kevin ~]# fab -f fabric6.py go 

示例七: 分享一个自动化部署 Django 项目的配置

[root@kevin ~]# vim fabric7.py
# -*- coding: utf-8 -*-
# 文件名要保存为 fabfile.pyfrom __future__ import unicode_literals
from fabric.api import *# 登录用户和主机名:
env.user = 'root'
# 如果没有设置,在需要登录的时候,fabric 会提示输入
env.password = 'youpassword'
# 如果有多个主机,fabric会自动依次部署
env.hosts = ['www.example.com']TAR_FILE_NAME = 'deploy.tar.gz'def pack():"""定义一个pack任务, 打一个tar包:return:"""tar_files = ['*.py', 'static/*', 'templates/*', 'vue_app/', '*/*.py', 'requirements.txt']exclude_files = ['fabfile.py', 'deploy/*', '*.tar.gz', '.DS_Store', '*/.DS_Store','*/.*.py', '__pycache__/*']exclude_files = ['--exclude=\'%s\'' % t for t in exclude_files]local('rm -f %s' % TAR_FILE_NAME)local('tar -czvf %s %s %s' % (TAR_FILE_NAME, ' '.join(exclude_files), ' '.join(tar_files)))print('在当前目录创建一个打包文件: %s' % TAR_FILE_NAME)def deploy():"""定义一个部署任务:return:"""# 先进行打包pack()# 远程服务器的临时文件remote_tmp_tar = '/tmp/%s' % TAR_FILE_NAMErun('rm -f %s' % remote_tmp_tar)# 上传tar文件至远程服务器, local_path, remote_pathput(TAR_FILE_NAME, remote_tmp_tar)# 解压remote_dist_base_dir = '/home/python/django_app'# 如果不存在, 则创建文件夹run('mkdir -p %s' % remote_dist_dir)# cd 命令将远程主机的工作目录切换到指定目录 with cd(remote_dist_dir):print('解压文件到到目录: %s' % remote_dist_dir)run('tar -xzvf %s' % remote_tmp_tar)print('安装 requirements.txt 中的依赖包')# 我使用的是 python3 来开发run('pip3 install -r requirements.txt')remote_settings_file = '%s/django_app/settings.py' % remote_dist_dirsettings_file = 'deploy/settings.py' % nameprint('上传 settings.py 文件 %s' % settings_file)put(settings_file, remote_settings_file)nginx_file = 'deploy/django_app.conf'remote_nginx_file = '/etc/nginx/conf.d/django_app.conf'print('上传 nginx 配置文件 %s' % nginx_file)put(nginx_file, remote_nginx_file)# 在当前目录的子目录 deploy 中的 supervisor 配置文件上传至服务器supervisor_file = 'deploy/django_app.ini'remote_supervisor_file = '/etc/supervisord.d/django_app.ini'print('上传 supervisor 配置文件 %s' % supervisor_file)put(supervisor_file, remote_supervisor_file)# 重新加载 nginx 的配置文件run('nginx -s reload')run('nginx -t')# 删除本地的打包文件local('rm -f %s' % TAR_FILE_NAME)# 载入最新的配置文件,停止原有进程并按新的配置启动所有进程run('supervisorctl reload')# 执行 restart all,start 或者 stop fabric 都会提示错误,然后中止运行# 但是服务器上查看日志,supervisor 有重启# run('supervisorctl restart all')执行 pack 任务
[root@kevin ~]# fab -f fabric7.py pack执行 deploy 任务
[root@kevin ~]# fab -f fabric7.py deploy

示例八:  代码的自动化部署

[root@kevin ~]# vim fabric8.py
#coding=utf-8
from fabric.api import local, abort, settings, env, cd, run
from fabric.colors import *
from fabric.contrib.console import confirmenv.hosts = ["root@115.28.×××××"]
env.password = "×××××"def get_git_status():git_status_result = local("git status", capture=True)if "无文件要提交,干净的工作区" not in git_status_result:print red("****当前分支还有文件没有提交")print git_status_resultabort("****已经终止")def local_unit_test():with settings(warn_only=True):test_result = local("python manage.py test")if test_result.failed:print test_resultif not confirm(red("****单元测试失败,是否继续?")):abort("****已经终止")def server_unit_test():with settings(warn_only=True):test_result = run("python manage.py test")if test_result.failed:print test_resultif not confirm(red("****单元测试失败,是否继续?")):abort("****已经终止")def upload_code():local("git push origin dev")print green("****代码上传成功")def deploy_at_server():print green("****ssh到服务器进行下列操作")with cd("/var/www/××××××"):#print run("pwd")print green("****将在远程仓库下载代码")run("git checkout dev")get_git_status()run("git pull origin dev")print green("****将在服务器上运行单元测试")server_unit_test()run("service apache2 restart", pty=False)print green("****重启apache2成功")print green("********代码部署成功********")def deploy():get_git_status()local("git checkout dev", capture=False)print green("****切换到dev分支")get_git_status()print green("****将开始运行单元测试")local_unit_test()print green("****单元测试完成,开始上传代码")upload_code()deploy_at_server()fabric可以将自动化部署或者多机操作的命令固化到一个脚本里,从而减少手动的操作。上面是今天第一次接触这东西后写的,确实很实用。
运行
[root@kevin ~]# fab -ff abric8.py deploy主要逻辑就是将本地的dev分支跑单元测试,然后提交到服务器,ssh登陆到服务器,然后pull下来,再跑单元测试,然后重启apache2。
这个写的还是比较简单的。

===============这里贴出之前线上环境使用过的一个Fabric自动化配置===============

1) 通过Fabric配置的自动化python上线脚本(包括回滚脚本):
[work@qd-op-zhongkong op]$ cat xcspam-celery.py
from fabric.api import *
from fabric.context_managers import *
import datetimeenv.hosts=['qd-vpc-op-rule01']def antiwater():with cd('/app/release'):date=datetime.datetime.now().strftime("%Y%m%d%H%M%S")repo='http://git.kevinweb.com/zuiyou_server/xcspam.git';run('git clone --depth=1 %s' % repo)newNmae="xcspam"+"-"+daterun('mv xcspam %s ' % newNmae)with cd('/app/web/xcspam'):newRelease=run('ls /app/release/ |tail -1f')run('cp -rp /app/release/%s /app/web/xcspam/ ' % newRelease)run('unlink bin')run('ln -sn %s bin' % newRelease)run('superctl restart antiwater:*')def rollantiwater():with cd('/app/web/xcspam'):lastrelease=run('ls -rtd xcspam* |tail -2 |head -1')run('unlink bin')run('ln -sn %s bin' % lastrelease)run('superctl restart antiwater:*')def report():with cd('/app/release'):date=datetime.datetime.now().strftime("%Y%m%d%H%M%S")repo='http://git.kevinweb.com/zuiyou_server/xcspam.git';run('git clone --depth=1 %s' % repo)newNmae="xcspam"+"-"+daterun('mv xcspam %s ' % newNmae)with cd('/app/web/xcspam'):newRelease=run('ls /app/release/ |tail -1f')run('cp -rp /app/release/%s /app/web/xcspam/ ' % newRelease)run('unlink bin')run('ln -sn %s bin' % newRelease)run('superctl restart report')def rollreport():with cd('/app/web/xcspam'):lastrelease=run('ls -rtd xcspam* |tail -2 |head -1')run('unlink bin')run('ln -sn %s bin' % lastrelease)run('superctl restart report')def chat():with cd('/app/release'):date=datetime.datetime.now().strftime("%Y%m%d%H%M%S")repo='http://git.kevinweb.com/zuiyou_server/xcspam.git';run('git clone --depth=1 %s' % repo)newNmae="xcspam"+"-"+daterun('mv xcspam %s ' % newNmae)with cd('/app/web/xcspam'):newRelease=run('ls /app/release/ |tail -1f')run('cp -rp /app/release/%s /app/web/xcspam/ ' % newRelease)run('unlink bin')run('ln -sn %s bin' % newRelease)run('superctl restart chat')def rollchat():with cd('/app/web/xcspam'):lastrelease=run('ls -rtd xcspam* |tail -2 |head -1')run('unlink bin')run('ln -sn %s bin' % lastrelease)run('superctl restart chat')可以在一个脚本中定义多个上线项目,上线的时候可以选择,如下(回滚的时候选择对应的roll即可):
[work@qd-op-zhongkong op]$ fab -f xcspam-celery.py antiwater
[work@qd-op-zhongkong op]$ fab -f xcspam-celery.py report
[work@qd-op-zhongkong op]$ fab -f xcspam-celery.py chat2) 脚本2,其实跟上面无异:
[work@qd-op-zhongkong op]$ cat xcspam-consumer.py
from fabric.api import *
from fabric.context_managers import *
import datetimeenv.hosts=['qd-vpc-op-consumer01','qd-vpc-op-consumer02']def xcspam():with cd('/app/release'):date=datetime.datetime.now().strftime("%Y%m%d%H%M%S")repo='http://git.kevinweb.com/zuiyou_server/xcspam.git';run('git clone --depth=1 %s' % repo)newNmae="xcspam"+"-"+daterun('mv xcspam %s ' % newNmae)with cd('/app/web/xcspam'):newRelease=run('ls /app/release/ |tail -1f')run('cp -rp /app/release/%s /app/web/xcspam/ ' % newRelease)run('unlink bin')run('ln -sn %s bin' % newRelease)run('superctl restart xcspam:*')def rollxcspam():with cd('/app/web/xcspam'):lastrelease=run('ls -rtd xcspam* |tail -2 |head -1')run('unlink bin')run('ln -sn %s bin' % lastrelease)run('superctl restart xcspam:*')def chatxcspam():with cd('/app/release'):date=datetime.datetime.now().strftime("%Y%m%d%H%M%S")repo='http://git.kevinweb.com/zuiyou_server/xcspam.git';run('git clone --depth=1 %s' % repo)newNmae="xcspam"+"-"+daterun('mv xcspam %s ' % newNmae)with cd('/app/web/xcspam'):newRelease=run('ls /app/release/ |tail -1f')run('cp -rp /app/release/%s /app/web/xcspam/ ' % newRelease)run('unlink bin')run('ln -sn %s bin' % newRelease)run('superctl restart chatxcspam:*')def chatxcspam():with cd('/app/web/xcspam'):lastrelease=run('ls -rtd xcspam* |tail -2 |head -1')run('unlink bin')run('ln -sn %s bin' % lastrelease)run('superctl restart chatxcspam:*’)3) 脚本3
[work@qd-op-zhongkong op]$ cat xcspam-consumer-all.py
from fabric.api import *
from fabric.context_managers import *
import datetimeenv.hosts=['qd-vpc-op-consumer01','qd-vpc-op-consumer02']def xcspam():with cd('/app/release'):date=datetime.datetime.now().strftime("%Y%m%d%H%M%S")repo='http://git.kevinweb.com/zuiyou_server/xcspam.git';run('git clone --depth=1 %s' % repo)newNmae="xcspam"+"-"+daterun('mv xcspam %s ' % newNmae)with cd('/app/web/xcspam'):newRelease=run('ls /app/release/ |tail -1f')run('cp -rp /app/release/%s /app/web/xcspam/ ' % newRelease)run('unlink bin')run('ln -sn %s bin' % newRelease)run('superctl restart xcspam:*')def rollxcspam():with cd('/app/web/xcspam'):lastrelease=run('ls -rtd xcspam* |tail -2 |head -1')run('unlink bin')run('ln -sn %s bin' % lastrelease)run('superctl restart xcspam:*')def chatxcspam():with cd('/app/release'):date=datetime.datetime.now().strftime("%Y%m%d%H%M%S")repo='http://git.kevinweb.com/zuiyou_server/xcspam.git';run('git clone --depth=1 %s' % repo)newNmae="xcspam"+"-"+daterun('mv xcspam %s ' % newNmae)with cd('/app/web/xcspam'):newRelease=run('ls /app/release/ |tail -1f')run('cp -rp /app/release/%s /app/web/xcspam/ ' % newRelease)run('unlink bin')run('ln -sn %s bin' % newRelease)run('superctl restart chatxcspam:*')def chatxcspam():with cd('/app/web/xcspam'):lastrelease=run('ls -rtd xcspam* |tail -2 |head -1')run('unlink bin')run('ln -sn %s bin' % lastrelease)run('superctl restart chatxcspam:*')def all():with cd('/app/release'):date=datetime.datetime.now().strftime("%Y%m%d%H%M%S")repo='http://git.kevinweb.com/zuiyou_server/xcspam.git';run('git clone --depth=1 %s' % repo)newNmae="xcspam"+"-"+daterun('mv xcspam %s ' % newNmae)with cd('/app/web/xcspam'):newRelease=run('ls /app/release/ |tail -1f')run('cp -rp /app/release/%s /app/web/xcspam/ ' % newRelease)run('unlink bin')run('ln -sn %s bin' % newRelease)run('superctl restart all')def rollall():with cd('/app/web/xcspam'):lastrelease=run('ls -rtd xcspam* |tail -2 |head -1')run('unlink bin')run('ln -sn %s bin' % lastrelease)run('superctl restart all')可以根据需求去选择具体对那个项目进行上线,上述脚本定义了两个项目上线,第三个(all)即表示同时上线两个项目。
[work@qd-op-zhongkong op]$ fab -f xcspam-consumer-all.py xcspam
[work@qd-op-zhongkong op]$ fab -f xcspam-consumer-all.py chatxcspam
[work@qd-op-zhongkong op]$ fab -f xcspam-consumer-all.py all

Python自动化运维工具-Fabric部署及使用总结相关推荐

  1. Python自动化运维工具fabric的安装

    使用shell命令进行复杂的运维时,代码往往变得复杂难懂,而使用python脚本语言来编写运维程序,就相当于开发普通的应用一样,所以维护和扩展都比较简单,更重要的是python运维工具fabric能自 ...

  2. 轻量级自动化运维工具Fabric的安装与实践

    一.背景环境 在运维工作中,经常会遇到重复性的劳动,这个时候为了效率就必须要使用自动化运维工具. 这里我给大家介绍轻量级自动化运维工具Fabric,Fabric是基于Python语言开发的,是开发同事 ...

  3. mysql 自动化运维工具_部署MySQL自动化运维工具inception+archer

    *************************************************************************** 部署MySQL自动化运维工具inception+ ...

  4. Python自动化运维介绍

    一 技能要求 1 了解Python基础知识 2 了解运维的基础知识 3 运行环境:python2.7 二 运维发展的不同阶段 1 传统运维 命令行 批量脚本 2 自动化运维 3 云运维 三 传统运维特 ...

  5. 自动化运维工具Ansible详细部署

    一.基础介绍 ================================================================================= 1.简介 ansibl ...

  6. DevOps实战 —— 如何高效地远程部署?自动化运维利器 Fabric 教程

    如何高效地远程部署?自动化运维利器 Fabric 教程 关于 Python 自动化的话题,在上一篇文章中,我介绍了 Invoke 库,它是 Fabric 的最重要组件之一.Fabric 也是一个被广泛 ...

  7. 自动化运维工具Ansible实战(一)简介和部署

    一.Ansible的介绍 Ansible是新出现的自动化运维工具,基于Python开发,集合了众多运维工具(puppet.cfengine.chef.func.fabric)的优点.实现了批量系统配置 ...

  8. Ansible自动化运维工具介绍与部署

    ansible自动化运维工具介绍与部署 文章目录 一.什么是自动化运维? 二.常用的自动化运维工具 2.1 Ansible 2.2 SaltStack 2.3 Puppet 2.4 三种自动化工具特点 ...

  9. python开发web运维工具_【实战小项目】python开发自动化运维工具--批量操作主机...

    有很多开源自动化运维工具都很好用如ansible/salt stack等,完全不用重复造轮子.只不过,很多运维同学学习Python之后,苦于没小项目训练,本篇演示用Python写一个批量操作主机的工具 ...

最新文章

  1. 强化学习最新作品:谷歌最新思想、MIT新书推荐、Sutton经典之作!
  2. 中国第一大善人是他!福布斯2019中国慈善榜发布:马云才排第三
  3. 传统的主从复制的概念和要点
  4. 11gR2conceptes Memory Architecture中文翻译
  5. Linux下创建与解压zip, tar, tar.gz和tar.bz2文件--转 .
  6. promise.prototype.catch()
  7. 编写程序,求柱体的体积:
  8. 阿里程序员,工作6年,真实薪资曝光
  9. 一维条码之code93码的生成和打印
  10. cnzz.php,CNZZ站长统计代码报错解决方法
  11. Travis CI mysql_连续集成 – 使用Travis CI配置Mysql 5.7
  12. 计算机制作贺卡教案,三八爱心节贺卡教案
  13. hp ilo 服务器磁盘定位
  14. Linux下进入PostgresSQL数据库有哪些比较常用的操作命令
  15. HTML5期末大作业:漫画网站设计——海贼王我当定了(6页) web前端期末大作业 html+css+javascript网页设计实例 企业网站制作 计算机毕设网页设计源码
  16. 07uec++多人游戏【瞄准镜效果】
  17. 复旦大学和中科大 计算机,强基计划遇冷?!复旦大学和中科大都没招满...
  18. 借助计算机音乐,计算机音乐教育在高校中的重要性
  19. 中文输入法/搜狗输入法的配置 搜狗输入法选词乱码 谷歌浏览器安装
  20. 洲际酒店品牌中国西北地区首家酒店在西安开业

热门文章

  1. ITK:从标量图像创建矢量图像
  2. C++ sodoku solve数独算法(附完整源码)
  3. C++平衡二叉树(AVL树)
  4. QT的QAudioOutput类的使用
  5. c++STL容器的List
  6. 程序设计方法的发展历程
  7. C++STL容器大全
  8. ubuntu 命令卡住_如何在Ubuntu系统中重置root密码
  9. android 讯飞语音评测,讯飞语音评测demo
  10. Hive集成Tez引擎跑任务出现的问题(Java heap space问题)