ansible

本文围绕自动化运维工具Ansible展开,介绍其基于Python开发、模块化、幂等性等特点,阐述了架构、工作原理,详细讲解搭建与配置方法,包括主配置文件、主机清单等。还列举常用模块、相关工具,以及Playbook的执行流程、格式、核心元素等内容。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

自动化运维工具分类

运维自动化发展
在这里插入图片描述

ansible介绍与原理

ansible是基于python开发的
ansible的名字来自于科幻小说
ansible不用配置代理也就是C/S结构,saltstack需要配置代理,ansible不用装代理服务器是因为ssh面密,但是ansible的性能没有saltstack好,ansible因为是基于ssh去远程控制,当我们用ansible去控制几百台主机后他的性能就会下降,而saltstack并不是,它基于agent与server通讯,性能远高于ssh,如果主机再多就用puppet,
ansible他也是模块化,一个模块相当于我们linux的一个命令比如
paramiko:这个模块是基于python开发的,他可以实现ssh远程的连接管理
pyYAML:这个模块是一个类似脚本语言,他不光ansible会用他在别处也会用,它是用来写剧本(playbook)的
ansible有一个特新就是幂等性,多次执行和一次执行的结果是一样的 ,比如你执行多次创建账号命令首先第一次执行成功,第二次发现已经有这个账号了就不会执行

ansible架构

在这里插入图片描述
注: host inventory里面记录了主机清单,如果不加入清单就不能被执行

ansible工作原理

在这里插入图片描述
我们可以通过CMDN或者公有云,私有云,用户去调用ansible的模块,或者开发者用api,模块,插件等等来管理HOST或者网络设备

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

ansible搭建

在这里插入图片描述

ansibe 配置

ansible的配置文件

在这里插入图片描述

ansible的主配置文件

/etc/ansible/ansible.cfg位ansible的主配置文件
这个文件也是由中括号分成了多个语句块

[default] //就是默认的一些配置  
#inventory      = /etc/ansible/hosts	#主机清单
#library        = /usr/share/my_modules/
#module_utils   = /usr/share/my_module_utils/	#模块路径
#remote_tmp     = ~/.ansible/tmp		#远程临时目录
#local_tmp      = ~/.ansible/tmp		#这个目录的作用是当你输入一个远程命令比如ping时他会转换成py脚本然后放到这个目录下然后复制到上remote_tmp目录和所有的远程主机下这个目录下,完成后就删掉
#plugin_filters_cfg = /etc/ansible/plugin_filters.yml
#forks          = 5		#fork除5个子程序并发执行
#poll_interval  = 15 
#sudo_user      = root		#在远程执行命令的时候用sudo到root
#ask_sudo_pass = True
#ask_pass      = True
#transport      = smart
#remote_port    = 22		#远程主机端口号  
#host_key_checking = False #远程连接主机的时候是否验证其公钥(/root/.ssh/known_hosts),如果没有就不能建立连接,建议取消注释  
#log_path=/var/log/ansible.log		#记录日志,默认不记录,这个文件默认没有当我们执行一次远程管理操作就自动生成
#module_lang    = C
#module_set_locale = False  


//以下时关于颜色的定义
[colors]
#highlight = white
#verbose = blue
#warn = bright purple
#error = red
#debug = dark gray
#deprecate = purple
#skip = cyan
#unreachable = red	//不可到达
#ok = green
#changed = yellow	//完成命令并且改过对方主机(重启了某个服务,或者改了某个文件)
#diff_add = green
#diff_remove = red
#diff_lines = cyan

ansible命令

ansible-doc + 模块名字,查看模块怎么用的  
ansible-doc -l  #列出所有模块    
ansible命令格式  
ansible <host-patten> [-m modle_name] [-a args]//模块的参数   
			          --version   
	     			  -m module //指定模块   
	     			  -v //详细信息-vv更详细,-vvv更更详细   
	      group/all	  --list-hosts //显示主机列表可以简写成--list  
	     			  -k //--ask-pass 提示输入ssh连接密码,默认key验证   
	     			  -K 	//--ask-become-pass 提示输入sudo时的口令
	     			  -C //--check 检查不执行  
	     			  -T	//--timeout设置执行命令时的超时时间默认10S  
	     			  -u	//--user=REMOTE_USER执行远程执行的用户  
	     			  -b	//--become 代替旧版本的sudo切换
//例如    
[root@zhr ~]# ansible switch -m command -a 'ls /root' -u cumulus -k -b -K  //我们对应switch组做操作,调用command模块-a指定模块的参数,其中参数就是ls /root -u选的远程执行命令的用户(用户是远程本地的用户)-k远程连接时输入口另,-b进行sudo切换默认切换到root,-K输入切换时的口另也是用户cumulus的密码,前提时cumulus需要有sudo的权利我们可以通过visudo进行指定  
//注意host-patten支持通配符比如*itch,192.168.100.*,
//如果想要执行2个group可以用逻辑符或者:例如  ansible ‘webserver:switch’ -m ping  
// ansible又有逻辑与  ansible ’webserver:&switch‘ -m ping  他代表webserver中并且也在switch中的主机  
//逻辑非 ansible ’webserver:!switch‘  -m ping  他代表在webserver中的主机但是这个主机不能出现在switch组(注意此处位单引号)  
//也支持正则表达式  

主机清单 inventory

主机清单是我们首要要配置的,如果不把待控制的主机放入主机清单,那么我们就不能去远程管理他
我们要检查主机是否存活我们一般会选择ping命令,但是我们的ansible里面也有ping命令,但是他和linux里的ping不一样,linux里的ping是基于icmp,而我们的这个ping他是一个模块,如果对端主机收到就会回一个pong例如

[root@ansible ~]# ansible 192.168.10.121 -m ping 
 [WARNING]: provided hosts list is empty, only localhost is available. Note that the implicit localhost does not match 'all'

 [WARNING]: Could not match supplied host pattern, ignoring: 192.168.10.121

