13-Ansible-playbook剧本进阶
Ansible-playbook 有许多高级特性,这些特性可以帮助用户编写更复杂、灵活和高效的自动化脚本。以下为你详细介绍一些常见的高级特性:
1. 变量和事实(Variables and Facts)
变量定义与使用
在 Playbook 中可以定义多种类型的变量,如全局变量、主机变量、组变量等,并且可以在任务中引用这些变量。
---
- name: Use variables in playbook
hosts: webservers
vars:
app_port: 8080
tasks:
- name: Start application
command: ./app start --port {{ app_port }}
事实(Facts)
Ansible 会自动收集目标主机的系统信息,即事实(Facts),这些信息可以作为变量在 Playbook 中使用。例如,ansible_os_family 可以用于判断目标主机的操作系统家族。
---
- name: Install package based on OS family
hosts: all
tasks:
- name: Install appropriate package
package:
name: "{{ 'apache2' if ansible_os_family == 'Debian' else 'httpd' }}"
state: present
2. 条件判断(When Statements)
使用 when 语句可以根据条件决定是否执行某个任务。
---
- name: Conditional task execution
hosts: servers
tasks:
- name: Restart service on specific hosts
service:
name: myservice
state: restarted
when: ansible_hostname in ['server1', 'server2']
3. 循环(Loops)
简单循环
可以使用 loop 关键字对列表或字典进行循环操作。
---
- name: Install multiple packages
hosts: all
tasks:
- name: Install packages
apt:
name: "{{ item }}"
state: present
loop:
- nginx
- mysql-server
- php
嵌套循环
支持嵌套循环,处理更复杂的数据结构。
---
- name: Create multiple users with different groups
hosts: all
tasks:
- name: Create users
user:
name: "{{ item[0] }}"
groups: "{{ item[1] }}"
state: present
loop:
- ['user1', 'group1']
- ['user2', 'group2']
4. 错误处理(Error Handling)
忽略错误
使用 ignore_errors 关键字可以忽略某个任务执行过程中产生的错误,继续执行后续任务。
---
- name: Ignore errors in a task
hosts: all
tasks:
- name: Try to run a command that may fail
command: /path/to/command
ignore_errors: true
- name: Continue with the next task
debug:
msg: "This task will run even if the previous one failed."
失败时重试
使用 retries 和 delay 关键字可以在任务失败时进行重试。
---
- name: Retry a task on failure
hosts: all
tasks:
- name: Run a command with retries
command: /path/to/command
retries: 3
delay: 5
5. 角色(Roles)
角色是一种组织 Playbook 代码的方式,将相关的任务、变量、模板等组织在一起,提高代码的复用性和可维护性。
角色目录结构
roles/
└── webserver/
├── defaults/
│ └── main.yml
├── files/
├── handlers/
│ └── main.yml
├── meta/
│ └── main.yml
├── tasks/
│ └── main.yml
├── templates/
└── vars/
└── main.yml
在 Playbook 中使用角色
---
- name: Use roles in playbook
hosts: webservers
roles:
- webserver
6. 块(Blocks)
块可以将多个任务组合在一起,方便进行统一的错误处理、条件判断等操作。
---
- name: Use blocks in playbook
hosts: all
tasks:
- block:
- name: Task 1
command: /path/to/command1
- name: Task 2
command: /path/to/command2
when: ansible_os_family == "Debian"
rescue:
- name: Handle errors
debug:
msg: "An error occurred in the block."
7. 标签(Tags)
使用标签可以选择性地执行 Playbook 中的部分任务。
---
- name: Use tags in playbook
hosts: all
tasks:
- name: Task 1
command: /path/to/command1
tags: tag1
- name: Task 2
command: /path/to/command2
tags: tag2
# 只执行带有 tag1 标签的任务
ansible-playbook playbook.yml --tags tag1
8. 异步执行(Asynchronous Execution)
对于一些耗时较长的任务,可以使用异步执行来避免长时间等待。
---
- name: Asynchronous task execution
hosts: all
tasks:
- name: Run a long-running command asynchronously
command: /path/to/long-running-command
async: 3600 # 最大执行时间(秒)
poll: 0 # 不轮询结果
剧本高级特性篇
循环
在写 playbook 的时候发现了很多 task 都要重复引用某个相同的模块,比如一次启动10个服务,或者一次拷贝10个文件,如果按照传统的写法最少要写10次,这样会显得 playbook 很臃肿。
如果使用循环的方式来编写 playbook ,这样可以减少重复编写 task 带来的臃肿。
https://docs.ansible.com/ansible/latest/user_guide/playbooks_loops.html?highlight=loop
关于循环的标准用法
早期ansible教程中,关于循环关键字是with_item
ansible自2.5版本后,通过loop关键字提供循环功能
[root@master-61 /script]#ansible --version
ansible 2.9.27
config file = /etc/ansible/ansible.cfg
configured module search path = [u'/root/.ansible/plugins/modules', u'/usr/share/ansible/plugins/modules']
ansible python module location = /usr/lib/python2.7/site-packages/ansible
executable location = /usr/bin/ansible
python version = 2.7.5 (default, Apr 11 2018, 07:36:10) [GCC 4.8.5 20150623 (Red Hat 4.8.5-28)]
在 Ansible Playbook 里,loop 是一个强大的特性,它能够对列表、字典等数据结构进行迭代,从而让单个任务可以多次执行,下面为你详细介绍 loop 的语法和不同使用场景。
基本语法
loop 的基本使用形式是在任务中添加 loop 关键字,后面紧跟要迭代的数据结构。示例如下:
- name: 任务名称
模块名:
参数: "{{ item }}"
loop:
- 元素1
- 元素2
- 元素3
在这个结构中,item 是一个特殊的变量,它在每次迭代时会依次代表列表里的各个元素。
不同数据结构的使用
1. 列表迭代
当 loop 用于迭代列表时,item 会逐个获取列表中的元素。
---
- name: 安装多个软件包
hosts: all
become: true
tasks:
- name: 使用 loop 安装软件包
apt:
name: "{{ item }}"
state: present
loop:
- nginx
- mysql-server
- php-fpm
在这个例子中,apt 模块会依次安装 nginx、mysql-server 和 php-fpm 这三个软件包,每次迭代时 item 会分别代表一个软件包的名称。
2. 字典迭代
要是 loop 迭代的是字典,item 会代表字典中的每一个键值对。可以通过 item.key 和 item.value 来访问键和值。
---
- name: 配置多个服务的端口
hosts: all
become: true
vars:
services:
http: 80
https: 443
ssh: 22
tasks:
- name: 输出服务及其端口
debug:
msg: "服务 {{ item.key }} 的端口是 {{ item.value }}"
loop: "{{ services.items() }}"
这里,services.items() 把字典转换为键值对的列表,每次迭代时 item.key 是服务名称,item.value 是对应的端口号。
3. 嵌套列表迭代
对于嵌套列表,同样可以使用 loop 进行迭代。
---
- name: 嵌套列表迭代示例
hosts: all
tasks:
- name: 输出嵌套列表元素
debug:
msg: "外层元素: {{ item.0 }}, 内层元素: {{ item.1 }}"
loop:
- [1, 'a']
- [2, 'b']
- [3, 'c']
在这个例子中,item 代表每个子列表,item.0 是子列表的第一个元素,item.1 是第二个元素。
高级用法
1. 使用 with_ 系列(旧语法)
在较旧的 Ansible 版本中,使用 with_ 系列关键字来实现循环,不过现在推荐使用 loop。例如,with_items 等同于 loop。
---
- name: 使用 with_items 安装软件包
hosts: all
become: true
tasks:
- name: 安装软件包
apt:
name: "{{ item }}"
state: present
with_items:
- nginx
- mysql-server
- php-fpm
2. 结合过滤器使用
可以结合 Ansible 的过滤器来处理迭代的数据。例如,使用 product 过滤器进行嵌套循环。
---
- name: 使用 product 过滤器进行嵌套循环
hosts: all
vars:
users:
- user1
- user2
groups:
- group1
- group2
tasks:
- name: 输出用户和组的组合
debug:
msg: "用户 {{ item.0 }} 属于组 {{ item.1 }}"
loop: "{{ users | product(groups) | list }}"
product 过滤器会生成 users 和 groups 的所有可能组合,然后 loop 对这些组合进行迭代。
创建多个系统用户
需求,在nfs机器组中创建5个用户test1~5,且均设置密码yuchao666
比较low的写法,看着都头疼,但是没办法,语法就是这样
(添加、或是删除用户,区别在于state=absent)
---
- name: create user test1~5
hosts: nfs
tasks:
- name: create test1
user:
name: test1
state: absent
- name: create test2
user:
name: test2
state: absent
- name: create test3
user:
name: test3
state: absent
- name: create tes4
user:
name: test4
state: absent
- name: create test5
user:
name: test5
state: absent
循环创建用户
在 Ansible Playbook 中使用 loop 循环可以很方便地创建多个系统用户。以下是详细的实现步骤和示例代码。
实现思路
- 定义用户列表:在 Playbook 中定义一个包含多个用户信息的列表,每个用户信息可以包含用户名、密码、家目录等。
- 使用
loop循环:在创建用户的任务中使用loop关键字,对用户列表进行迭代,为每个用户执行创建操作。 - 使用
user模块:user模块是 Ansible 中用于管理系统用户的模块,可以通过该模块指定用户名、密码、家目录等参数来创建用户。
示例代码
---
- name: Create multiple system users using loop
hosts: all
become: true # 使用 sudo 权限执行任务
vars:
# 定义用户列表,每个元素是一个字典,包含用户信息
users:
- name: user1
password: "$6$rounds=656000$saltstring$hashedpassword1" # 使用 mkpasswd --method=sha-512 生成的哈希密码
comment: "Regular user 1"
- name: user2
password: "$6$rounds=656000$saltstring$hashedpassword2"
comment: "Regular user 2"
- name: user3
password: "$6$rounds=656000$saltstring$hashedpassword3"
comment: "Regular user 3"
tasks:
- name: Create users
user:
name: "{{ item.name }}"
password: "{{ item.password }}"
comment: "{{ item.comment }}"
state: present
createhome: yes # 为用户创建家目录
shell: /bin/bash # 设置用户的默认 shell
loop: "{{ users }}"
代码解释
vars部分:定义了一个名为users的变量,它是一个包含多个用户信息的列表。每个用户信息是一个字典,包含name(用户名)、password(用户密码的哈希值)和comment(用户注释)。tasks部分:name: Create users:任务的名称,用于描述该任务的作用。user模块:用于创建系统用户。name: "":指定要创建的用户名,item.name表示当前迭代的用户信息中的name字段。password: "":指定用户的密码,item.password表示当前迭代的用户信息中的password字段。comment: "":指定用户的注释,item.comment表示当前迭代的用户信息中的comment字段。state: present:表示确保用户存在。createhome: yes:表示为用户创建家目录。shell: /bin/bash:设置用户的默认 shell 为/bin/bash。loop: "":使用loop关键字对users列表进行迭代,为每个用户执行创建操作。
注意事项
- 密码哈希:在实际使用中,建议使用
mkpasswd --method=sha-512命令生成密码的哈希值,以确保密码的安全性。 - 权限问题:由于创建系统用户需要
sudo权限,因此在 Playbook 中使用了become: true。 - 用户唯一性:确保用户名在系统中是唯一的,避免重复创建用户。
执行 Playbook
将上述代码保存为一个 YAML 文件,例如 create_users.yml,然后使用以下命令执行 Playbook:
ansible-playbook create_users.yml
通过这种方式,你可以方便地使用 loop 循环创建多个系统用户。
循环删除用户
---
- name: create test1~5
hosts: nfs
tasks:
- name: create test1~5
user:
name: "{{ item }}"
state: absent
loop:
- test1
- test2
- test3
- test4
- test5
通过vars变量定义循环变量
上面会发现已然有重复的变量,还可以再简化
- 通过vars关键字定义用户列表,变量一般定义在任务开始之前
- 通过item关键字提取loop中每次循环的数据
循环创建用户且设置密码
---
- name: create user
hosts: nfs
vars:
users_list:
- test1
- test2
- test3
tasks:
- name: create user
user:
name: "{{ item }}"
state: present
loop: "{{ users_list }}"
- name: set password
shell: echo 'yuchao666' | passwd --stdin "{{ item }}"
loop: "{{ users_list }}"
循环处理字典数据
创建用户以及用户id号
low办法超哥就不再写了,太墨迹
循环字典数据如下,字典就是key:value这样的数据
字典用法,主要是根据key、获取value
---
- name: create user
hosts: nfs
tasks:
- name: create user and uid
user:
name: "{{ item.user }}"
uid: "{{ item.uid }}"
loop:
- {user: 'test1', uid: '2000'}
- {user: 'test2', uid: '2001'}
- {user: 'test3', uid: '2002'}
- {user: 'test4', uid: '2003'}
写法2:通过vars定义字典数据
- vars定义字典数据
- loop提供循环功能,通过item变量提取循环数据
---
- name: create user
hosts: nfs
vars:
users_list:
- {user: 'test1', uid: '2000'}
- {user: 'test2', uid: '2001'}
- {user: 'test3', uid: '2002'}
- {user: 'test4', uid: '2003'}
tasks:
- name: create user and uid
user:
name: "{{ item.user}}"
uid: "{{ item.uid }}"
loop: "{{ users_list }}"
案例
在 Ansible Playbook 里,你可以借助 loop 对字典数据进行循环处理。下面为你详细介绍不同场景下循环处理字典数据的方法和示例。
场景一:遍历字典的键值对
当你需要对字典中的每一个键值对进行操作时,可以采用以下方式。
示例代码
---
- name: Loop through dictionary key - value pairs
hosts: all
gather_facts: no
vars:
user_info:
name: John
age: 30
occupation: Engineer
tasks:
- name: Print key - value pairs
debug:
msg: "Key: {{ item.key }}, Value: {{ item.value }}"
loop: "{{ user_info.items() }}"
代码解释
- **`vars` 部分**:定义了一个名为 `user_info` 的字典,其中包含用户的姓名、年龄和职业信息。
- **`tasks` 部分**:
- `debug` 模块用于输出调试信息。
- `loop: "{{ user_info.items() }}"`:`items()` 方法会把字典转换为键值对的列表,这样 `loop` 就能对这些键值对进行迭代。
- `item.key` 和 `item.value`:在每次迭代时,`item` 代表一个键值对,通过 `item.key` 可以获取键,通过 `item.value` 可以获取值。
场景二:根据字典数据创建多个文件
假设你有一个字典,其中键表示文件名,值表示文件内容,你可以利用循环来创建这些文件。
示例代码
---
- name: Create files based on dictionary data
hosts: all
gather_facts: no
become: true
vars:
file_content:
file1.txt: "This is the content of file1."
file2.txt: "This is the content of file2."
file3.txt: "This is the content of file3."
tasks:
- name: Create files
copy:
content: "{{ item.value }}"
dest: "/tmp/{{ item.key }}"
loop: "{{ file_content.items() }}"
代码解释
vars部分:定义了一个名为file_content的字典,键为文件名,值为文件内容。tasks部分:copy模块用于将指定内容复制到目标文件。content: "":指定文件的内容为当前迭代的字典值。dest: "/tmp/":指定文件的目标路径,路径中的文件名是当前迭代的字典键。
场景三:根据字典数据配置多个服务
假设你有一个字典,包含多个服务的配置信息,你可以使用循环来配置这些服务。
示例代码
---
- name: Configure services based on dictionary data
hosts: all
gather_facts: no
become: true
vars:
service_config:
httpd:
state: started
enabled: yes
nginx:
state: stopped
enabled: no
tasks:
- name: Configure services
service:
name: "{{ item.key }}"
state: "{{ item.value.state }}"
enabled: "{{ item.value.enabled }}"
loop: "{{ service_config.items() }}"
代码解释
vars部分:定义了一个名为service_config的字典,键为服务名,值为包含服务状态和是否开机自启的子字典。tasks部分:service模块用于管理系统服务。name: "":指定要管理的服务名称。state: ""和enabled: "":分别指定服务的状态和是否开机自启,这些值从当前迭代的子字典中获取。
循环安装多个软件(yum基础环境安装)
在咱们期中综合架构开篇时,需要大家系统初始化,这个初始化步骤也是需要你做成ansible脚本的。
比如如下大量的基础软件,如何安装?
yum install -y tree wget bash-completion bash-completion-extras lrzsz net-tools sysstat iotop iftop htop unzip telnet ntpdate lsof
必然不能挨个的执行yum模块去安装,那得累死,循环写法如下
- name: yuchaoit.cn
hosts: nfs
remote_user: root
tasks:
- name: install basic packages
yum:
name: "{{ item }}"
state: installed
loop:
- tree
- wget
- bash-completion
- bash-completion-extras
- lrzsz
- net-tools
- sysstat
- iotop
- iftop
- htop
- unzip
- telnet
- ntpdate
- lsof
写法2:通过vars定义变量
- name: yuchaoit.cn
hosts: nfs
remote_user: root
vars:
basic_packages:
- tree
- wget
- bash-completion
- bash-completion-extras
- lrzsz
- net-tools
- sysstat
- iotop
- iftop
- htop
- unzip
- telnet
- ntpdate
- lsof
tasks:
- name: install basic packages
yum:
name: "{{ item }}"
state: installed
loop: "{{ basic_packages }}"
案例
在 Ansible Playbook 中,你可以使用 loop 来循环安装多个软件。以下分别针对不同操作系统家族(Debian 和 Red Hat)给出具体示例。
针对 Debian 系系统(如 Ubuntu)
示例 Playbook
---
- name: Install multiple packages on Debian systems
hosts: debian_servers
become: true
tasks:
- name: Install packages
apt:
name: "{{ item }}"
state: present
update_cache: yes
loop:
- nginx
- mysql-server
- php-fpm
代码解释
hosts:指定该 Playbook 要在哪些主机或主机组上执行,这里假设存在名为debian_servers的主机组。become: true:表示使用sudo权限执行任务,因为安装软件通常需要管理员权限。tasks:name:任务的描述性名称,方便在执行时识别。apt:Ansible 中用于在 Debian 系系统上管理软件包的模块。name: "":item是loop迭代时的变量,每次迭代会依次取loop列表中的元素作为软件包名称。state: present:确保软件包已安装。update_cache: yes:在安装软件包之前更新软件包缓存。loop:包含要安装的软件包名称的列表。
针对 Red Hat 系系统(如 CentOS)
示例 Playbook
---
- name: Install multiple packages on Red Hat systems
hosts: redhat_servers
become: true
tasks:
- name: Install packages
yum:
name: "{{ item }}"
state: present
loop:
- httpd
- mariadb-server
- php
代码解释
hosts:指定目标主机或主机组,这里假设存在名为redhat_servers的主机组。become: true:同样是为了获取管理员权限。tasks:name:任务名称。yum:Ansible 中用于在 Red Hat 系系统上管理软件包的模块。name: "":通过item变量迭代获取软件包名称。state: present:保证软件包已安装。loop:列出要安装的软件包。
通用示例(兼容不同系统)
示例 Playbook
---
- name: Install multiple packages on different systems
hosts: all
become: true
tasks:
- name: Install packages on Debian systems
apt:
name: "{{ item }}"
state: present
update_cache: yes
loop:
- nginx
- mysql-server
- php-fpm
when: ansible_os_family == "Debian"
- name: Install packages on Red Hat systems
yum:
name: "{{ item }}"
state: present
loop:
- httpd
- mariadb-server
- php
when: ansible_os_family == "RedHat"
代码解释
hosts: all:表示该 Playbook 会在所有主机上执行。when条件:根据目标主机的操作系统家族(通过ansible_os_family变量判断)来决定执行哪个安装任务。如果是 Debian 系系统,则执行apt模块的安装任务;如果是 Red Hat 系系统,则执行yum模块的安装任务。
你可以将上述 Playbook 保存为一个 .yml 文件,然后使用 ansible-playbook 命令来执行,例如:
ansible-playbook install_packages.yml
这样就能通过循环的方式在目标主机上安装多个软件包了。
rsync文件夹场景
比如部署nfs、rsync、nginx的综合剧本;
1.要安装多个软件
2.创建多个目录
3.复制多个目录
4.每个文件的权限都不一样
循环风格1:单行模式
比如rsync创建备份目录,有多个目录需要创建,普通的写法出现了诸多重复语句
- name: create data dir
file: path=/data state=directory owner=www group=www
- name: create backup dir
file: path=/backup state=directory owner=www group=www
循环风格2:缩进模式
上述创建备份目录的剧本语法,也可以用如下的缩进模式写,但是依然很多重复语句
- name: create data dir
file:
path: /data
state: directory
owner: www
group: www
- name: create backup dir
file:
path: /backup
state: directory
owner: www
group: www
改造为循环语句,使用yaml的缩进语法
- name: create data,backup dir
file:
path: "{{ item }}"
state: directory
owner: www
group: www
loop:
- /data
- /backup
循环风格3:混合语法
- 等号赋值语法
- 缩进语法
- name: create data backup
file: path="{{ item }}" state=directory owner=www group=www
loop:
- /data
- /backup
循环风格4:循环结合字典取值
比如rsync服务部署,需要创建多个文件夹,以及对应的权限设置
- name: yuchaoit.cn
hosts: backup
tasks:
- name: create_data
file:
path: "{{ item.file_path }}"
state: directory
owner: www
group: www
mode: "{{ item.mode }}"
loop:
- { file_path:'/data' ,mode:'755' }
- { file_path:'/backup' ,mode:'755' }
变量定义
官网文档
https://docs.ansible.com/ansible/latest/user_guide/playbooks_variables.html
在ansible中使用变量,能让我们的工作变得更加灵活,在ansible中,变量的使用方式有很多种,我们慢慢聊。
先说说怎样定义变量,变量名应该由字母、数字、下划线组成,变量名需要以字母开头,ansible内置的关键字不能作为变量名。
变量我们已经在循环知识中使用过了,主要通过vars关键字定义变量名、以及对应的变量值。
在 Ansible Playbook 中,变量是非常重要的特性,它可以让 Playbook 更加灵活和可复用。以下从变量的定义、作用域、优先级以及使用方法等方面详细介绍 Ansible Playbook 变量。
变量定义方式
1. 在 Playbook 中直接定义
可以在 Playbook 的 vars 部分直接定义变量。
---
- name: Use variables in playbook
hosts: all
vars:
app_port: 8080
app_name: "my_app"
tasks:
- name: Print variables
debug:
msg: "The application {{ app_name }} is running on port {{ app_port }}."
在这个例子中,app_port 和 app_name 是在 vars 部分定义的变量,然后在 debug 模块的 msg 参数中引用。
2. 在 Inventory 文件中定义
可以在 Ansible 的 Inventory 文件(如 /etc/ansible/hosts)中为特定的主机或主机组定义变量。
[webservers]
webserver1.example.com app_port=80
webserver2.example.com app_port=8080
[webservers:vars]
app_name="web_app"
这里为 webservers 主机组中的每个主机定义了 app_port 变量,同时为整个 webservers 主机组定义了 app_name 变量。在 Playbook 中可以直接使用这些变量。
3. 在单独的变量文件中定义
可以将变量定义在单独的 YAML 文件中,然后在 Playbook 中引用。
变量文件 vars.yml
app_port: 8080
app_name: "my_app"
Playbook
---
- name: Use variables from file
hosts: all
vars_files:
- vars.yml
tasks:
- name: Print variables
debug:
msg: "The application {{ app_name }} is running on port {{ app_port }}."
通过 vars_files 关键字引用变量文件。
4. 通过命令行传递变量
在执行 ansible-playbook 命令时,可以使用 -e 或 --extra-vars 选项传递变量。
ansible-playbook playbook.yml -e "app_port=8080 app_name=my_app"
在 Playbook 中可以直接使用这些传递的变量。
变量作用域
- 全局变量:在
group_vars/all或host_vars/all中定义的变量对所有主机和所有 Playbook 都有效。 - 组变量:在
group_vars目录下为特定主机组定义的变量,只对该主机组的主机有效。 - 主机变量:在
host_vars目录下为特定主机定义的变量,只对该主机有效。 - Play 变量:在 Playbook 的
vars部分定义的变量,只对当前 Play 有效。 - 任务变量:在任务中使用
vars关键字定义的变量,只对当前任务有效。
变量优先级
当同一个变量在不同的地方定义时,Ansible 会根据以下优先级来决定使用哪个值(从高到低):
- 命令行传递的变量(
-e或--extra-vars) - 任务变量
- Play 变量
- 主机变量
- 组变量
- 全局变量
变量使用方法
1. 在任务中引用变量
在任务的参数中可以使用双花括号 {{ }} 来引用变量。
---
- name: Use variable in task
hosts: all
vars:
package_name: "nginx"
tasks:
- name: Install package
apt:
name: "{{ package_name }}"
state: present
2. 在条件判断中使用变量
可以在 when 语句中使用变量进行条件判断。
---
- name: Conditional task based on variable
hosts: all
vars:
is_production: true
tasks:
- name: Restart service in production
service:
name: myservice
state: restarted
when: is_production
3. 变量的运算和过滤
可以对变量进行运算和使用过滤器来处理变量的值。
---
- name: Variable operation and filtering
hosts: all
vars:
num1: 10
num2: 20
tasks:
- name: Print sum of variables
debug:
msg: "The sum of {{ num1 }} and {{ num2 }} is {{ num1 + num2 }}"
- name: Print variable in uppercase
debug:
msg: "The uppercase of 'hello' is {{ 'hello' | upper }}"
在这个例子中,进行了变量的加法运算和字符串的大小写转换。
应用场景
1.通过自定义变量,可以在多个tasks中,通过变量名调用,取值
2.ansible在启动时,默认收集了客户端机器大量的静态属性(变量),可以提取该客户端的机器信息。
vars自定义变量
定义多个文件夹变量,创建rsync的数据目录,配置文件
- hosts: backup
vars:
data_path: /data
dest_path: /etc
config_path: /etc/rsync.passwd
tasks:
- name: 01 mkdir data dir
file:
path: "{{ data_path }}"
state: directory
- name: 02 copy config file
copy:
src: "{{ config_path }}"
dest: "{{ dest_path }}"
获取主机静态属性(ip地址)
内置获取ip的变量
ansible_all_ipv4_addresses #适用于多ip
ansible_default_ipv4.address #适用单ip
剧本
[root@master-61 ~]#cat get_ip.yaml
- hosts: web
tasks:
- name: 01 get ip address
debug: msg="该web组机器,ip是 {{ ansible_all_ipv4_addresses }}"
- name: 02 get hostname
debug: msg="该web组,主机名是 {{ ansible_hostname }}"
- name: 03 单ip
debug: msg="{{ansible_default_ipv4.address }}"
- name: 04 eth0 ip地址是
debug: msg="{{ansible_facts.eth0.ipv4.address}}"
- name: 05 eth1 ip地址是
debug: msg="{{ansible_facts.eth1.ipv4.address}}"
完整的ansible内置变量手册
https://docs.ansible.com/ansible/latest/user_guide/playbooks_vars_facts.html
通过setup模块可以看到所有的内置变量,提取变量的值需要遵循python的数据类型语法,如列表还是字典取值
[root@master-61 ~]#ansible web -m ansible.builtin.setup |wc -l
主机清单文件中也用到了变量
1.主机清单文件中定义变量
[root@master-61 ~]#tail -20 /etc/ansible/hosts
[all:vars]
ansible_port=22999
#ansible_user=root
#ansible_password=123123
[web:vars]
nginx_version='1.19'
[web]
172.16.1.7 port=22999
172.16.1.8 port=22999
172.16.1.9 port=22999
[nfs]
172.16.1.31
[backup]
172.16.1.41
2.只要操作该主机组,即可使用该变量
- hosts: web
tasks:
- name: 01 get nginx port
debug: msg="nginx port is {{port}}"
- name: 02 get nginx version
debug: msg="nginx version is {{nginx_version}}"
执行
[root@master-61 ~]#ansible-playbook get_nginx.yaml
loop循环中引用变量
- hosts: backup
tasks:
vars: rsyncd_config=/script/rsyncd.conf rsyncd_pwd=/script/rsync.passwd
tasks:
- name: 01 copy config
copy:
src: "{{ item.src }}"
dest: "{{ item.dest }}"
mode: "{{ item.mode }}"
loop:
- {src:"{{ rsyncd_config }}",dest:"/etc/",mode:'0644'}
- {src:"{{ rsyncd_pwd }}",dest:"/etc/",mode:'0600'}
注册变量
在 Ansible Playbook 里,注册变量(Registered Variables)是一项非常实用的功能。借助它,你能够捕获某个任务的执行结果,并将这些结果存储到一个变量中,方便在后续的任务里使用。以下为你详细介绍注册变量的用法、应用场景和示例。
基本语法
要注册一个变量,需要在任务中使用 register 关键字,后面紧跟变量的名称。示例如下:
- name: 执行命令并注册结果
command: ls -l /tmp
register: command_output
在这个例子中,command 模块执行 ls -l /tmp 命令,执行结果会被存储到 command_output 变量里。
注册变量的结构
注册变量通常是一个字典,包含多个键值对,常见的键有:
changed:一个布尔值,表明任务是否对目标主机的状态产生了改变。stdout:命令执行后的标准输出内容,以字符串形式呈现。stderr:命令执行后的错误输出内容,以字符串形式呈现。rc:命令执行后的返回码,0通常表示命令成功执行,非0则表示有错误发生。
示例
1. 简单示例
---
- name: 使用注册变量示例
hosts: all
tasks:
- name: 执行命令并注册结果
command: ls -l /tmp
register: command_output
- name: 输出命令执行结果
debug:
var: command_output
- name: 输出标准输出内容
debug:
msg: "命令的标准输出是: {{ command_output.stdout }}"
在这个示例中,第一个任务执行 ls -l /tmp 命令,并把结果注册到 command_output 变量中。第二个任务使用 debug 模块输出整个 command_output 变量的内容,第三个任务则只输出 stdout 键的值。
2. 基于注册变量进行条件判断
---
- name: 基于注册变量进行条件判断
hosts: all
tasks:
- name: 检查文件是否存在
stat:
path: /etc/passwd
register: file_status
- name: 若文件存在则输出信息
debug:
msg: "/etc/passwd 文件存在"
when: file_status.stat.exists
在这个示例中,stat 模块用于检查 /etc/passwd 文件是否存在,结果被注册到 file_status 变量中。后续任务根据 file_status.stat.exists 的值进行条件判断,若文件存在则输出相应信息。
3. 循环结合注册变量
---
- name: 循环结合注册变量
hosts: all
tasks:
- name: 循环执行命令并注册结果
command: echo "{{ item }}"
loop:
- "Hello"
- "World"
register: loop_output
- name: 输出每次循环的结果
debug:
msg: "第 {{ item.loop_index }} 次循环的输出是: {{ item.stdout }}"
loop: "{{ loop_output.results }}"
在这个示例中,command 模块在循环中执行 echo 命令,每次循环的结果都会被注册到 loop_output 变量中。loop_output.results 是一个包含每次循环结果的列表,后续任务对这个列表进行循环,输出每次循环的标准输出内容。
注意事项
- 数据类型和结构:要清楚注册变量的数据类型和结构,这样才能正确地访问其中的值。
- 错误处理:在使用注册变量进行条件判断或后续操作时,要考虑可能出现的错误情况,例如命令执行失败时返回码和输出内容的处理。
使用场景
调试,回显命令的执行结果
把状态保存为变量,其他task再继续调用
用内置变量获取IP地址写入文件,并且显示文件内容
- hosts: nfs
tasks:
- name: echo ip address
shell: "echo {{ ansible_default_ipv4.address }} >> /tmp/ip.log"
- name: cat ip.log
shell: "cat /tmp/ip.log"
register: about_ip_log
- name: debug about_ip_log
debug:
msg: "{{ about_ip_log.stdout_lines }}"
注册多个变量
同时记录且显示客户端的ip信息、主机名信息
结合循环知识,打印多个命令的结果
- name: yuchaoit.cn
hosts: nfs
tasks:
- name: 01 get ip
shell: "echo {{ ansible_default_ipv4.address }} > /tmp/ip.log"
- name: 02 get hostname
shell: "echo {{ ansible_hostname }} > /tmp/hostname.log"
- name: 03 echo hostname
shell: "cat /tmp/hostname.log"
register: hostname_log
- name: 04 echo ip
shell: "cat /tmp/ip.log"
register: ip_log
- name: 05 show mount info
shell: "showmount -e 172.16.1.31"
register: showmount_log
- debug:
msg: "{{item}}"
loop:
- "{{ showmount_log.stdout_lines}}"
- "{{ ip_log.stdout_lines}}"
- "{{ hostname_log.stdout_lines}}"
判断当配置文件变化后,就重启服务
我们重启配置服务的标准是,修改了配置文件,否则无须重启
例如,判断rsyncd.conf文件状态发生变化后,就重启服务。
- name: yuchaoit.cn
hosts: backup
tasks:
- name: 01 copy rsyncd.conf
copy: src=/script/rsyncd.conf dest=/etc/
register: conf_status
- name: 02 start rsyncd.service
systemd: name=rsyncd state=started enabled=yes
- name: 03 restart rsyncd.service
systemd:
name: rsyncd
state: restarted
when: conf_status.changed
查看rsync进程端口是否更新,即为rsyncd服务是否重启
[root@master-61 ~]#ansible backup -m shell -a "netstat -tunlp|grep rsync"
172.16.1.41 | CHANGED | rc=0 >>
tcp 0 0 0.0.0.0:873 0.0.0.0:* LISTEN 635/rsync
tcp6 0 0 :::873 :::* LISTEN 635/rsync
修改rsyncd.conf,再次执行剧本
[root@master-61 ~]#ansible backup -m shell -a "netstat -tunlp|grep rsync"
172.16.1.41 | CHANGED | rc=0 >>
tcp 0 0 0.0.0.0:873 0.0.0.0:* LISTEN 8274/rsync
tcp6 0 0 :::873 :::* LISTEN 8274/rsync
when条件判断语句
文档
https://docs.ansible.com/ansible/latest/user_guide/playbooks_conditionals.html
在 Ansible Playbook 中,when 语句是一个非常重要的特性,它允许你根据特定条件来决定是否执行某个任务。以下将从基本语法、常见使用场景、示例代码等方面详细介绍 when 语句。
基本语法
when 语句通常放在任务的定义中,其基本形式如下:
- name: 任务名称
模块名:
参数: 值
when: 条件表达式
其中,条件表达式 是一个布尔表达式,当该表达式的值为 true 时,任务会被执行;当值为 false 时,任务会被跳过。
常见使用场景及示例
1. 根据目标主机的操作系统类型执行任务
---
- name: Install package based on OS family
hosts: all
become: true
tasks:
- name: Install Apache on Debian systems
apt:
name: apache2
state: present
when: ansible_os_family == "Debian"
- name: Install Apache on Red Hat systems
yum:
name: httpd
state: present
when: ansible_os_family == "RedHat"
在这个示例中,ansible_os_family 是 Ansible 自动收集的目标主机操作系统家族信息。根据这个信息,使用 when 语句判断目标主机是 Debian 系还是 Red Hat 系,然后执行相应的软件包安装任务。
2. 根据变量的值执行任务
---
- name: Conditional task based on variable
hosts: all
vars:
is_production: true
tasks:
- name: Restart service in production
service:
name: myservice
state: restarted
when: is_production
这里定义了一个变量 is_production,并在任务的 when 语句中使用该变量进行判断。如果 is_production 的值为 true,则执行重启服务的任务;否则,跳过该任务。
3. 根据注册变量的值执行任务
---
- name: Conditional task based on registered variable
hosts: all
tasks:
- name: Check if file exists
stat:
path: /etc/passwd
register: file_status
- name: Print message if file exists
debug:
msg: "/etc/passwd file exists"
when: file_status.stat.exists
在这个示例中,首先使用 stat 模块检查 /etc/passwd 文件是否存在,并将结果注册到 file_status 变量中。然后,在后续任务的 when 语句中,根据 file_status.stat.exists 的值判断文件是否存在,如果存在则输出相应的消息。
4. 多条件判断
when 语句支持使用逻辑运算符(如 and、or、not)进行多条件判断。
---
- name: Multi - condition task
hosts: all
vars:
is_production: true
has_sufficient_memory: true
tasks:
- name: Perform action if conditions are met
command: /path/to/command
when: is_production and has_sufficient_memory
这里使用 and 运算符将两个条件组合起来,只有当 is_production 和 has_sufficient_memory 的值都为 true 时,才会执行任务。
注意事项
- 变量引用:在
when语句中引用变量时,不需要使用双花括号 ,因为when语句本身就是一个表达式上下文。 - 语法正确性:确保
when语句中的条件表达式语法正确,否则可能会导致任务执行逻辑出错。
通过使用 when 语句,你可以根据不同的条件灵活控制 Ansible Playbook 中任务的执行,从而实现更复杂的自动化场景。
使用场景
判断nfs配置文件是否存在
1.存在,则显示其文件内容
2.不存在,则输出 /etc/exports is not exists。
答案
- name: yuchaoit.cn
hosts: nfs
vars:
nfs_file: /etc/exports
tasks:
- name: 01 check nfs config
shell: "cat {{nfs_file}}"
register: nfs_result
ignore_errors: true
- name: 02 debug nfs config
debug:
msg: "{{ansible_hostname}} has {{nfs_file}},file content is : {{nfs_result.stdout}}"
when: nfs_result is success
- name: 03 debug nfs not exists
debug: msg="{{nfs_file}} is not exists."
when: nfs_result is failed
高级特性handler
官网文档
https://docs.ansible.com/ansible/latest/user_guide/playbooks_handlers.html
Handlers: running operations on change
处理程序:对更改运行操作
在 Ansible Playbook 里,handler(处理程序)是一项关键特性,它能够让你在特定任务的执行结果满足条件时,触发相应的操作,最常见的应用场景是在配置文件发生变更后重启服务。下面为你详细介绍 handler 的概念、使用方法、工作原理以及示例。
概念
handler 本质上是一种特殊的任务,只有在其他任务通过 notify 关键字对其进行通知时才会被执行。而且,handler 会在当前 Play 里所有任务都执行完毕之后统一执行,就算有多个任务都通知了同一个 handler,该 handler 也仅会执行一次。
使用方法
定义 handler
handler 通常在 Playbook 的 handlers 部分进行定义,其语法格式和普通任务类似。示例如下:
handlers:
- name: Restart Nginx service
service:
name: nginx
state: restarted
在这个例子中,定义了一个名为 Restart Nginx service 的 handler,其作用是重启 nginx 服务。
通知 handler
在普通任务中,使用 notify 关键字来通知 handler。示例如下:
tasks:
- name: Copy Nginx configuration file
copy:
src: nginx.conf
dest: /etc/nginx/nginx.conf
mode: '0644'
notify:
- Restart Nginx service
这里的 copy 任务负责复制 nginx 配置文件,当该任务的执行结果为 changed(即配置文件被修改)时,会通知名为 Restart Nginx service 的 handler。
工作原理
- 任务执行:Ansible 按照
Playbook中定义的顺序依次执行各个任务。 - 状态检测:每个任务执行完毕后,Ansible 会检查其执行结果是否导致目标主机的状态发生改变。如果发生改变,任务状态会被标记为
changed。 - 通知
handler:当任务的状态为changed且使用了notify关键字时,会记录要通知的handler。 handler执行:在当前Play里所有任务都执行完毕后,Ansible 会统一执行被通知的handler。
示例
以下是一个完整的 Playbook 示例,展示了如何使用 handler 在 Nginx 配置文件变更后重启 Nginx 服务。
---
- name: Manage Nginx service and configuration
hosts: webservers
become: true # 使用 sudo 权限执行任务
tasks:
- name: Copy Nginx configuration file
copy:
src: nginx.conf
dest: /etc/nginx/nginx.conf
mode: '0644'
notify:
- Restart Nginx service
handlers:
- name: Restart Nginx service
service:
name: nginx
state: restarted
注意事项
handler名称:notify中指定的handler名称必须和handlers部分定义的名称完全一致,否则handler不会被触发。- 执行时机:
handler会在当前Play中所有任务执行完毕后执行,而不是在通知它的任务执行后立即执行。 - 权限问题:由于重启服务等操作通常需要管理员权限,所以在
Playbook中可能需要使用become: true来获取相应权限。
通过合理运用 handler,可以有效地管理系统服务,确保在配置文件变更等情况下及时更新服务状态。
handler这个机制一般用于服务状态管理,如
- 你在tasks中修改了nginx的配置文件,你就必须得重启nginx服务,才能生效
handler解决什么问题
1.现状、配置文件修改了,程序不可能自己重启,得手动restart
利用handler添加在剧本中,实现效果
1.配置文件没变化,就不执行restart重启
2.配置文件发生了变化,就执行restart重启
在 Ansible Playbook 里,要实现当配置文件发生变化后就重启服务,可以借助 Ansible 的 handlers(处理程序)和 notify(通知)机制。下面为你详细介绍实现步骤和示例代码。
实现思路
- 复制或修改配置文件:使用
copy或者template模块来复制或修改目标主机上的配置文件。 - 检测文件变化:当配置文件被修改时,Ansible 会将该任务标记为
changed。 - 使用
notify通知处理程序:在复制或修改配置文件的任务中,使用notify关键字指定一个处理程序。 - 定义处理程序:在
handlers部分定义一个处理程序,用于重启服务。当notify被触发时,这个处理程序会被执行。
示例代码
以下是一个具体的示例,假设要管理 Nginx 服务,当 Nginx 配置文件发生变化时,就重启 Nginx 服务。
---
- name: Manage Nginx service and configuration
hosts: webservers
become: true # 使用 sudo 权限执行任务
tasks:
- name: Copy Nginx configuration file
copy:
src: nginx.conf
dest: /etc/nginx/nginx.conf
mode: '0644'
notify:
- Restart Nginx service
handlers:
- name: Restart Nginx service
service:
name: nginx
state: restarted
代码解释
tasks部分:name: Copy Nginx configuration file:任务的名称,用于描述该任务的作用。copy模块:用于将本地的nginx.conf文件复制到目标主机的/etc/nginx/nginx.conf路径下,并设置文件权限为0644。notify: - Restart Nginx service:当这个任务的执行结果为changed(即配置文件被修改)时,会通知名为Restart Nginx service的处理程序。
handlers部分:name: Restart Nginx service:处理程序的名称,要和notify中指定的名称一致。service模块:用于管理系统服务,这里将nginx服务的状态设置为restarted,即重启服务。
注意事项
- 处理程序的执行时机:处理程序会在当前 Play 中所有任务执行完毕后统一执行。也就是说,如果多个任务都通知了同一个处理程序,该处理程序只会执行一次。
- 权限问题:由于重启服务通常需要管理员权限,所以在 Playbook 中使用了
become: true。确保 Ansible 控制节点在目标主机上有足够的权限来执行这些操作。 - 服务名称:要根据目标主机的实际情况确保服务名称(如
nginx)的正确性。不同的操作系统可能对服务名称的命名有所不同。
通过上述方法,你可以在 Ansible Playbook 中实现当配置文件变化后自动重启服务的功能。
low办法实现
[root@master-61 ~]#cat restart_rsync.yaml
- name: yuchaoit.cn
hosts: backup
remote_user: root
tasks:
- name: copy rsyncd.conf
copy:
src=/script/rsyncd.conf
dest=/etc/
- name: restart rsyncd.service
systemd:
name=rsyncd
state=restarted
你会发现,这个用法,无论你配置文化改没改,都必然会执行重启的task,这个写法就不太合理。
改造为handler
1.handlers中的任务会被tasks调用
2.只有tasks的确执行了,发生了change状态,handler才会执行
3.在tasks任务列表中,定义notify属性,用于触发handler的执行
剧本
- name: yuchaoit.cn
hosts: backup
remote_user: root
tasks:
- name: 01 copy rsyncd.conf
copy:
src=/script/rsyncd.conf
dest=/etc/
notify:
- restart rsyncd.service
handlers:
- name: restart rsyncd.service
systemd:
name: rsyncd
state: restarted
细节注意
1.handlers必须写在结尾
2.handlers定义的任务名字,必须和notify一致
给task打上tag标签
在 Ansible Playbook 中,tag(标签)是一个非常实用的特性,它允许你选择性地执行 Playbook 中的部分任务,而不是执行整个 Playbook。以下详细介绍 tag 的使用方法、应用场景及示例。
基本语法
在任务定义中,可以使用 tags 关键字为任务添加一个或多个标签。示例如下:
- name: Task with tag
apt:
name: nginx
state: present
tags:
- install
- webserver
在这个任务中,为其添加了 install 和 webserver 两个标签。
使用 tag 执行部分任务
当执行 ansible-playbook 命令时,可以使用 --tags 选项指定要执行的标签,使用 --skip-tags 选项指定要跳过的标签。
执行指定标签的任务
ansible-playbook playbook.yml --tags "install"
这会执行 playbook.yml 中所有带有 install 标签的任务。
跳过指定标签的任务
ansible-playbook playbook.yml --skip-tags "webserver"
这会执行 playbook.yml 中除了带有 webserver 标签之外的所有任务。
应用场景
1. 分阶段执行任务
假设一个 Playbook 包含安装、配置和启动服务三个阶段的任务,你可以为每个阶段的任务添加不同的标签,以便根据需要分阶段执行。
---
- name: Manage web server
hosts: webservers
become: true
tasks:
- name: Install web server
apt:
name: nginx
state: present
tags:
- install
- name: Configure web server
copy:
src: nginx.conf
dest: /etc/nginx/nginx.conf
tags:
- configure
- name: Start web server
service:
name: nginx
state: started
tags:
- start
如果你只想安装服务,可以执行:
ansible-playbook playbook.yml --tags "install"
如果你已经完成了安装和配置,只想启动服务,可以执行:
ansible-playbook playbook.yml --tags "start"
2. 调试和测试
在开发和调试 Playbook 时,你可能只想执行部分任务来验证其功能。通过为这些任务添加特定的标签,可以方便地进行测试。
---
- name: Test task
hosts: all
tasks:
- name: Task for testing
debug:
msg: "This is a test task."
tags:
- test
执行以下命令只运行测试任务:
ansible-playbook playbook.yml --tags "test"
3. 维护和更新
在对系统进行维护或更新时,可能只需要执行部分相关任务。例如,只更新配置文件而不重新安装软件。
---
- name: Update web server configuration
hosts: webservers
become: true
tasks:
- name: Install web server
apt:
name: nginx
state: present
tags:
- install
- name: Update web server configuration
copy:
src: new_nginx.conf
dest: /etc/nginx/nginx.conf
tags:
- update_config
- name: Restart web server
service:
name: nginx
state: restarted
tags:
- restart
若要只更新配置文件并重启服务,可以执行:
ansible-playbook playbook.yml --tags "update_config,restart"
注意事项
- 标签的命名:标签名应具有描述性,方便识别和管理。
- 标签的继承:如果一个
role中的任务有标签,在 Playbook 中使用该role时,这些标签也会被继承。
通过使用 tag,可以提高 Playbook 的灵活性和可维护性,根据不同的需求灵活执行部分任务。
你写了一个很长的playbook,其中有很多的任务,这并没有什么问题,不过在实际使用这个剧本时,你可能只是想要执行其中的一部分任务而已
或者,你只想要执行其中一类任务而已,而并非想要执行整个剧本中的全部任务
这个时候我们该怎么办呢?我们可以借助tags实现这个需求。
见名知义,tags可以帮助我们对任务进行'打标签'
当任务存在标签以后,我们就可以在执行playbook时,借助标签,指定执行哪些任务,或者指定不执行哪些任务了。
tag作用
调试,选择性的执行某个task
1.部署nfs-server剧本参考
- name: yuchaoit.cn
hosts: nfs
tasks:
- name: 01 安装nfs-utils 服务
yum: name=nfs-utils state=installed
tags: 01_install_nfs_service
- name: 02 安装rpcbind 服务
yum: name=rpcbind state=installed
tags: 02_install_rpcbind_service
- name: 03 创建组
group: name=www gid=666
tags: 03_add_group
- name: 04 创建用户
user: name=www uid=666 group=www create_home=no shell=/sbin/nologin
tags: 04_add_user
- name: 05 创建共享目录
file: path=/data owner=www group=www state=directory
tags: 05_create_data_dir
- name: 06 拷贝配置文件
copy: src=/script/exports dest=/etc/exports
tags: 06_copy_nfs_exports
- name: 07 创建关于rsync密码文件
copy: content='yuchao666' dest=/etc/rsync.passwd mode=600
tags: 07_create_rsync_passwd
- name: 08 启动rpcbind
service: name=rpcbind state=started enabled=yes
tags: 08_start_rpcbind
- name: 09 启动nfs
systemd: name=nfs state=started enabled=yes
tags: 09_start_nfs
2.打印剧本中可用的标签
也就是你可以直接选择执行哪些任务
[root@master-61 ~]#ansible-playbook --list-tags tag_nfs.yaml
playbook: tag_nfs.yaml
play #1 (nfs): yuchaoit.cn TAGS: []
TASK TAGS: [01_install_nfs_service, 02_install_rpcbind_service, 03_add_group, 04_add_user, 05_create_data_dir, 06_copy_nfs_exports, 07_create_rsync_passwd, 08_start_rpcbind, 09_start_nfs]
3.指定运行某个标签
[root@master-61 ~]#ansible-playbook -t 01_install_nfs_service tag_nfs.yaml
[root@master-61 ~]#ansible-playbook -t 04_add_user tag_nfs.yaml
4.指定运行多个标签
[root@master-61 ~]#ansible-playbook -t 01_install_nfs_service,05_create_data_dir,04_add_user tag_nfs.yaml
5.指定不运行一个/多个标签
[root@master-61 ~]#ansible-playbook --skip-tags 01_install_nfs_service,05_create_data_dir,04_add_user tag_nfs.yaml
选择tasks执行
使用场景
1.调试剧本时,task数量太多,不想从头执行,可以指定执行位置
查看task列表
[root@master-61 ~]#ansible-playbook --list-tasks tag_nfs.yaml
playbook: tag_nfs.yaml
play #1 (nfs): yuchaoit.cn TAGS: []
tasks:
01 安装nfs-utils 服务 TAGS: [01_install_nfs_service]
02 安装rpcbind 服务 TAGS: [02_install_rpcbind_service]
03 创建组 TAGS: [03_add_group]
04 创建用户 TAGS: [04_add_user]
05 创建共享目录 TAGS: [05_create_data_dir]
06 拷贝配置文件 TAGS: [06_copy_nfs_exports]
07 创建关于rsync密码文件 TAGS: [07_create_rsync_passwd]
08 启动rpcbind TAGS: [08_start_rpcbind]
09 启动nfs TAGS: [09_start_nfs]
选择执行的task位置
从第五步骤开始
[root@master-61 ~]#ansible-playbook --start-at-task '05 创建共享目录' tag_nfs.yaml
总结(playbook规范流程)
通过这个流程,去编写、检验、阅读所有的playbook都是一个靠谱的办法
无论是你自己写好剧本,进行校验
还是工作后,先看公司里现成的剧本,进行维护,都可以基于这个思路
1.检查剧本语法
如果语法不对,ansible会具体告诉你错误的位置
[root@master-61 ~]#ansible-playbook --syntax-check tag_nfs.yaml
playbook: tag_nfs.yaml
2.检查该剧本操作的主机有哪些
搞清楚这个剧本会影响到哪些主机,关乎于这些机器的作用
[root@master-61 ~]#ansible-playbook --list-hosts get_ip.yaml
playbook: get_ip.yaml
play #1 (web): web TAGS: []
pattern: [u'web']
hosts (3):
172.16.1.7
172.16.1.8
172.16.1.9
3.查看剧本有哪些任务
轻松的搞清楚这个剧本有什么作用,整体的工作流程
[root@master-61 ~]#ansible-playbook --list-tasks tag_nfs.yaml
playbook: tag_nfs.yaml
play #1 (nfs): yuchaoit.cn TAGS: []
tasks:
01 安装nfs-utils 服务 TAGS: [01_install_nfs_service]
02 安装rpcbind 服务 TAGS: [02_install_rpcbind_service]
03 创建组 TAGS: [03_add_group]
04 创建用户 TAGS: [04_add_user]
05 创建共享目录 TAGS: [05_create_data_dir]
06 拷贝配置文件 TAGS: [06_copy_nfs_exports]
07 创建关于rsync密码文件 TAGS: [07_create_rsync_passwd]
08 启动rpcbind TAGS: [08_start_rpcbind]
09 启动nfs TAGS: [09_start_nfs]
4.模拟剧本执行
模拟执行,查看执行流程是否存在错误,以及执行的状态
[root@master-61 ~]#ansible-playbook -C tag_nfs.yaml
5.真正执行剧本
对目标机器发生实质性的改变、修改操作
[root@master-61 ~]#ansible-playbook tag_nfs.yaml
ansible剧本大作业(吐血提醒)
等你坐在访客室、开始1v1和面试官交流面试
你就会回想起,当初于超老师让我好好学ansible,结合备份同步访问写剧本,以及让我锻炼口述能力,叙述架构流程的重要性,悔不当初啊!!
以及面试官问你
ansible熟悉吗?写下你用过的哪些模块?
用过ansible高级特性吗?说一说有哪些
你心中一万个羊驼。。。超哥当时怎么教来着,我为什么没好好做作业,害!
使用学过的模块
如
shell
copy
file
group
user
script
yum
systemd
等
尽量结合剧本高级特性
使用高级特性,是为了简化脚本写法,提升可维护性,同时也会提升阅读难度,需要额外学习。
循环 loop
变量 vars
注册变量 register
条件语句 when
触发任务 handler
标签tag
综合练习
继续改造 ,完全改造为ansible-playbook 一键部署
rsync
nfs
lsyncd
nginx
Nginx综合案例
以下是一个基于 Ubuntu 系统,使用 Ansible 完成 Nginx 部署的 Playbook,综合运用了你所提到的模块(shell、copy、file、group、user、script、yum 这里替换为 apt 因为是 Ubuntu 系统、systemd)以及高级特性(loop、vars、register、when、handler)。
需求概述
在 Ubuntu 目标主机上部署并配置 Nginx,涵盖创建 Nginx 用户和组、安装 Nginx、复制配置文件、启动并管理 Nginx 服务等步骤。
Playbook 代码
---
- name: Deploy and Configure Nginx on Ubuntu
hosts: ubuntu_web_servers
become: true
vars:
nginx_user: www-data
nginx_group: www-data
nginx_config_dir: /etc/nginx
nginx_log_dir: /var/log/nginx
nginx_conf_file: nginx.conf
nginx_sites_available: /etc/nginx/sites-available
nginx_sites_enabled: /etc/nginx/sites-enabled
nginx_site_name: default
nginx_service_name: nginx
tasks:
- name: Ensure nginx group exists
group:
name: "{{ nginx_group }}"
state: present
- name: Ensure nginx user exists
user:
name: "{{ nginx_user }}"
group: "{{ nginx_group }}"
home: /var/www
createhome: no
state: present
- name: Update apt cache
apt:
update_cache: yes
cache_valid_time: 3600
- name: Install Nginx
apt:
name: nginx
state: present
- name: Create Nginx log directory
file:
path: "{{ nginx_log_dir }}"
state: directory
owner: "{{ nginx_user }}"
group: "{{ nginx_group }}"
mode: '0755'
- name: Create Nginx sites-available and sites-enabled directories
file:
path: "{{ item }}"
state: directory
owner: root
group: root
mode: '0755'
loop:
- "{{ nginx_sites_available }}"
- "{{ nginx_sites_enabled }}"
- name: Copy Nginx main configuration file
copy:
src: "{{ nginx_conf_file }}"
dest: "{{ nginx_config_dir }}/{{ nginx_conf_file }}"
owner: root
group: root
mode: '0644'
notify:
- Reload Nginx configuration
- name: Copy Nginx site configuration file
copy:
src: "{{ nginx_site_name }}"
dest: "{{ nginx_sites_available }}/{{ nginx_site_name }}"
owner: root
group: root
mode: '0644'
notify:
- Reload Nginx configuration
- name: Create symbolic link for the site configuration
file:
src: "{{ nginx_sites_available }}/{{ nginx_site_name }}"
dest: "{{ nginx_sites_enabled }}/{{ nginx_site_name }}"
state: link
notify:
- Reload Nginx configuration
- name: Check if Nginx service is running
shell: systemctl is-active {{ nginx_service_name }}
register: nginx_service_status
ignore_errors: true
- name: Start and enable Nginx service
systemd:
name: "{{ nginx_service_name }}"
state: started
enabled: yes
when: nginx_service_status.rc != 0
handlers:
- name: Reload Nginx configuration
systemd:
name: "{{ nginx_service_name }}"
state: reloaded
listen: "Reload Nginx configuration"
详细解释
1. vars 部分
- 定义了一系列变量,用于在后续任务中引用。
nginx_user和nginx_group:通常 Ubuntu 上 Nginx 默认使用www-data用户和组。nginx_config_dir:Nginx 配置文件所在目录。nginx_log_dir:Nginx 日志文件所在目录。nginx_conf_file:Nginx 主配置文件名称。nginx_sites_available和nginx_sites_enabled:Nginx 虚拟主机配置文件目录。nginx_site_name:虚拟主机配置文件名称。nginx_service_name:Nginx 服务名称。
2. tasks 部分
- 用户和组管理:
- 使用
group模块确保nginx_group存在。 - 使用
user模块确保nginx_user存在,并将其归属到nginx_group。
- 使用
- 软件安装:
- 使用
apt模块更新软件包缓存,cache_valid_time设定缓存有效期为 3600 秒(1 小时)。 - 继续使用
apt模块安装 Nginx。
- 使用
- 目录创建:
- 使用
file模块创建 Nginx 日志目录,并设置正确的用户、组和权限。 - 利用
loop特性,使用file模块创建sites-available和sites-enabled目录。
- 使用
- 配置文件复制:
- 使用
copy模块复制 Nginx 主配置文件和虚拟主机配置文件到目标位置,同时使用notify关键字通知handler在配置文件有变化时重新加载 Nginx 配置。
- 使用
- 符号链接创建:使用
file模块为虚拟主机配置文件创建符号链接,并通知handler。 - 服务状态检查与启动:
- 使用
shell模块检查 Nginx 服务是否正在运行,并将结果注册到nginx_service_status变量中。 - 使用
systemd模块,结合when条件判断,如果服务未运行则启动并设置为开机自启。
- 使用
3. handlers 部分
- 重新加载 Nginx 配置:当配置文件发生变化时,
handler会接收到notify通知,使用systemd模块重新加载 Nginx 服务配置。
使用说明
- 准备工作
- 确保
ubuntu_web_servers主机组在 Ansible 清单文件中正确定义。 - 在本地准备好
nginx.conf和default配置文件。
- 确保
- 执行 Playbook
ansible-playbook playbook.yml
通过这个案例,你可以综合运用 Ansible 的模块和高级特性完成 Ubuntu 系统上 Nginx 的部署和配置。