ansible是基于Python的paramiko模块开发的自动化运维工具,实现批量系统配置、批量程序部署、批量运行命令等功能。
ansible不需要在远程主机上安装client/agents,因为它是基于ssh来和远程主机通讯的。
其本身没有批量管理的能力,真正具有批量管理的是ansible所运行的模块,ansible只是提供一种框架。
ansible任务执行有两种模式
ad-hoc模式
使用单个模块,是一种可以快速输入的命令,无需保存就相当于bash中的一句话shell,
playbook模式
需事先编写一个yaml文件作为剧本,在yaml文件中集合了多个tasks任务调用多个模块。
建议使用epel源进行yum 安装
yum install epel-release -y
yum install ansible –y
/etc/ansible/ansible.cfg
是ansible的主配置文件,下面介绍常用的配置参数
inventory = /etc/ansible/hosts #这个参数表示资源清单inventory文件(即主机清单)的位置
library = /usr/share/ansible #指向存放Ansible模块的目录,支持多个目录方式,只要用冒号(:)隔开就可以
forks = 5 #并发操作远程主机的连接数,默认为5
sudo_user = root #设置默认执行命令的用户
remote_port = 22 #指定连接远程主机的管理端口,默认为22端口,建议修改,能够更加安全
host_key_checking = False #设置是否检查SSH主机的密钥,值为True/False。关闭后第一次连接不会提示配置实例
timeout = 60 #设置SSH连接的超时时间,单位为秒
log_path = /var/log/ansible.log #指定一个存储ansible日志的文件(默认不记录日志)
/etc/ansible/hosts
由主配置设定主机清单文件,可以在文件中设置远程主机的IP地址或主机名,对主机进行分组,设置主机的ansible参数及专属变量。
主机分组
[apps]
192.168.80.111
192.168.80.120
[webservers]
www[01:50].jintian.com
[databases]
db-[a:f].jintian.com
#上面指定了从web1到web50,webservers主机组共计50台主机;databases主机组有db-a到db-f共6台主机。
主机的ansible参数
主机地址后空一格再填写主机参数,常用参数如下
ansible_ssh_port
#用于指定连接到被管理主机的ssh端口号,默认是22
ansible_ssh_user
#ssh连接时默认使用的用户名
ansible_ssh_pass
#ssh连接时的密码
ansible_sudo_pass
#使用sudo连接用户时的密码
ansible_sudo_exec
#如果sudo命令不在默认路径,需要指定sudo命令路径
ansible_ssh_private_key_file
#秘钥文件路径,秘钥文件如果不想使用ssh-agent管理时可以使用此选项
ansible_shell_type
#目标系统的shell的类型,默认sh
ansible_connection
#SSH 连接的类型: local , ssh , paramiko,在 ansible 1.2 之前默认是 paramiko ,后来智能选择,优先使用基于 ControlPersist 的 ssh (支持的前提)
ansible-doc 命令常用于获取模块信息及其使用帮助,一般用法如下:
ansible-doc -l #获取全部模块的信息
ansible-doc -s MOD_NAME #获取指定模块的使用帮助
格式:ansible [-f forks] [-m module_name] [-a args]
Host-pattern
指明哪些主机执行操作;多个名称之间用逗号隔开;all表示/etc/ansible/hosts文件中的所有主机;该文件中的组名,服务器名均可被调用。
-f forks
:forks值为数值,指明一批次完成多少主机的操作
-m module
:module为模块名,指明要使用ansible的哪个模块
-a args
:args为指定模块的参数,args的引用格式:key=value;调用command和shell模块时,args直接填写系统命令。
-u
指定使用远程主机的哪个用户,默认为root
-k
输入密码完成ssh连接认证,若无免密认证
-b
指定远程主机使用sudo为哪个用户执行,默认root
-K
输入远程主机sudo的密码认证
我们使用ansible web -m ping命令来进行主机连通性测试,效果如下:
[root@server ~]# ansible web -m ping
192.168.37.122 | SUCCESS => {
"changed": false,
"ping": "pong"
}
192.168.37.133 | SUCCESS => {
"changed": false,
"ping": "pong"
}
这样就说明我们的主机是连通状态的。接下来的操作才可以正常进行。
直接在远程主机上执行命令,并将结果返回本主机
[root@server ~]# ansible web -a 'ss -ntl'
192.168.37.122 | SUCCESS | rc=0 >>
State Recv-Q Send-Q Local Address:Port Peer Address:Port
LISTEN 0 128 *:22 *:*
LISTEN 0 100 127.0.0.1:25 *:*
LISTEN 0 128 :::22 :::*
LISTEN 0 100 ::1:25 :::*
192.168.37.133 | SUCCESS | rc=0 >>
State Recv-Q Send-Q Local Address:Port Peer Address:Port
LISTEN 0 128 *:22 *:*
LISTEN 0 100 127.0.0.1:25 *:*
LISTEN 0 128 :::22 :::*
LISTEN 0 100 ::1:25 :::*
注意
给定的命令将在所有选定的节点上执行。它不会通过shell进行处理,比如$HOME变量引用和操作如"<",">","|",";","&" 等工作,需要使用shell模块实现这些功能。
下面来看一看该模块下常用的几个命令:
chdir # 在执行命令之前,先切换到该目录
executable # 切换shell来执行命令,需要使用命令的绝对路径
free_form # 要执行的Linux指令,一般使用Ansible的-a参数代替。
creates # 一个文件名,当这个文件存在,则该命令不执行,可以用来做判断
removes # 一个文件名,这个文件不存在,则该命令不执行
下面我们来看看这些命令的执行效果:
[root@server ~]# ansible web -m command -a 'chdir=/data/ ls' #先切换到/data/ 目录,再执行“ls”命令
192.168.37.122 | SUCCESS | rc=0 >>
aaa.jpg
wKgleloeYoCAMLtZAAAWEekAtkc497.jpg
192.168.37.133 | SUCCESS | rc=0 >>
aaa.jpg
wKgleloeYoCAMLtZAAAWEekAtkc497.jpg
[root@server ~]# ansible web -m command -a 'creates=/data/aaa.jpg ls' #如果/data/aaa.jpg存在,则不执行“ls”命令
192.168.37.122 | SUCCESS | rc=0 >>
skipped, since /data/aaa.jpg exists
192.168.37.133 | SUCCESS | rc=0 >>
skipped, since /data/aaa.jpg exists
[root@server ~]# ansible web -m command -a 'removes=/data/aaa.jpg cat /data/a' #如果/data/aaa.jpg存在,则执行“cat /data/a”命令
192.168.37.122 | SUCCESS | rc=0 >>
hello
192.168.37.133 | SUCCESS | rc=0 >>
hello
shell模块可以在远程主机上调用shell解释器运行命令,支持shell的各种功能,例如管道等。
[root@server ~]# ansible web -m shell -a 'cat /etc/passwd |grep "keer"'
192.168.37.122 | SUCCESS | rc=0 >>
keer:x:10001:1000:keer:/home/keer:/bin/sh
192.168.37.133 | SUCCESS | rc=0 >>
keer:x:10001:10001::/home/keer:/bin/sh
注意1
:使用shell模块,在远程命令通过/bin/sh来执行;所以,我们在终端输入的各种命令,都可以使用;
但是我们自己定义在.bashrc/.bash_profile中的环境变量shell模块由于没有加载,所以无法识别;如果需要使用自定义的环境变量,就需要在最开始,执行加载自定义脚本的语句;
注意2
: 在-a“”中若出现$需要转义处理,但playbook中不需要。举例:
ansible all -m shell -a "ps aux | grep xx | awk ‘{print $2}’
cron模块常用的args如下:
- user #指定执行该计划任务的用户
- job #指定计划任务要执行的命令
- name #为计划任务定义任务名
- state #指定计划任务的状态
- state=present#表示创建计划任务,默认为此操作
- state=absent #表示取消计划任务
- minute #指定计划任务执行的时间(分)
- hour #指定计划任务执行的时间(小时)
- day #指定计划任务执行的时间(日期,号)
- month #指定计划任务执行的时间(日期,月份)
- weekday #指定计划任务执行的时间(周几)
如果没有设置,则默认为*。
添加计划任务
[root@server ~]# ansible web -m cron -a 'name="ntp update every 5 min" minute=*/5 job="/sbin/ntpdate 172.17.0.1 &> /dev/null"'
192.168.37.122 | SUCCESS => {
"changed": true,
"envs": [],
"jobs": [
"ntp update every 5 min"
]
}
192.168.37.133 | SUCCESS => {
"changed": true,
"envs": [],
"jobs": [
"ntp update every 5 min"
]
}
[root@server ~]# ansible web -m shell -a 'crontab -l'
192.168.37.122 | SUCCESS | rc=0 >>
#Ansible: ntp update every 5 min
*/5 * * * * /sbin/ntpdate 172.17.0.1 &> /dev/null
删除计划任务
[root@server ~]# ansible web -m cron -a 'name="ntp update every 5 min" state=absent'
192.168.37.122 | SUCCESS => {
"changed": true,
"envs": [],
"jobs": []
}
Copy常用的模块的agrs如下
- backup # 是否让远程主机创建一个备份文件包括时间戳信息,如果重创错了,还可以拿回原始文件 取值yes或no
- content # 取代src=,表示直接用此处指定的信息生成为目标文件内容;
- src # 指定复制的源文件,可以是相对路径或者绝对路径, 如果给出的源是目录,那么会把目录下的所有都复制过去
- dest # 远程节点存放文件的路径,必须是绝对路径
- force # 如果目标主机已存在文件,内容不同,如设置为yes,则强制覆盖,如设置为no,则只有当目标主机的目标位置不存在该文件时,才复制。默认为yes
- group # 复制到远程主机后,指定文件或目录的属组
- owner # 复制到远程主机后,指定文件或目录属主
- mode # 复制到远程主机后,指定文件或目录权限,类似与chmod命令 使用 644
- directory_mode # 递归复制,设置目录权限,默认为系统默认权限
复制文件
[root@server ~]# ansible web -m copy -a 'src=~/hello dest=/data/hello'
192.168.37.122 | SUCCESS => {
"changed": true,
"checksum": "22596363b3de40b06f981fb85d82312e8c0ed511",
"dest": "/data/hello",
"gid": 0,
"group": "root",
"md5sum": "6f5902ac237024bdd0c176cb93063dc4",
"mode": "0644",
"owner": "root",
"size": 12,
"src": "/root/.ansible/tmp/ansible-tmp-1512437093.55-228281064292921/source",
"state": "file",
"uid": 0
}
给定内容生成文件,并制定权限
[root@server ~]# ansible web -m copy -a 'content="I am keer\n" dest=/data/name mode=666'
192.168.37.122 | SUCCESS => {
"changed": true,
"checksum": "0421570938940ea784f9d8598dab87f07685b968",
"dest": "/data/name",
"gid": 0,
"group": "root",
"md5sum": "497fa8386590a5fc89090725b07f175c",
"mode": "0666",
"owner": "root",
"size": 10,
"src": "/root/.ansible/tmp/ansible-tmp-1512437327.37-199512601767687/source",
"state": "file",
"uid": 0
}
#我们现在可以去查看一下我们生成的文件及其权限:
[root@server ~]# ansible web -m shell -a 'ls -l /data/'
192.168.37.122 | SUCCESS | rc=0 >>
total 28
-rw-rw-rw- 1 root root 12 Dec 6 09:45 name
192.168.37.133 | SUCCESS | rc=0 >>
total 40
-rw-rw-rw- 1 root root 12 Dec 5 09:45 name
#可以看出我们的name文件已经生成,并且权限为666。
覆盖并备份文件
[root@server ~]# ansible web -m copy -a 'content="I am keerya\n" backup=yes dest=/data/name mode=666'
192.168.37.122 | SUCCESS => {
"backup_file": "/data/name.4394.2017-12-06@09:46:25~",
"changed": true,
"checksum": "064a68908ab9971ee85dbc08ea038387598e3778",
"dest": "/data/name",
"gid": 0,
"group": "root",
"md5sum": "8ca7c11385856155af52e560f608891c",
"mode": "0666",
"owner": "root",
"size": 12,
"src": "/root/.ansible/tmp/ansible-tmp-1512438383.78-228128616784888/source",
"state": "file",
"uid": 0
}
# 现在我们可以去查看一下:
[root@server ~]# ansible web -m shell -a 'ls -l /data/'
192.168.37.122 | SUCCESS | rc=0 >>
total 28
-rw-rw-rw- 1 root root 12 Dec 6 09:46 name
-rw-rw-rw- 1 root root 10 Dec 6 09:45 name.4394.2017-12-06@09:46:25~
file模块常用的args如下
- path #必选项,定义文件/目录的路径
- owner #定义文件/目录的属主
- group #定义文件/目录的属组
- mode #定义文件/目录的权限
- recurse #递归的设置文件的属性,只对目录有效
- src #要被链接的源文件路径,只应用于state=link的情况
- dest #被链接到的路径,只应用于state=link的情况
- state #如下几种
#directory:如果目录不存在,创建目录
#file:即使文件不存在,也不会被创建
#link:创建软链接
#hard:创建硬链接
#absent:删除目录、文件或者取消链接文件
#touch:如果文件不存在,则会创建一个新的文件,如果文件或目录已存在,则更新其最后修改时间
创建目录
[root@server ~]# ansible web -m file -a 'path=/data/app state=directory'
192.168.37.122 | SUCCESS => {
"changed": true,
"gid": 0,
"group": "root",
"mode": "0755",
"owner": "root",
"path": "/data/app",
"size": 6,
"state": "directory",
"uid": 0
}
创建链接文件
[root@server ~]# ansible web -m file -a 'dest=/data/bbb.jpg src=aaa.jpg state=link'
192.168.37.122 | SUCCESS => {
"changed": true,
"dest": "/data/bbb.jpg",
"gid": 0,
"group": "root",
"mode": "0777",
"owner": "root",
"size": 7,
"src": "aaa.jpg",
"state": "link",
"uid": 0
}
删除文件
[root@server ~]# ansible web -m file -a 'path=/data/a state=absent'
192.168.37.122 | SUCCESS => {
"changed": true,
"path": "/data/a",
"state": "absent"
}
常用的args如下
- dest #用来存放文件的目录
- src #在远程拉取的文件,并且必须是一个file,不能是目录
注意
复制而来的文件保存在我们设置的接收目录中一个名字为远程主机ip的目录中,举例
[root@server ~]# ansible web -m fetch -a 'src=/data/hello dest=/data'
192.168.37.122 | SUCCESS => {
"changed": true,
"checksum": "22596363b3de40b06f981fb85d82312e8c0ed511",
"dest": "/data/192.168.37.122/data/hello",
"md5sum": "6f5902ac237024bdd0c176cb93063dc4",
"remote_checksum": "22596363b3de40b06f981fb85d82312e8c0ed511",
"remote_md5sum": null
}
[root@server ~]# cd /data/
[root@server data]# ls
192.168.37.122
[root@server data]# cd 192.168.37.122
[root@server 192.168.37.122]# ls
data
[root@server 192.168.37.122]# ls data/
hello
常用参数如下
- name= #需要yum管理的包名称
- state= #present--->安装, latest--->安装最新的, absent--->卸载软件。 update_cache #强制更新yum的缓存
- conf_file #指定远程主机yum安装时所依赖的配置文件(安装本地已有的包)。
- disable_pgp_check #是否禁止GPGchecking,只用于presentor latest。
- disablerepo #临时禁止使用yum库。 只用于安装或更新时。
- enablerepo #临时使用的yum库。只用于安装或更新时。
yum安装htop
[root@server ~]# ansible web -m yum -a 'name=htop state=present'
192.168.37.122 | SUCCESS => {
"changed": true,
"msg": "",
"rc": 0,
"results": [
"Loaded plugins: fastestmirror, langpacks\nLoading mirror speeds from cached hostfile\nResolving Dependencies\n--> Running transaction check\n---> Package htop.x86_64 0:2.0.2-1.el7 will be installed\n--> Finished Dependency Resolution\n\nDependencies Resolved\n\n================================================================================\n Package Arch Version Repository Size\n================================================================================\nInstalling:\n htop x86_64 2.0.2-1.el7 epel 98 k\n\nTransaction Summary\n================================================================================\nInstall 1 Package\n\nTotal download size: 98 k\nInstalled size: 207 k\nDownloading packages:\nRunning transaction check\nRunning transaction test\nTransaction test succeeded\nRunning transaction\n Installing : htop-2.0.2-1.el7.x86_64 1/1 \n Verifying : htop-2.0.2-1.el7.x86_64 1/1 \n\nInstalled:\n htop.x86_64 0:2.0.2-1.el7 \n\nComplete!\n"
]
}
常用参数如下:
- name: #指定需要管理的服务名,例如crond.service,最好带上后缀.service
- state: #需要的进行的管理操作,reloaded,restarted, started, stopped
- enabled:#指定的服务是否需要开机启动
- daemon_reload:#systemd读取配置文件,每次修改了文件,最好都运行一次,确保应用了
关闭应用
[root@192-168-80-114 ~]# ansible 192.168.80.134 -m systemd -a "name=nginx state=stopped"
192.168.80.134 | SUCCESS => {
"changed": true,
"name": "nginx",
"state": "stopped",
"status": {
"ActiveEnterTimestamp": "四 2019-11-28 16:03:40 CST",
"ActiveEnterTimestampMonotonic": "13586518310507",
"ActiveExitTimestampMonotonic": "0",
"ActiveState": "active",
"After": "network.target systemd-journald.socket -.mount nss-lookup.target tmp.mount basic.target system.slice remote-fs.target"...
举例
[root@server ~]# vim /tmp/df.sh
#!/bin/bash
date >> /tmp/disk_total.log
[root@server ~]# ansible web -m script -a '/tmp/df.sh'
192.168.37.122 | SUCCESS => {
"changed": true,
"rc": 0,
"stderr": "Shared connection to 192.168.37.122 closed.\r\n",
"stdout": "",
"stdout_lines": []
}
[root@server ~]# ansible web -m shell -a 'cat /tmp/disk_total.log'
192.168.37.122 | SUCCESS | rc=0 >>
Tue Dec 5 15:58:21 CST 2017
常用参数如下
- copy: #默认为yes,当copy=yes,那么拷贝的文件是从ansible主机复制到远程主机上的,如果设置为copy=no,那么会在远程主机上寻找src源文件
- src: #源路径,可以是ansible主机上的路径,也可以是远程主机上的路径,如果是远程主机上的路径,则需要设置copy=no
- dest: #远程主机上的目标路径
- mode: #设置解压缩后的文件权限