[root@ansible ~]#   
//报错了因为我们的这个主机不在主机清单里面所以我们加入他  
[root@ansible ~]# vim /etc/ansible/hosts   
//我们先简单配置直接再文件里面加上ip  
192.168.10.121 
192.168.10.214  
:wq  


[root@ansible ~]# ansible 192.168.10.121 -m ping 
The authenticity of host '192.168.10.121 (192.168.10.121)' can't be established.
ECDSA key fingerprint is SHA256:7sA3ENaSbSsc9XygbQduoX1YG4rMLLa/awgwHWtmFUo.
ECDSA key fingerprint is MD5:0e:80:3d:91:79:b6:aa:a8:32:57:5c:b7:6f:3a:fe:be.
Are you sure you want to continue connecting (yes/no)?   yes
//这明显是ssh的界面说明我们的ping是走的是ssh协议我们输入yes  
192.168.10.121 | UNREACHABLE! => {
    "changed": false, 
    "msg": "Failed to connect to the host via ssh: Warning: Permanently added '192.168.10.121' (ECDSA) to the list of known hosts.\r\nroot@192.168.10.121: Permission denied (publickey,gssapi-keyex,gssapi-with-mic,password).\r\n", 
    "unreachable": true
}
//报错了,因为ansible默认是基于key的也就是ssh我们没有配置key,所以我们就进行传统的方法登陆  
[root@ansible ~]# ansible 192.168.10.121 -m ping  -k 
SSH password:  //192.168.10.121密码
192.168.10.121 | SUCCESS => {
    "changed": false, 
    "ping": "pong"
}
[root@ansible ~]#   
//成功! 

我们管理多台主机

[root@ansible ~]# ansible 192.168.10.121,192.168.10.214 -m ping  -k   
SSH password: 
192.168.10.214 | FAILED! => {
    "msg": "Using a SSH password instead of a key is not possible because Host Key checking is enabled and sshpass does not support this.  Please add this host's fingerprint to your known_hosts file to manage this host."
}
192.168.10.121 | SUCCESS => {
    "changed": false, 
    "ping": "pong"
}
[root@ansible ~]#  
//失败了,因为我们输入密码是10.121的密码我们10.214的密码和我们输入的不一样所以只能访问121,而我们的214访问不了

主机清单中我们也可以加入主机组

[root@zhr ~]# vim /etc/ansible/hosts   
[switch]
192.168.100.21
192.168.100.22  
//他等同于  
[swith]
192.168.100.2[1:2]   //使用扩展我们linux bash的扩展是大括号这个是中括号  
//如果主机的ssh端口号为了安全把ssh端口号改成非标准的22号端口,我们需要特别指定例如   
[swith]  
192.168.100.2:2222 //指定ssh端口位2222  
//指定组后我们可以直接根据组来操作例如  
:wq 
[root@zhr ~]# ansible switch -m ping -k  
SSH password: 
192.168.100.22 | FAILED! => {
    "msg": "Using a SSH password instead of a key is not possible because Host Key checking is enabled and sshpass does not support this.  Please add this host's fingerprint to your known_hosts file to manage this host."
}
192.168.100.21 | FAILED! => {
    "msg": "Using a SSH password instead of a key is not possible because Host Key checking is enabled and sshpass does not support this.  Please add this host's fingerprint to your known_hosts file to manage this host."
}

报错了,为什么?因为我们他是基于known_hosts文件的,如果这个文件里面没有对应的hosts和对应公钥他ansible就不会发起连接,known_hosts是我们每ssh连接一个主机他就会加入到/root/.ssh/known_hosts文件中我们使用ssh连接一下不用输密码只需输入前面的yes就会记录在案,然后我们再连接

[root@zhr ~]# ansible switch -m ping -k          
SSH password: 
192.168.100.21 | SUCCESS => {
    "changed": false, 
    "ping": "pong"
}
192.168.100.22 | SUCCESS => {
    "changed": false, 
    "ping": "pong"
}
[root@zhr ~]#   
//成功

基于key验证

所以输入口另的方式只适合密码一样的情况,所以我们建议基于key验证
使用key验证我们回顾一下ssh面密登陆的原理
首先我们基于密码的验证

我们的client端要访问server端要基于密码验证,首先client想server端发起连接请求,然后server端把自己的公钥发送到client端上,client端把server端的密码用公钥加密然后发送给server端,server端用私钥解密,得到密码再验证密码是否正确,如果正确就同意client的连接,注意我们的client每连接一个主机都会收到公钥,公钥文件就存在/root/.ssh/known_hosts每一次连接会核对这个公钥,如果公钥和ip不一致会警告,需要你手动删除
在这里插入图片描述

基于key的面密登陆

首先我们的client想要面密连接server端,client要有一对公钥和私钥,并且client的公钥需要在server的本地(/.ssh/authorized_keys文件中),然后第一步客户端发送连接请求给服务端,并且将自己的公钥发给server端,server端验证公钥的合法性(验证/.ssh/authorized_keys文件),然后用这个公钥随机生成一端密钥,并且将密钥发送给client,client收到后用自己的私钥解密,得到server随机生成的密文,然后client将密文发送给server,server核对密文如果正确就于客户端建立连接
在这里插入图片描述

//1,主控端生成密钥
[root@zhr ~]# ssh-key
ssh-keygen   ssh-keyscan  
[root@zhr ~]# ssh-keygen 
Generating public/private rsa key pair.
Enter file in which to save the key (/root/.ssh/id_rsa): 
/root/.ssh/id_rsa already exists.
Overwrite (y/n)? y
Enter passphrase (empty for no passphrase): 
Enter same passphrase again: 
Your identification has been saved in /root/.ssh/id_rsa.
Your public key has been saved in /root/.ssh/id_rsa.pub.
The key fingerprint is:
SHA256:/ep9erf1L0Gr3NLheITKvFR2pmzYIP3lzt7DJlYpblQ root@zhr
The key's randomart image is:
+---[RSA 2048]----+
|                 |
|                 |
|                 |
|         o    .E |
|        S + oo=..|
|         . X.O=o |
|         oooXB=o.|
|         .++=BO=+|
|         .+.=B*+B|
+----[SHA256]-----+
[root@zhr ~]#   

