简介

Ansible是一个简单的IT自动化管理系统,它能够实现自动化配置管理、应用程序部署、云服务管理、持续交付等功能,它是基于Python的paramiko模块实现的,使用ssh协议与Client通信,因此不需要在Client安装Agent。

Ansible有三个最吸引人的特点:

  • 无客户端
  • 简单易用
  • 日志集中控管

安装

快速安装

1
2
3
sudo esay_install ansible
#或者
sudo pip install ansible

源码安装

1
2
3
4
5
6
7
8
9
yum install python-docutils python2-devel python-paramiko python2-cryptography     #安装依赖

git clone git://github.com/ansible/ansible.git
cd ./ansible
make rpm
rpm -Uvh ./rpm-build/ansible-*.noarch.rpm

mkdir -pv /etc/ansible
cp examples/{ansible.cfg,hosts} /etc/ansible

Ansible组件

ansible命令

1
2
3
4
5
6
语法:ansible <host-pattern> [-f forks] [-m module_name] [-a args] [options]
host-pattern:这次的命令对哪些主机生效,all表示对所有主机生效
-f forks:启动的并发线程数,一次并行处理多少主机
-m module_name:要使用的模块
-a args:模块特有的参数
-h:获取帮助

ansible配置文件

ansible执行的时候会按照以下顺序查找配置项:

1
2
3
4
ANSIBLE_CONFIG (环境变量)
ansible.cfg (当前目录下)
.ansible.cfg (用户家目录下)
/etc/ansible/ansible.cfg

配置文件解析

1
2
3
4
5
6
7
8
9
10
11
12
13
[defaults]
action_plugins=/usr/share/ansible_plugins/action_plugins #用于加载一些外部插件

ansible_managed=Ansible managed: {file} modified on %Y-%m-%d %H:%M:%S by {uid} on {host} #可以在模板中插入{{ ansible_managed }}来表示执行

host_key_checking = False #当主机不在known_hosts时是否提示
ask_pass=False #控制Ansible playbook执行时是否会自动弹出询问密码,使用SSH 密钥匙做身份认证时需要关闭
ask_sudo_pass=False #控制Ansible playbook在执行sudo之前是否询问sudo密码
executable = /bin/bash
_forks=5
remote_port=22 #设置默认远程SSH端口号,不指定为22
remote_user = root #使用ansible playbook执行的默认用户名,不指定默认使用当前用户名称:
roles_path = /opt/mysite/roles #路径指的是’roles/’下的额外目录,用于playbook搜索Ansible roles,多个路径可以用冒号分隔。

Inventory文件

Ansible可同时操作属于一个组的多台主机,组和主机之间的关系通过Inventory 文件配置.

本地Inventory文件

默认为/etc/ansible/hosts

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
#配置文件格式
mail.jaydenz.org

[webservers] #设置组名
web1.jaydenz.org:8080 #可指明端口号
web2.jaydenz.org
web[3:10].jaydenz.org

[dbservers]
db1.jaydenz.org ansible_connection=ssh ansible_ssh_user=jaydenz #对于单个链接可以设置连接类型和用户名
db2.jaydenz.org

#通过jumper关键字设置别名
jumper ansible_ssh_port=5555 ansible_ssh_host=192.168.1.50 #会连接 192.168.1.50:5555

#其他参数说明
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 #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 的路径....

远程Inventory文件

Ansible支持使用其他软件系统保存Inventory配置信息

  • 从云端拉取 inventory
  • LDAP(Lightweight Directory Access Protocol,轻量级目录访问协议)
  • Cobbler http://cobbler.github.com
  • CMDB(配置管理数据库)软件

    模块

    查看模块说明

1
2
3
4
ansible-doc [options] [modules]     #查看模块信息
options:
-l #列出所有的ansible模块
-s #列出该模块的相关指令

常用模块

调试和测试类的module

  • ping:最常用的测试一个节点有没有配置好ssh连接的module,如果可以通过ansible成功连接,那么返回pong,使用时不需要传入参数

    1
    ansible servers -m ping
  • debug:用于调试的module,只是简单打印一些消息,有点像linux的echo命令。

通过参数msg定义打印的字符串,msg中可以嵌入变量,下面的例子中注入了系统变量,ansible在执行Playbook之前会收集一些比较常用的系统变量,在Playbook中不需要定义直接就可以使用。

1
2
- debug:
msg: "System {{ inventory_hostname }} has gateway {{ ansible_default_ipv4.gateway }}"

