运维自动化工具Ansible(二)
Playbook
playbook介绍
官方链接
https://docs.ansible.com/ansible/latest/user_guide/playbooks_intro.html
Playbook 组成
- 一个 playbook(剧本)文件是一个YAML语言编写的文本文件
- 通常一个playbook只包括一个play
- 一个 play的主要包括两部分: 主机和tasks. 即实现在指定一组主机上执行一个tasks定义好的任务列表。
- 一个tasks中可以有一个或多个task任务
- 每一个Task本质上就是调用ansible的一个module
- 在复杂场景中,一个playbook中也可以包括多个play,实现对多组不同的主机执行不同的任务
Playbook 与 Ad-Hoc 对比
- Playbook是对多个 AD-Hoc 的一种编排组合的实现方式
- Playbook能控制任务执行的先后顺序
- Playbook可以持久保存到文件中从而方便多次调用运行,而Ad-Hoc只能临时运行。
- Playbook适合复杂的重复性的任务,而Ad-Hoc适合做快速简单的一次性任务
YAML 语言
YAML 语言介绍
YAML:YAML Ain't Markup Language,即YAML不是标记语言。不过,在开发的这种语言时,YAML的
意思其实是:"Yet Another Markup Language"(仍是一种标记语言)
YAML是一个可读性高的用来表达资料序列的格式。
YAML参考了其他多种语言,包括:XML、C语言、Python、Perl以及电子邮件格式RFC2822等。
Clark Evans在2001年在首次发表了这种语言,另外Ingy döt Net与Oren Ben-Kiki也是这语言的共同设计者
目前很多最新的软件比较流行采用此格式的文件存放配置信息,如:ubuntu,anisble,docker,kubernetes等
YAML 官方网站:
http://www.yaml.org
ansible 官网:
https://docs.ansible.com/ansible/latest/reference_appendices/YAMLSyntax.html
YAML 语言特性
- YAML的可读性好
- YAML和脚本语言的交互性好
- YAML使用实现语言的数据类型
- YAML有一个一致的信息模型
- YAML易于实现
- YAML可以基于流来处理
- YAML表达能力强,扩展性好
YAML语法简介
- 在单一文件第一行,用连续三个连字号"-" 开始,还有选择性的连续三个点号( ... )用来表示文件结尾
- 次行开始正常写Playbook的内容,一般建议写明该Playbook的功能
- 使用#号注释代码
- 缩进的级别也必须是一致的,同样的缩进代表同样的级别,程序判别配置的级别是通过缩进结行来实现的
- 缩进不支持tab,必须使用空格进行缩进
- 缩进的空格数不重要,只要相同层级的元素左对齐即可
- YAML文件内容是区别大小写的,key/value的值均需大小写敏感
- 多个key/value可同行写也可换行写,同行使用,分隔
- key后面冒号要加一个空格 比如: key: value
- value可是个字符串,也可是另一个列表
- YAML文件扩展名通常为yml或yaml
支持的数据类型
YAML 支持以下常用几种数据类型:
- 标量:单个的、不可再分的值
- 对象:键值对的集合,又称为: 字典(dictionary)/ 哈希(hashes) / 映射(mapping)
- 数组:一组按次序排列的值,又称为: 列表(list)/ 序列(sequence)
scalar 标量
key对应value
name: wang
age: 18
使用缩进的方式
name:
wang
age:
18
标量是最基本的,不可再分的值,包括:
- 字符串
- 布尔值
- 整数
- 浮点数
- Null
- 时间
- 日期
Dictionary 字典
一个字典是由一个或多个key与value构成
key和value之间用冒号 :分隔
冒号 : 后面有一个空格
所有 k/v 可以放在一行,,每个 k/v 之间用逗号分隔
所有每个 k/v 也可以分别放在不同行,一对k/v放在独立的一行
格式
account: { name: wang, age: 30 }
使用缩进方式
account:
name: wang
age: 18
范例:
#不同行
# An employee record
name: Example Developer
job: Developer
skill: Elite(社会精英)
#同一行,也可以将key:value放置于{}中进行表示,用,分隔多个key:value
# An employee record
{name: "Example Developer", job: "Developer", skill: "Elite"}
List 列表
列表由多个元素组成
每个元素放在不同行,每个元素一行,且元素前均使用中横线 - 开头,并且中横线 - 和元素之间有一个空格
也可以将所有元素用 [ ] 括起来放在同一行,每个元素之间用逗号分隔
格式
course: [ linux , golang , python ]
也可以写成以 - 开头的多行
course:
- linux
- golang
- python
course:
- linux: manjaro
- golang: gin
- python: django
范例:
#不同行,行以-开头,后面有一个空格
# A list of tasty fruits
- Apple
- Orange
- Strawberry
- Mango
#同一行
[Apple,Orange,Strawberry,Mango]
范例:YAML 表示一个家庭
name: John Smith
age: 41
gender: Male
spouse: { name: Jane Smith, age: 37, gender: Female } # 写在一行里
name: Jane Smith #也可以写成多行
age: 37
gender: Female
children: [ {name: Jimmy Smith,age: 17, gender: Male}, {name: Jenny Smith, age:13, gender: Female}, {name: hao Smith, age: 20, gender: Male } ] #写在一行
- name: Jimmy Smith #写在多行,更为推荐的写法
age: 17
gender: Male
- {name: Jenny Smith, age: 13, gender: Female}
- {name: hao Smith, age: 20, gender: Male }
三种常见的数据格式
- XML:Extensible Markup Language,可扩展标记语言,可用于数据交换和配置
- JSON:JavaScript Object Notation, JavaScript 对象表记法,主要用来数据交换或配置,不支持注释
- YAML:YAML Ain't Markup Language YAML 不是一种标记语言, 主要用来配置,大小写敏感,不支持tab
可以用工具互相转换,参考网站:
Playbook 核心组件
官方文档
https://docs.ansible.com/ansible/latest/reference_appendices/playbooks_keywords.html#playbook-keywords
一个playbook 中由多个组件组成,其中所用到的常见组件类型如下:
- Hosts 执行的远程主机列表
- Tasks 任务集,由多个task的元素组成的列表实现,每个task是一个字典,一个完整的代码块功能需少元素需包括 name 和 task,一个name只能包括一个task
- Variables 内置变量或自定义变量在playbook中调用
- Templates 模板,可替换模板文件中的变量并实现一些简单逻辑的文件
- Handlers 和 notify 结合使用,由特定条件触发的操作,满足条件方才执行,否则不执行
- tags 标签 指定某条任务执行,用于选择运行playbook中的部分代码。ansible具有幂等性,因此 会自动跳过没有变化的部分,即便如此,有些代码为测试其确实没有发生变化的时间依然会非常地长。此时,如果确信其没有变化,就可以通过tags跳过此些代码片断
hosts 组件
Hosts:playbook中的每一个play的目的都是为了让特定主机以某个指定的用户身份执行任务。hosts用于指定要执行指定任务的主机,须事先定义在主机清单中
one.example.com
one.example.com:two.example.com
192.168.1.50
192.168.1.*
Websrvs:dbsrvs #或者,两个组的并集
Websrvs:&dbsrvs #与,两个组的交集
webservers:!dbsrvs #在websrvs组,但不在dbsrvs组
案例:
- hosts: websrvs:appsrvs
remote_user 组件
remote_user: 可用于Host和task中。也可以通过指定其通过sudo的方式在远程主机上执行任务,其可用于play全局或某任务;此外,甚至可以在sudo时使用sudo_user指定sudo时切换的用户
- hosts: websrvs
remote_user: root
tasks:
- name: test connection
ping:
remote_user: magedu
sudo: yes #默认sudo为root
sudo_user:wang #sudo为wang
task列表和action组件
play的主体部分是task list,task list中有一个或多个task,各个task 按次序逐个在hosts中指定的所有主机上执行,即在所有主机上完成第一个task后,再开始第二个task
task的目的是使用指定的参数执行模块,而在模块参数中可以使用变量。模块执行是幂等的,这意味着多次执行是安全的,因为其结果均一致
每个task都应该有其name,用于playbook的执行结果输出,建议其内容能清晰地描述任务执行步骤。
如果未提供name,则action的结果将用于输出
task两种格式:
action: module arguments #示例: action: shell wall hello
module: arguments #建议使用 #示例: shell: wall hello
注意:shell和command模块后面跟命令,而非key=value
范例:
[root@ansible ansible]#cat hello.yml
---
#first yaml文件
#
- hosts: websrvs
remote_user: root
gather_facts: no
tasks:
- name: task1
debug: msg="task1 running"
- name: task2
debug: msg="task2 running"
- hosts: appsrvs
remote_user: root
gather_facts: no
tasks:
- name: task3
debug: msg="task3 running"
- name: task4
debug: msg="task4 running"
其它组件说明
某任务的状态在运行后为changed时,可通过"notify"通知给相应的handlers任务
还可以通过"tags"给task 打标签,可在ansible-playbook命令上使用-t指定进行调用
ShellScripts VS Playbook 案例
#SHELL脚本实现
#!/bin/bash
# 安装Apache
yum install --quiet -y httpd
# 复制配置文件
cp /tmp/httpd.conf /etc/httpd/conf/httpd.conf
cp/tmp/vhosts.conf /etc/httpd/conf.d/
# 启动Apache,并设置开机启动
systemctl enable --now httpd
#Playbook实现
---
- hosts: websrvs
remote_user: root
gather_facts: no
tasks:
- name: "安装Apache"
yum: name=httpd
- name: "复制配置文件"
copy: src=/tmp/httpd.conf dest=/etc/httpd/conf/
- name: "复制配置文件"
copy: src=/tmp/vhosts.conf dest=/etc/httpd/conf.d/
- name: "启动Apache,并设置开机启动"
service: name=httpd state=started enabled=yes
playbook 命令
格式
ansible-playbook <filename.yml> ... [options]
选项
--syntax,--syntax-check #语法检查,功能相当于bash -n
-C --check #模拟执行dry run ,只检测可能会发生的改变,但不真正执行操作
--list-hosts #列出运行任务的主机
--list-tags #列出tag
--list-tasks #列出task
--limit 主机列表 #只针对主机列表中的特定主机执行
-i INVENTORY, --inventory INVENTORY #指定主机清单文件,通常一个项对应一个主机清单文件
--start-at-task START_AT_TASK #从指定task开始执行,而非从头开始,START_AT_TASK为任务的name
-v -vv -vvv #显示过程
范例: 一个简单的 playbook
[root@ansible ansible]#cat hello.yml
---
- hosts: websrvs
tasks:
- name: hello
command: echo "hello ansible"
[root@ansible ansible]#ansible-playbook hello.yml
[root@ansible ansible]#ansible-playbook -v hello.yml
范例: 检查和限制主机
ansible-playbook file.yml --check #只检测
ansible-playbook file.yml
ansible-playbook file.yml --limit websrvs
范例: 一个playbook 多个play
cat test_plays.yaml
---
- hosts: localhost
remote_user: root
gather_facts: no
tasks:
- name: play1
command: echo "play1"
- hosts: centos7
remote_user: root
gather_facts: no
tasks:
- name: play2
command: echo "play2"
忽略错误 ignore_errors
如果一个task出错,默认将不会继续执行后续的其它task
利用 ignore_errors: yes 可以忽略此task的错误,继续向下执行playbook其它task
[root@ansible ansible]#cat test_ignore.yml
---
- hosts: centos7
tasks:
- name: error
command: /bin/false
ignore_errors: yes
- name: continue
command: wall continue
ansible-playbook案例
安装nginx
---
- hosts: centos7
# yum install nginx
remote_user: root
gather_facts: no
tasks:
- name: install nginx
yum: name=nginx state=present
- name:
service: name=nginx state=started enabled=yes
卸载httpd
#remove_httpd.yml
---
- hosts: webservers
remote_user: root
gather_facts: no
tasks:
- name: remove httpd package
yum: name=httpd state=absent
- name: remove apache user
user: name=apache state=absent
- name: remove config file
file: name=/etc/httpd state=absent
- name: remove web html
file: name=/data/html/ state=absent
Playbook中使用handlers和notify
handlers和notify
Handlers本质是task list ,类似于MySQL中的触发器触发的行为,其中的task与前述的task并没有本质上的不同,只有在关注的资源发生变化时,才会采取一定的操作。
Notify对应的action 在所有task都执行完才会最后被触发,这样可避免多个task多次改变发生时每次都触发执行指定的操作,Handlers仅在所有的变化发生完成后一次性地执行指定操作。
在notify中列出的操作称为handler,也即notify中调用handler中定义的操作
注意:
- 如果多个task通知了相同的handlers, 此handlers仅会在所有task结束后运行一 次。
- 只有notify对应的task发生改变了才会通知handlers, 没有改变则不会触发handlers
- handlers 是在所有前面的tasks都成功执行才会执行,如果前面任何一个task失败,会导致handle跳过执行
案例:
案例:
案例:
范例: 部署haproxy
force_handlers
如果不论前面的task成功与否,都希望handlers能执行, 可以使用force_handlers: yes 强制执行handler
范例: 强制调用handlers
Playbook中使用tags组件
官方文档:
https://docs.ansible.com/ansible/latest/user_guide/playbooks_tags.html
默认情况下, Ansible 在执行一个 playbook 时,会执行 playbook 中所有的任务,在playbook文件中,可以利用tags组件,为特定 task 指定标签,当在执行playbook时,可以只执行特定tags的task,而非整个playbook文件
可以一个task对应多个tag,也可以多个task对应同一个tag
还有另外3个特殊关键字用于标签, tagged, untagged 和 all,它们分别是仅运行已标记,只有未标记和所有任务。
tags 主要用于调试环境
范例: tag 标签
Playbook中使用变量
Playbook中同样也支持变量
变量名:仅能由字母、数字和下划线组成,且只能以字母开头
变量定义:
variable=value
variable: value
范例:
http_port=80
http_port: 80
通过 {{ variable_name }} 调用变量,且变量名前后建议加空格,有时用"{{ variable_name }}"才生效
变量来源:
- ansible 的 setup facts 远程主机的所有变量都可直接调用
- 通过命令行指定变量,优先级最高
ansible-playbook -e varname=value test.yml
3.在playbook文件中定义
vars:
var1: value1
var2: value2
4.在独立的变量YAML文件中定义
- hosts: all
vars_files:
- vars.yml
在主机清单文件中定义
主机(普通)变量:主机组中主机单独定义,优先级高于公共变量
组(公共)变量:针对主机组中所有主机定义统一变量
在项目中针对主机和主机组定义
在项目目录中创建 host_vars和group_vars目录
在role中定义
变量的优先级从高到低如下
-e 选项定义变量 -->playbook中vars_files --> playbook中vars变量定义 -->host_vars/主机名文件 -->主机清单中主机变量--> group_vars/主机组名文件-->group_vars/all文件--> 主机清单组变量
使用 setup 模块中变量
使用 facts 变量
本模块自动在playbook调用,生成的系统状态信息, 并将之存放在facts变量中
facts 包括的信息很多,如: 主机名,IP,CPU,内存,网卡等
facts 变量的实际使用场景案例
- 通过facts变量获取被控端CPU的个数信息,从而生成不同的Nginx配置文件
- 通过facts变量获取被控端内存大小信息,从而生成不同的memcached的配置文件
- 通过facts变量获取被控端主机名称信息,从而生成不同的Zabbix配置文件
- 通过facts变量获取被控端网卡信息,从而生成不同的主机名
案例:使用setup变量
[root@ansible ~]# ansible localhost -m setup -a 'filter="ansible_default_ipv4"'
localhost | SUCCESS => {
"ansible_facts": {
"ansible_default_ipv4": {
"address": "192.168.32.133",
"alias": "ens160",
"broadcast": "192.168.32.255",
"gateway": "192.168.32.2",
"interface": "ens160",
"macaddress": "00:0c:29:7c:80:cd",
"mtu": 1500,
"netmask": "255.255.255.0",
"network": "192.168.32.0",
"prefix": "24",
"type": "ether"
}
},
"changed": false
}
[root@ansible ~]#
范例:显示ens33的网卡的IP地址
---
- hosts: centos7
tasks:
- name: show ens33 ip
debug:
msg: IP address {{ ansible_ens33.ipv4.address }}
#msg: IP address {{ ansible_facts["ens33"]["ipv4"]["address"] }}
#msg: IP address {{ ansible_facts.ens33.ipv4.address }}
#msg: IP address {{ ansible_default_ipv4.address }}
#msg: IP address {{ ansible_ens33.ipv4.address }}
#msg: IP address {{ ansible_ens33.ipv4.address.split('.')[-1] }} #取IP中的最后一个数字
[root@ansible ansible]# ansible-playbook -v show_ip.yml
Using /etc/ansible/ansible.cfg as config file
PLAY [centos7] *************************************************************************************************************************
TASK [Gathering Facts] *****************************************************************************************************************
ok: [192.168.32.179]
ok: [192.168.32.178]
TASK [show ens33 ip] *******************************************************************************************************************
ok: [192.168.32.178] => {
"msg": "IP address 192.168.32.178"
}
ok: [192.168.32.179] => {
"msg": "IP address 192.168.32.179"
}
PLAY RECAP *****************************************************************************************************************************
192.168.32.178 : ok=2 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
192.168.32.179 : ok=2 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
[root@ansible ansible]#
范例:修改主机名称为web-IP
- hosts: centos7
tasks:
- name: 打印facts变量
debug: msg={{ ansible_ens33.ipv4.address }}
- name: 修改主机名
hostname: name=web-{{ ansible_ens33.ipv4.address }}
#- name: 获取facts变量提取IP地址,以.结尾的最后一列,修改主机名为web-hostid
#hostname: name=web-{{ ansible_ens33.ipv4.address.split('.')[-1] }}
[root@ansible ansible]# ansible-playbook change_hostname.yml
PLAY [centos7] *************************************************************************************************************************
TASK [Gathering Facts] *****************************************************************************************************************
ok: [192.168.32.178]
ok: [192.168.32.179]
TASK [打印facts变量] *******************************************************************************************************************
ok: [192.168.32.178] => {
"msg": "192.168.32.178"
}
ok: [192.168.32.179] => {
"msg": "192.168.32.179"
}
TASK [修改主机名] **********************************************************************************************************************
changed: [192.168.32.179]
changed: [192.168.32.178]
PLAY RECAP *****************************************************************************************************************************
192.168.32.178 : ok=3 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
192.168.32.179 : ok=3 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
[root@ansible ansible]#
性能优化
每次执行playbook,默认会收集每个主机的所有facts变量,将会导致速度很慢,可以采用下面方法加速
方法1
关闭facts采集加速执行,此方法将导致无法使用facts变量
- hosts: all
gather_facts: no
方法2
当使用 gather_facts: no 关闭 facts,确实能加速 Ansible 执行,但是有时候又需要使用 facts 中的内容,还希望执行的速度快,这时候可以设置facts 的缓存,将facts变量信息存在redis服务器中
[root@ansible ~]# cat /etc/ansible/ansible.cfg
[defaults]
# smart 表示默认收集 facts,但 facts 已有的情况下不会收集,即使用缓存 facts
# implicit 表示默认收集 facts,要禁止收集,必须使用 gather_facts: False
# explicit 则表示默认不收集,要显式收集,必须使用gather_facts: True
gathering = smart #在使用 facts 缓存时设置为smart
fact_caching_timeout = 86400 #缓存时长
fact_caching = redis #缓存存在redis中
fact_caching_connection = 10.0.0.100:6379:0 #0表示redis的0号数据库
#若redis设置了密码
fact_caching_connection = 10.0.0.100:6379:0:password
register 注册变量
在playbook中可以使用register将捕获命令的输出保存在临时变量中,方便后续调用此变量,比如可以使用debug模块进行显示输出
范例: 利用debug 模块输出变量
---
- hosts: centos7
tasks:
- name: get variable
shell: hostname
register: name
- name: print variable
debug:
msg: "{{ name }}" #输出register注册的name变量的全部信息,注意变量要加" "引起来
#msg: "{{ name.cmd }}" #显示命令
#msg: "{{ name.rc }}" #显示命令成功与否
#msg: "{{ name.stdout }}" #显示命令的输出结果为字符串形式,所有结果都放在一行里显示,适合于结果是单行输出
#msg: "{{ name.stdout_lines }}" #显示命令的输出结果为列表形式,逐行标准输出,适用于多行显示
#msg: "{{ name['stdout_lines'] }}" #显示命令的执行结果为列表形式,和效果上面相同
#msg: "{{ name.stdout_lines[0] }}" #显示命令的输出结果的列表中的第一个元素
#说明 第一个 task 中,使用了 register 注册变量名为 name ;当 shell 模块执行完毕后,会将数据放到该变量中。第二给 task 中,使用了 debug 模块,并从变量name中获取数据。
[root@ansible ansible]# ansible-playbook -C register.yml
PLAY [centos7] *************************************************************************************************************************
TASK [Gathering Facts] *****************************************************************************************************************
ok: [192.168.32.179]
ok: [192.168.32.178]
TASK [get variable] ********************************************************************************************************************
skipping: [192.168.32.179]
skipping: [192.168.32.178]
TASK [print variable] ******************************************************************************************************************
ok: [192.168.32.178] => {
"msg": {
"changed": false,
"cmd": "hostname",
"delta": null,
"end": null,
"failed": false,
"msg": "Command would have run if not in check mode",
"rc": 0,
"skipped": true,
"start": null,
"stderr": "",
"stderr_lines": [],
"stdout": "",
"stdout_lines": []
}
}
ok: [192.168.32.179] => {
"msg": {
"changed": false,
"cmd": "hostname",
"delta": null,
"end": null,
"failed": false,
"msg": "Command would have run if not in check mode",
"rc": 0,
"skipped": true,
"start": null,
"stderr": "",
"stderr_lines": [],
"stdout": "",
"stdout_lines": []
}
}
PLAY RECAP *****************************************************************************************************************************
192.168.32.178 : ok=2 changed=0 unreachable=0 failed=0 skipped=1 rescued=0 ignored=0
192.168.32.179 : ok=2 changed=0 unreachable=0 failed=0 skipped=1 rescued=0 ignored=0
[root@ansible ansible]#
范例: 安装启动服务并检查
---
- hosts: centos7
vars:
package_name: nginx
service_name: nginx
tasks:
- name: install {{ package_name }}
yum: name={{ package_name }}
- name: start {{ service_name }}
service: name={{ service_name }} state=started enabled=yes
- name: check
shell: ps axu|grep {{ service_name }}
register: check_service
- name: debug
debug:
msg: "{{ check_service.stdout_lines }}"
范例: 修改主机名形式为 web_<随机字符>
- hosts: centos7
tasks:
- name: genarate random
shell:
cmd: openssl rand -base64 12 |tr -dc '[:alnum:]'
register:
num
- name: show random
debug:
msg: "{{ num }}"
- name: change hostname
hostname:
name: web-{{ num.stdout }}
范例: 修改主机名形式为 web_随机数
- hosts: centos7
tasks:
- name: 定义一个随机数,设定为变量,然后后续调用
shell: echo $((RANDOM%255))
register: web_number
- name: 使用debug输出变量结果
debug: msg={{ web_number }}
- name: 使用hostname模块将主机名修改为web_随机数
hostname: name=web_{{ web_number.stdout }}
范例: 批量修改主机名为随机字符
- hosts: centos7
vars:
host: web
domain: wang.org
tasks:
- name: get variable
shell: echo $RANDOM | md5sum | cut -c 1-8
register: get_random
- name: print variable
debug:
msg: "{{ get_random.stdout }}"
- name: set hostname
hostname: name={{ host }}-{{ get_random.stdout }}.{{ domain }}
范例: 批量修改主机名为IP最后1位数字
- hosts: centos7
vars:
host: web
domain: wang.org
tasks:
- name: get variable
shell: hostname -I | awk '{print $1}'
register: get_ip
- name: print variable
debug:
msg: "{{ get_ip.stdout.split('.')[3] }}"
- name: set hostname
hostname: name={{ host }}-{{ get_ip.stdout.split('.')[3] }}.{{ domain }}
在 Playbook 命令行中定义变量
范例:
---
- hosts: centos7
remote_user: root
tasks:
- name: install nginx
yum: name={{ pkname }} state=present
[root@ansible ~]#ansible-playbook -e pkname=nginx var2.yml
范例:
#也可以将多个变量放在一个文件中
[root@ansible ~]#cat vars
pkname1: memcached
pkname2: vsftpd
[root@ansible ~]#vim var2.yml
---
- hosts: centos7
remote_user: root
tasks:
- name: install package {{ pkname1 }
yum: name={{ pkname1 }} state=present
- name: install package {{ pkname2 }
yum: name={{ pkname2 }} state=present
[root@ansible ~]#ansible-playbook -e pkname1=memcached -e pkname2=httpd var2.yml
[root@ansible ~]#ansible-playbook -e '@vars' var2.yml
在playbook文件中定义变量
此方式定义的是私有变量,即只能在当前playbook中使用,不能被其它Playbook共用
范例:
- hosts: webservers
remote_user: root
vars:
username: user1
groupname: group1
tasks:
- name: create group {{ groupname }}
group: name={{ groupname }} state=present
- name: create user {{ username }}
user: name={{ username }} group={{ groupname }} state=present
[root@ansible ~]#ansible-playbook -e "username=user2 groupname=group2" var3.yml
范例:变量的相互调用
---
- hosts: centos7
remote_user: root
vars:
collect_info: "/data/test/{{ansible_default_ipv4['address']}}/"
tasks:
- name: create IP directory
file: name="{{collect_info}}" state=directory
使用专用的公共的变量文件
可以在一个独立的playbook文件中定义公共变量,在其它的playbook文件中可以引用变量文件中的变量
此方式比playbook中定义的变量优化级高
vim vars.yml
---
# variables file
package_name: mariadb-server
service_name: mariadb
vim var5.yml
---
#install package and start service
- hosts: dbsrvs
remote_user: root
vars_files:
# 指定变量文件名
- vars.yml
tasks:
- name: install package
yum: name={{ package_name }}
tags: install
- name: start service
service: name={{ service_name }} state=started enabled=yes
在主机清单中定义主机和主机组的变量
所有项目的主机变量
在inventory 主机清单文件中为指定的主机定义变量以便于在playbook中使用
范例:
[webservers]
www1.wang.org http_port=80 maxRequestsPerChild=808
www2.wang.org http_port=8080 maxRequestsPerChild=909
所有项目的组(公共)变量
在inventory 主机清单文件中赋予给指定组内所有主机上的在playbook中可用的变量,如果和主机变是同名,优先级低于主机变量
案例:
[webservers:vars]
http_port=80
ntp_server=ntp.wang.org
nfs_server=nfs.wang.org
[all:vars]
# --------- Main Variables ---------------
# Cluster container-runtime supported: docker, containerd
CONTAINER_RUNTIME="docker"
# Network plugins supported: calico, flannel, kube-router, cilium, kube-ovn
CLUSTER_NETWORK="calico"
# Service proxy mode of kube-proxy: 'iptables' or 'ipvs'
PROXY_MODE="ipvs"
# K8S Service CIDR, not overlap with node(host) networking
SERVICE_CIDR="192.168.0.0/16"
# Cluster CIDR (Pod CIDR), not overlap with node(host) networking
CLUSTER_CIDR="172.16.0.0/16"
# NodePort Range
NODE_PORT_RANGE="20000-60000"
# Cluster DNS Domain
CLUSTER_DNS_DOMAIN="magedu.local."
范例:
[root@ansible ~]#vim /etc/ansible/hosts
[webservers]
10.0.0.8 hname=www1 domain=magedu.io
10.0.0.7 hname=www2
[webservers:vars]
mark="-"
[all:vars]
domain=wang.org
[root@ansible ~]#ansible webservers -m hostname -a 'name={{ hname }}{{ mark }}
{{ domain }}'
#命令行指定变量:
[root@ansible ~]#ansible webservers -e domain=magedu.cn -m hostname -a 'name=
{{ hname }}{{ mark }}{{ domain }}'
针对当前项目的主机和主机组的变量
上面的方式是针对所有项目都有效,而官方更建议的方式是使用ansible特定项目的主机变量和组变量.生产建议在每个项目对应的目录中创建额外的两个变量目录,分别是host_vars和group_vars
- host_vars下面的文件名和主机清单主机名一致,针对单个主机进行变量定义格式:host_vars/hostname
- group_vars下面的文件名和主机清单中组名一致, 针对单个组进行变量定义格式: group_vars/groupname
- group_vars/all文件内定义的变量对所有组都有效
范例: 特定项目的主机和组变量
[root@ansible ansible]#pwd
/data/ansible
[root@ansible ansible]#mkdir host_vars
[root@ansible ansible]#mkdir group_vars
[root@ansible ansible]#cat host_vars/10.0.0.8
id: 2
[root@ansible ansible]#cat host_vars/10.0.0.7
id: 1
[root@ansible ansible]#cat group_vars/webservers
name: web
[root@ansible ansible]#cat group_vars/all
domain: wang.org
[root@ansible ansible]#tree host_vars/ group_vars/
host_vars/
├── 10.0.0.7
└── 10.0.0.8
group_vars/
├── all
└── webservers
0 directories, 4 files
[root@ansible ansible]#cat test.yml
- hosts: webservers
tasks:
- name: get variable
command: echo "{{name}}{{id}}.{{domain}}"
register: result
- name: print variable
debug:
msg: "{{result.stdout}}"
[root@ansible ansible]#ansible-playbook test.yml
PLAY [webservers]
********************************************************************************
***************************************
TASK [Gathering Facts]
********************************************************************************
*******************************
ok: [10.0.0.7]
ok: [10.0.0.8]
TASK [get variable]
********************************************************************************
**********************************
changed: [10.0.0.7]
changed: [10.0.0.8]
TASK [print variable]
********************************************************************************
********************************
ok: [10.0.0.7] => {
"msg": "web1.wang.org"
}
ok: [10.0.0.8] => {
"msg": "web2.wang.org"
}
PLAY RECAP
********************************************************************************
*******************************************
10.0.0.7 : ok=3 changed=1 unreachable=0 failed=0
skipped=0 rescued=0 ignored=0
10.0.0.8 : ok=3 changed=1 unreachable=0 failed=0
skipped=0 rescued=0 ignored=0
Template 模板
模板是一个文本文件,可以用于根据每个主机的不同环境而为生成不同的文件
模板文件中支持嵌套jinja2语言的指令,来实现变量,条件判断,循环等功能
需要使用template模块实现文件的复制到远程主机,但和copy模块不同,复制过去的文件每个主机可以会有所不同
jinja2语言
Jinja2 是一个现代的,设计者友好的,仿照 Django 模板的 Python 模板语言。 它速度快,被广泛使用,并且提供了可选的沙箱模板执行环境保证安全:
特性:
- 沙箱中执行
- 强大的 HTML 自动转义系统保护系统免受 XSS
- 模板继承
- 及时编译最优的 python 代码
- 可选提前编译模板的时间
- 易于调试。异常的行数直接指向模板中的对应行。
- 可配置的语法
官方网站:
http://jinja.pocoo.org/
https://jinja.palletsprojects.com/en/2.11.x/
官方中文文档
http://docs.jinkan.org/docs/jinja2/
https://www.w3cschool.cn/yshfid/
jinja2 语言支持多种数据类型和操作:
字面量,如: 字符串:使用单引号或双引号,数字:整数,浮点数
列表:[item1, item2, ...]
元组:(item1, item2, ...)
字典:{key1:value1, key2:value2, ...}
布尔型:true/false
算术运算:+, -, *, /, //, %, **
比较操作:==, !=, >, >=, <, <=
逻辑运算:and,or,not
流表达式:For,If,When
字面量:
表达式最简单的形式就是字面量。字面量表示诸如字符串和数值的 Python 对象。如"Hello World"
双引号或单引号中间的一切都是字符串。无论何时你需要在模板中使用一个字符串(比如函数调用、过滤器或只是包含或继承一个模板的参数),如42,42.23
数值可以为整数和浮点数。如果有小数点,则为浮点数,否则为整数。在 Python 里, 42 和 42.0 是不一样的
算术运算:
Jinja 允许用计算值。支持下面的运算符
+:把两个对象加到一起。通常对象是素质,但是如果两者是字符串或列表,你可以用这 种方式来衔接
它们。无论如何这不是首选的连接字符串的方式!连接字符串见 ~ 运算符。 {{ 1 + 1 }} 等于 2
-:用第一个数减去第二个数。 {{ 3 - 2 }} 等于 1
/:对两个数做除法。返回值会是一个浮点数。 {{ 1 / 2 }} 等于 0.5
//:对两个数做除法,返回整数商。 {{ 20 // 7 }} 等于 2
%:计算整数除法的余数。 {{ 11 % 7 }} 等于 4
:用右边的数乘左边的操作数。 {{ 22 }} 会返回 4 。也可以用于重 复一个字符串多次。 {{ '=' * 80 }}
会打印 80 个等号的横条
:取左操作数的右操作数次幂。 {{ 23 }} 会返回 8
比较操作符
== 比较两个对象是否相等
!= 比较两个对象是否不等
如果左边大于右边,返回 true
= 如果左边大于等于右边,返回 true
< 如果左边小于右边,返回 true
<= 如果左边小于等于右边,返回 true
逻辑运算符
对于 if 语句,在 for 过滤或 if 表达式中,它可以用于联合多个表达式
and 如果左操作数和右操作数同为真,返回 true
or 如果左操作数和右操作数有一个为真,返回 true
not 对一个表达式取反
(expr)表达式组
true / false true 永远是 true ,而 false 始终是 false
template
template功能:可以根据和参考模块文件,动态生成相类似的配置文件
template文件存建议放于templates目录下,且命名为 .j2 结尾
yaml/yml 文件和templates目录平级,此时playbook中指定模版文件时可不用指定路径, 目录结构如下
示例:
./
├── temnginx.yml
└── templates
└── nginx.conf.j2
范例:利用template 同步nginx配置文件
#准备templates/nginx.conf.j2文件
[root@ansible ~]#vim temnginx.yml
---
- hosts: centos7
remote_user: root
tasks:
- name: template config to remote hosts
template: src=nginx.conf.j2 dest=/etc/nginx/nginx.conf
[root@ansible ~]#ansible-playbook temnginx.yml
template变更替换
范例:
#修改文件nginx.conf.j2
[root@ansible ~]#mkdir templates
[root@ansible ~]#vim templates/nginx.conf.j2
......
worker_processes {{ ansible_processor_vcpus }};
......
[root@ansible ~]#vim temnginx2.yml
---
- hosts: centos7
remote_user: root
tasks:
- name: install nginx
yum: name=nginx
- name: template config to remote hosts
template: src=nginx.conf.j2 dest=/etc/nginx/nginx.conf
- name: start service
service: name=nginx state=started enabled=yes
[root@ansible ~]#ansible-playbook temnginx2.yml
Roles 角色
角色是ansible自1.2版本引入的新特性,用于层次性、结构化地组织playbook。roles能够根据层次型结构自动装载变量文件、tasks以及handlers等。要使用roles只需要在playbook中使用include指令即可。简单来讲,roles就是通过分别将变量、文件、任务、模板及处理器放置于单独的目录中,并可以便捷地include它们的一种机制。角色一般用于基于主机构建服务的场景中,但也可以是用于构建守护进程等场景中
运维复杂的场景:建议使用 roles,代码复用度高
roles:多个角色的集合目录, 可以将多个的role,分别放至roles目录下的独立子目录中,如下示例
roles/
mysql/
nginx/
tomcat/
redis/
默认roles存放路径
/root/.ansible/roles
/usr/share/ansible/roles
/etc/ansible/roles
官方文档:
https://docs.ansible.com/ansible/latest/user_guide/playbooks_reuse_roles.html
Ansible Roles目录编排
roles目录结构如下所示
每个角色,以特定的层级目录结构进行组织
roles目录结构:
playbook1.yml
playbook2.yml
roles/
project1/
tasks/
files/
vars/
templates/
handlers/
default/
meta/
project2/
tasks/
files/
vars/
templates/
handlers/
default/
meta/
Roles各目录作用
roles/project/ :项目名称,有以下子目录
- files/ :存放由copy或script模块等调用的文件
- templates/:template模块查找所需要模板文件的目录
- tasks/:定义task,role的基本元素,至少应该包含一个名为main.yml的文件;其它的文件需要在此文件中通过include进行包含
- handlers/:至少应该包含一个名为main.yml的文件;此目录下的其它的文件需要在此文件中通过include进行包含
- vars/:定义变量,至少应该包含一个名为main.yml的文件;此目录下的其它的变量文件需要在此文件中通过include进行包含,也可以通过项目目录中的group_vars/all定义变量,从而实现角色通用代码和项目数据的分离
- meta/:定义当前角色的特殊设定及其依赖关系,至少应该包含一个名为main.yml的文件,其它文件需在此文件中通过include进行包含
- default/:设定默认变量时使用此目录中的main.yml文件,比vars的优先级低
创建 role
创建role的步骤
1 创建role的目录结构.在以roles命名的目录下分别创建以各角色名称命名的目录,如mysql等,在每个角色命名的目录中分别创建相关的目录和文件,比如tasks、files、handlers、templates和vars等目录;用不到的目录可以创建为空目录,也可以不创建
2 编写和准备指定role的功能文件,包括: tasks,templates,vars等相关文件
3 编写playbook文件调用上面定义的role,应用到指定的主机
针对大型项目使用Roles进行编排
范例: 利用 ansible-galaxy 创建角色目录的结构
#创建初始化目录结构
[root@ansible roles]#ansible-galaxy role init test_role
- Role test_role was created successfully
[root@ansible roles]#tree test_role/
test_role/
├── defaults
│ └── main.yml
├── files
├── handlers
│ └── main.yml
├── meta
│ └── main.yml
├── README.md
├── tasks
│ └── main.yml
├── templates
├── tests
│ ├── inventory
│ └── test.yml
└── vars
└── main.yml
8 directories, 8 files
范例:roles的目录结构
nginx-role.yml
roles/
└── nginx
├── files
│ └── nginx.conf
├── tasks
│ ├── groupadd.yml
│ ├── install.yml
│ ├── main.yml
│ ├── restart.yml
│ └── useradd.yml
└── vars
└── main.yml
Playbook 调用角色
调用角色方法1:
---
- hosts: webservers
remote_user: root
roles:
- mysql
- memcached
- nginx
调用角色方法2:
键role用于指定角色名称,后续的k/v用于传递变量给角色
---
- hosts: all
remote_user: root
roles:
- role: mysql
username: mysql
- { role: nginx, username: nginx }
调用角色方法3:
还可基于条件测试实现角色调用
---
- hosts: all
remote_user: root
roles:
- { role: nginx, username: nginx, when: ansible_distribution_major_version == '7' }
Roles 中 Tags 使用
[root@ansible ~]#vi app-role.yml
---
#可以有多个play
- hosts: lbserver
roles:
- role: haproxy
- role: keepalived
- hosts: appsrvs
remote_user: root
roles:
- { role: nginx ,tags: [ 'nginx', 'web' ] ,when:
ansible_distribution_major_version == "6" }
- { role: httpd ,tags: [ 'httpd', 'web' ] }
- { role: mysql ,tags: [ 'mysql', 'db' ] }
- role: mariadb
tags:
- mariadb
- db
tags: app #play的tag
[root@ansible ~]#ansible-playbook --tags="nginx,mysql" app-role.yml
实战案例
实现httpd角色
# 创建role目录
[root@ansible data]# ansible-galaxy role init httpd
- Role htppd was created successfully
[root@ansible data]# tree httpd/
httpd/
├── defaults
│ └── main.yml
├── files
├── handlers
│ └── main.yml
├── meta
│ └── main.yml
├── README.md
├── tasks
│ └── main.yml
├── templates
├── tests
│ ├── inventory
│ └── test.yml
└── vars
└── main.yml
8 directories, 8 files
[root@ansible data]#
#main.yml 是task的入口文件
[root@ansible tasks]# cat main.yml
---
# tasks file for httpd
- include: group.yml
- include: user.yml
- include: install_httpd.yml
- include: config.yml
- inclusde: index.yml
- include: service.yml
[root@ansible tasks]#
# 创建用户组
[root@ansible httpd]# cat tasks/group.yml
- name: add group
group: name={{ httpd_group}} system=yes gid={{ httpd_gid }}
[root@ansible htppd]#
# 创建用户
[root@ansible httpd]# cat tasks/user.yml
- name: add httpd user
user: name={{ httpd_user }} system=yes shel=/sbin/nologin home=/var/www uid={{ httpd_uid }} group={{ httpd_group }}
[root@ansible htppd]#
# yum install httpd
[root@ansible httpd]# cat tasks/install_httpd.yml
- name: install httpd
yum: name=httpd
[root@ansible httpd]#
# 拷贝配置文件
#注意: 文件是放在files目录下,但src的路径无需写files目录名
[root@ansible htppd]# cat tasks/config.yml
- name: httpd config
copy: src=httpd.conf dest=/etc/httpd/conf backup=yes
notify: restart httpd
# 准备测试文件
[root@ansible htppd]# cat tasks/index.yml
- name: copy index.html
copy: src=index.html dest=/var/www/html
[root@ansible htppd]#
# start httpd
[root@ansible htppd]# cat tasks/service.yml
- name: start httpd
service: name=httpd state=started enabled=yes
[root@ansible htppd]#
# 配置文件修改则重启httpd
[root@ansible htppd]# cat handlers/main.yml
---
# handlers file for httpd
- name: restart httpd
service: name=httpd state=restarted
[root@ansible htppd]#
#在files目录下准备两个文件
[root@ansible data]# ll httpd/files
total 16
-rw-r--r-- 1 root root 11753 Mar 1 18:36 httpd.conf
-rw-r--r-- 1 root root 23 Mar 1 21:10 index.html
# 准备变量文件
[root@ansible data]# cat httpd/vars/main.yml
---
# vars file for httpd
httpd_group: apache
httpd_gid: 88
httpd_user: apache
httpd_uid: 88
[root@ansible data]#
#在playbook中调用角色
[root@ansible data]# cat web_roles.yml
---
- hosts: centos7
remote_user: root
roles:
- httpd
#运行playbook
[root@ansible data]# ansible-playbook /data/web_roles.yml
实现Nginx角色
# 创建roles目录
[root@ansible data]# ansible-galaxy init nginx
- Role nginx was created successfully
[root@ansible data]# ll
total 12
-rw-r--r-- 1 root root 614 Mar 1 21:07 ansible.cfg
-rw-r--r-- 1 root root 1382 Mar 1 21:07 hosts
drwxr-xr-x 10 root root 154 Mar 1 18:07 httpd
drwxr-xr-x 10 root root 154 Mar 1 21:52 nginx
-rw-r--r-- 1 root root 63 Mar 1 21:14 web_roles.yml
[root@ansible data]#
# 创建tasks文件
[root@ansible data]# cat nginx/tasks/main.yml
---
# tasks file for nginx
- include: install_nginx.yml
- import_playbook: config.yml
- include: index.yml
- import_playbook: service.yml
[root@ansible data]#
# 安装nginx
[root@ansible data]# cat nginx/tasks/install_nginx.yml
---
- name: install nginx
yum:
name: nginx
state: present
[root@ansible data]#
# 配置文件
[root@ansible data]# cat nginx/tasks/config.yml
---
- name: copy config
template: src=nginx.conf.j2 dest=/etc/nginx/nginx.conf
notify: restart nginx
# 创建测试文件
[root@ansible data]# cat nginx/tasks/index.yml
---
- name: copt index.html
copy: src=index.html dest=/usr/share/nginx/html/
# 启动nginx
[root@ansible data]# cat nginx/tasks/service.yml
---
- name: start nginx
service: name=nginx state=started enabled=yes
#创建handler文件
[root@ansible data]# cat nginx/handlers/main.yml
---
# handlers file for nginx
- name: restart nginx
service: naem=nginx state=restarted
[root@ansible data]# ll
#创建template文件
[root@ansible data]# ll nginx/templates/
total 4
-rw-r--r-- 1 root root 2336 Mar 1 22:12 nginx.conf.j2
[root@ansible data]#
# 创建测试文件
[root@ansible data]# ll nginx/files/
total 4
-rw-r--r-- 1 root root 23 Mar 1 22:14 index.html
[root@ansible data]#
#在playbook中调用角色
[root@ansible data]# cat web_roles.yml
---
- hosts: centos7
remote_user: root
roles:
# - httpd
- nginx
[root@ansible data]#
#运行playbook
[root@ansible data]# ansible-playbook web_roles.yml
实现MySql8角色
- 创建角色目录
[root@ansible data]# ansible-galaxy init mysql8
[root@ansible data]# ll
total 12
-rw-r--r-- 1 root root 614 Mar 1 21:07 ansible.cfg
-rw-r--r-- 1 root root 1382 Mar 1 21:07 hosts
drwxr-xr-x 10 root root 154 Mar 1 18:07 httpd
drwxr-xr-x 10 root root 154 Mar 1 22:55 mysql8
drwxr-xr-x 8 root root 125 Mar 1 22:44 nginx
-rw-r--r-- 1 root root 75 Mar 1 22:38 web_roles.yml
[root@ansible data]#
- 创建tasks yml文件
# 安装包
[root@ansible data]# cat mysql8/tasks/install_package.yml
---
- name: install package
yum: name={{ item }} state=latest
loop:
- libaio
- numactl-libs
# add group
[root@ansible data]# cat mysql8/tasks/group.yml
---
- name: add group
group: name={{ group }} gid={{ group_gid }}
[root@ansible data]#
# add user
[root@ansible data]# cat mysql8/tasks/user.yml
---
- name: add user
user: name={{ user }} uid={{ user_uid }} shell=/sbin/nologin group={{ group }} create_home=no system=yes home=/data/mysql
[root@ansible data]#
# 准备my.cnf文件
[root@ansible data]# cat mysql8/files/my.cnf
[mysqld]
server-id=1
log-bin
datadir=/data/mysql
socket=/data/mysql/mysql.sock
log-error=/data/mysql/mysql.log
pid-file=/data/mysql/mysql.pid
[client]
socket=/data/mysql/mysql.sock
# 准备mysql二进制包
[root@ansible data]# ll mysql8/files/
total 1176056
-rw-r--r-- 1 root root 181 Mar 1 23:10 my.cnf
-rw-r--r-- 1 root root 1204277208 Dec 18 2021 mysql-8.0.28-linux-glibc2.12-x86_64.tar.xz
[root@ansible data]#
# 将mysql二进制包解压到远程主机
[root@ansible data]# cat mysql8/tasks/unarchive.yml
---
- name: copy mysql tar host
# mysql_tar 为mysql二进制的压缩包名称
unarchive: src={{ mysql_tar }} dest=/usr/local/ owner=root group=root
[root@ansible data]#
# 将远程主机解压出的二进制包创建软连接
[root@ansible data]# cat mysql8/tasks/linkfile.yml
---
- name: create link
file: src=/usr/local/mysql-{{ mysql_version }}-linux-glibc2.12-x86_64 dest=/usr/local/mysql state=link
[root@ansible data]#
# 初始化数据库
[root@ansible data]# cat mysql8/tasks/init_mysql_data.yml
---
- name: create datadir dir
file: path=/data/mysql state=directory owner={{ user }} group={{ group }
- name: init mysql data
shell: /usr/local/mysql/bin/mysqld --initialize-insecure --user=mysql --datadir=/data/mysql
[root@ansible data]#
# copy config.con
[root@ansible data]# cat mysql8/tasks/config.yml
---
- name: copy my.cnf
copy: src=my.cnf dest=/etc/my.cnf
[root@ansible data]#
[root@ansible data]# cat mysql8/tasks/script.yml
---
- name: service script
shell: /bin/cp /usr/local/mysql/support-files/mysql.server /etc/init.d/mysqld
[root@ansible data]#
[root@ansible data]# cat mysql8/tasks/path.yml
---
- name: path
copy: content='PATH=/usr/local/mysql/bin:$PATH' dest=/etc/profile.d/mysql.sh
[root@ansible data]#
[root@ansible data]# cat mysql8/tasks/service.yml
---
- name: service
shell: chkconfig --add mysqld;/etc/init.d/mysqld start
[root@ansible data]#
[root@ansible data]# cat mysql8/tasks/main.yml
---
# tasks file for mysql8
- include: install_package.yml
- include: group.yml
- include: user.yml
- include: unarchive.yml
- include: linkfile.yml
- include: linkfile.yml
- include: init_mysql_data.yml
- include: config.yml
- include: script.yml
- include: path.yml
- include: service.yml
- include: secure.yml
# 创建变量文件
[root@ansible data]# cat mysql8/vars/main.yml
---
# vars file for mysql8
group: mysql
group_gid: 306
user: mysql
user_uid: 306
mysql_tar: mysql-8.0.28-linux-glibc2.12-x86_64.tar.xz
mysql_version: 8.0.28
mysql_root_password: 123456
[root@ansible data]#
# 调用角色
[root@ansible data]# cat web_roles.yml
---
- hosts: centos7
remote_user: root
roles:
- mysql8
# 运行
[root@ansible data]# ansible-playbook web_roles.yml
实现Redis角色
# 创建角色目录
[root@ansible data]# ansible-galaxy init redis
[root@ansible data]# tree redis/
redis/
├── defaults
│ └── main.yml
├── files
├── handlers
│ └── main.yml
├── meta
│ └── main.yml
├── README.md
├── tasks
│ └── main.yml
├── templates
├── tests
│ ├── inventory
│ └── test.yml
└── vars
└── main.yml
# 创建tasks文件
[root@ansible data]# cat redis/tasks/main.yml
---
# tasks file for redis
- name: Installed Redis Server
yum:
name: redis
state: present
- name: Configure Redis Server
template:
src: redis.conf.j2
dest: /etc/redis.conf
owner: redis
group: root
mode: '0640'
notify: Restart Redis Server
- name: Start Redis Server
systemd:
name: redis
state: started
enabled: yes
[root@ansible data]#
# 创建handlers文件
[root@ansible data]# cat redis/handlers/main.yml
---
# handlers file for redis
- name: Restart Redis Server
systemd:
name: redis
state: restarted
[root@ansible data]#
# 在/data/redis/templates目录下准备如下文件
[root@ansible data]# ll redis/templates/
total 48
-rw-r----- 1 root root 46729 Mar 2 02:51 redis.conf.j2
[root@ansible data]#
# 调用角色
# 调用角色
[root@ansible data]# cat web_roles.yml
---
- hosts: centos7
remote_user: root
roles:
- redis
# 运行
[root@ansible data]# ansible-playbook web_roles.yml
Ansible推荐学习资料
http://galaxy.ansible.com
https://galaxy.ansible.com/explore#/
http://github.com/
http://ansible.com.cn/
https://github.com/ansible/ansible
https://github.com/ansible/ansible-examples
评论区