//2.将主控端的公钥发送到被控端  


[root@zhr ~]# ssh-copy-id 192.168.10.121 
/usr/bin/ssh-copy-id: INFO: Source of key(s) to be installed: "/root/.ssh/id_rsa.pub"
The authenticity of host '192.168.10.121 (192.168.10.121)' can't be established.
ECDSA key fingerprint is SHA256:7sA3ENaSbSsc9XygbQduoX1YG4rMLLa/awgwHWtmFUo.
ECDSA key fingerprint is MD5:0e:80:3d:91:79:b6:aa:a8:32:57:5c:b7:6f:3a:fe:be.
Are you sure you want to continue connecting (yes/no)? yes
/usr/bin/ssh-copy-id: INFO: attempting to log in with the new key(s), to filter out any that are already installed
/usr/bin/ssh-copy-id: INFO: 1 key(s) remain to be installed -- if you are prompted now it is to install the new keys
root@192.168.10.121's password: 

Number of key(s) added: 1

Now try logging into the machine, with:   "ssh '192.168.10.121'"
and check to make sure that only the key(s) you wanted were added.

[root@zhr ~]# ssh-copy-id 192.168.10.214 
/usr/bin/ssh-copy-id: INFO: Source of key(s) to be installed: "/root/.ssh/id_rsa.pub"
The authenticity of host '192.168.10.214 (192.168.10.214)' can't be established.
ECDSA key fingerprint is SHA256:xcJyWfNhjT3HCBkvM0GZUrAcBxJxoKuW16niLDAVPqM.
ECDSA key fingerprint is MD5:d7:96:35:cc:fa:a3:d3:c6:c4:b3:e9:f8:f6:f7:48:9d.
Are you sure you want to continue connecting (yes/no)? yes
/usr/bin/ssh-copy-id: INFO: attempting to log in with the new key(s), to filter out any that are already installed
/usr/bin/ssh-copy-id: INFO: 1 key(s) remain to be installed -- if you are prompted now it is to install the new keys  
...
...
...  
3,我们使用ansible远程操作主机只用加模块和模块命令即可  
[root@zhr ~]# ansible all -m ping       
192.168.100.22 | SUCCESS => {
    "changed": false, 
    "ping": "pong"
}
192.168.100.21 | SUCCESS => {
    "changed": false, 
    "ping": "pong"
}

ansible常用模块

command

command模块就是执行shell命令,他也是默认模块
模块参数就是命令 -a就是执行模块命令

[root@zhr ~]#ansible all -m command -a ‘ ls -al /root’  
[root@zhr ~]#ansible  all -a 'ls -al /root'  //因为是默认模块  
[root@zhr ~]#ansible-doc command  
creates  当文件存在就不执行后面的命令
removes 当文件不存在就不执行后面的命令   
chdir 切换到某个文件夹下 
[root@zhr ~]#ansible all -a 'removes=/etc/fs cat /etc/fstab' 	//当/etc/fs不存在就不执行后面的命令,也就是说如果他存在就执行后面的命令也就是cat...  
[root@zhr ~]#ansible all -a 'creates=/etc/fs cat/etc/fstab'  //当/etc/fs存在就不执行后面的命令,也就是如果这个文件不存在就执行后面的命令  
[root@zhr ~]#ansible all -a ‘chdir=/etc ls -al’  //我们先切到/etc下然后在执行ls -al的命令   
//我们也可以跑某个脚本    
//但是我们要小心,command命令对管道,对重定向,对变量都有问题,他不能满足我们的需求,所以我们还有一个模块Shell

shell模块

shell模块和command模块差不多都是用来远程执行命令的但是shell模块不是标准模块所以要加上-m 例如

[root@zhr ~]# ansible 192.168.10.214 -m shell  -a 'echo $HOSTNAME'
192.168.10.214 | SUCCESS | rc=0 >>
node1
//如果我们用双引号则是打印本地的变量  
[root@zhr ~]# ansible 192.168.10.214 -m shell  -a "echo $HOSTNAME" 
192.168.10.214 | SUCCESS | rc=0 >>
zhr
command的其他功能shell也支持   

script模块

script模块是专门用来在远端执行本地脚本的

script也支持create,remove等等
我们本地/root下有一个脚本host.sh我们想在别的机器上执行他  
[root@zhr ~]# ansible 192.168.100.21,192.168.10.214 -m script -a '/root/host.sh'        
192.168.100.21 | SUCCESS => {
    "changed": true, 
    "rc": 0, 
    "stderr": "Shared connection to 192.168.100.21 closed.\r\n", 
    "stdout": "cumulus\r\n", 
    "stdout_lines": [
        "cumulus"
    ]
}
192.168.10.214 | SUCCESS => {
    "changed": true, 
    "rc": 0, 
    "stderr": "Shared connection to 192.168.10.214 closed.\r\n", 
    "stdout": "node1\r\n", 
    "stdout_lines": [
        "node1"
    ]
}
[root@zhr ~]#   
//成功

copy模块

copy模块用来拷贝文件的,他的主要参数
src= //指定源文件
dest= //指定目标文件
backup=yes //当我们把文件复制到远程主机后如果出现覆盖先把源文件备份一份
owner=zhr //拷贝过去后将拥有着改编成zhr
mode=000 //拷贝过去后权限改成000
content=“。。。。。。” //指定内容,然后写入到指定文件中例如
-a ‘content=“hello/nhello/n” dest=/etc/fs’ //将hello/nhello/n 传递到远端的/etc/fs中如果没有就创建

