阅读本文大约需要 10 分钟
ansible 简介
ansible 是一款强大的配置管理工具,诣在帮助系统管理员高效率地管理成百上千台主机。设想一个主机是一个士兵,那么有了 ansible ,作为系统管理员的你就是一个将领,你可以通过口头命令,即一次下发一条命令(ansible ad-hoc 模式)方式让一个或一组或全部的士兵按你的指令行事,也可以将多条命令写在纸上(ansible playbook 模式), 需要执行命令时只需要提供这张纸即可。你可以让多个士兵同时做相同或不同的事情,可以方便的让新加入的士兵快速加入已有的兵种队伍,也以快速改变兵种(配置管理),一句话,士兵都严格听你的,你做好命令的设计,ansible 自动帮你发布和执行。
我们只需要在一台机器(类 unix 系统)上安装 ansible,即可在这台机器上管理其他主机,ansible 使用 ssh 协议与被管理的主机通讯,只要能 ssh 连接这些主机,ansible 便可以控制他们。
ansible 安装
ansible 的安装轻而易举,安装方法如下:
1. 使用 pip 安装
pip 是 python 的包管理工具,使用起来非常方便,只要操作系统安装有 pip,直接 pip install 包名即可,安装 ansible 的方法如下:
代码语言:javascript复制pip install ansible
2. 使用 apt-get 安装
在基于 Debian/Ubuntu Linux 的系统中可使用 apt-get 安装 ansible
代码语言:javascript复制sudo apt-get install software-properties-common
sudo apt-add-repository ppa:ansible/ansible
sudo apt-get update
sudo apt-get install ansible
3. 使用 yum 安装 在基于 RHEL/CentOS Linux 的系统中可使用 yum 安装 ansible
代码语言:javascript复制sudo yum install ansible
4. 使用源码安装 可以从 github 上安装最新版本
代码语言:javascript复制cd ~
git clone git://github.com/ansible/ansible.git
cd ./ansible
source ./hacking/env-setup
ansible 配置文件
ansible 的配置文件有多个位置,查找顺序如下:
1. 环境变量 ANSIBLE_CONFIG 所指向的位置
2. 当前目录下的 ansible.cfg
3. HOME 目录下的配置文件 ~/.ansible.cfg
4. /etc/ansible/ansible.cfg
在大多数场景下默认的配置就能满足大多数用户的需求,在一些特殊场景下,用户还是需要自行修改这些配置文件, 如果安装后没有在以上 3 个位置找到配置文件的话,自己在 HOME 目录新建一个 .ansible.cfg 即可。
ansible 常见的配置参数如下所示:
代码语言:javascript复制inventory = ~/ansible_hosts #这个参数表示主机清单 inventory 文件的位置
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日志的文件(默认不记录日志)
更为详细的配置参数详见
ansible 详细配置文件 见 https://raw.githubusercontent.com/ansible/ansible/devel/examples/ansible.cfg
Inventory 文件
Ansible 可同时操作属于一个组的多台主机,组和主机之间的关系通过 inventory 文件配置. 默认的文件路径为 /etc/ansible/hosts,我们也可以通过 ansible 的配置文件来指定 inventory 文件位置。 除默认文件外,你还可以同时使用多个 inventory 文件,也可以从动态源,或云上拉取 inventory 配置信息。
一个简单的 Inventory 文件示例
代码语言:javascript复制192.168.0.111
也可以对主机进行分组
代码语言:javascript复制mail.example.com[webservers]
foo.example.com
bar.example.com[dbservers]
one.example.com
two.example.com
three.example.com
方括号[]中是组名,用于对系统进行分类,便于对不同系统进行个别的管理。一个系统可以属于不同的组,比如一台服务器可以同时属于 webserver 组和 dbserver 组。这时属于两个组的变量都可以为这台主机所用。
主机变量 前面已经提到过,分配变量给主机很容易做到,这些变量定义后可在 playbooks 中使用:
代码语言:javascript复制[atlanta]
host1 http_port=80 maxRequestsPerChild=808
host2 http_port=303 maxRequestsPerChild=909
组的变量 也可以定义属于整个组的变量:
代码语言:javascript复制[atlanta]
host1
host2[atlanta:vars]
ntp_server=ntp.atlanta.example.com
proxy=proxy.atlanta.example.com
把一个组作为另一个组的子成员 可以把一个组作为另一个组的子成员,以及分配变量给整个组使用. 这些变量可以给 /usr/bin/ansible-playbook 使用,但不能给 /usr/bin/ansible 使用:
代码语言:javascript复制[atlanta]
host1
host2
[raleigh]
host2
host3
[southeast:children]
atlanta
raleigh
[southeast:vars]
some_server=foo.southeast.example.com
halon_system_timeout=30
self_destruct_countdown=60
escape_pods=2
[usa:children]
southeast
northeast
southwest
northwest
对于每一个 host,你还可以选择连接类型和连接用户名:
代码语言:javascript复制[targets]localhost ansible_connection=local
other1.example.com ansible_connection=ssh ansible_ssh_user=mpdehaan
other2.example.com ansible_connection=ssh ansible_ssh_user=mdehaan
Inventory 参数的说明
如同前面提到的,通过设置下面的参数,可以控制 ansible 与远程主机的交互方式,如下:
代码语言:javascript复制ansible_ssh_host
将要连接的远程主机名.与你想要设定的主机的别名不同的话,可通过此变量设置.
ansible_ssh_port
ssh端口号.如果不是默认的端口号,通过此变量设置.
ansible_ssh_user
默认的 ssh 用户名
ansible_ssh_pass
ssh 密码(这种方式并不安全,我们强烈建议使用 --ask-pass 或 SSH 密钥)
ansible_sudo_pass
sudo 密码(这种方式并不安全,我们强烈建议使用 --ask-sudo-pass)
ansible_sudo_exe (new in version 1.8)
sudo 命令路径(适用于1.8及以上版本)
ansible_connection
与主机的连接类型.比如:local, ssh 或者 paramiko. Ansible 1.2 以前默认使用 paramiko.1.2 以后默认使用 'smart','smart' 方式会根据是否支持 ControlPersist, 来判断'ssh' 方式是否可行.
ansible_ssh_private_key_file
ssh 使用的私钥文件.适用于有多个密钥,而你不想使用 SSH 代理的情况.
ansible_shell_type
目标系统的shell类型.默认情况下,命令的执行使用 'sh' 语法,可设置为 'csh' 或 'fish'.
ansible_python_interpreter
目标主机的 python 路径.适用于的情况: 系统中有多个 Python, 或者命令路径不是"/usr/bin/python",比如 *BSD, 或者 /usr/bin/python
不是 2.X 版本的 Python.我们不使用 "/usr/bin/env" 机制,因为这要求远程用户的路径设置正确,且要求 "python" 可执行程序名不可为 python以外的名字(实际有可能名为python26).
与 ansible_python_interpreter 的工作方式相同,可设定如 ruby 或 perl 的路径....
一个主机文件的例子
代码语言:javascript复制some_host ansible_ssh_port=2222 ansible_ssh_user=manager
aws_host ansible_ssh_private_key_file=/home/example/.ssh/aws.pem
freebsd_host ansible_python_interpreter=/usr/local/bin/python
ruby_module_host ansible_ruby_interpreter=/usr/bin/ruby.1.9.3
执行 ansible 命令(ad-hoc 命令)
接下来我们展示如何 ansible 命令,配置文件如下所示:
代码语言:javascript复制(py37env) aaron@ubuntu:~$ cat ~/.ansible.cfg
[defaults]
inventory = ~/ansible_hosts
inventory 文件如下所示:
代码语言:javascript复制(py37env) aaron@ubuntu:~$ cat ~/ansible_hosts
[master]
localhost ansible_connection=local ansible_ssh_user=aaron
192.168.0.111 ansible_ssh_user=aaron
[slave]
192.168.0.112 ansible_ssh_user=aaron
可能每台机器登陆的用户名都不一样,这里我指明了每台机器连接的 ssh 登陆用户名,在执行 ansible 命令时就不需要再指定用户名,如果不指定用户名,andible 则尝试使用本机已登陆的用户去登陆远程主机。
使用 ansible 命令的帮助
代码语言:javascript复制(py37env) aaron@ubuntu:~$ ansible -help
Usage: ansible <host-pattern> [options]
Define and run a single task 'playbook' against a set of hosts
Options:
-a MODULE_ARGS, --args=MODULE_ARGS
module arguments
--ask-vault-pass ask for vault password
-B SECONDS, --background=SECONDS
run asynchronously, failing after X seconds
(default=N/A)
-C, --check don't make any changes; instead, try to predict some
of the changes that may occur
-D, --diff when changing (small) files and templates, show the
differences in those files; works great with --check
-e EXTRA_VARS, --extra-vars=EXTRA_VARS
set additional variables as key=value or YAML/JSON, if
filename prepend with @
-f FORKS, --forks=FORKS
specify number of parallel processes to use
(default=5)
-h, --help show this help message and exit
-i INVENTORY, --inventory=INVENTORY, --inventory-file=INVENTORY
specify inventory host path or comma separated host
list. --inventory-file is deprecated
-l SUBSET, --limit=SUBSET
further limit selected hosts to an additional pattern
--list-hosts outputs a list of matching hosts; does not execute
anything else
......
所有的命令参数都可以从 ansible -h 找到,接下接让我们列出主机列表
代码语言:javascript复制(py37env) aaron@ubuntu:~$ ansible all --list-host
hosts (3):
192.168.0.112
localhost
192.168.0.111
(py37env) aaron@ubuntu:~$ ansible master --list-host
hosts (2):
localhost
192.168.0.111
执行第一条 ansible 命令
可以看出 ansible 命令后跟的是主机的组的名称,all 代表所有的主机。 接下来让我们执行第一条 ansible 命令.
ping 所有主机
代码语言:javascript复制(py37env) aaron@ubuntu:~$ ansible all -m ping
localhost | SUCCESS => {
"changed": false,
"ping": "pong"
}
192.168.0.112 | UNREACHABLE! => {
"changed": false,
"msg": "Failed to connect to the host via ssh: Permission denied (publickey,password).rn",
"unreachable": true
}
192.168.0.111 | UNREACHABLE! => {
"changed": false,
"msg": "Failed to connect to the host via ssh: Permission denied (publickey,password).rn",
"unreachable": true
}
可以看出 ansible 返回的类型是一个键值对的 json 格式的数据,其中 localhost 成功,其他两个主机均失败了,原因是 ssh 是一个安全的协议,如果不提供用户名密码就可以随便连接,会出大问题的。
我们使用密码来执行 ansible 的 ping 命令:
代码语言:javascript复制(py37env) aaron@ubuntu:~$ ansible all -m ping --ask-pass
SSH password:
localhost | SUCCESS => {
"changed": false,
"ping": "pong"
}
192.168.0.111 | SUCCESS => {
"changed": false,
"ping": "pong"
}
192.168.0.112 | SUCCESS => {
"changed": false,
"ping": "pong"
}
输入密码后(如果每台机器密码相同,则只需要执行一次命令,输入一次密码,若不同,需要多次执行命令,每次输入不同的密码),命令被成功执行,在一些机器上你会需要安装 sshpass 或者指定 -c paramiko。 从运行结果可以看出,都是 ping 通的,返回结果为 “pong”, changed 是 false 表示未改变远程主机任何文件。 这样一指令就分别发送到 3 台主机进行执行,是不是很高效?短时间内无需再重复输入密码。 那么问题来了,每次都输入密码太烦了,有没有不输入密码的方法呢?当然有了,ansible 使用 ssh 协议登陆远程主机,接下来我们使用 ansible 将 localhost 的公钥复制到远程主机的 authorized_keys
首先检查本机是否已生成公钥,如果没有则在 shell 中执行 ssh-keygen 命令后一直回车即可。
代码语言:javascript复制(py37env) aaron@ubuntu:~$ ls -ltr ~/.ssh
total 12
-rw-r--r-- 1 aaron aaron 394 Aug 2 21:39 id_rsa.pub
-rw------- 1 aaron aaron 1679 Aug 2 21:39 id_rsa
-rw-r--r-- 1 aaron aaron 666 Aug 4 09:11 known_hosts
如果有 id_rsa.pub 则说明已经生成了公钥
接下来我们使用 ansible 将公钥文件的内容复制到远程主机的 authorized_keys 里去。
ansible 批量执行 ssh 授信
代码语言:javascript复制(py37env) aaron@ubuntu:~/.ssh$ ansible all -m authorized_key -a "user=aaron key='{{ lookup('file', '/home/aaron/.ssh/id_rsa.pub') }}' path=/home/aaron/.ssh/authorized_keys manage_dir=yes" --ask-pass
SSH password:
localhost | SUCCESS => {
"changed": true,
"comment": null,
"exclusive": false,
"gid": 1001,
"group": "aaron",
"key": "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDjf6e7DpOI/7eARUNvo7xD51X1fp9/am1hYn2aCkZyhPWRKUYiJQHm7JtPJQAV2o6LyAaZxcksLEbRD2bOHjTyu9uV2y8dfmejG7ISn/jOWXLQ mjgtxxOKUj 0Hu5vRbv1zi7ggfHsZc2l 7Zgpc3XHoCPXM/E514TE6OPt1 5l4IdZWErNX255dXDqrCmd7VEvSTvvI1K/tkSY8oTBEg87TRscrgmsQyLyOoSswvCqWpvy VrTfSoabZzVb1XvCH apA41wHN4BnQYsQzk2sdl75rsn8rhzGiZUWc67K4nqbMbqs1Dxek3u2enFRQlVHbs8xHuBvcqwk5XRkkiCp aaron@ubuntu",
"key_options": null,
"keyfile": "/home/aaron/.ssh/authorized_keys",
"manage_dir": true,
"mode": "0600",
"owner": "aaron",
"path": "/home/aaron/.ssh/authorized_keys",
"size": 394,
"state": "file",
"uid": 1001,
"unique": false,
"user": "aaron",
"validate_certs": true
}
192.168.0.111 | SUCCESS => {
"changed": true,
"comment": null,
"exclusive": false,
"gid": 1000,
"group": "aaron",
"key": "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDjf6e7DpOI/7eARUNvo7xD51X1fp9/am1hYn2aCkZyhPWRKUYiJQHm7JtPJQAV2o6LyAaZxcksLEbRD2bOHjTyu9uV2y8dfmejG7ISn/jOWXLQ mjgtxxOKUj 0Hu5vRbv1zi7ggfHsZc2l 7Zgpc3XHoCPXM/E514TE6OPt1 5l4IdZWErNX255dXDqrCmd7VEvSTvvI1K/tkSY8oTBEg87TRscrgmsQyLyOoSswvCqWpvy VrTfSoabZzVb1XvCH apA41wHN4BnQYsQzk2sdl75rsn8rhzGiZUWc67K4nqbMbqs1Dxek3u2enFRQlVHbs8xHuBvcqwk5XRkkiCp aaron@ubuntu",
"key_options": null,
"keyfile": "/home/aaron/.ssh/authorized_keys",
"manage_dir": true,
"mode": "0600",
"owner": "aaron",
"path": "/home/aaron/.ssh/authorized_keys",
"size": 394,
"state": "file",
"uid": 1000,
"unique": false,
"user": "aaron",
"validate_certs": true
}
192.168.0.112 | SUCCESS => {
"changed": true,
"comment": null,
"exclusive": false,
"gid": 1000,
"group": "aaron",
"key": "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDjf6e7DpOI/7eARUNvo7xD51X1fp9/am1hYn2aCkZyhPWRKUYiJQHm7JtPJQAV2o6LyAaZxcksLEbRD2bOHjTyu9uV2y8dfmejG7ISn/jOWXLQ mjgtxxOKUj 0Hu5vRbv1zi7ggfHsZc2l 7Zgpc3XHoCPXM/E514TE6OPt1 5l4IdZWErNX255dXDqrCmd7VEvSTvvI1K/tkSY8oTBEg87TRscrgmsQyLyOoSswvCqWpvy VrTfSoabZzVb1XvCH apA41wHN4BnQYsQzk2sdl75rsn8rhzGiZUWc67K4nqbMbqs1Dxek3u2enFRQlVHbs8xHuBvcqwk5XRkkiCp aaron@ubuntu",
"key_options": null,
"keyfile": "/home/aaron/.ssh/authorized_keys",
"manage_dir": true,
"mode": "0600",
"owner": "aaron",
"path": "/home/aaron/.ssh/authorized_keys",
"size": 394,
"state": "file",
"uid": 1000,
"unique": false,
"user": "aaron",
"validate_certs": true
}
我们利用 ansible 有一个更加方便的内置 SSH 密钥管理支持来执行我们的任务,输入密码后,得到以上运行结果说明成功执行。如果两台 远程主机的密码不相同,执行两次命令,分别输入不同的密码即可。
注意 ssh 对 authorized_keys 的权限要求比较严格,仅所属用户才有读写权限(600)时才生效
到目前为止 ssh 授信成功了,后续可以免密码执行命令了,下面验证下。
获取被管理机器的当前时间
代码语言:javascript复制(py37env) aaron@ubuntu:~/.ssh$ ansible all -a "date '%Y-%m-%d %T'"
localhost | SUCCESS | rc=0 >>
2018-08-04 15:04:55
192.168.0.111 | SUCCESS | rc=0 >>
2018-08-04 00:04:57
192.168.0.112 | SUCCESS | rc=0 >>
2018-08-04 00:04:57
现在,不需要输入密码,即可同时获取三台主机的时间,主机的时钟可能不一致,这是正常现象。
使用 ansible 批量传文件。
将一个文本文件上传至远程主机的用户 home 目录中。
先查看远程主机上用户 home 目录上的文件
代码语言:javascript复制(py37env) aaron@ubuntu:~$ ansible all -m shell -a "ls ~/*.*"
localhost | SUCCESS | rc=0 >>
/home/aaron/030303.mp4
/home/aaron/aaa.py
/home/aaron/dfasdfasdfad.py
/home/aaron/examples.desktop
/home/aaron/hello.py
/home/aaron/new.py
/home/aaron/playbook.retry
/home/aaron/playbook.yaml
/home/aaron/setting.py
/home/aaron/test.py
/home/aaron/vimrc.bak_20180719
/home/aaron/你好.txt
192.168.0.111 | SUCCESS | rc=0 >>
/home/aaron/examples.desktop
192.168.0.112 | SUCCESS | rc=0 >>
/home/aaron/examples.desktop
将 “你好.txt” 上传至另外两台服务器
代码语言:javascript复制(py37env) aaron@ubuntu:~$ ansible all -m copy -a "src=/home/aaron/你好.txt dest=/home/aaron"
localhost | SUCCESS => {
"changed": false,
"checksum": "da39a3ee5e6b4b0d3255bfef95601890afd80709",
"dest": "/home/aaron/你好.txt",
"gid": 1001,
"group": "aaron",
"mode": "0664",
"owner": "aaron",
"path": "/home/aaron/你好.txt",
"size": 0,
"state": "file",
"uid": 1001
}
192.168.0.112 | SUCCESS => {
"changed": true,
"checksum": "da39a3ee5e6b4b0d3255bfef95601890afd80709",
"dest": "/home/aaron/你好.txt",
"gid": 1000,
"group": "aaron",
"md5sum": "d41d8cd98f00b204e9800998ecf8427e",
"mode": "0664",
"owner": "aaron",
"size": 0,
"src": "/home/aaron/.ansible/tmp/ansible-tmp-1533367280.2415307-170986393705436/source",
"state": "file",
"uid": 1000
}
192.168.0.111 | SUCCESS => {
"changed": true,
"checksum": "da39a3ee5e6b4b0d3255bfef95601890afd80709",
"dest": "/home/aaron/你好.txt",
"gid": 1000,
"group": "aaron",
"md5sum": "d41d8cd98f00b204e9800998ecf8427e",
"mode": "0664",
"owner": "aaron",
"size": 0,
"src": "/home/aaron/.ansible/tmp/ansible-tmp-1533367280.2476053-270780127291475/source",
"state": "file",
"uid": 1000
}
可以看出,localhost 本就有 “你好.txt” 默认不会被覆盖。重新执行第一条命令验证。
代码语言:javascript复制(py37env) aaron@ubuntu:~$ ansible all -m shell -a "ls ~/*.*"
localhost | SUCCESS | rc=0 >>
/home/aaron/030303.mp4
/home/aaron/aaa.py
/home/aaron/dfasdfasdfad.py
/home/aaron/examples.desktop
/home/aaron/hello.py
/home/aaron/new.py
/home/aaron/playbook.retry
/home/aaron/playbook.yaml
/home/aaron/setting.py
/home/aaron/test.py
/home/aaron/vimrc.bak_20180719
/home/aaron/你好.txt
192.168.0.112 | SUCCESS | rc=0 >>
/home/aaron/examples.desktop
/home/aaron/你好.txt
192.168.0.111 | SUCCESS | rc=0 >>
/home/aaron/examples.desktop
/home/aaron/你好.txt
可以看出文件已经上传成功了。
使用 ansible 的模块帮助文档 ansible-doc
一个优秀的工具一定有着便捷的帮助文档,ansible 也不例外,前述操作,使用了 ansible 的模块有 ping,authorized_key,copy,shell等模块。 如果想知道这些模块的详细说明,只需要执行 ansible-doc 模块名即可。
代码语言:javascript复制(py37env) aaron@ubuntu:~$ ansible-doc copy
> COPY (/home/aaron/py37env/lib/python3.7/site-packages/ansible/modules/files/copy.py)
The `copy' module copies a file from the local or remote machine to a
location on the remote machine. Use the [fetch] module to copy files
from remote locations to the local box. If you need variable
interpolation in copied files, use the [template] module. For Windows
targets, use the [win_copy] module instead.
* note: This module has a corresponding action plugin.
OPTIONS (= is mandatory):
- 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'.
(Aliases: attr)[Default: (null)]
version_added: 2.3
- backup
Create a backup file including the timestamp information so you can get
the original file back if you somehow clobbered it incorrectly.
[Default: no]
type: bool
version_added: 0.7
- checksum
SHA1 checksum of the file being transferred. Used to validate that the
copy of the file was successful.
If this is not provided, ansible will use the local calculated checksum
of the src file.
......
ansible 常用的模块及介绍如下:
.
1. ping: 主机连通性测试。
2. command: 在远程主机上执行命令,并将结果返回。
3. shell: 在远程主机上调用 shell 解释器运行命令,支持 shell 的各种功能。
4. copy: 将文件复制到远程主机,同时支持给定内容生成文件和修改权限等.
5. file: 设置文件的属性,比如创建文件、创建链接文件、删除文件等。
6. fetch: 从远程主机获取文件到本地。
7. cron: 管理远程主机的 crontab 计划任务。
8. yum: 用于软件的安装。
9. service: 用于服务程序的管理。
10. user: 用来管理远程主机的用户账号。
11. group: 用于在添加或删除组。
12. script: 用于将本机的脚本在被管理端的机器上运行.
13. setup: 主要用于收集信息,是通过调用facts组件来实现的.
Playbooks
前述操作对远程执行的命令都是相同的,那么可以同时对不同的主机执行不同的指令吗,当让可以,这就是 Plakbooks。
借用官方的描述,Playbooks 是 Ansible的配置,部署,编排的语言.他们可以被描述为一个需要希望远程主机执行命令的方案,或者一组IT程序运行的命令集合.如果 Ansible 模块你是工作室中的工具,那么 playbooks 就是你设置的方案计划.
首先查看 ansible-playbook 的帮助命令
代码语言:javascript复制(py37env) aaron@ubuntu:~$ ansible-playbook -h
Usage: ansible-playbook [options] playbook.yml [playbook2 ...]Runs Ansible playbooks, executing the defined tasks on the targeted hosts.Options:
--ask-vault-pass ask for vault password个
-C, --check don't make any changes; instead, try to predict some
of the changes that may occur
-D, --diff when changing (small) files and templates, show the
differences in those files; works great with --check
-e EXTRA_VARS, --extra-vars=EXTRA_VARS
set additional variables as key=value or YAML/JSON, if
filename prepend with @
--flush-cache clear the fact cache for every host in inventory
--force-handlers run handlers even if a task fails
-f FORKS, --forks=FORKS
specify number of parallel processes to use
(default=5)
-h, --help show this help message and exit
-i INVENTORY, --inventory=INVENTORY, --inventory-file=INVENTORY
......
发现,ansible-playbook 需要一个 plauybook.yml 的文件。
什么是 yml 文件
yml 文件是 yaml语法格式的文件,我们使用 YAML 是因为它像 XML 或 JSON 是一种利于人们读写的数据格式。此外在大多数变成语言中有使用 YAML 的库。 对于 Ansible, 每一个 YAML 文件都是从一个列表开始。 列表中的每一项都是一个键值对, 通常它们被称为一个 “哈希” 或 “字典”。 所以, 我们需要知道如何在 YAML 中编写列表和字典。 YAML 还有一个小的怪癖。 所有的 YAML 文件(无论和 Ansible 有没有关系)开始行都应该是 —-。 这是 YAML 格式的一部分, 表明一个文件的开始。 列表中的所有成员都开始于相同的缩进级别, 并且使用一个 “- “ 作为开头(一个横杠和一个空格):
代码语言:javascript复制---
#一个美味水果的列表
- Apple
- Orange
- Strawberry
- Mango
一个字典是由一个简单的 键: 值 的形式组成(这个冒号后面必须是一个空格):
代码语言:javascript复制---
# 一位职工的记录
name: Example Developer
job: Developer
skill: Elite
字典也可以使用缩进形式来表示, 如果你喜欢这样的话:
代码语言:javascript复制---
# 一位职工的记录
{name: Example Developer, job: Developer, skill: Elite}
Ansible并不是太多的使用这种格式, 但是你可以通过以下格式来指定一个布尔值(true/fase):
代码语言:javascript复制---
create_key: yes
needs_agent: no
knows_oop: True
likes_emacs: TRUE
uses_cvs: false
让我们把目前所学到的 YAML 例子组合在一起。 这些在 Ansible 中什么也干不了, 但这些格式将会给你感觉:
代码语言:javascript复制---
# 一位职工记录
name: Example Developer
job: Developer
skill: Elite
employed: True
foods:
- Apple
- Orange
- Strawberry
- Mango
languages:
ruby: Elite
python: Elite
dotnet: Lame
这就是你开始编写 Ansible playbooks 所需要知道的所有 YAML 语法。
现在 让我们写一个简单的 playbook
文件名 myplaybook.yml
代码语言:javascript复制---
- hosts: master
remote_user: aaron
tasks:
- name: read sys time
shell: echo "`date '%Y-%m-%d %T'`">time.txt
- hosts: slave
remote_user: aaron
tasks:
- name: list file
shell: ls -ltr>list.txt
上述 yaml 文件分别定义了对两组主机执行不同的 task ,注意缩进格式。
执行 ansible-playbook myplaybook.yml 结果如下:
代码语言:javascript复制(py37env) aaron@ubuntu:~$ ansible-playbook myplaybook.yml
PLAY [master] **************************************************************************************
TASK [Gathering Facts] *****************************************************************************
ok: [localhost]
ok: [192.168.0.111]
TASK [read sys time] *******************************************************************************
changed: [localhost]
changed: [192.168.0.111]
PLAY [slave] ***************************************************************************************
TASK [Gathering Facts] *****************************************************************************
ok: [192.168.0.112]
TASK [list file] ***********************************************************************************
changed: [192.168.0.112]
PLAY RECAP *****************************************************************************************
192.168.0.111 : ok=2 changed=1 unreachable=0 failed=0
192.168.0.112 : ok=2 changed=1 unreachable=0 failed=0
localhost : ok=2 changed=1 unreachable=0 failed=0
说明3台主机上的任务已成功执行。
验证
代码语言:javascript复制(py37env) aaron@ubuntu:~$ ansible all -m shell -a "ls -ltr *.txt"
localhost | SUCCESS | rc=0 >>
-rw-rw-r-- 1 aaron aaron 0 Jun 14 06:57 你好.txt
-rw-rw-r-- 1 aaron aaron 20 Aug 4 21:54 time.txt
192.168.0.111 | SUCCESS | rc=0 >>
-rw-rw-r-- 1 aaron aaron 0 Aug 4 00:21 你好.txt
-rw-rw-r-- 1 aaron aaron 20 Aug 4 06:54 time.txt
192.168.0.112 | SUCCESS | rc=0 >>
-rw-rw-r-- 1 aaron aaron 0 Aug 4 00:21 你好.txt
-rw-rw-r-- 1 aaron aaron 637 Aug 4 06:54 list.txt
当有许多主机许多任务要执行时,可以指定并发进程数
代码语言:javascript复制ansible-playbook myplaybook.yml -f 10 # 表示由 10 个并发的进程来执行任务
上述仅为 ansible-playbook 的冰山一角,ansible-playbook 还可以实现 Handlers,当在发生改变时执行的相应的操作,最佳的应用场景是用来重启服务,或者触发系统重启操作。 配置的 yaml 文件支持 Ansible-Pull 进行拉取配置等。 详见 官方文档 http://www.ansible.com.cn/docs/playbooks_intro.html
END