通过参数var定义需要打印的变量,变量可以是系统变量,也可以是动态的执行结果,通过关键字regester注入到变量中。

1
2
3
- name: Display all variables/facts known for a host
debug:
var: hostvars[inventory_hostname]["ansible_default_ipv4"]["gateway"]

通过Ad Hoc Command执行

1
ansible all -m debug -a 'msg={{ inventory_hostname }}'

  • setup:收集远程主机的facts。
    1
    ansible all -m setup

引用收集到的Facts信息

1
2
3
4
5
6
#可以在playbook中这样引用第一个硬盘的模型:
{{ ansible_devices.sda.model }}
#同样,作为系统报告的主机名如以下所示:
{{ ansible_nodename }}
#不合格的主机名显示了句号(.)之前的字符串:
{{ ansible_hostname }}

关闭fact

1
2
- hosts: whatever
gather_facts: no

文件类的module

  • copy:从本地拷贝文件到远程节点

参数

1
2
3
4
5
6
7
8
9
10
11
12
13
mode:
backup:参数为yes的时候,如果发生了拷贝操作,那么会先备份目标节点上的原文件
checksum:
src:源地址。如果路径以/结尾,则只复制路径中的内容;不以/结尾,该目录及其内部内容都会被复制
remote_src:当mode=preserve有效,
dest:复制的目的路径。当src指定为一个目录时,dest也必须为目录;当dest以/结尾或路径不存在时或者src是一个目录时,dest指明的路径将被创建;当src和dest都是文件时,dest的父目录不存在将不会被创建,任务将会失败
content:
follow:
validate:验证文件的命令。一般需要验证拷贝后的文件,所以%s可以指代拷贝后的文件。只有复制和验证都完成才算执行成功
force:为yes时将会覆盖与源路径不同的目的内容,为no时仅会传输远程目的路径不存在的内容,默认为yes
owner:类似于chown命令,改变所属主
group:类似于chown命令,改变所属组
mode:设置文件权限。mode设置权限可以是用数字,也可以是符号的形式”u=rw,g=r,o=r”和”u+rw,g-wx,o-rwx”

例子

1
2
3
4
- copy:
src: /mine/sudoers
dest: /etc/sudoers
validate: 'visudo -cf %s' #visudo -cf /etc/sudoers是验证sudoers文件有没有语法错误的命令。

  • template:拷贝一个文件,并且根据需要调整部分内容。

指定替换个部分用变量来表示,template使用的是python的j2模版引擎,变量的表示法是

参数

1
2
3
4
5
6
backup:建立包含时间戳的备份,默认为no
src:本地Jinjia2模版的template文件位置
dest:远程节点上的绝对路径,用于放置template文件
owner:设置文件或目录所属主
group:设置文件或目录所属组
mode:设置远程节点上的template文件权限。类似Linux中chmod的用法

例子

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
- template:
src: /mytemplates/foo.j2
dest: /etc/file.conf
owner: bin
group: wheel
mode: 0644

- template:
src: config.ini.j2
dest: /share/windows/config.ini
newline_sequence: '\r\n'

- template:
src: /mine/sudoers
dest: /etc/sudoers
validate: '/usr/sbin/visudo -cf %s' #验证配置文件是否正确

  • file:设置文件的属性

参数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
attributes:改变文件、目录属性,相当于chattr命令
follow:如果原来的文件是link,拷贝后是否依旧是link,默认为yes
force:需要在两种情况下强制创建软链接,一种是源文件不存在但之后会建立的情况下;另一种是目标软链接已存在,需要先取消之前的软链,然后创建新的软链,默认为no
state:参数:
directory:如果目录不存在,创建目录
file:即使文件不存在,也不会被创建,默认参数
link:创建软链接
hard:创建硬链接
touch:如果文件不存在,则会创建一个新的文件,如果文件或目录已存在,则更新其最后修改时间
absent:删除目录、文件或者取消链接文件
src:要被链接的源文件的路径,只应用于state=link的情况
dest:当state=link时,表示创建的指向src的链接文件放置路径
path:需要管理的文件路径
recurse:递归的设置文件的属性,只对目录有效
owner:设置文件或目录所属主
group:设置文件或目录所属组
mode:设置远程节点上的文件权限。类似Linux中chmod的用法

例子

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
- file:
path: /etc/foo.conf
owner: foo
group: foo
mode: 0644
- file:
src: /file/to/link/to
dest: /path/to/symlink
owner: foo
group: foo
state: link
- file:
src: '/tmp/{{ item.src }}'
dest: '{{ item.dest }}'
state: link
with_items:
- { src: 'x', dest: 'y' }
- { src: 'z', dest: 'k' }