[root@zhr selinux]# ansible 192.168.100.21,192.168.10.214 -m copy -a 'src=/etc/sysconfig/selinux dest=/etc/sysconfig/selinux backup=yes'  

[root@zhr selinux]# ansible 192.168.10.214  -a 'ls -al  /etc/sysconfig/'  
-rw-r--r--.   1 root root  547 Dec  3 18:41 selinux
-rw-r--r--.   1 root root  547 Dec  3 18:37 selinux.31994.2018-12-03@18:41:41~  
//的确做了备份

fetch模块

fetch模块用来从远端抓取文件(单个文件,不能是目录)和copy相反
dest= //指定目标文件(将远端的文件保存在本地哪里如果这个文件不存在就自动的创建一个然后报错,当然他会执行成功),他不支持通配符,所以我们要抓多个文件可以先用shell给多个文件打包然后再抓取
src= //指定远端的文件

[root@zhr log]# ansible all -m fetch -a 'src=/var/log/messages dest=/data'  
[root@zhr log]# pwd
/data/192.168.10.214/var/log  
#我们看到他会自动的在本地创建一个data(如果data不存在的话),然后创建一个文件这个文件为ip地址,然后创建/var/log/再把messages放到里面,

file 模块

file模块专门针对文件的创建,权限的更改,
name= 指定远端的文件,dest,path他们三个的意义都一样
state= 指定状态,比如touch(创建空文件),absent(删除文件),directory(创建文件夹) ,link(创建软连接)
owner=zhr 指定文件拥有者为zhr
mode=755 指定文件权限为755

[root@zhr log]# ansible 192.168.100.21 -m file -a 'name=/home/fs state=touch'    	#创建一个文件再home下为fs
192.168.100.21 | SUCCESS => {
    "changed": true, 
    "dest": "/home/fs", 
    "gid": 0, 
    "group": "root", 
    "mode": "0644", 
    "owner": "root", 
    "size": 0, 
    "state": "file", 
    "uid": 0
}  
[root@zhr log]# ansible 192.168.100.21 -m shell -a 'ls /home'                #创建成功!      
192.168.100.21 | SUCCESS | rc=0 >>
cumulus
fs
[root@zhr log]# ansible 192.168.100.21 -m file -a 'name=/home/fs state=absent'	#删除他
192.168.100.21 | SUCCESS => {
    "changed": true, 
    "path": "/home/fs", 
    "state": "absent"
}
[root@zhr log]# ansible 192.168.100.21 -m shell -a 'ls /home'                 #查看删除成功
192.168.100.21 | SUCCESS | rc=0 >>
cumulus  
[root@zhr log]# ansible 192.168.100.21 -m file -a 'name=/home/dir1 state=directory'
192.168.100.21 | SUCCESS => {
    "changed": true, 
    "gid": 0, 
    "group": "root", 
    "mode": "0755", 
    "owner": "root", 
    "path": "/home/dir1", 
    "size": 0, 
    "state": "directory", 
    "uid": 0
}  

[root@zhr log]# ansible 192.168.100.21 -m shell -a 'ls -d /home/*'  #创建文件夹成功
192.168.100.21 | SUCCESS | rc=0 >>
/home/cumulus
/home/dir1  
[root@zhr log]# ansible 192.168.100.21 -m file -a 'name=/home/dir1 state=absent'	#删除文件夹
192.168.100.21 | SUCCESS => {
    "changed": true, 
    "path": "/home/dir1", 
    "state": "absent"
}
[root@zhr log]# ansible 192.168.100.21 -m shell -a 'ls -d /home/*'              #删除文件夹成功
192.168.100.21 | SUCCESS | rc=0 >>
/home/cumulus  
[root@zhr log]# ansible 192.168.100.21 -m file -a 'src=/etc/fstab dest=/home/fstab.link state=link' 	#创建一个软连接,注意这里的src是远程主机中的文件,dest也是远程主机的文件
192.168.100.21 | SUCCESS => {
    "changed": true, 
    "dest": "/home/fstab.link", 
    "gid": 0, 
    "group": "root", 
    "mode": "0777", 
    "owner": "root", 
    "size": 10, 
    "src": "/etc/fstab", 
    "state": "link", 
    "uid": 0
}
[root@zhr log]#   
[root@zhr log]# ansible 192.168.100.21 -m shell -a 'ls -al /home/' 	#查看创建软连接成功
192.168.100.21 | SUCCESS | rc=0 >>
total 4
drwxr-xr-x 1 root    root     34 Dec  4 10:52 .
drwxr-xr-x 1 root    root    210 Oct 12 08:16 ..
drwxr-xr-x 1 cumulus cumulus  98 Nov 30 09:26 cumulus
lrwxrwxrwx 1 root    root     10 Dec  4 10:52 fstab.link -> /etc/fstab  
}
[root@zhr log]# ansible 192.168.100.21 -m file -a 'name=/root/fs mode=755 owner=root'      #改变远端/root/fs文件的属性为755,拥有者为root          
192.168.100.21 | SUCCESS => {
    "changed": true, 
    "gid": 0, 
    "group": "root", 
    "mode": "0755", 
    "owner": "root", 
    "path": "/root/fs", 
    "size": 0, 
    "state": "file", 
    "uid": 0
}
[root@zhr log]# ansible 192.168.100.21 -m shell -a 'ls -al /root/fs'                 #查看改变成功
192.168.100.21 | SUCCESS | rc=0 >>
-rwxr-xr-x 1 root root 0 Dec  4 11:02 /root/fs

[root@zhr log]# 

hostname模块

此模块专门用来更改主机名的,而且他会更改远端主机名而且也会写入配置文件,但是他不会更改hosts文件
直接指定name=… 指定主机名

