ansible 学习笔记
1.安装
1.1安装ansible
注意: 只需要在控制端安装即可,比如本地机控制云端机的情况下,只需要在你的笔记本或者台式机安装ansible
ubuntu:
$ sudo apt-get install software-properties-common
$ sudo apt-add-repository ppa:ansible/ansible
$ sudo apt-get update
$ sudo apt-get install ansible
centos:
sudo yum install ansible
1.2配置ssh免密码登录
# 生成公私钥
ssh-keygen -t rsa
# 将公钥拷贝到节点
ssh-copy-id root@127.0.0.1 -p 40022
ssh-copy-id root@127.0.0.1 -p 40023
ssh-copy-id root@127.0.0.1 -p 40024
2.配置Inventory文件
Ansible 可同时操作属于一个组的多台主机,组和主机之间的关系通过 inventory 文件配置. 默认的文件路径为 /etc/ansible/hosts
2.1主机与组
mail.example.com
[webservers]
foo.example.com
bar.example.com
[dbservers]
one.example.com
two.example.com
three.example.com
方括号[]中是组名,用于对系统进行分类,便于对不同系统进行个别的管理.一个服务器可以同时属于两个或多个组,这时属于两个组的变量都可以为这台所用
如果主机的ssh端口不是标准的22端口,可以在配置文件中以主机+端口号形式配置,用冒号分隔.SSH 配置文件中列出的端口号不会在 paramiko 连接中使用,会在 openssh 连接中使
badwolf.example.com:5309
为静态ip设置别名
jumper ansible_ssh_port=5555 ansible_ssh_host=192.168.1.50
在这个例子中,通过 “jumper” 别名,会连接 192.168.1.50:5555,但是这不是设置变量最好的方式
如果有相似的ip/hosename 可以简写
192.168.125.[120:122] ansible_ssh_user=root ansible_ssh_port=22
以上会匹配以下地址段:
192.168.125.120, 192.168.125.121, 192.168.125.122
对于每一个 host,你还可以选择连接类型和连接用户名:
[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
2.2主机变量
前面已经提到过,分配变量给主机很容易做到,这些变量定义后可在 playbooks 中使用:
[atlanta]
host1 http_port=80 maxRequestsPerChild=808
host2 http_port=303 maxRequestsPerChild=909
2.3组的变量
也可以定义属于整个组的变量:
[atlanta]
host1
host2
[atlanta:vars]
ntp_server=ntp.atlanta.example.com
proxy=proxy.atlanta.example.com
2.4把一个组作为另一个组的成员
可以把一个组作为另一个组的子成员,以及分配变量给整个组使用. 这些变量可以给 /usr/bin/ansible-playbook 使用,但不能给 /usr/bin/ansible 使用:
[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
2.5分文件定义 Host
在 inventory 主文件中保存所有的变量并不是最佳的方式.还可以保存在独立的文件中
首先修改/etc/ansible/ansible.cfg文件
# 该配置将inventory文件指定一个inventory目录
[defaults]
# some basic default values...
inventory = /etc/ansible/inventory
#inventory = /etc/ansible/hosts
然后在inventory文件夹中建新的文件夹,然后在新建的文件夹中建host文件
cd /etc/ansible/inventory
vim hosts
.....
2.6inventory参数说明
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 的路径....
2.7动态inventory
也可以用外部自定义的hosts
ansible -i autoDeploy all -m ping # autoDeploy 为自定义的host文件
3.Patterns
在Ansible中,Patterns 是指我们怎样确定由哪一台主机来管理. 意思就是与哪台主机进行交互. 但在:doc:playbooks 中它指的是对应主机应用特定的配置或执行特定进程.
命令语法:
ansible <pattern_goes_here> -m <module_name> -a <arguments>
一个pattern通常关联到一系列组(主机的集合) –如上示例中,所有的主机均在 “webservers” 组中.不管怎么样,在使用Ansible前,我们需事先告诉Ansible哪台机器将被执行. 能这样做的前提是需要预先定义唯一的 host names 或者 主机组
ansible webservers -m service -a "name=httpd state=restarted"
ansible auto -a "yum -y install vim" -f 3 # 启用三个进程, -a 代表参数, -f 代表进程
如下的patterns等同于目标为仓库(inventory)中的所有机器:
all
也可以写IP地址或系列主机名:
one.example.com
one.example.com:two.example.com
192.168.1.50
192.168.1.*
如下patterns分别表示一个或多个groups.多组之间以冒号分隔表示或的关系.这意味着一个主机可以同时存在多个组:
webservers
webservers:dbservers
你也可以排队一个特定组,如下实例中,所有执行命令的机器必须隶属 webservers 组但同时不在 phoenix组:
webservers:!phoenix
你也可以指定两个组的交集,如下实例表示,执行命令有机器需要同时隶属于 webservers 和 staging 组.
webservers:&staging
你也可以不必严格定义groups,单个的host names, IPs , groups都支持通配符:
*.example.com
*.com
Ansible同时也支持通配和groups的混合使用:
one*.com:dbservers
在高级语法中,你也可以在group中选择对应编号的server:
webservers[0]
或者一个group中的一部分servers:
webservers[0-25]
大部分人都在patterns应用正则表达式,但你可以.只需要以 ‘~’ 开头即可:
~(web|db).*\.example\.com
4.ad-hoc
所谓 ad-hoc 命令是什么呢?
这其实是一个概念性的名字,是相对于写 Ansible playbook 来说的.类似于在命令行敲入shell命令和 写shell scripts两者之间的关系
如果我们敲入一些命令去比较快的完成一些事情,而不需要将这些执行的命令特别保存下来, 这样的命令就叫做 ad-hoc 命令
Ansible提供两种方式去完成任务,一是 ad-hoc 命令,一是写 Ansible playbook.前者可以解决一些简单的任务, 后者解决较复杂的任务.
4.1Parallelism and Shell Commands
启动三个进程,打印,同时制定-k 询问密码
➜ ~ ansible auto -a "echo haha" -f 3 -k
SSH password:
192.168.125.122 | CHANGED | rc=0 >>
haha
192.168.125.121 | CHANGED | rc=0 >>
haha
192.168.125.120 | CHANGED | rc=0 >>
haha
指定用户名:
➜ ~ ansible auto -a "echo haha" -f 3 -u jack
192.168.125.122 | CHANGED | rc=0 >>
haha
192.168.125.121 | CHANGED | rc=0 >>
haha
192.168.125.120 | CHANGED | rc=0 >>
haha
4.2File Transfer
这是 /usr/bin/ansible 的另一种用法.Ansible 能够以并行的方式同时 SCP 大量的文件到多台机器. 命令如下:
ansible auto -m copy -a "src=/home/jack/faas-cli dest=/home" -f 3
删除:
ansible auto -a "rm -rf /home/faas-cli"
使用 file
模块可以做到修改文件的属主和权限,(在这里可替换为 copy
模块,是等效的):
$ ansible webservers -m file -a "dest=/srv/foo/a.txt mode=600"
$ ansible webservers -m file -a "dest=/srv/foo/b.txt mode=600 owner=mdehaan group=mdehaan"
使用 file
模块也可以创建目录,与执行 mkdir -p
效果类似:
$ ansible webservers -m file -a "dest=/path/to/c mode=755 owner=mdehaan group=mdehaan state=directory"
删除目录(递归的删除)和删除文件:
$ ansible webservers -m file -a "dest=/path/to/c state=absent"
4.3Managing Packages
Ansible 提供对 yum 和 apt 的支持.这里是关于 yum 的示例.
确认一个软件包已经安装,但不去升级它:
➜ ~ ansible auto -m yum -a "name=vim state=present"
192.168.125.121 | SUCCESS => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/bin/python"
},
"changed": false,
"msg": "",
"rc": 0,
"results": [
"2:vim-enhanced-7.4.629-6.el7.x86_64 providing vim is already installed"
]
......
确认一个软件包的安装版本:
➜ ~ ansible auto -m yum -a "name=vim-8.0 state=present"
192.168.125.122 | FAILED! => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/bin/python"
},
"changed": false,
"msg": "No package matching 'vim-8.0' found available, installed or updated",
"rc": 126,
"results": [
"No package matching 'vim-8.0' found available, installed or updated"
]
}
确认一个软件包还没有安装:
➜ ~ ansible auto -m yum -a "name=acme state=absent"
192.168.125.121 | SUCCESS => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/bin/python"
},
"changed": false,
"msg": "",
"rc": 0,
"results": [
"acme is not installed"
]
...
4.4Users and Groups
使用 ‘user’ 模块可以方便的创建账户,删除账户,或是管理现有的账户:
$ ansible all -m user -a "name=foo password=<crypted password here>"
$ ansible all -m user -a "name=foo state=absent"
4.5Deploying From Source Control
直接使用 git 部署 webapp:
$ ansible webservers -m git -a "repo=git://foo.example.org/repo.git dest=/srv/myapp version=HEAD"
因为Ansible 模块可通知到 change handlers ,所以当源码被更新时,我们可以告知 Ansible 这个信息,并执行指定的任务, 比如直接通过 git 部署 Perl/Python/PHP/Ruby, 部署完成后重启 apache.
4.6Managing Services
$ ansible webservers -m service -a "name=httpd state=started"
$ ansible webservers -m service -a "name=httpd state=restarted"
$ ansible webservers -m service -a "name=httpd state=stopped"
4.7Time Limited Background Operations
需要长时间运行的命令可以放到后台去,在命令开始运行后我们也可以检查运行的状态.如果运行命令后,不想获取返回的信息, 可执行如下命令:
$ ansible all -B 3600 -P 0 -a "/usr/bin/long_running_operation --do-stuff"
如果你确定要在命令运行后检查运行的状态,可以使用 async_status 模块.前面执行后台命令后会返回一个 job id, 将这个 id 传给 async_status 模块:
$ ansible web1.example.com -m async_status -a "jid=488359678239.2844"
获取状态的命令如下:
$ ansible all -B 1800 -P 60 -a "/usr/bin/long_running_operation --do-stuff"
其中 -B 1800
表示最多运行30分钟, -P 60
表示每隔60秒获取一次状态信息
Polling 获取状态信息的操作会在后台工作任务启动之后开始.若你希望所有的工作任务快速启动, --forks
这个选项的值 要设置得足够大,这是前面讲过的并发进程的个数.在运行指定的时间(由-B
选项所指定)后,远程节点上的任务进程便会被终止.
一般你只能在把需要长时间运行的命令或是软件升级这样的任务放到后台去执行.对于 copy 模块来说,即使按照前面的示例想放到 后台执行文件传输,实际上并不会如你所愿.
4.8Gathering Facts
在 playbooks 中有对于 Facts 做描述,它代表的是一个系统中已发现的变量.These can be used to implement conditional execution of tasks but also just to get ad-hoc information about your system. 可通过如下方式查看所有的 facts:
$ ansible all -m setup
5.ansible 的配置文件
Ansible的一些的设置可以通过配置文件完成.在大多数场景下默认的配置就能满足大多数用户的需求,在一些特殊场景下,用户还是需要自行修改这些配置文件
用户可以修改一下配置文件来修改设置,他们的被读取的顺序如下:
* ANSIBLE_CONFIG (一个环境变量)
* ansible.cfg (位于当前目录中)
* .ansible.cfg (位于家目录中)
* /etc/ansible/ansible.cfg
详细配置见官方文档
6.Playbooks
Playbooks 是 Ansible的配置,部署,编排语言.他们可以被描述为一个需要希望远程主机执行命令的方案,或者一组IT程序运行的命令集合.
如果 Ansible 模块你是工作室中的工具,那么 playbooks 就是你设置的方案计划.
在基础层面, playbooks 可以被用来管理用于部署到远程主机的配置文件.在更高的层面上,playbooks 可以依次对多层式架构上的服务器执行上线包括滚动更新在内的操作并可以将操作委托给其他主机包括在此过程中发生的与监视服务器,负载均衡服务器的交互操作在内.
6.1Playbooks简介
Playbooks 与 adhoc 相比,是一种完全不同的运用 ansible 的方式,是非常之强大的.
简单来说,playbooks 是一种简单的配置管理系统与多机器部署系统的基础.与现有的其他系统有不同之处,且非常适合于复杂应用的部署.
Playbooks 可用于声明配置,更强大的地方在于,在 playbooks 中可以编排有序的执行过程,甚至于做到在多组机器间,来回有序的执行特别指定的步骤.并且可以同步或异步的发起任务.
我们使用 adhoc 时,主要是使用 /usr/bin/ansible 程序执行任务.而使用 playbooks 时,更多是将之放入源码控制之中,用之推送你的配置或是用于确认你的远程系统的配置是否符合配置规范.
示例单个playbooks:
---
- hosts: webservers
vars:
http_port: 80
max_clients: 200
remote_user: root
tasks:
- name: ensure apache is at the latest version
yum:
name: httpd
state: latest
- name: write the apache config file
template:
src: /srv/httpd.j2
dest: /etc/httpd.conf
notify:
- restart apache
- name: ensure apache is running
service:
name: httpd
state: started
handlers:
- name: restart apache
service:
name: httpd
state: restarted
多个playbooks:
---
- hosts: webservers
remote_user: root
tasks:
- name: ensure apache is at the latest version
yum:
name: httpd
state: latest
- name: write the apache config file
template:
src: /srv/httpd.j2
dest: /etc/httpd.conf
- hosts: databases
remote_user: root
tasks:
- name: ensure postgresql is at the latest version
yum:
name: postgresql
state: latest
- name: ensure that postgresql is started
service:
name: postgresql
state: started
6.2playbook基础
6.2.1主机与用户
你可以为 playbook 中的每一个 play,个别地选择操作的目标机器是哪些,以哪个用户身份去完成要执行的步骤(called tasks).
hosts 行的内容是一个或多个组或主机的 patterns,以逗号为分隔符,remote_user 就是账户名:
---
- hosts: webservers
remote_user: root
再者,在每一个 task 中,可以定义自己的远程用户:
---
- hosts: webservers
remote_user: root
tasks:
- name: test connection
ping:
remote_user: yourname
还支持以其他用户身份运行事务
---
- hosts: webservers
remote_user: yourname
become: yes
become_method: sudo
您还可以become
在特定任务而不是整个host中使用关键字:
---
- hosts: webservers
remote_user: yourname
tasks:
- service:
name: nginx
state: started
become: yes
become_method: sudo
您还可以以您的身份登录,然后成为不同于root用户的用户:
---
- hosts: auto1
remote_user: jack
tasks:
- name: test connection
become: yes
become_user: testname
service: name=sshd state=started
您还可以使用其他特权升级方法,例如su:
---
- hosts: webservers
remote_user: yourname
become: yes
become_method: su
重要的是还可以控制主机的执行顺序, 默认是按照顺序执行的
- hosts: all
order: sorted
gather_facts: False
tasks:
- debug:
var: inventory_hostname
inventory: 默认的排序方式,按照inventory规则顺序执行
reverse_inventory: 和上面相反
sorted: 按主机名字母顺序
reverse_sorted:和sorted相反
shuffle: 随机
6.2.2Tasks列表
每一个 play 包含了一个 task 列表(任务列表).一个 task 在其所对应的所有主机上(通过 host pattern 匹配的所有主机)执行完毕之后,下一个 task 才会执行.有一点需要明白的是(很重要),在一个 play 之中,所有 hosts 会获取相同的任务指令,这是 play 的一个目的所在,也就是将一组选出的 hosts 映射到 task
在运行 playbook 时(从上到下执行),如果一个 host 执行 task 失败,这个 host 将会从整个 playbook 的 rotation 中移除. 如果发生执行失败的情况,请修正 playbook 中的错误,然后重新执行即可.
每个 task 的目标在于执行一个 moudle, 通常是带有特定的参数来执行.在参数中可以使用变量(variables).
modules 具有”幂等”性,意思是如果你再一次地执行 moudle(译者注:比如遇到远端系统被意外改动,需要恢复原状),moudle 只会执行必要的改动,只会改变需要改变的地方.所以重复多次执行 playbook 也很安全.
对于 command module 和 shell module,重复执行 playbook,实际上是重复运行同样的命令.如果执行的命令类似于 ‘chmod’ 或者 ‘setsebool’ 这种命令,这没有任何问题.也可以使用一个叫做 ‘creates’ 的 flag 使得这两个 module 变得具有”幂等”特性 (不是必要的).
每一个 task 必须有一个名称 name,这样在运行 playbook 时,从其输出的任务执行信息中可以很好的辨别出是属于哪一个 task 的. 如果没有定义 name,‘action’ 的值将会用作输出信息中标记特定的 task.
如果要声明一个 task,以前有一种格式: “action: module options” (可能在一些老的 playbooks 中还能见到).现在推荐使用更常见的格式:”module: options” ,本文档使用的就是这种格式.
下面是一种基本的 task 的定义,service moudle 使用 key=value 格式的参数,这也是大多数 module 使用的参数格式:
tasks:
- name: make sure apache is running
service:
name: httpd
state: started
比较特别的两个 modudle 是 command 和 shell ,它们不使用 key=value 格式的参数,而是这样:
tasks:
- name: disable selinux
command: /sbin/setenforce 0
使用 command module 和 shell module 时,我们需要关心返回码信息,如果有一条命令,它的成功执行的返回码不是0, 你或许希望这样做:
tasks:
- name: run this command and ignore the result
shell: /usr/bin/somecommand || /bin/true
或者:
tasks:
- name: run this command and ignore the result
shell: /usr/bin/somecommand
ignore_errors: True
如果 action 行看起来太长,你可以使用 space(空格) 或者 indent(缩进) 隔开连续的一行:
tasks:
- name: Copy ansible inventory file to client
copy: src=/etc/ansible/hosts dest=/etc/ansible/hosts
owner=root group=root mode=0644
在 action 行中可以使用变量.假设在 ‘vars’ 那里定义了一个变量 ‘vhost’ ,可以这样使用它:
tasks:
- name: create a virtual host file for {{ vhost }}
template:
src: somefile.j2
dest: /etc/httpd/conf.d/{{ vhost }}
在一个基础的 playbook 中,所有的 task 都是在一个 play 中列出,更合理的安排task的方式是:使用include
6.2.3Action Shorthand
在 0.8 及以后的版本中,ansible 更喜欢使用如下的格式列出 modules:
template:
src: templates/foo.j2
dest: /etc/foo.conf
以前的版本:
action: template src=templates/foo.j2 dest=/etc/foo.conf
6.2.4Handlers: 在发生改变时执行的操作
上面我们曾提到过,module 具有”幂等”性,所以当远端系统被人改动时,可以重放 playbooks 达到恢复的目的. playbooks 本身可以识别这种改动,并且有一个基本的 event system(事件系统),可以响应这种改动.
(当发生改动时)’notify’ actions 会在 playbook 的每一个 task 结束时被触发,而且即使有多个不同的 task 通知改动的发生, ‘notify’ actions 只会被触发一次.
举例来说,比如多个 resources 指出因为一个配置文件被改动,所以 apache 需要重新启动,但是重新启动的操作只会被执行一次.
这里有一个例子,当一个文件的内容被改动时,重启两个 services:
- name: template configuration file
template:
src: template.j2
dest: /etc/foo.conf
notify:
- restart memcached
- restart apache
‘notify’ 下列出的即是 handlers.
Handlers 也是一些 task 的列表,通过名字来引用,它们和一般的 task 并没有什么区别.Handlers 是由通知者进行 notify, 如果没有被 notify,handlers 不会执行.不管有多少个通知者进行了 notify,等到 play 中的所有 task 执行完成之后,handlers 也只会被执行一次.
这里是一个 handlers 的示例:
handlers:
- name: restart memcached
service:
name: memcached
state: restarted
- name: restart apache
service:
name: apache
state: restarted
Handlers 最佳的应用场景是用来重启服务,或者触发系统重启操作.除此以外很少用到了.
从Ansible 2.2开始,处理程序还可以“侦听”通用主题,任务可以如下通知这些主题:
handlers:
- name: restart memcached
service:
name: memcached
state: restarted
listen: "restart web services"
- name: restart apache
service:
name: apache
state: restarted
listen: "restart web services"
tasks:
- name: restart everything
command: echo "this task will restart the web services"
notify: "restart web services"
handlers 会在 ‘pre_tasks’, ‘roles’, ‘tasks’, 和 ‘post_tasks’ 之间自动执行. 如果你想立即执行所有的 handler 命令:
tasks:
- shell: some tasks go here
- meta: flush_handlers
- shell: some other tasks
在以上的例子中,任何在排队等候的 handlers 会在执行到 ‘meta’ 部分时,优先执行.这个技巧在有些时候也能派上用场.
6.2.5执行一个palybook
ansible-playbook playbook.yml -f 10
6.2.6 使用ansible-lint 检测playbook的yaml配置文件
ansible-lint test.yaml
6.2.7Ansible-Pull(拉取配置而非推送配置)
我们可不可以将 ansible 的体系架构颠倒过来,让托管节点从一个 central location 做 check in 获取配置信息,而不是 推送配置信息到所有的托管节点?是可以的.
Ansible-pull 是一个小脚本,它从 git 上 checkout 一个关于配置指令的 repo,然后以这个配置指令来运行 ansible-playbook.
假设你对你的 checkout location 做负载均衡,ansible-pull 基本上可以无限的提升规模.
可执行 ansible-pull --help
获取详细的帮助信息.
也有一个叫做 clever playbook 的东西: clever playbook . 这个可以通过 crontab 来配置 ansible-pull(from push mode)
如果你想看到执行成功的 modules 的输出信息,使用 --verbose
flag(否则只有执行失败的才会有输出信息)
7创建可重用的playbook
尽管可以在一个非常大的文件中编写一本剧本(并且您可能会开始以这种方式学习剧本),但最终您将需要重用文件并开始进行整理。在Ansible中,有三种方法可以做到这一点:includes, imports, and roles.
includes, imports(在Ansible 2.4版中添加)允许用户将大型剧本拆分成较小的文件,这些文件可以在多个父级剧本中使用,甚至可以在同一本Playbook中多次使用。
roles不仅可以将任务打包在一起,还可以包括变量,处理程序,甚至模块和其他插件。与包含和导入不同,角色也可以通过Ansible Galaxy上传和共享
7.1动态与静态
如果使用任何include*
任务(include_tasks
,include_role
等),它将是动态的。如果您使用任何import*
Task(import_playbook
,import_tasks
等),它将是静态的。
裸include
任务(已用于任务文件和Playbook级包含的裸任务)仍然可用,但是现在认为已弃用
动态和静态的区别:
动态包含在运行时在遇到该任务时进行处理。
Ansible在Playbook解析期间会预处理所有静态导入。
对于Ansible任务选项,例如tags和条件语句(when:):
import_tasks(Static)方法会在playbooks解析阶段将父task变量和子task变量全部读取并加载
include_tasks(Dynamic)方法则是在执行play之前才会加载自己变量
include_tasks方法调用的文件名称可以加变量
import_tasks方法调用的文件名称不可以有变量
7.2include vs import
import * 在解析时会进行预处理
include在执行playbook时,进行处理
- import_playbook: webservers.yml
- import_playbook: databases.yml
列出的每个playbook中的play和task将按照列出的顺序运行
2.4之前的版本仅include
在导入和包含时可用,并且可同时用于playbook和task。
7.2.1include和import task
将任务分解为不同的文件是组织复杂任务集或重用它们的绝佳方法。任务文件仅包含一个平面任务列表:
# common_tasks.yml
- name: placeholder foo
command: /bin/foo
- name: placeholder bar
command: /bin/bar
然后,您可以使用import_tasks
或include_tasks
执行主任务列表中文件中的任务:
tasks:
- import_tasks: common_tasks.yml
# or
- include_tasks: common_tasks.yml
您还可以将变量传递到imports和includes:
tasks:
- import_tasks: wordpress.yml
vars:
wp_user: timmy
- import_tasks: wordpress.yml
vars:
wp_user: alice
- import_tasks: wordpress.yml
vars:
wp_user: bob
注意:
静态和动态可以混合使用,但是不建议这样做,因为这可能会导致难以诊断的剧本中的错误。
key=value不建议使用传递变量以导入和包含的语法。请改用YAML vars:。
包含和导入也可以在本handlers:
节中使用。例如,如果要定义如何重启Apache,则只需对所有剧本执行一次。您可能会制作一个handlers.yml
看起来像:
# more_handlers.yml
- name: restart apache
service:
name: apache
state: restarted
handlers:
- include_tasks: more_handlers.yml
# or
- import_tasks: more_handlers.yml
8.roles
ansible
自1.2
版本引入的新特性,用于层次性、结构化地组织playbook
。roles
能够根据层次型结构自动装载变量文件、tasks
以及handlers
等。要使用roles
只需要在playbook
中使用include
指令引入即可。简单来讲,roles
就是通过分别将变量、文件、任务、模板及处理器放置于单独的目录中,并可以便捷的include
它们的一种机制。角色一般用于基于主机构建服务的场景中,但也可以是用于构建守护进程等场景中。主要使用场景代码复用度较高的情况下。
8.1各目录含义解释
roles: <--所有的角色必须放在roles目录下,这个目录可以自定义位置,默认的位置在/etc/ansible/roles
project: <---具体的角色项目名称,比如nginx、tomcat、php
files: <--用来存放由copy模块或script模块调用的文件。
templates: <--用来存放jinjia2模板,template模块会自动在此目录中寻找jinjia2模板文件。
tasks: <--此目录应当包含一个main.yml文件,用于定义此角色的任务列表,此文件可以使用include包含其它的位于此目录的task文件。
main.yml
handlers: <--此目录应当包含一个main.yml文件,用于定义此角色中触发条件时执行的动作。
main.yml
vars: <--此目录应当包含一个main.yml文件,用于定义此角色用到的变量。
main.yml
defaults: <--此目录应当包含一个main.yml文件,用于为当前角色设定默认变量。
main.yml
meta: <--此目录应当包含一个main.yml文件,用于定义此角色的特殊设定及其依赖关系。
main.yml
8.2Roles示例
通过ansible roles
安装配置httpd
服务,此处的roles
使用默认的路径/etc/ansible/roles
①创建目录
[root@ansible ~]# cd /etc/ansible/roles/
# 创建需要用到的目录
[root@ansible roles]# mkdir -p httpd/{handlers,tasks,templates,vars}
[root@ansible roles]# cd httpd/
[root@ansible httpd]# tree .
.
├── handlers
├── tasks
├── templates
└── vars
directories, 0 file
②变量文件准备vars/main.yml
[root@ansible httpd]# vim vars/main.yml
PORT: 8088 #指定httpd监听的端口
USERNAME: www #指定httpd运行用户
GROUPNAME: www #指定httpd运行组
③配置文件模板准备templates/httpd.conf.j2
# copy一个本地的配置文件放在templates/下并已j2为后缀
[root@ansible httpd]# cp /etc/httpd/conf/httpd.conf templates/httpd.conf.j2
# 进行一些修改,调用上面定义的变量
[root@ansible httpd]# vim templates/httpd.conf.j2
Listen {{ PORT }}
User {{ USERNAME }}
Group {{ GROUPNAME }}
④任务剧本编写,创建用户、创建组、安装软件、配置、启动等
# 创建组的task
[root@ansible httpd]# vim tasks/group.yml
- name: Create a Startup Group
group: name=www gid=60 system=yes
# 创建用户的task
[root@ansible httpd]# vim tasks/user.yml
- name: Create Startup Users
user: name=www uid=60 system=yes shell=/sbin/nologin
# 安装软件的task
[root@ansible httpd]# vim tasks/install.yml
- name: Install Package Httpd
yum: name=httpd state=installed
# 配置软件的task
[root@ansible httpd]# vim tasks/config.yml
- name: Copy Httpd Template File
template: src=httpd.conf.j2 dest=/etc/httpd/conf/httpd.conf
notify: Restart Httpd
# 启动软件的task
[root@ansible httpd]# vim tasks/start.yml
- name: Start Httpd Service
service: name=httpd state=started enabled=yes
# 编写main.yml,将上面的这些task引入进来
[root@ansible httpd]# vim tasks/main.yml
- include: group.yml
- include: user.yml
- include: install.yml
- include: config.yml
- include: start.ym
⑤编写重启httpd的handlers
,handlers/main.yml
[root@ansible httpd]# vim handlers/main.yml
# 这里的名字需要和task中的notify保持一致
- name: Restart Httpd
service: name=httpd state=restarted
⑥编写主的httpd_roles.yml
文件调用httpd角色
[root@ansible httpd]# cd ..
[root@ansible roles]# vim httpd_roles.yml
---
- hosts: all
remote_user: root
roles:
- role: httpd #指定角色名称
⑦整体的一个目录结构查看
[root@ansible roles]# tree .
.
├── httpd
│ ├── handlers
│ │ └── main.yml
│ ├── tasks
│ │ ├── config.yml
│ │ ├── group.yml
│ │ ├── install.yml
│ │ ├── main.yml
│ │ ├── start.yml
│ │ └── user.yml
│ ├── templates
│ │ └── httpd.conf.j2
│ └── vars
│ └── main.yml
└── httpd_roles.yml
directories, 10 files
⑧测试
ansible-playbook -C httpd_roles.yml