linux上常用的操作

  • user:管理用户账户

参数

1
2
3
4
5
6
7
8
9
10
11
state:present表示添加用户,absent表示删除用户
name:用户名
create_home:是否创建家目录,默认为yes
home:用于设定家目录路径
uid:用户的uid
group:所属组,即私有组
groups:附加组
password:设置用户密码(加密过后的值)
remove:当state=absent时使用,等同于userdel --remove,删除用户并删除家目录及其文件
shell:设置用户所使用的shell
system:创建一个用户时是否加入管理员组,对已存在用户无效

例子

1
2
3
ansible mysql -m user -a 'name="mysql" group="mysql" create_home=no shell="/sbin/nologin"'
ansible mysql -a 'cat /etc/passwd' | grep mysql #查看是否添加成功
ansible mysql -m user -a 'state=absent name="mysql"' #删除用户

  • yum:Red Hat系linux上的包管理,同样还有支持Debian系的apt模块

参数

1
2
3
state:present表示安装,latest表示升级最新版,absent表示删除
name:指明包名
list:指定不同参数列出相应信息:packages, installed, updates, available, repos

例子

1
ansible all -m yum -a 'list=installed'

  • service:管理服务

参数

1
2
3
4
5
6
7
state:包含多个选项:reloaded, restarted, running, started, stopped
arguments:
enable:是否开机启动
name:服务名
pattern:
runlevel:
sleep:

  • cron:可以让每一个被管理节点能够自动生成一个定期任务计划,生成的任务文件在/var/spool/cron/对应的用户名文件中

参数

1
2
3
4
5
state:present表示添加crontab任务;absent表示移除crontab任务
job:指明运行的命令是什么
name:crontab任务的名字
minute:指明分钟周期,未指明默认为*
day:指明天周期,未指明默认为*

例子

1
2
3
ansible mysql -m cron -a 'state=present minute="*/10" job="/usr/bin/echo hello" name="test cron job"'
ansible mysql -a 'crontab -l' #查看是否成功添加
ansible mysql -a 'cat /var/spool/cron/root' #查看生成的文件

执行Shell命令

  • shell:在节点上执行shell命令,支持$HOME和”<”, “>”, “|”, “;” and “&”,用于执行复杂命令

参数

1
2
3
4
5
chdir:运行命令前进入指定的目录
creates:创建一个文件,如果已存在则不会运行此步骤
executable:更改用于执行命令的Shell,必须使用绝对路径
removes:删除一个文件,如果不存在则不会进行
stdin:设置执行的命令的stdin为一个特定来源

例子

1
2
3
4
5
- name: 
shell: somescript.sh >> somelog.txt #重定向输出
args:
chdir: somedir/ #改变目录
creates: somelog.txt #当somelog.txt不存在时创建它

  • command:在远程节点上面执行命令,不支持$HOME和”<”, “>”, “|”, “;” and “&”
    默认的模块,表示在被管理主机上运行一个命令。对于command模块,-a不再是指定参数,而是命令本身,所以该模块无法传递参数或变量
    例子

    1
    ansible all -m command -a "date"
  • script:将本地脚本复制到远程主机并运行

参数

1
2
3
chdir:运行命令前进入指定的目录
creates:创建一个文件,如果已存在则不会运行此步骤
removes:删除一个文件,如果不存在则不会进行

例子

1
2
3
- script: /some/local/script.sh --some-arguments 1234
args:
creates: /the/created/file.txt

  • template:从本地拷贝文件到远程节点,并进行变量替换

ansbile在管理每一个主机时,这些主机在被运行管理命令之前,会首先向ansible节点报告自己主机当前的各种可能被ansible主机用到的状态信息,如操作系统版本、ip地址等信息,这些信息都是以变量的形式,ansible主机可以在jinjia2中调用,为不同的服务器生成不同的配置文件。

参数

1
2
3
4
5
backup:是否生成一个包含时间戳的备份
src:指明本地j2模板文件地址
dest:指明远程主机应用配置文件的路径
mode:设置文件权限
validate:验证配置文件是否正确