[root@zhr ~]# ansible 192.168.100.21 -m hostname -a 'name=cumulus1'     
192.168.100.21 | SUCCESS => {
    "ansible_facts": {
        "ansible_domain": "", 
        "ansible_fqdn": "cumulus1", 
        "ansible_hostname": "cumulus1", 
        "ansible_nodename": "cumulus1"
    }, 
    "changed": true, 
    "name": "cumulus1"
}
#生效  
[root@zhr ~]# ansible 192.168.100.21 -m shell -a 'cat /etc/hostname'                             
192.168.100.21 | SUCCESS | rc=0 >>
cumulus1 
发现已经更改

cron模块

此模块是专门指定远端主机的计划任务

  • - minute=:指定分钟 格式和crontab一样支持*,/1,“1,3,5”,1-5 如果不写默认是,后面的分时日月周都是一样
  • - hour= :指定小时
  • - day=:指定日期
  • - month=:指定月
  • - weekday=:指定周
  • - job="":指定命令命令用双引号括起来
  • - name=:指定计划任务的名字
  • -disabled=true/false yes/no:注释计划任务但是要在后面加上job指定是什么计划任务,也要加上计划任务的名字如果不加上名字他不会报错,但是他会输出# job,原计划任务不会删除,所以一定要加上name
  • -state=absent:删除计划任务,加上名字和job
#我们计划每周1,2,5的每分钟都执行wall FBI warning 命令此命令是打印出FBI warning这个字符串给每一个用户    
[root@zhr ~]# ansible 192.168.100.21 -m cron -a 'minute=* weekday=1,2,4 job="/usr/bin/wall FBI Warning" name=fbi_warning'
192.168.100.21 | SUCCESS => {
    "changed": true, 
    "envs": [], 
    "jobs": [
        "fbi_warning"
    ]
}
[root@zhr ~]# 
[root@zhr ~]# ansible 192.168.100.21 -m cron -a 'disabled=true job="/usr/bin/wall FBI Warning" name=fbi_warning ' 
192.168.100.21 | SUCCESS => {
    "changed": true, 
    "envs": [], 
    "jobs": [
        "fbi_warning"
    ]
}
[root@zhr ~]# ansible 192.168.100.21 -m shell -a 'crontab -l'                                                         
192.168.100.21 | SUCCESS | rc=0 >>
#Ansible: fbi_warning
#* * * * * /usr/bin/wall FBI Warning
#创建成功,我们来删除他  
[root@zhr ~]# ansible 192.168.100.21 -m cron -a 'job="/usr/bin/wall FBI Warning" name=fbi_warning  state=absent' 
192.168.100.21 | SUCCESS => {
    "changed": true, 
    "envs": [], 
    "jobs": []
}
[root@zhr ~]# ansible 192.168.100.21 -m shell -a 'crontab -l'
192.168.100.21 | SUCCESS | rc=0 >>
#删除成功

yum模块

用来管理rpm包的模块,
name= :#指定软件的名字
list=: #列出信息,常用的参数有installed(列出已安装的),updates(列出更新的),available(列出可用的),reoo(列出仓库)
state=: #设置状态,比如常用的installed,present(安装),latest(为更新),removed,absent(为删除),默认是installed
disable_gpg_check=yes/no #禁用key检查
update_cache=yes/no #升级缓存

[root@zhr ~]# ansible all -m yum -a 'name=vsftpd' #装vsftpd软件在所有被控制的主机上,但是注意被控制的主机要已经配好了yum源    
[root@zhr ~]# ansible FS-hosts -m  yum -a 'list=installed'	#列出所有已安装的软件
[root@zhr ~]# ansible FS-hosts -m  yum -a 'name=tree state=installed'		#另外一种安装方法  
[root@zhr ~]# ansible FS-hosts -m  yum -a 'name=tree state=removed'	#删除某一个包

service模块

此模块用来管理服务用的
enabled=yes/no #开机启动
state= #设定状态,started,stopped,restarted,reloaded
name= #指定服务名字

[root@zhr ~]# ansible FS-hosts -m service -a 'name=vsftpd state=started enabled=yes' 	#开启某个服务并且开机启动  

user模块

此模块用来创建用户的
name= #指定用户的名字
state= #指定命令的状态有present和absent(默认present如果不指定state的话)
remove=yes/no # 此命令相当于我们userdel -r选项删除他的家目录邮箱等等信息
shell= #指定用户的shell
system=yes/no #是否为系统用户
home=/to/somewahre #为用户指定家目录
groups= #指定附加组
group= #指定主组
uid= #指定uid
comment="…" #指定用户信息注释

[root@zhr ~]# ansible FS-hosts -m user -a 'name=zhr1 shell=/sbin/nologin system=yes home=/var/zhr groups=root,bin uid=1200 comment="this is a user"'

group

此模块用来创建组
gid= #指定组的gid
name= #指定组名字
state= #指定此命令的状态,有absent和present(默认present)
system=yes/no #指定是否为系统组

setup

此模块用来收集远端主机信息的,而且输出格式是 变量:值,并且这个变量可以直接在playbook中用

如果我们直接的输入setup会输出一长段信息所以setup支持过滤   
[root@zhr ~]# ansible switch -m setup  -a 'filter='     	#filter就是过滤的意思=后面加上过滤的选项

ansible相关的工具

ansible-galaxy

专门用来下载galaxy.ansible.com中别人写好的角色(role)

安装某一个role在galaxy.ansible.com中

[root@zhr ~]# ansible-galaxy install 	maxlareo.cumuluslinux	
#当我们下载完成后他会在/root/.ansible/roles下生成一个以role名字命名的文件夹里面
[root@zhr ~]# cd /root/.ansible/roles/
[root@zhr roles]# ls
maxlareo.cumuluslinux
[root@zhr roles]# cd maxlareo.cumuluslinux/
[root@zhr maxlareo.cumuluslinux]# ls
defaults  handlers  LICENSE  lookup_plugins  meta  README.md  tasks  tests  vars
#其中task是放剧本的文件剧本都是由yml语言写的   
[root@zhr maxlareo.cumuluslinux]# cd tasks/
[root@zhr tasks]# ls
bond.yml  commands.yml  common.yml  interface.yml  license.yml  main.yml  snmp.yml  syslog.yml  vlan.yml
[root@zhr tasks]# 

