第五章:Playbook 剧本¶
什么是 Playbook?¶
Playbook 是 Ansible 的核心概念,是用 YAML 格式编写的自动化剧本,定义了一系列要在目标主机上执行的任务。
基本结构¶
简单示例¶
- name: Install and configure nginx
hosts: webservers
become: yes
tasks:
- name: Install nginx
ansible.builtin.apt:
name: nginx
state: present
update_cache: yes
- name: Start nginx
ansible.builtin.service:
name: nginx
state: started
enabled: yes
- name: Copy index.html
ansible.builtin.copy:
src: index.html
dest: /var/www/html/index.html
mode: '0644'
Playbook 语法¶
Play 定义¶
- name: 第一个 Play
hosts: webservers
remote_user: admin
become: yes
become_method: sudo
become_user: root
gather_facts: yes
tasks:
- name: Task 1
...
- name: 第二个 Play
hosts: dbservers
become: yes
tasks:
- name: Task 1
...
任务定义¶
tasks:
# 基本任务
- name: Install nginx
ansible.builtin.apt:
name: nginx
state: present
# 带条件的任务
- name: Install nginx on Ubuntu
ansible.builtin.apt:
name: nginx
state: present
when: ansible_distribution == "Ubuntu"
# 带循环的任务
- name: Install multiple packages
ansible.builtin.apt:
name: "{{ item }}"
state: present
loop:
- nginx
- vim
- git
# 带标签的任务
- name: Install nginx
ansible.builtin.apt:
name: nginx
state: present
tags:
- install
- nginx
变量¶
定义变量¶
- name: Using variables
hosts: webservers
vars:
http_port: 80
server_name: example.com
packages:
- nginx
- vim
- git
tasks:
- name: Print variable
ansible.builtin.debug:
msg: "HTTP Port is {{ http_port }}"
- name: Install packages
ansible.builtin.apt:
name: "{{ packages }}"
state: present
变量文件¶
- name: Include variables
hosts: webservers
vars_files:
- vars/main.yml
tasks:
- name: Print variable
ansible.builtin.debug:
msg: "Server name is {{ server_name }}"
变量优先级¶
1. 命令行变量 (-e)
2. Playbook vars
3. Playbook vars_files
4. host_vars
5. group_vars
6. Inventory 主机变量
7. Inventory 组变量
8. Role defaults
Facts 变量¶
- name: Using facts
hosts: all
tasks:
- name: Print OS
ansible.builtin.debug:
msg: "OS is {{ ansible_distribution }} {{ ansible_distribution_version }}"
- name: Print IP
ansible.builtin.debug:
msg: "IP is {{ ansible_default_ipv4.address }}"
- name: Print memory
ansible.builtin.debug:
msg: "Total memory is {{ ansible_memtotal_mb }} MB"
条件判断¶
when 条件¶
tasks:
- name: Install nginx on Ubuntu
ansible.builtin.apt:
name: nginx
state: present
when: ansible_distribution == "Ubuntu"
- name: Install nginx on CentOS
ansible.builtin.yum:
name: nginx
state: present
when: ansible_distribution == "CentOS"
- name: Install on production
ansible.builtin.apt:
name: nginx
state: present
when: env == "production"
- name: Multiple conditions
ansible.builtin.apt:
name: nginx
state: present
when:
- ansible_distribution == "Ubuntu"
- ansible_distribution_version == "22.04"
条件运算符¶
# 比较运算符
when: ansible_memtotal_mb > 1024
when: ansible_distribution == "Ubuntu"
when: ansible_distribution != "CentOS"
# 逻辑运算符
when: ansible_distribution == "Ubuntu" and ansible_distribution_version == "22.04"
when: ansible_distribution == "Ubuntu" or ansible_distribution == "Debian"
when: not ansible_check_mode
# 列表包含
when: "'nginx' in installed_packages"
when: "'apache' not in installed_packages"
# 变量定义检查
when: my_var is defined
when: my_var is not defined
循环¶
loop 循环¶
# 基本循环
- name: Install packages
ansible.builtin.apt:
name: "{{ item }}"
state: present
loop:
- nginx
- vim
- git
# 字典循环
- name: Create users
ansible.builtin.user:
name: "{{ item.name }}"
group: "{{ item.group }}"
shell: "{{ item.shell }}"
loop:
- { name: 'user1', group: 'developers', shell: '/bin/bash' }
- { name: 'user2', group: 'admins', shell: '/bin/bash' }
# 循环索引
- name: Print with index
ansible.builtin.debug:
msg: "Item {{ index }} is {{ item }}"
loop:
- nginx
- vim
loop_control:
index_var: index
with_items(旧语法)¶
- name: Install packages
ansible.builtin.apt:
name: "{{ item }}"
state: present
with_items:
- nginx
- vim
- git
with_dict¶
- name: Create users
ansible.builtin.user:
name: "{{ item.key }}"
comment: "{{ item.value.comment }}"
with_dict:
user1:
comment: "User One"
user2:
comment: "User Two"
Handlers¶
Handler 是特殊的任务,只在被通知时执行。
- name: Configure nginx
hosts: webservers
become: yes
handlers:
- name: Restart nginx
ansible.builtin.service:
name: nginx
state: restarted
- name: Reload nginx
ansible.builtin.service:
name: nginx
state: reloaded
tasks:
- name: Copy nginx config
ansible.builtin.copy:
src: nginx.conf
dest: /etc/nginx/nginx.conf
notify: Restart nginx
- name: Copy site config
ansible.builtin.template:
src: site.conf.j2
dest: /etc/nginx/sites-available/default
notify:
- Reload nginx
- Restart nginx
模块¶
template 模块¶
- name: Deploy config
ansible.builtin.template:
src: nginx.conf.j2
dest: /etc/nginx/nginx.conf
mode: '0644'
backup: yes
validate: nginx -t -c %s
# nginx.conf.j2
user www-data;
worker_processes {{ ansible_processor_vcpus }};
http {
server {
listen {{ http_port }};
server_name {{ server_name }};
location / {
proxy_pass http://{{ backend_host }}:{{ backend_port }};
}
}
}
block 模块¶
tasks:
- name: Handle errors
block:
- name: Try to do something
ansible.builtin.command: /bin/false
- name: This won't run
ansible.builtin.debug:
msg: "This won't run"
rescue:
- name: Handle error
ansible.builtin.debug:
msg: "An error occurred"
always:
- name: Always run
ansible.builtin.debug:
msg: "This always runs"
Tags¶
- name: Deploy application
hosts: webservers
become: yes
tasks:
- name: Install nginx
ansible.builtin.apt:
name: nginx
state: present
tags:
- install
- nginx
- name: Configure nginx
ansible.builtin.template:
src: nginx.conf.j2
dest: /etc/nginx/nginx.conf
tags:
- config
- nginx
- name: Start nginx
ansible.builtin.service:
name: nginx
state: started
tags:
- service
- nginx
# 运行指定标签的任务
ansible-playbook site.yml --tags install
ansible-playbook site.yml --tags nginx,config
# 跳过指定标签
ansible-playbook site.yml --skip-tags install
Include 和 Import¶
include_tasks¶
# tasks/main.yml
- name: Install nginx
ansible.builtin.apt:
name: nginx
state: present
- name: Start nginx
ansible.builtin.service:
name: nginx
state: started
# playbook.yml
- name: Deploy nginx
hosts: webservers
tasks:
- name: Include nginx tasks
ansible.builtin.include_tasks: tasks/main.yml
import_tasks¶
- name: Deploy nginx
hosts: webservers
tasks:
- name: Import nginx tasks
ansible.builtin.import_tasks: tasks/main.yml
include_vars¶
实战示例¶
完整 Web 服务器部署¶
- name: Deploy Web Server
hosts: webservers
become: yes
vars:
nginx_version: "1.24"
http_port: 80
server_name: example.com
handlers:
- name: Restart nginx
ansible.builtin.service:
name: nginx
state: restarted
- name: Reload nginx
ansible.builtin.service:
name: nginx
state: reloaded
tasks:
- name: Update apt cache
ansible.builtin.apt:
update_cache: yes
cache_valid_time: 3600
- name: Install dependencies
ansible.builtin.apt:
name:
- nginx
- python3-pip
- git
state: present
- name: Create web directory
ansible.builtin.file:
path: /var/www/{{ server_name }}
state: directory
owner: www-data
group: www-data
mode: '0755'
- name: Deploy nginx config
ansible.builtin.template:
src: templates/nginx.conf.j2
dest: /etc/nginx/sites-available/{{ server_name }}
mode: '0644'
notify: Reload nginx
- name: Enable site
ansible.builtin.file:
src: /etc/nginx/sites-available/{{ server_name }}
dest: /etc/nginx/sites-enabled/{{ server_name }}
state: link
notify: Reload nginx
- name: Remove default site
ansible.builtin.file:
path: /etc/nginx/sites-enabled/default
state: absent
notify: Reload nginx
- name: Start nginx
ansible.builtin.service:
name: nginx
state: started
enabled: yes
- name: Check nginx status
ansible.builtin.uri:
url: "http://localhost:{{ http_port }}"
method: GET
status_code: 200
register: result
until: result.status == 200
retries: 5
delay: 10
小结¶
本章学习了:
- ✅ Playbook 基本结构
- ✅ 变量定义和使用
- ✅ 条件判断
- ✅ 循环
- ✅ Handlers
- ✅ Tags
- ✅ Include 和 Import
下一章¶
第六章:Roles 角色 - 学习如何组织和复用 Playbook。