例子

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
- template:
src: /mytemplates/foo.j2
dest: /etc/file.conf
owner: bin
group: wheel
mode: 0644
#配置sudoers文件并验证是否正确
- template:
src: /mine/sudoers
dest: /etc/sudoers
validate: '/usr/sbin/visudo -cf %s'
#配置sshd并验证配置文件是否正确
- template:
src: etc/ssh/sshd_config.j2
dest: /etc/ssh/sshd_config
owner: root
group: root
mode: '0600'
validate: /usr/sbin/sshd -t -f %s
backup: yes

Ad Hoc Commands

Ansible提供的命令行工具,用于在ansible中快速执行,并且不需要保存的命令。

例子

1
2
3
4
5
ansible all -m setup             #查看远程主机facts
ansible all -m ping -u jaydenz #检查所有的远程主机,是否以jaydenz用户创建了ansible主机可以访问的环境。
ansible all -a "/bin/echo hello" #在所有的远程主机上,以当前bash的同名用户,在远程主机执行“echo hello”
ansible web -m copy -a "src=/etc/hosts dest=/tmp/hosts" #拷贝文件/etc/host到远程主机(组)web,位置为/tmp/hosts
ansible web -m git -a "repo=git://foo.example.org/repo.git dest=/srv/myapp version=HEAD" #git一个项目到web主机本地目录

Playbook

Playbook是由一个或多个play组成的列表,针对每一组server的所有操作就组成一个play。Playbook的主要功能在于将事先归并为一组的主机装扮成事先通过ansible中的task定义好的角色。从根本上来讲,所谓task无非是调用ansible的一个module。在写Playbook的时候,一定要记住在hosts、模块名等后面带空格,否则会报错。
执行Playbook:

1
ansible-playbook deploy.yml

在运行Playbook的时候也可以传递一些变量供Playbook使用:

1
ansible-playbook test.yml --extra-vars "hosts=mysql user=jaydenz"

Playbook关键字

  • hosts和remote_users

    1
    2
    3
    4
    5
    6
    7
    8
    - hosts: mysql       #指明执行任务的主机,可以是一个或多个由冒号分隔主机组
    remote_user: root #指定远程主机上执行任务的用户
    tasks: #建立一个任务列表
    - name: Test To Connect MySQL Server #任务名
    ping:
    remote_user: root #在tasks中也可以定义执行的用户身份
    sudo: yes #指定使用sudo方式运行
    sudo_user: jaydenz #指定sudo时切换的用户
  • tasks:任务,调用模块完成某操作

Playbook的核心,定义按顺序执行的动作action,每个action调用一个ansbile module,如果中途发生错误所有任务将会回滚。每个Task都需要使用- name指定一个名用于Playbook的执行结果输出,如果未提供name,则Action的结果将用于输出。

1
2
3
4
tasks:
- name: make sure apache is running
service: name=httpd state=running #定义一个Action,建议使用module:module_parameter=module_value格式的语法
#如果action一行的内容过多,也中使用在行首使用几个空白字符进行换行。

在众多模块中,只有command和shell模块仅需要给定一个列表而无需使用“key=value”格式,例如:

1
2
3
tasks:
- name: disable selinux
command: /sbin/setenforce 0

如果命令或脚本的退出码不为零,可以使用如下方式替代:

1
2
3
tasks:
- name: run this command and ignore the result
shell: /usr/bin/somecommand || /bin/true

或者使用ignore_errors来忽略错误信息:

1
2
3
4
tasks:
- name: run this command and ignore the result
shell: /usr/bin/somecommand
ignore_errors: True

  • vars

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    - hosts: webservers
    vars:
    package: httpd #定义一个变量
    service: httpd
    tasks:
    - name: install httpd package
    yum: name={{ package }} state=latest #引用package变量

    #注意:
    - hosts: app_servers
    vars:
    app_path: "{{ base_path }}/22" #YAML语法要求如果值以{{ foo }}开头的话我们需要将整行用双引号包起来
  • register

把任务的输出定义为变量,然后用于其他任务。

1
2
3
4
tasks:
- shell: /usr/bin/foo
register: foo_result #把shell的输出赋值给foo_result
ignore_errors: True

  • when

在task后添加when子句即可使用条件测试;when语句支持Jinja2表达式语法。例如:

1
2
3
4
tasks:
- name: "shutdown Debian flavored systems"
command: /sbin/shutdown -h now
when: ansible_os_family == "Debian"

when语句中还可以使用Jinja2的大多“filter”,例如要忽略此前某语句的错误并基于其结果(failed或者sucess)运行后面指定的语句,可使用类似如下形式:

1
2
3
4
5
6
7
8
9
10
tasks:
- command: /bin/false
register: result
ignore_errors: True
- command: /bin/something
when: result|failed
- command: /bin/something_else
when: result|success
- command: /bin/still/something_else
when: result|skipped