查看某一个role

[root@zhr tasks]# ansible-galaxy list maxlareo.cumuluslinux
- maxlareo.cumuluslinux, 1.1.0
[root@zhr tasks]#    

如果我们想删除的话可以直接删除目录也可以使用命令

[root@zhr tasks]# ansible-galaxy remove maxlareo.cumuluslinux	#删除某个role

ansible-vault

专门用来加密playbook文件的
比如

[root@zhr ~]# ansible-vault encrypt first_playbook.yml  	#加密first_playbook.yml文件
New Vault password: 	#为他提供口令
Confirm New Vault password: 	
Encryption successful
[root@zhr ~]#   
我们在查看playbook文件  
[root@zhr ~]# cat  first_playbook.yml                       
$ANSIBLE_VAULT;1.1;AES256
64633265613063353136313563666138316565666364303931323831346162633365373130396437
3634623534666535393461396266393136343832356666610a393138356361653733366161313737
37653562393937376437626437636463333265666330626138636236343564303333613138343232
6439383134303162650a653366356166343432623462643164306362393461326334343236306431
63313432663237313135636331613865623036333132363038303736353530653730366330633634
64373130363238316236653139396662623861353663363132376261643537316632653566363463
65363131306235333935343330623437356362336366656133363630383763623662663732323636
37316662396436353065663938383366636161633537373633643836636337343532366366363633
63616163663733366634356433373265616331303136333235336239313930316239346634623535
3661356435343736323237333939383462646232313635646462
[root@zhr ~]# 
#为一堆密文  
#加密之后不能直接运行,如果我们想运行所以我们要先解密  
[root@zhr ~]# ansible-vault view first_playbook.yml 	#我们可以查看加密的playbook文件
Vault password: 
---
  - hosts: switch  
    remote_user: root
    tasks:  
      - name: hello      
        command: hostname

[root@zhr ~]#   
[root@zhr ~]# ansible-vault edit first_playbook.yml   	#我们也可以编辑他,但是当我们编辑他的时候他会让我们设置新的口令  
Vault password: 
New Vault password: 
Confirm New Vault password:   
[root@zhr ~]# ansible-vault  decrypt first_playbook.yml   		#我们也可以使用命令去解密first_playbook.yml文件
Vault password: 
Decryption successful
[root@zhr ~]#   
[root@zhr ~]# ansible-vault rekey  first_playbook.yml	#重新加密         
Vault password: 
New Vault password: 
Confirm New Vault password: 

ansible-console

此命令可以交互式执行命令

[root@zhr ~]# ansible-console
Welcome to the ansible console.
Type help or ? to list commands.

root@all (7)[f:5]$				#root代表我们是什么身份,all说明我们可以对那些主机执行命令,7代表我们控制的有几台机器,f:5代表我们可以并发执行5台主机   
root@all (7)[f:5]$ cd switch	#进入switch组,也可以cd 某一个ip进入某个主机
root@switch (5)[f:5]$ 
root@switch (5)[f:5]$ forks 10	#设置并发链接为10
root@switch (5)[f:10]$   
root@switch (5)[f:10]$ shell hostname	#指定模块后加命令不用-a选项
192.168.100.22 | SUCCESS | rc=0 >>
cumulus-fs

192.168.100.19 | SUCCESS | rc=0 >>
cumulus

192.168.100.21 | SUCCESS | rc=0 >>
cumulus

192.168.100.18 | SUCCESS | rc=0 >>
cumulus

ansible-push

ansible-pull

ansible playbook

ansible-playbook --help 查看playbook帮助,playbook是一个相当于脚本一样的工具我们可以去自己编写让远端主机完成某一些特定的业务
playbook后缀建议用yml

playbook执行流程

在这里插入图片描述
首先用户写playbook,一个playbook里面有多个play,每个play有可能都有一个task,然后task去调用模块,掉完后去看主机清单确定在那些主机上执行,然后ssh远程到对端执行

playbook格式

习惯第一行写三个杠—,也可以不写,我们举一个例子来学习playbook语法

vim first_playbook.yml
---
  - hosts: switch	#指定要对谁进行操作我们写的是一个组switch注意-后面有一个空格,:后面也有一个空格  
    remote_user: root	#指定以谁的身份执行  
    task:	#task可以调用多个模块
      -name: hello 	#知识一个说明性的一个名字
        command: hostname	#command为模块名字:后面是模块命令相当于省略了-a
:wq  
#ansible-playbook的坑,首先缩进问题,如果缩进不对那么就会报错,比如上面hosts是一个大项他指定多个功能,这些功能都是对于这个hosts来说的,然后后面的都是他的子项,所以后面最少要跟他隔2隔空格(2隔空格是我自己的标准),然后remote_user指定用户,然后task:这时候注意前面remote_user和task都是与- hosts隔了2个空格,task里面还有功能我们要指定task名字,有可能有多个task,所以每一个task名字后面都可以加上模块,这个模块相当于task的子项要用2个空格隔开 

yml语法

在这里插入图片描述

列表(list)

list所有元素都是以-开头,表示同一类型的元素例如
- apple
- orange
- banana

字典(通常由多个K/V值组成)

例如
name: example devloper
jon: develop
skill: elite

yml语法示意

name: john smith 	#键值对 
age: 41  	#键值对
gender: male 	#键值对
spouse: 	#键值对(它对应的值是另外一个字典)
  name: jane smith
  age: 37
  gender: female  
