文章目录
- 一、变量 variables
- 1.1 什么是变量
- 1.2 定义变量的几种方式
- 二、变量实战
- 2.1 在playbook中定义变量
- 2.2 在 vars_files 文件中定义变量
- 2.3 在Inventory中定义变量
- 2.3.1 在Inventory文件中定义变量
- 2.3.2 使用host_vars定义变量
- 2.3.3 使用group_vars定义变量
- 2.4 通过执行Playbook传递变量
- 2.5 变量的优先级
- 2.6 nfs 服务端和客户端实现变量方式写法
- 三、 Ansible Register
- 3.1 什么是Register
- 3.2 register批量修改主机名称
- 3.3 使用register 完成jumpserver key 的创建
- 五、Ansible Facts Variables
- 5.1 什么是facts Ansible
- 5.2 facts 应用场景
- 5.3 示例
- 5.4 根据不同的ip地址生成不同的Redis配置文件
- 5.5 根据不同的主机cup数生成不同的nginx配置文件
- 5.6 根据主机内存生成Memcached配置
- 5.6 批量修改主机名称
- 5.7 facts变量优化
- 六、 Ansible task control
- 6.1 when
- 6.1.1 根据不同操作系统安装相同的软件
- 6.1.2 为特定的主机添加Nginx仓库
- 6.1.3 判断服务是否正常运行
- 6.1.4 判断是否安装nginx 未按装可以执行不同的操作,例如安装nginx
- 6.2 loop循环
- 6.2.1 使用循环批量启动服务与安装软件
- 6.2.2 使用loop循环批量创建用户
- 6.2.3 使用loop循环copy文件
- 6.3.Handlers与Notify
- 6.4 tags 任务标签
- 6.5 include任务复用
- 6.5.1 多个项目同时需要重启nginx
- 6.5.2 Inlcude结合tags应用 安装tomcat
- 6.7 Playbook异常处理
- 6.8 change状态
- 6.9 changed_when检查任务结果
一、变量 variables
1.1 什么是变量
变量提供了便捷的方式来管理 ansible 项目中的动态值。 比如 nginx-1.12,可能后期会反复的使用到这个版本的值,那么如果将此值设置为变量,后续使用和修改都将变得非常方便。
1.2 定义变量的几种方式
- 通过命令行传递变量参数定义
- 在play文件中定义变量
2.1 通过vars定义变量
2.2 通过vars_files定义变量 - 通过inventory在主机组或单个主机中设置变量
3.1 通过host_vars对主机进行定义
3.2 通过group_vars对主机组进行定义
二、变量实战
2.1 在playbook中定义变量
在 playbook 的文件中开头通过 vars 关键字进行变量定义
[root@manager playbook_vars]# cat playbook_vars1.yml
- hosts: localhost
vars:
- web_server: httpd
- nfs_server: nfs
tasks:
- name: Output vaiables
debug:
msg:
- "{{ web_server }}"
- "{{ nfs_server }}"
[root@manager playbook_vars]# ansible-playbook playbook_vars1.yml
PLAY [localhost] *****************************************************************************************************************************
TASK [Gathering Facts] ***********************************************************************************************************************
ok: [localhost]
TASK [Output vaiables] ***********************************************************************************************************************
ok: [localhost] => {
"msg": [
"httpd",
"nfs"
]
}
PLAY RECAP ***********************************************************************************************************************************
localhost : ok=2 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
2.2 在 vars_files 文件中定义变量
在 playbook 中使用 vars_files 指定文件作为变量文件,好处就是其他的 playbook 也可以调用;
1.准备vars_file文件
[root@manager playbook_vars]# cat vars_file.yml
web_server: httpd
nfs_serve: nfs
2.在playbook中play阶段调用
[root@manager playbook_vars]# cat playbook_vars2.yml
- hosts: localhost
vars_files: ./vars_file.yml
tasks:
- name: Output vaiables
debug:
msg:
- "{{ web_server }}"
- "{{ nfs_server }}"
2.3 在Inventory中定义变量
2.3.1 在Inventory文件中定义变量
1.定义
[root@manager playbook_vars]# cat hosts
[webservers]
172.16.1.7 state=MASTER
172.16.1.8 state=BACKUP
[webservers:vars]
port=80
2.调用
[root@manager playbook_vars]# cat playbook_vars3.yml
- hosts: webservers
tasks:
- name: Output variables
debug:
msg:
- " {{ state }} {{ port }}"
3.输出
[root@manager playbook_vars]# ansible-playbook playbook_vars3.yml
TASK [Output variables]
*****************************************************
ok: [172.16.1.7] => {
"msg": [
" MASTER 80"
]
}
ok: [172.16.1.8] => {
"msg": [
" BACKUP 80"
]
}
2.3.2 使用host_vars定义变量
1.在项目目录中创建 host_vars目录,然后在创建一个文件,文件的文件名称要与 inventory 清单中的主机名称要保持完全一致,如果是ip地址,则创建相同ip地址的文件即可
1.创建host_vars目录
[root@manager playbook_vars]# mkdir host_vars
2.编写相同主机名的文件
[root@manager playbook_vars]# touch host_vars/172.16.1
name: bertwu
age: 18
3.调用
[root@manager playbook_vars]# cat playbook_vars4.yml
- hosts: 172.16.1.7
tasks:
- name: Output variables
debug:
msg: "{{ name }} {{ age }}"
4.执行测试
[root@manager playbook_vars]# ansible-playbook playbook_vars4.yml
*******************************************************************
ok: [172.16.1.7] => {
"msg": "bertwu 18"
}
如果主机清单中的其他主机区调用,会报错
2.3.3 使用group_vars定义变量
1.在项目目录中创建 group_vars目录,然后在创建一个文件,文件的文件名称要与 inventory 清单中的组名称保持完全一致;
[root@manager playbook_vars]# mkdir group_vars
2.在 group_vars 目录中创建 webservers文件,为 webservers主机组设定变量;
[root@manager group_vars]# cat webservers
name: Jay
age:30
3.编写 playbook,只需在 playbook 文件中使用变量即可
[root@manager playbook_vars]# cat playbook_vars5.yml
- hosts: webservers
tasks:
- name: Output varibles
debug:
msg:
- "{{ name }} {{ age }}"
4.调用
[root@manager playbook_vars]# ansible-playbook playbook_vars5.yml
TASK [Output varibles] *************************************************
ok: [172.16.1.7] => {
"msg": [
"bertwu 18"
]
}
ok: [172.16.1.8] => {
"msg": [
"Jay 30"
]
}
5.测试其他组能否使用 webservers 组中定义的变量;测试后会发现无法调用;
6.系统提供了特殊的 all 组,也就说在 group_vars 目录下创建一个 all 文件,定义变量对所有的主机组都生效;
2.4 通过执行Playbook传递变量
在执行Playbook时,可以通过命令行--extra-vars
或-e
外置传参设定变量;
[root@manager playbook_vars]# cat vars6.yml
- hosts: localhost
tasks:
- name: Output variables
debug:
msg:
- "{{ user }} {{ uid }}"
执行,并且传递多个参数
[root@manager playbook_vars]# ansible-playbook vars6.yml -e "user=tom" -e "uid=666"
TASK [Output variables] ***********************************************************
ok: [localhost] => {
"msg": [
"tom 666"
]
}
2.5 变量的优先级
1)在plabook中定义vars变量
2)在playbook中定义vars_files变量
3)在host_vars中定义变量
4)在group_vars中定义变量
5)通过执行命令传递变量
结果:
1.命令行传参
2.play中的vars_files
3.play中的vars
4.invetory主机清单中的vars
5.host_vars
6.group_vars
7.group_vars/all
8.inventory 组变量
2.6 nfs 服务端和客户端实现变量方式写法
[root@manager playbook_vars]# tree -L 1
.
├── ansible.cfg
├── exports.j2
├── hosts
├── nfs_varibles.yml
└── vars_file.yml
1.vars_flle变量文件
[root@manager playbook_vars]# cat vars_file.yml
## nfs
webservers: test
group_name: xxx
user_name: xxx
nfs_gid: 555
nfs_uid: 555
nfs_share_directory: /nfs_data
local_mount_directory: /opt
nfs_ip_range: 172.16.1.0/24
2.nfs配置文件
[root@manager playbook_vars]# cat exports.j2
{{ nfs_share_directory }} {{ nfs_ip_range }}(rw,sync,all_squash,anonuid={{nfs_uid }},anongid={{ nfs_gid }})
3.nfs客户端和服务端:
[root@manager playbook_vars]# cat nfs_varibles.yml
- hosts: "{{ webservers }}"
vars_files: ./vars_file.yml
tasks:
- name: Installed nfs servers
yum:
name: nfs-utils
state: present
- name: Configure nfs
template:
src: ./exports.j2
dest: /etc/exports
backup: yes
notify: Restart nfs server
- name: Create group
group:
name: "{{ group_name }}"
gid: "{{ nfs_gid }}"
system: yes
state: present
- name: Create user
user:
name: "{{ user_name }}"
uid: "{{ nfs_uid }}"
group: "{{ group_name }}"
system: yes
- name: Create share directory
file:
path: "{{ nfs_share_directory }}"
owner: "{{ user_name }}"
group: "{{ group_name }}"
mode: 0755
state: directory
recurse: yes
- name: start nfs
systemd:
name: nfs
state: started
enabled: yes
handlers:
- name: Restart nfs server
systemd:
name: nfs
state: restarted
- hosts: localhost
vars_files: ./vars_file.yml
tasks:
- name: Remote Mount
mount:
src: "172.16.1.99:{{ nfs_share_directory }}"
path: "{{ local_mount_directory }}"
state: mounted
fstype: nfs
opts: defaults
三、 Ansible Register
3.1 什么是Register
register 可以将 task 执行的任务结果存储至某个变量中,便于后续的引用;
[root@manager playbook_vars]# cat register1.yml
- hosts: webservers
tasks:
- name: check netstat
shell: netstat -lntp
register: system_status
- name: print state
debug:
msg:
- "{{ system_status.cmd }}"
- "{{ system_status.stdout_lines }}"
[root@manager playbook_vars]# ansible-playbook register1.yml
TASK [print state] ***************************************************************************************************************************
ok: [172.16.1.7] => {
"msg": [
"netstat -lntp",
[
"Active Internet connections (only servers)",
"Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name ",
"tcp 0 0 0.0.0.0:2049 0.0.0.0:* LISTEN - ",
"tcp 0 0 0.0.0.0:50565 0.0.0.0:* LISTEN 911/rpc.statd ",
"tcp 0 0 127.0.0.1:9000 0.0.0.0:* LISTEN 3553/php-fpm: maste ",
"tcp 0 0 0.0.0.0:873 0.0.0.0:* LISTEN 555/rsync ",
"tcp 0 0 0.0.0.0:111 0.0.0.0:* LISTEN 551/rpcbind ",
"tcp 0 0 0.0.0.0:80 0.0.0.0:* LISTEN 3591/nginx: master ",
"tcp 0 0 0.0.0.0:20048 0.0.0.0:* LISTEN 924/rpc.mountd ",
"tcp 0 0 0.0.0.0:22 0.0.0.0:* LISTEN 905/sshd ",
"tcp 0 0 0.0.0.0:36696 0.0.0.0:* LISTEN - ",
"tcp 0 0 127.0.0.1:25 0.0.0.0:* LISTEN 1100/master ",
"tcp6 0 0 :::36673 :::* LISTEN - ",
"tcp6 0 0 :::2049 :::* LISTEN - ",
"tcp6 0 0 127.0.0.1:8005 :::* LISTEN 1238/java ",
"tcp6 0 0 :::873 :::* LISTEN 555/rsync ",
"tcp6 0 0 :::56394 :::* LISTEN 911/rpc.statd ",
"tcp6 0 0 :::111 :::* LISTEN 551/rpcbind ",
"tcp6 0 0 :::8080 :::* LISTEN 1238/java ",
"tcp6 0 0 :::20048 :::* LISTEN 924/rpc.mountd ",
"tcp6 0 0 :::22 :::* LISTEN 905/sshd ",
"tcp6 0 0 ::1:25 :::* LISTEN 1100/master "
]
]
}
3.2 register批量修改主机名称
[root@manager playbook_vars]# cat register2.yml
- hosts: test
tasks:
- name: check netstat
shell: echo echo $RANDOM | md5sum | cut -c 1-8 # 生成8位随机数
register: random_name
- name: print state
debug:
msg:
- "{{ random_name.stdout }}"
- name: Change hostname
hostname:
name: "{{ random_name.stdout}}"
3.3 使用register 完成jumpserver key 的创建
[root@manager playbook_vars]# cat key.yml
- hosts: localhost
tasks:
- name: Create jumpserver key
shell: 'if grep "BOOTSTRAP_TOKEN" ~/.bashrc;then
echo $BOOTSTRAP_TOKEN;
else
BOOTSTRAP_TOKEN=`cat /dev/urandom | tr -dc A-Za-z0-9 | head -c 24`;
echo "BOOTSTRAP_TOKEN=$BOOTSTRAP_TOKEN" >> ~/.bashrc ;
echo $BOOTSTRAP_TOKEN
fi'
register: JMS_BOOTSTRAP_TOKEN
- name: Create jumpserver key
shell: 'if grep "SECRET_KEY" ~/.bashrc;then
echo $SECRET_KEY;
else
SECRET_KEY=`cat /dev/urandom | tr -dc A-Za-z0-9 | head -c 49`;
echo "SECRET_KEY=$SECRET_KEY" >> ~/.bashrc ;
echo $SECRET_KEY
fi'
register: JMS_SECRET_KEY
- name: Output test
debug:
msg:
- "{{ JMS_BOOTSTRAP_TOKEN.stdout.split('=')[-1] }}"
- "{{ JMS_SECRET_KEY.stdout.split('=')[-1] }}"
root@manager playbook_vars]# ansible-playbook key.yml
TASK [Output test] ****************************************************
ok: [localhost] => {
"msg": [
"ecUjA0BytELzk2zAOBJfni86dguxhWGEnV4ZLPVZklhwWheXA",
"QTZwLs7uG1TO0jVCBSM6XeTU7uxY1XFiDdxFPAOhUNfvr10KZ"
]
}
五、Ansible Facts Variables
5.1 什么是facts Ansible
设备管理控制与时间调度程序:Facilities Administration Control and Time Schedule
facts 变量主要用来自动采集”被控端主机“ 自身的状态信息。比如:被控端的,主机名、IP地址、系统版本、CPU数量、内存状态、磁盘状态等等。
5.2 facts 应用场景
1.通过facts变量检查被控端硬件CPU信息,从而生成不同的Nginx配置文件。
2.通过facts变量检查被控端内存状态信息,从而生成不同的memcached的配置文件。
3.通过facts变量检查被控端主机名称信息,从而生成不同的Zabbix配置文件。
4.通过facts变量检查被控端主机IP地址信息,从而生成不同的redis配置文件。
5.3 示例
查看本机状态信息
[root@manager playbook_vars]# ansible localhost -m setup
[root@manager playbook_vars]# cat facts_print_information.yml
- hosts: localhost
tasks:
- name: Print the basic information of centos
debug:
msg:
- "{{ ansible_eth0.ipv4.address }}"
- "{{ ansible_eth1.ipv4.address }}"
- "{{ ansible_distribution }}" # 平台信息 centos 或ubuntu
- "{{ ansible_fqdn}}" # 主机名称
- "{{ ansible_processor_count }}"
- "{{ansible_hostname}}" # 主机名
[root@manager playbook_vars]# ansible-playbook facts_print_information.yml
TASK [Print the basic information of centos] *******************************************************
ok: [localhost] => {
"msg": [
"10.0.0.62",
"172.16.1.62",
"CentOS",
"manager",
1
]
}
如果没有使用facts变量需求,可以关闭其功能,加速ansible执行性能;
在play阶段定义 gather_facts: no
,因为获取后端的facts 变量是非常慢的。
[root@manager playbook_vars]# cat facts_print_information.yml
- hosts: localhost
gather_facts: no
tasks:
- name: Print the basic information of centos
debug:
5.4 根据不同的ip地址生成不同的Redis配置文件
[root@manager playbook_vars]# cat redis.yml
- hosts: webservers
tasks:
- name: install redis server
yum:
name: redis
state: present
- name: configure redis server
template:
src: ./redis.conf.j2
dest: /etc/redis.conf
notify: restart redis server
- name: start redis server
systemd:
name: redis
state: started
enabled: yes
handlers:
- name: restart redis server
systemd:
name: redis
state: restarted
配置文件写成动态的
[root@manager playbook_vars]# cat redis.conf.j2
bind 127.0.0.0 {{ ansible_eth1.ipv4.address }}
5.5 根据不同的主机cup数生成不同的nginx配置文件
"ansible_processor_cores": 3, # 每个处理器的核心数
"ansible_processor_count": 2, # 处理器cpu总数
"ansible_processor_threads_per_core": 1, # 每个线程需要的核心数
"ansible_processor_vcpus": 6, # 总核心数
worker_processes {{ ansible_processor_vcpus * 2 }};
5.6 根据主机内存生成Memcached配置
# memcached配置文件如下
[root@ansible project1]# cat memcached.j2 PORT="11211"
USER="memcached"
MAXCONN="1024"#根据内存状态生成不同的配置(支持+-*/运算)
CACHESIZE="{{ ansible_memtotal_mb //2 }}" # 总内存/2#
CACHESIZE="{{ ansible_memtotal_mb * 0.8 }}" # 使用内存80%
OPTIONS=""
5.6 批量修改主机名称
[root@manager playbook_vars]# cat change_hostname.yml
- hosts: localhost
tasks:
- name: Change hostname
hostname:
name: "web_{{ ansible_eth1.ipv4.address.split(".")[-1] }}"
5.7 facts变量优化
当我们使用 gather_facts: no 关闭 facts,确实能加速 Ansible 执行,但是有时候又需要使用 facts 中的内容,还希望执行的速度快一点,这时候可以设置 facts 的缓存存入redis中;
修改ansibl.cfg配置文件
# smart 表示默认收集 facts,但 facts 已有的情况下不会收集,即使用缓存 facts
# implicit 表示默认收集 facts,要禁止收集,必须使用 gather_facts: False;
# explicit 则表示默认不收集,要显式收集,必须使用 gather_facts: Ture。
host_key_checking = False
gathering = smart
fact_caching_timeout = 86400
fact_caching = redis
fact_caching_connection = 172.16.1.41:6379:1
# 若 redis 设置了密码# fact_caching_connection = 172.16.1.41:6379:1:passwd
[root@manager playbook_vars]# yum install python-pip
[root@manager playbook_vars]# pip install redis # 安装redis模块
# 查看redis服务器库,看是否缓存成功。
127.0.0.1:6379[1]> select 1 #选择1号库
OK
127.0.0.1:6379[1]> keys *
1) "ansible_cache_keys"
2) "ansible_factslocalhost"
127.0.0.1:6379[1]>
六、 Ansible task control
6.1 when
when 关键字主要针对 TASK 任务进行判断,对于此前我们使用过的 yum 模块是可以自动检测软件包是否已被安装,无需人为干涉;但对于有些任务则是需要进行判断才可以实现的。
- 比如:web 节点都需要配置 nginx 仓库,但其他节点并不需要,此时就会用到 when 判断。
- 比如: Centos 与 Ubuntu 都需要安装 Apache,而 Centos 系统软件包为 httpd,而 Ubuntu系统软件包为httpd2,那么此时就需要判断主机系统,然后为不同的主机系统安装不同的软件包。
6.1.1 根据不同操作系统安装相同的软件
[root@manager playbook_vars]# cat when_system.yml
- hosts: webservers
tasks:
- name: centos Install httpd
yum:
name: httpd
state: present
when: (ansible_distribution == "CentOS")
- name: ubuntu install apache2
yum:
name: httpd2
state: present
when: (ansible_distribution == "Ubuntu")
6.1.2 为特定的主机添加Nginx仓库
为主机名为web或lb开头的主机添加nginx yum仓库
[root@manager playbook_vars]# cat when_nginx.yml
- hosts: all
tasks:
- name: add ningx yum repository
yum_repository:
name: nginx
description: add nginx yum repository
baseurl: http://nginx.org/packages/centos/7/$basearch/
gpgcheck: no
when: (ansible_hostname is match("web*")) or (ansible_hostname is match("lb*"))
6.1.3 判断服务是否正常运行
判断httpd 是否启动, 启动则重启,否则不做处理
[root@manager playbook_vars]# cat when_isactive.yml
- hosts: webservers
tasks:
- name: Check service is active
shell: systemctl is-active httpd
ignore_errors: yes
register: check_service
- name: Output debug
debug:
msg:
- "{{check_service}}"
- name: httpd restarted
systemd:
name: httpd
state: restarted
when: (check_service.rc == 0)
6.1.4 判断是否安装nginx 未按装可以执行不同的操作,例如安装nginx
[root@manager playbook_vars]# cat when_is_install_nginx.yml
#- hosts: webservers
- hosts: localhost
tasks:
- name: Check is_install nginx
shell: yum list installed | grep nginx
ignore_errors: yes
register: check_service
- name: Output debug
debug:
msg:
- "{{check_service}}"
- name: install nginx
yum:
name: nginx
state: present
enablerepo: nginx
when: (check_service.rc == 1)
6.2 loop循环
在写 playbook 的时候发现了很多 task 都要重复引用某个相同的模块,比如一次启动10个服务,或者一次拷贝10个文件,如果按照传统的写法最少要写10次,这样会显得 playbook 很臃肿。如果使用循环的方式来编写 playbook,这样可以减少重复编写 task 带来的臃肿;
6.2.1 使用循环批量启动服务与安装软件
[root@manager loop]# cat loop_service.yml
- hosts: test
tasks:
- name: install mariadb maraidb-server httpd
yum:
name: "{{ item }}"
state: present
loop:
- mariadb
- mariadb-server
- httpd
- name : start all
systemd:
name: "{{ item }}"
state: started
loop:
- httpd
- mariadb
6.2.2 使用loop循环批量创建用户
[root@manager ~]# cat loop-user.yml
- hosts: webservers
tasks:
- name: Add Users
user:
name: "{{ item.name }}"
groups: "{{ item.groups }}"
loop:
- { name: 'testuser1', groups: 'bin' }
- { name: 'testuser2', groups: 'root' }
6.2.3 使用loop循环copy文件
[root@manager loop]# cat loop_copy.yml
- hosts: test
tasks:
- name: Copy rsync file
copy:
src: "{{ item.src }}"
dest: "{{ item.dest }}"
mode: "{{ item.mode}}"
owner: root
group: root
loop:
- { src: ./rsync.conf,dest: /etc/rsync.conf,mode: "0644" }
- { src: ./rsync.pass,dest: /etc/rsypc.pass, mode: "0600" }
6.3.Handlers与Notify
Handlers 是一个触发器,同时是一个特殊的 tasks,它无法直接运行,它需要被 tasks 通知后才会运行。比如:httpd 服务配置文件发生变更,我们则可通过 Notify 通知给指定的 handlers 触发器,然后执行相应重启服务的操作,如果配置文件不发生变更操作,则不会触发 Handlers 任务的执行。
handlers 注意事项
- 无论多少个 task 通知了相同的 handlers, handlers 仅会在所有 tasks 结束后运行一次。
- 只有 task 发生改变了才会通知 handlers ,没有改变则不会触发handlers
- 不能使用 handlers 替代 tasks、因为 handlers 是一个特殊的tasks
6.4 tags 任务标签
默认情况下,Ansible 在执行一个 playbook 时,会执行 playbook 中所有的任务。而标签功能是用来指定要运行 playbook 中的某个特定的任务;
- 为 playbook 添加标签的方式有如下几种:
对一个 task 打一个标签
对一个 task 打多个标签
对多个 task 打一个标签 - task打完标签使用的几种方式
-t 执行指定tag标签对应的任务
–skip-tags 执行除 --skip-tags 标签之外的所有任务
例:
[root@manager loop]# cat loop_service.yml
- hosts: test
tasks:
- name: install mariadb maraidb-server httpd
yum:
name: "{{ item }}"
state: present
loop:
- mariadb
- mariadb-server
- httpd
tags: # 为一个任务打多个标签
- install_mariadb
- install_httpd
- name : start all
systemd:
name: "{{ item }}"
state: started
loop:
- httpd
- mariadb
tags: # 为一个任务打多个标签
- start_httpd
- start_mariadb
使用 -t
指定 tags 标签对应的任务, 多个 tags 使用逗号隔开即可
使用 --skip-tags
指定要排除的 tags 标签对应的任务, 多个 tags 使用逗号隔开即可
[root@manager loop]# ansible-playbook -t install_mariadb,start_httpd loop_service.yml
[root@manager loop]# ansible-playbook --skip-tags install_mariadb, loop_service.yml
6.5 include任务复用
有时,我们发现大量的 Playbook 内容需要重复编写,各 Tasks 之间功能需相互调用才能完成各自功能,Playbook 庞大到维护困难,这时我们需要使用include比如:A项目需要用到重启 httpd,B项目需要重启 httpd,那么我们可以使用 Include来减少重复编写。
6.5.1 多个项目同时需要重启nginx
1.编写 restart_nginx.yml 文件
不包含任何play阶段信息
[root@manager loop]# cat restart_nginx.yml
- name: Restart nginx server
systemd:
name: nginx
state: restarted
2.project_1 如下
[root@manager loop]# cat restart_nginx.yml
- name: Restart nginx server
systemd:
name: nginx
state: restarted
[root@manager loop]# cat project_1.yml
- hosts: webservers
tasks:
- name: echo a
shell: echo 'a project'
- name: Restart nginx server
include: ./restart_nginx.yml
3.project_2 如下
[root@manager loop]# cat project_2.yml
- hosts: webservers
tasks:
- name: echo b
shell: echo 'b project'
- name: Restart nginx server
include: ./restart_nginx.yml
[root@manager loop]# cat project_2.yml
- hosts: webservers
tasks:
- name: echo b
shell: echo 'b project'
- name: Restart nginx server
include: ./restart_nginx.yml
6.5.2 Inlcude结合tags应用 安装tomcat
1.下载jdk解压到remote
2.yum本地安装jdk
3.远程创建/soft 目录
4.远程解压tomcat到/soft目录
5.制作软连接
6.推送tomcat启停文件
7.推送配置文件 权限0600
8.启动tomcat
方式1
1.总入口文件
[root@web_62 loop]# cat main.yml
- hosts: test
vars :
- src_jdk_path: /root/jdk-8u281-linux-x64.rpm
- dest_jdk: /root
- tomcat_dir: /soft
- tomcat_version: 8.5.71
- tomcat_service: ./tomcat.service
- tomcat_name: tomcat8
tasks:
- name: install tomcat8
include: ./install_tomcat8.yml
tags: install_tomcat8
- name: install tomcat9
include: ./install_tomcat9.yml
tags: install_tomcat9
handlers:
- name: reload tomcat
systemd:
name: tomcat
state: restarted
2.install_tomcat8.yml
[root@web_62 loop]# cat install_tomcat8.yml
- name: copy jdk_rpm to remote
copy:
src: "{{ src_jdk_path }}"
dest: "{{ dest_jdk }}"
- name: install_jdk_rpm
yum:
name: "{{ src_jdk_path }}"
state: present
- name: create /soft to remote host
file:
path: "{{ tomcat_dir }}"
state: directory
- name: unarchive tomcat package to remote /soft
unarchive:
src: "{{ dest_jdk }}/apache-tomcat-{{ tomcat_version }}.tar.gz"
dest: "{{ tomcat_dir}}"
- name: make tomcat link
file:
src: "{{ tomcat_dir }}/apache-tomcat-{{ tomcat_version }}"
dest: "{{ tomcat_dir }}/{{tomcat_name}}"
state: link
- name: copy systemd start file
template:
src: "{{ tomcat_service }}"
dest: /usr/lib/systemd/system/tomcat.service
- name: copy tomcat configure file
copy:
src: ./server.xml.j2
dest: "{{tomcat_dir}}/{{tomcat_name}}/conf/server.xml"
notify: reload tomcat
- name: start tomcat
systemd:
name: tomcat
state: restarted
3.install_tomcat9.yml 文件与8一模一样
默认会装8 ,如果装tomcat9 只需要指定参数即可
[root@web_62 loop]# ansible-playbook -t install_tomcat9 main.yml -e "tomcat_version=9.0.53" -e "tomcat_name=tomcat9"
方式2
直接在main.yml写一个tasks , 只需一个install_tomcat.yml文件,默认安装的是tomcat8 ,安装tomcat需要指定版本号及目录。
[root@web_62 loop]# cat main.yml
- hosts: localhost
vars :
- src_jdk_path: /root/jdk-8u281-linux-x64.rpm
- dest_jdk: /root
- tomcat_dir: /soft
- tomcat_version: 8.5.71
- tomcat_service: ./tomcat.service
- tomcat_name: tomcat8
tasks:
- name: install tomcat
include: ./install_tomcat.yml
tags: install_tomcat
handlers:
- name: reload tomcat
systemd:
name: tomcat
state: restarted
[root@web_62 loop]# cat install_tomcat.yml
#- hosts: test
# vars:
# - src_jdk_path: /root/jdk-8u281-linux-x64.rpm
# - dest_jdk: /root
# - tomcat_dir: /soft
# - tomcat_version: 8.5.71
# - tomcat_service: ./tomcat.service
# - tomcat_name: tomcat8
#
# tasks:
- name: copy jdk_rpm to remote
copy:
src: "{{ src_jdk_path }}"
dest: "{{ dest_jdk }}"
- name: install_jdk_rpm
yum:
name: "{{ src_jdk_path }}"
state: present
- name: create /soft to remote host
file:
path: "{{ tomcat_dir }}"
state: directory
- name: unarchive tomcat package to remote /soft
unarchive:
src: "{{ dest_jdk }}/apache-tomcat-{{ tomcat_version }}.tar.gz"
dest: "{{ tomcat_dir}}"
- name: make tomcat link
file:
src: "{{ tomcat_dir }}/apache-tomcat-{{ tomcat_version }}"
dest: "{{ tomcat_dir }}/{{tomcat_name}}"
state: link
- name: copy systemd start file
template:
src: "{{ tomcat_service }}"
dest: /usr/lib/systemd/system/tomcat.service
- name: copy tomcat configure file
copy:
src: ./server.xml.j2
dest: "{{tomcat_dir}}/{{tomcat_name}}/conf/server.xml"
notify: reload tomcat
- name: start tomcat
systemd:
name: tomcat
state: restarted
默认安装tomcat8:
[root@web_62 loop]# ansible-playbook -t install_tomcat main.yml
安装tomcat9:
[root@web_62 loop]# ansible-playbook -t install_tomcat main.yml -e "tomcat_version=9.0.53" -e "tomcat_name=tomcat9"
tomcat.service配置文件如下:
[root@web_62 loop]# cat tomcat.service
[Unit]
Description=tomcat - high performance web server
Documentation=https://tomcat.apache.org/
After=network-online.target remote-fs.target nss-lookup.target
Wants=network-online.target
[Service]
Type=forking
#Environment=JAVA_HOME=/usr/local/jdk
Environment=CATALINA_HOME=/soft/{{ tomcat_name }}
Environment=CATALINA_BASE=/soft/{{ tomcat_name }}
ExecStart=/soft/{{ tomcat_name }}/bin/startup.sh
ExecStop=/soft/{{ tomcat_name }}/bin/shutdown.sh
[Install]
WantedBy=multi-user.target
6.7 Playbook异常处理
在 playbook 执行的过程中,难免会遇到一些错误。由于 playbook 遇到错误后,不会执行之后的任务,不便于调试,此时,可以在tasks中使用 ignore_errors: yes
来暂时忽略错误,使得 playbook 继续执行。
[root@manager ~]# cat ignore.yml
- hosts: all
tasks:
- name: Ignore False
command: /bin/false
ignore_errors: yes
通常情况下,当 task 失败后,play将会终止,任何在前面已经被 tasks notify 的 handlers 都不会被执行。如果你在 play 中设置了force_handlers: yes
参数,被通知的 handlers 就会被强制执行。(有些特殊场景可能会使用到)
- hosts: web
force_handlers: yes #强制调用handlers
tasks:
- name: Touch File
file:
path=/tmp/bgx_handlers
state=touch
notify: Restart Httpd Server
....
6.8 change状态
[root@web_62 loop]# cat change.yml
- hosts: webservers
tasks:
- name: get nginx port
shell: netstat -lntp | grep nginx
register: nginx_port
- name: output nginx port
debug:
msg:
- "{{ nginx_port.stdout_lines }}"
执行 playbook 会发现第一个 task 运行 shell 模块报告的改变,即使它没有真正的在远端系统做出改变,如果你一直运行,它会一直处在改变状态。
shell 任务不应该每次都报告 changed 状态,因为它没有在被管理主机执行后发生变化。添加 changed_when: false
来抑制这个改变
[root@web_62 loop]# cat change.yml
- hosts: webservers
tasks:
- name: get nginx port
shell: netstat -lntp | grep nginx
register: nginx_port
changed_when: false
- name: output nginx port
debug:
msg:
- "{{ nginx_port.stdout_lines }}"
6.9 changed_when检查任务结果
如果结果正确,则正常往下执行,否则退出执行。
[root@web_62 loop]# cat change_when.yml
- hosts: webservers
tasks:
- name: check ningx server
shell: /usr/sbin/nginx -t
register: check_nginx
changed_when:
- check_nginx.stdout.find('successful')
- false
- name: start nginx server
systemd:
name: nginx
state: restarted