此外,when语句中还可以使用facts或playbook中定义的变量。

  • handlers

用于当监控的资源发生变化时采取一定的操作。使用handlers定义一个或一组action,每个action使用name关键字指明名称,在要监控的资源处定义notify并指明需要调用的handlers的名称,handlers也属于tasks

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
- hosts: web
vars:
http_port: 80
max_clients: 200
remote_user: root
tasks:
- name: ensure apache is at the latest version
yum: pkg=httpd state=latest

- name: Write the configuration file
template: src=templates/httpd.conf.j2 dest=/etc/httpd/conf/httpd.conf
notify: #定义一个notify监控配置文件是否发送改变
- restart apache #调用handlers中名称为restart apache的action

- name: Write the default index.html file
template: src=templates/index.html.j2 dest=/var/www/html/index.html

- name: ensure apache is running
service: name=httpd state=started

handlers: #定义一个handlers
- name: restart apache #定义一个处理动作
service: name=httpd state=restarted
- name: ping server
ping:

  • roles

ansilbe自1.2版本引入的新特性,用于层次性、结构化地组织playbook。roles能够根据层次型结构自动装载变量文件、tasks以及handlers等。要使用roles只需要在playbook中使用include指令即可。简单来讲,roles就是通过分别将变量、文件、任务、模块及处理器放置于单独的目录中,并可以便捷地include它们的一种机制。角色一般用于基于主机构建服务的场景中,但也可以是用于构建守护进程等场景中。

一个项目的目录结构

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
site.yml
webservers.yml
fooservers.yml
roles/
common/ #定义一个名为common的role
files/
templates/
tasks/
handlers/
vars/
defaults/
meta/
webservers/
files/
templates/
tasks/
handlers/
vars/
defaults/
meta/

该项目的一个playbook

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
- hosts: webservers
roles:
- common #使用名为common的role
- webservers

这个playbook 为一个角色 ‘x’ 指定了如下的行为:
如果 roles/x/tasks/main.yml 存在, 其中列出的 tasks 将被添加到 play 中
如果 roles/x/handlers/main.yml 存在, 其中列出的 handlers 将被添加到 play 中
如果 roles/x/vars/main.yml 存在, 其中列出的 variables 将被添加到 play 中
如果 roles/x/meta/main.yml 存在, 其中列出的 “角色依赖” 将被添加到 roles 列表中 (1.3 and later)

所有 copy tasks 可以引用 roles/x/files/ 中的文件,不需要指明文件的路径。
所有 script tasks 可以引用 roles/x/files/ 中的脚本,不需要指明文件的路径。
所有 template tasks 可以引用 roles/x/templates/ 中的文件,不需要指明文件的路径。
所有 include tasks 可以引用 roles/x/tasks/ 中的文件,不需要指明文件的路径。
在 Ansible 1.4 及之后版本,你可以为”角色”的搜索设定 roles_path 配置项。使用这个配置项将所有的 common 角色 check out 到一个位置,以便在多个 playbook 项目中可方便的共享使用它们。

#可以使用参数化的 roles,这种方式通过添加变量来实现
- hosts: webservers
roles:
- common
- { role: foo_app_instance, dir: '/opt/a', port: 5000 }
- { role: foo_app_instance, dir: '/opt/b', port: 5001 }
- { role: some_role, when: "ansible_os_family == 'RedHat'" } #为roles设置触发条件
- { role: foo, tags: ["bar", "baz"] } #给roles分配指定的tags
#注意:role、dir、port是变量名,冒号后面的是变量值。
#定义一些 tasks,让它们在 roles 之前以及之后执行,如果对tasks应用了tags,需确保给pre_tasks以及post_tasks也同样应用 tags,并且将它们一并传递。
- hosts: webservers
pre_tasks:
- shell: echo 'hello'
roles:
- { role: some_role }
tasks:
- shell: echo 'still busy'
post_tasks:
- shell: echo 'goodbye'

角色依赖:可以自动地将其他roles拉取到现在使用的role中,保存在roles目录下的 meta/main.yml 文件中。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
#roles/myapp/meta/main.yml示例
dependencies:
- { role: common, some_parameter: 3 }
- { role: apache, port: 80 }
- { role: postgres, dbname: blarg, other_parameter: 12 }
#角色依赖可以通过绝对路径指定,如同顶级角色的设置:
dependencies:
- { role: '/path/to/common/roles/foo', x: 1 }