children:  	#键值对(它对应的值是另外一个字典)
  - name: jimmy smith  #列表列表里面有这age,gender等相同的属性
    age:17
    gender: male
  -name: jenny smith	#列表列表里面有这age,gender等相同的属性
    age: 13
    gender: female
     	    

更详细的yaml语言
http://www.ansible.com.cn/docs/YAMLSyntax.html

playbook核心元素

hosts:

执行的远程主机列表

- hosts: switch	#也可以all也支持: :&等等   
  remote_user: root	#以什么的身份去运行  
  

tasks:

任务集

task: 
  - name: create new file	#这个name相当于一个描述  
    file: name=/data/newfile state=touch 	#调用file模块 :后面就是创建文件  
  - name: create a new user 
    user: name=user2 system=yes shell=/sbin/nologin 	#调用user模块  
  - name: install package  
    yum: name=httpd 	#调用yum模块安装httpd  
  - name: copy a index.html  
    copy: src=/var/www/index.html dest=/var/www/index.html  	#调用copy模块
  -name: start service  
    service: name=httpd state=started enable=yes 	#调用service模块  

如果我们的playbook这样写完了我们可以检查一下语法是否正确  
ansible-playbook -C playbook.yml	#-C的意思是跑一便playbook但是不做更改相当于--check
    

task其实是由多个action组成,其实action就是模块
如果你的语句有问题但是你又想他继续执行,那么可以这样写

- name: ----
  shell cat /etc/redhat-release || /bin/true  	#当我们的没有redhat-release文件就执行另外一个/bin/true就是返回true然后继续执行 

我们可以测试次play-book执行多少个主机

[root@zhr ~]# ansible-playbook first_playbook.yml  --list-hosts

playbook: first_playbook.yml

  play #1 (switch): switch      TAGS: []
    pattern: [u'switch']
    hosts (5):
      192.168.100.19
      192.168.100.18
      192.168.100.21
      192.168.100.22
      192.168.100.23
[root@zhr ~]# 

可以列出这个playbook有多个任务

[root@zhr ~]# ansible-playbook first_playbook.yml  --list-tasks

playbook: first_playbook.yml

  play #1 (switch): switch      TAGS: []
    tasks:
      hello     TAGS: []
[root@zhr ~]# 

但是注意一个模块对应一个name

varniables: 内置变量或者自定义变量在playbook中使用

变量的名称是以字母和下划线和数字组成,只能以字母开头 ,我们可以在playbook里面调用,定义变量,例如

---
  - hosts: switch  
    remote_user: root
    task: 
      - name: install packname  
        yum: name={{ pkname }}	#这个{{}}就是调用变量,在这个双大括号里面的是变量名字  
      - name: start server
        server: name={{pkname}} state=start enable=yes	#调用变量pkname  
[root@zhr ~]# ansible-playbook -e 'pkname=vsftpd' app.yml #-e指定变量pkname等于vsftpd  
#我们也可以在脚本中自己定义变量  
  - hosts: switch  
    remote_user: root
    vars:	#指定变量
      - pkname1: vsftpd 	#指定pkname1变量的值为vsftpd
      - pkname2: httpd	#指定变量pkname2的值为httpd
    tasks: 
      - name: install packname  
        yum: name={{ pkname }}	#这个{{}}就是调用变量,在这个双大括号里面的是变量名字  
      - name: start server
        server: name={{pkname}} state=start enable=yes	#调用变量pkname   

我们的变量也可以写在hosts文件中

[root@zhr ~]# vim /etc/ansible/hosts   
[switch]
192.168.100.21  HOSTNAME=switch1
192.168.100.18  HOSTNAME=switch2
192.168.100.19  HOSTNAME=switch3
192.168.100.22  HOSTNAME=switch4

[switch:vars]
...
...
...
:wq  
[root@zhr ~]# cat hostname.yml 	#写一个简单的更改主机名的playbook
---
  - hosts: switch 
    remote_user: root

    tasks:
      - name: configure hostname 
        hostname: name={{HOSTNAME}}	#调用HOSTNAME变量,其中HOSTNAME变量定义在/etc/ansible/hosts 中每一个ip的HOSTNAME变量不一样,所以他们执行时候每一个主机调用的变量不一样  
        #[switch:vars]是一个专门用来配置switch组中所有ip主机公用的变量也就是通用变量,格式也是 变量名=值
#如果我们的配置文件里面定义了一个变量,而我们运行playbook的时候用-e指定了相同的变量名而且他们的值不同,我们以-e指定的为准,因为命令行的优先级比文件的高,而且主机组中单独定义的变量优先级高于公共变量
#我们可以将所有的变量都放在一个文件中比如我们的test.yml,而test.yml这个专门定义变量的文件书写格式如下  

[root@zhr ~]#  cat test.yml  
var1:vsftpd	#第一个变量var1的值为vsftpd	
var2:vsftp	#第二个变量var2的值为vsftp
...
...
#我们在别的playbook文件中可以调用这个变量文件    
[root@zhr ~]# vim test1.yml  
---
  - hosts: switch 
    remote_user: root
    vars_files: test.yml	#调用变量文件
    tasks
      - name: install package 
        yum: name={{ var1 }} 	#调用变量文件中的var1
      - name: create file 
        file: name=/data/{{ var2 }}.log state=touch 	#调用变量文件中的var2

templates:

模板,可替换模板文件中的变量并且实现一些简单逻辑的文件 ,也就是说是一个配置文件由ansible发送到远端主机,他可以做到让不同的主机使用不同的配置文件

在这里插入图片描述

