ansible playbooks
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了ansible playbooks相关的知识,希望对你有一定的参考价值。
10.ansible playbooks
10.1简介
(1)playbook是由一个或多个“play”组成的列表
(2)play的主要功能在于将事先归并为一组的主机装扮成事先通过anaible中task定义好的角色。从根本上来将,所谓task无非是调用ansible的一个module,将多个play组织在一个playbook中,即可以让它们联通起来按事先编排的机制同唱一台大戏。
10.2组成结构
Inventory
Modules
Ad hoc commands
Playbooks
Tasks:任务,即调用模块完成的某操作
Variables:变量
Templates:模板
Handlers:处理器,由某时间触发执行的操作
10.3 playbook
基础组件包括:Tasks、Variables、Templates、Handlers、Roles
10.3.1hosts和users
(1)playbook中每一个play的目的都是为了让某个或某些主机以某个指定的用户身份执行任务。
(2)Hosts用于指定要执行指定任务的主机,其可以是一个或多个由冒号分割主机组:
(3)remote_user则用于指定远程主机上的执行任务的用户。如上面实例中的
-hosts:webnodes
remote_user:root
不过,remote_user也可用于各task中,也可以通过指定其通过sudo的方式在远程主机上执行任务,其可以用于play全局或某任务:此外,甚至可以在sudo时使用sudo_user指定sudo时切换的用户
- hosts:webnodes //定义一个主机组
remote_user:zhang //定义登录时的用户身份
tasks: //定义任务,可以有多个 - name: test connection //任务名称
gather_facts: false 这个参数指定了在以下任务执行前,是否先执行setup模块获取主机相关信息,这在后面的task会使用到task获取的信息,如果不需要,则选项为false,默认开启
ping: //动作
remote_user:zhang //在这可以使用自己定义的,相当于局部变量
sudo:yes //是否sudo到root用户
10.3.2任务列表和action
(1)Play的主体部分是task list
(2)Task list 中的各任务按次序逐个在hosts中指定的所有主机上执行,即在所有主机上完成第一个任务后再开始第二个
(3)在运行自下而上某playbook时,如果中途发生错误,所有已执行任务都可能回滚,因此,在更正playbook后重新执行一次即可
(4)Task的目的是使用指定的参数执行模块,而在模块参数中可以使用变量。模块执行是幂等的,这意味着多次执行是安全的,因为其结果一致
(5)每个task都应该有其name,用于playbook的执行结果输出,建议其内容尽可能清晰的秒数任务执行步骤,如果未提供name,则action的结果将用于输出
(6)定义task的可以使用“action:module options”或“module:option”的格式,推荐使用后者以实现向后兼容,前边的只是在较新的版本中才可以使用。如果action一行的内容过多,可以在行首使用几个空白字符进行替换
tasks:
-name:make sure apache is runing
service :name-httpd state=running //在运行这个模块时使用后面的参数
(7)在众多模块中,只有command和shell模块仅需要给定一个列表而无需使用“key-value”格式,例如
tasks:
-name:disbles selinux
command: /sbin/setenforce 0
(8)如果命令或脚本的退出码不为0,可以使用如下方式替代:
tasks:- name: run this command and ignore the result
shell: /usr/bin/somecommand || /bin/true //强行成功
(9)使用ignore_errors来忽略错误信息
tasks:
-name: run this command and ingore the result
shell: /usr/bin/somecommand
ignore errors:True //忽略失败,不影响后续执行
10.3.3例一
安装apache服务,并确保服务正常启动
- name: run this command and ignore the result
- hosts: webnodes //只对webnodes组里边的服务器生效,webnodes在inventory中定义
vars: //在这组主机上定义了一组变量,vars,是一个键值对,值是个字典
http_port:80
max_clients:256
remote_user:root //连接到远程主机时以哪个用户登录
tasks: //用来定义接下来执行的任务有哪些- name:ensure apache is at the lastest version //第一个任务
yum:name=httpd state=latest //基于yum模块来安装程序包 - name:ensure apache is runing //第二个任务
service:name=httpd state=started //基于service模块来启动服务
handlers: //处理器 - name:restart apache
service:name=httpd state=restarted
10.3.4例二
创建nginx组和用户,复制本地文件到远端服务器
- name:ensure apache is at the lastest version //第一个任务
- hosts: zhang
remote_user: root
tasks:- name: create nginx group
group: name=nginx system=yes gid=208 - name: create nginx user
user: name=nginx uid=208 group=nginx system=yes
- name: create nginx group
- hosts: wang
remote_user: root
tasks:- name: copy file to wang
copy: src=/etc/passwd dest=/tmp/wang.txt
执行后结果如下图,changed表示已经在远程主机上已经做了修改,后边有个PLAY RECAP是报告任务的执行情况
- name: copy file to wang
10.3.5例三
安装httpd服务,使用本地配置文件,启动服务
- hosts: zhang
remote_user: root
tasks:- name: install httpd package
yum: name=httpd state=latest - name: install configuration file for httpd
copy: src=/root/httpd.conf dest=/etc/httpd/conf/httpd.conf - name: start httpd service
service: enabled=true name=httpd state=started
- name: install httpd package
10.3.6例四
使用两个花括号来表示引用变量值
- hosts: zhang
remote_user: root
vars:- package: httpd
- service: httpd
tasks: - name: install httpd package
yum: name={{ package }} state=latest - name: install configuration file for httpd
copy: src=/root/httpd.conf dest=/etc/httpd/conf/httpd.conf
notify: restart httpd - name: start {{ service }} service
service: enabled=true name=httpd state=started
handlers: - name: restart httpd
service: name=httpd state=restarted
10.3.7 handlers
(1)用于当关注的资源发生变化时采取一定的操作
(2)举例说明,比如上面的实例二,当重新修改httpd.conf的时候,需要重启下服务,但是ansible并没有这么做,所以需要使用handlers这个action
(3)“notify”这个action可用于在每个play的最后被触发,这样可以避免多次有改变发生时每次都执行指定的操作,取而代之,仅在所有的变化发生完成后一次性的执行指定操作,(4)在notify中列出的操作称为handler,也即notify中调用handler中定义的操作,当有改变的时候notify通知handler执行下边的操作。
如果配置文件改变,将重启apache和memcache
- name: template configuration file
template: src=template.j2 dest=/etc/foo.conf
notify: //指明触发哪一个操作- restart memcached
- restart apache
handlers: - name: restart memcached
service: name=memcached state=restarted - name: restart apache
service: name=apache state=restarted
(5)headles跟tasks是同级,需要定义,一般不会执行,只有当触发了某一条件的时候才会执行。比如可以将上述例二修改为如下,这样就可以确保,当配置文件发生改变的时候,服务也会重启,配置文件将重读一次。
可以监控另外一个task,只有当这个task改变的时候才会触发notify执行
- hosts: zhang
remote_user: root
tasks:- name: install httpd package
yum: name=httpd state=latest - name: install configuration file for httpd
copy: src=/root/httpd.conf dest=/etc/httpd/conf/httpd.conf
notify: restart httpd - name: start httpd service
service: enabled=true name=httpd state=started
handlers: - name: restart httpd
service: name=httpd state=restarted
- name: install httpd package
(6)hendlers还可以监听某一个handers A,当A触发的时候,会触发这个handlers,这样多个handler监听A的时候,当触发了A,那么监听A的handlers都会被触发
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"
10.3.8条件测试
(1)when用于条件判断,只有满足条件的主机才会执行这个任务,这个信息可以在setup收集回来的信息上取值
(2)例如:- hosts: all
remote_user: root
vars: - username: user10
tasks: - name: create {{ username }} user
user: name={{ username }}
when: ansible_fqdn == "glusterfs.tarena.com"
如下,不满足条件的就被跳过了
10.3.9 迭代
(1)简介:当有需要重复执行的任务时,可以使用迭代机制,其使用格式为将需要迭代的内容定义为item变量引用,并通过with_items语句来指明迭代的元素
(2)item_items中可以使用元素还可为hashes
(3)item是固定的变量名,会循环with_items列表中的每一个值来替代,相当于遍历式的迭代循环
(4)with_items中的列表还也可以是字典,但是引用时需要使用item.key
(5)ansible的循环机制还有更多的高级功能,具体可以参见官方文档http://docs.ansible.com/playbooks_loops.html
例1:增加多个用户 - name: add serveral users
user: name={{ item }} state=present groups=wheel
with_items:- testuser1
- testuser2
例2:增加多个用户并且指定组
- name: add serveral users
user: name={{ item }} state=present groups={{ item.groups }}
with_items:
- hosts: all
- { name: ‘testuser1‘,groups: ‘wheel‘}
- { name: ‘testuser2‘,groups: ‘root‘}
10.3.10算数和比较运算符
(1)允许使用计算值,很少用到,但是为了完成性,允许其存在
(2)支持 + - * / //(取整) % **(幂)
(3)支持比较运算符 != == > >= < <=
(4)可以使用变量
(5)所有运算都必须在{{}}中
10.3.11 Tags
(1)Tags用于有选则的运行playbook中的代码,可以选择只运行有标签的代码,即调用playbook中的某一个任务
(2)Ansible具有幂等性,因此会自动跳过没有变化的部分,即使如此,有些代码为测试其没有发生变化的时间依然会非常长。此时,如果确信其没有变化,就可以使用tags跳过这些代码片段
(3)always_tags,这个选项的意思是无论如何被这个标记的任务都会执行
Tags: t3,always
(4)可以在play级别写,也可以在tasks级别写,写到play级别下边的tasks自动继承play的tags名称
(5)一个name可以有多个tag,如下
Tags: ts,http
(6)
例:
- name: install httpd package
yum: name={{ package }} state=latest
tags:- conf
10.3.12 roles
10.3.12.1简介
(1)Ansible自1.2版本引入的新特性,用于层次性、结构化的组织playbook
(2)roles能够根据层次型结构自动装载变量文件、tasks以及handlers等。要使用roles只需要在playbook中使用include命令即可。简单来讲,roles就是通过分别将变量、文件、任务、模块及处理器放置于单独的目录中,并可以便捷的include它们的一种机制。
(3)角色一般用于基于主机构建服务的场景中,但也可以是用于构建守护进程等场景中
10.3.12.2案例
一个roles的案例如下:
roles/
common/
files/ //分别将一些需要的东西放到对应的目录中
templates/
tasks/
handlers/
vars/
meta/
webservers/
files/
templates/
tasks/
handlers/
vars/
meta/
而在playbook中,可以这样使用roles,直接调用roles里边的参数 - hosts: webservers
roles: - common
- webservers
也可以向roles传递参数,例如 - hosts: webservers
roles:
- conf
- common
- { role: foo_app_instance, dir: ‘/opt/a‘, port:5000 }
- { role: foo_app_instance, dir: ‘/opt/b‘, port:5001 }
甚至也可以条件式的使用roles,例如:- hosts: webservers
roles:- { role: som_role, when: "ansible_os_family == ‘Redhat‘" }
10.3.12.3创建role的步骤
(1)构建以role命名的目录
(2)在roles目录中分别创建以各角色名称命名的目录,如webservers等
(3)在每个角色命名的目录中分别创建files、handlers、meta、tasks、templates和var目录;用不到的目录可以创建为空目录,也可以不创建
(4)在playbook文件中,请用各角色
10.3.12.4role内各目录中可用的文件
Tasks目录:至少应该包含一个名为main.yml的文件,其定义的此角色的任务列表:此文件可以使用include包含其它的位于此目录中的task文件
Files目录:存放由copy或scripts等模块调用的文件
Template目录:template模块会自动在此目录中寻找jinja2模板文件
Handlers目录:此目录中应当包含一个main
Yml文件:用于定义此角色用到的各handlers;在handlers中使用include包含的其它handler文件也应该位于此目录中
Vars目录:应当包含一个main.yml文件,用于定义此角色用到的变量
Meta目录:应当包含一个main.yml文件,用于定义此角色的特殊设定及其依赖关系;ansible1.3及其以后的版本才支持
Default目录:为当前角色设定默认变量时才使用此目录,应当包含一个main.yml文件
10.3.13 lookups
Lookup插件可以用来从外部数据读取信息,然后赋给一个变量。获取外部数据信息的种类包括:读取文件内容、随机生成password、执行shell命令、读取redis的键值等等。注意,lookup所有的运算都是在ansible中控机上完成的,而不是远程目标机
10.3.13.1 第一个参数为file
第一个参数为file,表示获取外部文件内容
- { role: som_role, when: "ansible_os_family == ‘Redhat‘" }
- name: test
hosts: self
vars:
contents: "{{ lookup(‘file‘, ‘/etc/foo.txt‘) }}"
tasks: - debug: msg="the value of foo.txt is {{ contents }}"
- debug: msg="the value of foo.txt is {{ lookup(‘file‘,‘/etc/foo.txt‘) }}"
10.3.13.2第一个参数为password
第一个参数为password,表示生成一个随机明文密码,并存储到指定文件中,生成的密码包括大小写字母、数字和.,:-_,长度为20个字符,该长度可以通过传递一个额外参数length=<length>修改
- hosts: webservers
除了length外,还可以使用chars=<chars>参数,用于自定义生成密码的字符集
chars=’ ascii_letters,digits,hexdigits,punctuation,,’ ,号本身用,号
- hosts: self
gather_facts: false
tasks: - debug: msg="password - {{ lookup(‘password‘, ‘/tmp/random_pass.txt length=10‘)}}"
10.3.13.3其它类型 -
hosts: all
tasks:-
debug: msg="{{ lookup(‘env‘,‘HOME‘) }} is an environment variable"
-
debug: msg="{{ lookup(‘pipe‘,‘date‘) }} is the raw result of running this command"
-
debug: msg="{{ lookup(‘redis_kv‘, ‘redis://localhost:6379,somekey‘) }} is value in Redis for somekey"
-
debug: msg="{{ lookup(‘dnstxt‘, ‘example.com‘) }} is a DNS TXT record for example.com"
- debug: msg="{{ lookup(‘template‘, ‘./some_template.j2‘) }} is a value from evaluation of this template"
10.3.14循环
-
以上是关于ansible playbooks的主要内容,如果未能解决你的问题,请参考以下文章