#角色依赖总是在role(包含角色依赖的role)之前执行,并且是递归地执行。默认情况下,作为角色依赖被添加的role只能被添加一次,如果另一个 role 将一个相同的角色列为角色依赖的对象,它不会被重复执行。
#但这种默认的行为可被修改,通过添加 allow_duplicates: yes 到 meta/main.yml 文件中。 比如,一个role名为car,它可以添加名为wheel的 role到它的角色依赖中:
dependencies:
- { role: wheel, n: 1 }
- { role: wheel, n: 2 }
- { role: wheel, n: 3 }
- { role: wheel, n: 4 }
wheel角色的 meta/main.yml 文件包含如下内容:
allow_duplicates: yes
dependencies:
- { role: tire }
- { role: brake }
最终的执行顺序是这样的:
tire(n=1)
brake(n=1)
wheel(n=1)
tire(n=2)
brake(n=2)
wheel(n=2)
...
car

  • tags:用于让用户选择运行或跳过Playbook中的部分代码。ansible具有幂等性,因此会自动跳过没有变化的部分,即便如此,有些代码为测试其确实没有发生变化的时间依然会非常地长。此时,如果确信其没有变化,就可以通过tags跳过此些代码片断。
    1
    2
    3
    4
    5
    6
    tasks:
    - name:
    tags:
    - conf

    # ansible-playbook apache.yml --tages='conf' #仅运行tages为conf的任务

特殊tags: always,

  • 迭代

当有需要重复性执行的任务时,可以使用迭代机制。其使用格式为将需要迭代的内容定义为item变量引用,并通过with_items语句来指明迭代的元素列表即可。例如:

1
2
3
4
5
- name: add several users
user: name={{ item }} state=present groups=wheel
with_items:
- testuser1
- testuser2

上面语句的功能等同于下面的语句:

1
2
3
4
- name: add user testuser1
user: name=testuser1 state=present groups=wheel
- name: add user testuser2
user: name=testuser2 state=present groups=wheel

注意:with_items中的列表值也可以是字典, 但引用时要使用item.KEY

  • include:用于引用其他文件中的tasks,可以将配置策略分解到更小的文件中,实现配置重用
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    tasks:
    - include: tasks/foo.yml
    - include: wordpress.yml wp_user=timmy

    #在1.4版本开始可以支持的语法
    - { include: wordpress.yml, wp_user: timmy, ssh_keys: [ 'keys/one.txt', 'keys/two.txt' ] }

    #1.0版本开始支持传递变量到include files
    - include: wordpress.yml
    vars:
    wp_user: timmy #在文件中使用{{ wp_user }}来定义变量
    some_list_variable:
    - alpha
    - beta
    - gamma

    #Include 语句可以和其他非 include 的 tasks 和 handlers 混合使用
    handlers:
    - include: handlers/handlers.yml

    #Include 语句也可用来将一个 playbook 文件导入另一个 playbook 文件。这种方式允许你定义一个 顶层的 playbook,这个顶层 playbook 由其他 playbook 所组成,但是在playbook中引用其他playbook时,不能使用变量替换。
    - name: this is a play at the top level of a file
    hosts: all
    remote_user: root

    tasks:

    - name: say hi
    tags: foo
    shell: echo "hi..."

    - include: load_balancers.yml #导入其他playbook
    - include: webservers.yml
    - include: dbservers.yml

简单流程

  1. 安装ansible
  2. 首先在/etc/ansible/hosts定义主机清单
  3. 配置生成密钥

    1
    2
    3
    4
    ssh-keygen -t rsa -P ''
    ssh-copy-id -i ~/.ssh/id_rsa.pub root@192.168.213.10
    ssh-copy-id -i ~/.ssh/id_rsa.pub root@192.168.213.20
    ssh-copy-id -i ~/.ssh/id_rsa.pub root@192.168.213.30
  4. 测试连通性

    1
    ansible all -m ping
  5. 执行Playbook

解决问题

PIP未安装

1
2
3
yum -y install epel-release
yum install python-pip
pip install --upgrade pip

执行ansible提示’you must install the sshpass program’

1
2
#在extras源中
yum install sshpass

附录

中文文档:https://getansible.com/

Ansible官方模块说明:http://docs.ansible.com/ansible/latest/modules/list_of_all_modules.html

个人常用Playbook:https://github.com/Jaydenz/playbook

Playbook指南:http://ansible-tran.readthedocs.io/en/latest/docs/playbooks.html