[root@zhr static]# ansible-doc  -s template	#查看模板的简介
- name: Templates a file out to a remote server
  template:
      attributes:            # Attributes the file or directory should have. To get supported flags look at the man page for `chattr' on the
                               target system. This string should contain the attributes in the same order as the
                               one displayed by `lsattr'.
      backup:                # Create a backup file including the timestamp information so you can get the original file back if you somehow
                               clobbered it incorrectly.
      block_end_string:      # The string marking the end of a block.
      block_start_string:    # The string marking the beginning of a block.
      dest:                  # (required) Location to render the template to on the remote machine.
      follow:                # This flag indicates that filesystem links in the destination, if they exist, should be followed. Previous to
                               Ansible 2.4, this was hardcoded as `yes'.
      force:                 # the default is `yes', which will replace the remote file when contents are different than the source.  If `no',
                               the file will only be transferred if the destination does not exist.
      group:                 # Name of the group that should own the file/directory, as would be fed to `chown'.
      mode:                  # Mode the file or directory should be. For those used to `/usr/bin/chmod' remember that modes are actually octal
                               numbers (like `0644' or `01777'). Leaving off the leading zero will likely have
                               unexpected results. As of version 1.8, the mode may be specified as a symbolic
                               mode (for example, `u+rwx' or `u=rw,g=r,o=r').
      newline_sequence:      # Specify the newline sequence to use for templating files.
      owner:                 # Name of the user that should own the file/directory, as would be fed to `chown'.
      selevel:               # Level part of the SELinux file context. This is the MLS/MCS attribute, sometimes known as the `range'. `_default'
                               feature works as for `seuser'.
      serole:                # Role part of SELinux file context, `_default' feature works as for `seuser'.
      setype:                # Type part of SELinux file context, `_default' feature works as for `seuser'.
      seuser:                # User part of SELinux file context. Will default to system policy, if applicable. If set to `_default', it will
                               use the `user' portion of the policy if available.
      src:                   # (required) Path of a Jinja2 formatted template on the Ansible controller. This can be a relative or absolute
                               path.
      trim_blocks:           # If this is set to True the first newline after a block is removed (block, not variable tag!).
      unsafe_writes:         # Normally this module uses atomic operations to prevent data corruption or inconsistent reads from the target
                               files, sometimes systems are configured or just broken in ways that prevent this.
                               One example are docker mounted files, they cannot be updated atomically and can
                               only be done in an unsafe manner. This boolean option allows ansible to fall back
                               to unsafe methods of updating files for those cases in which you do not have any
                               other choice. Be aware that this is subject to race conditions and can lead to
                               data corruption.
      validate:              # The validation command to run before copying into place. The path to the file to validate is passed in via '%s'
                               which must be present as in the example below. The command is passed securely so
                               shell features like expansion and pipes won't work.
      variable_end_string:   # The string marking the end of a print statement.
      variable_start_string:   # The string marking the beginning of a print statement.
(END)

tamplate只能用于playbook不能用于ansible的命令行 我们可以先将某个配置文件放到,自己创建的/ansible/templates下例如

[root@zhr templates]# ls
nginx.conf.j2	#模板文件以j2结尾,  
#然后我们就可以写一个playbook调用这个模板
[root@zhr templates]# vim txtemplates.yml  
---
  - hosts: switch  
    remote_user: root
    tasks:
      - name: install package  
        yum: name=nginx
      - name: copy template
        templates: src=nginx.conf.j2 dest=/etc/nginx/nginx.conf	#将原文件copy到目标,其中原文件如果为相对路径的话则必须放在templates目录下,否侧就写绝对路径  
      - name: start server
        service: name=nginx state=started enable=yes

handlers和notity

handlers和notity结合使用,由特定的条件触发操作,满足条件方可执行,否则不执行
handler也是一个task,并且和task并列他可以监控其中的一个action动作如果某个action执行成功了,他就会触发handler后面定义的命令,例如

---
  - hosts: switch  
    remote_user: root
    tasks:  
      - name: install package
        yum: name=httpd
      - name: copy conf file
        copy: src=files/httpd.conf dest=/etc/httpd/conf/ backup=yes  
      - name: start service 
        service: name=httpd state=started enable=yes  
  #当我们的文件更改了我们想再下发一遍命令,也就是再执行一遍playbook
  发现装包已经装过就不执行,文件改过就把文件改了,但是服务启动过,就不启动了,所以我们可以再源文件上加上handlers
--- 
  - hosts: switch  
    remote_user: root
    tasks:  
      - name: install package
        yum: name=httpd
      - name: copy conf file
        copy: src=files/httpd.conf dest=/etc/httpd/conf/ backup=yes  
        notify: restart service	#意思为如果上面的文件或者命令状态发生改变就执行以restart service为名字的handlers,这个restart service具体的操作就定义在下面的handlers中 
 #也可以写成多个notify执行多个动作比如  notify: \n - restart service \n - check nginx(\n为换行playbook中不能这样写)
      - name: start service 
        service: name=httpd state=started enable=yes  
    handlers:
      - name: restart service 
        service: name=httpd state=restart 
  

tags标签

指定某条任务执行,用于选择运行playbook中的部分代码。ansible具有幂等性,因此会自动跳过没有变化的部分,即便如此,有些代码为测试其确实没有发生变化的时间依然会非常长。此时,如果确信其没有变化,就可以通过tags跳过此些代码片段 ,也就是说标签(tag)定义在某个action后面(-name),我们可以单独的执行某个标签

---
  - hosts: switch  
    remote_user: root
    tasks:  
      - name: install package
        yum: name=httpd
        tags: installhttpd	#给此action(-name )打上一个标签为installhttpd,我们可以单独执行他,也可以执行多个action
      - name: copy conf file
        copy: src=files/httpd.conf dest=/etc/httpd/conf/ backup=yes  
      - name: start service 
        service: name=httpd state=started enable=yes   
        tags: rshttpd	#给次action也就是start service打上一个标签为rshttpd我们执行playbook的时候可以单独的执行者一项
[root@zhr ~]# ansible-playbook -t rshttpd,installhttpd first_playbook.yml 	#执行2个tags  
#我们也可以让多个动作公用一个标签,执行这个标签就执行多个任务  
  

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值