Ansible Playbook语法速查表 掌握自动化配置的核心技巧
Ansible Playbook语法速查表 掌握自动化配置的核心技巧
1. Ansible Playbook基础介绍
Ansible Playbook是Ansible的核心组件,它是一种使用YAML语言编写的配置、部署和编排文件。Playbook允许您描述IT应用基础设施的自动化策略,使复杂的配置管理任务变得简单易行。
Playbook的优势在于:
- 人类可读:使用YAML格式,语法简洁明了
- 幂等性:多次执行相同任务不会改变结果(除非需要改变)
- 高效性:可以并行执行多个任务
- 可扩展性:支持模块化设计,可以通过角色和包含来组织复杂任务
2. YAML语法基础
Ansible Playbook使用YAML(YAML Ain’t Markup Language)语言编写。了解YAML的基本语法对于编写Playbook至关重要。
2.1 基本语法规则
# 键值对 key: value # 列表(使用连字符开头) - item1 - item2 - item3 # 嵌套结构 key: nested_key1: value1 nested_key2: value2 # 列表中的字典 - name: item1 value: value1 - name: item2 value: value2
2.2 YAML中的数据类型
# 字符串 string_var: "This is a string" another_string: 'This is also a string' # 数字 integer_var: 42 float_var: 3.14 # 布尔值 boolean_true: yes boolean_false: no # null值 null_var: null
2.3 YAML中的注释
在YAML中,使用#
符号表示注释:
# 这是一个注释 key: value # 这也是一个行内注释
3. Playbook基本结构
一个基本的Ansible Playbook由一个或多个”play”组成,每个play定义了一组要在特定主机或主机组上执行的任务。
3.1 最简单的Playbook结构
--- - name: Playbook名称 hosts: 目标主机或主机组 tasks: - name: 任务1名称 module_name: parameter1: value1 parameter2: value2 - name: 任务2名称 module_name: parameter1: value1
3.2 完整的Playbook结构
--- - name: 第一个play hosts: webservers become: yes vars: http_port: 80 max_clients: 200 vars_files: - vars/external_vars.yml pre_tasks: - name: 预任务1 debug: msg: "开始执行预任务" roles: - common - webserver tasks: - name: 安装Apache yum: name: httpd state: present - name: 启动Apache服务 service: name: httpd state: started enabled: yes post_tasks: - name: 后任务1 debug: msg: "所有任务执行完成" handlers: - name: 重启Apache service: name: httpd state: restarted
4. 常用模块详解
Ansible提供了大量模块来执行各种任务。以下是一些最常用的模块及其用法。
4.1 文件和目录操作模块
copy模块
- name: 复制文件到远程主机 copy: src: /path/to/local/file dest: /path/to/remote/file owner: root group: root mode: '0644' backup: yes
file模块
- name: 创建目录 file: path: /path/to/directory state: directory owner: root group: root mode: '0755' - name: 创建符号链接 file: src: /path/to/source dest: /path/to/link state: link - name: 删除文件 file: path: /path/to/file state: absent
stat模块
- name: 检查文件状态 stat: path: /path/to/file register: file_stat - name: 显示文件信息 debug: msg: "文件大小: {{ file_stat.stat.size }} 字节" when: file_stat.stat.exists
4.2 软件包管理模块
yum模块(用于基于RPM的系统)
- name: 安装最新版本的Apache yum: name: httpd state: latest - name: 安装多个软件包 yum: name: - httpd - httpd-tools - mod_ssl state: present - name: 移除软件包 yum: name: httpd state: absent
apt模块(用于基于Debian的系统)
- name: 更新apt缓存并安装Nginx apt: name: nginx state: latest update_cache: yes - name: 安装特定版本的软件包 apt: name: nginx=1.18.0-0ubuntu1 state: present - name: 卸载软件包并删除配置文件 apt: name: nginx state: absent purge: yes
4.3 服务管理模块
- name: 启动并启用Apache服务 service: name: httpd state: started enabled: yes - name: 重启服务 service: name: httpd state: restarted - name: 停止服务 service: name: httpd state: stopped
4.4 用户和组管理模块
- name: 创建用户 user: name: johndoe comment: "John Doe" uid: 1040 group: users shell: /bin/bash password: "{{ 'password' | password_hash('sha512') }}" - name: 创建组 group: name: developers state: present gid: 1050 - name: 生成SSH密钥 user: name: johndoe generate_ssh_key: yes ssh_key_bits: 2048 ssh_key_file: .ssh/id_rsa
4.5 系统信息模块
setup模块
- name: 收集系统信息 setup: register: system_info - name: 显示操作系统信息 debug: msg: "系统: {{ system_info.ansible_distribution }} {{ system_info.ansible_distribution_version }}"
4.6 命令和脚本执行模块
command模块
- name: 检查磁盘空间 command: df -h register: disk_space - name: 显示磁盘使用情况 debug: msg: "{{ disk_space.stdout_lines }}"
shell模块
- name: 执行带有管道的命令 shell: ps aux | grep httpd register: httpd_processes - name: 显示Apache进程 debug: msg: "{{ httpd_processes.stdout_lines }}"
script模块
- name: 在远程主机上执行本地脚本 script: /path/to/local/script.sh --parameter1 value1
5. 变量使用
变量是Ansible Playbook中的重要组成部分,它们使Playbook更加灵活和可重用。
5.1 定义变量
在Playbook中直接定义变量
--- - name: 使用变量示例 hosts: webservers vars: package_name: httpd service_name: httpd config_file: /etc/httpd/conf/httpd.conf tasks: - name: 安装{{ package_name }} yum: name: "{{ package_name }}" state: present - name: 启动{{ service_name }}服务 service: name: "{{ service_name }}" state: started
在外部文件中定义变量
# vars/webserver.yml package_name: httpd service_name: httpd config_file: /etc/httpd/conf/httpd.conf
然后在Playbook中引用:
--- - name: 使用外部变量文件 hosts: webservers vars_files: - vars/webserver.yml tasks: - name: 安装{{ package_name }} yum: name: "{{ package_name }}" state: present
5.2 变量类型
字符串变量
vars: app_name: "my_web_app" app_version: "1.2.3"
数字变量
vars: http_port: 80 https_port: 443 max_connections: 1000
列表变量
vars: required_packages: - httpd - php - mysql - php-mysql
字典变量
vars: database_config: host: localhost port: 3306 name: webapp_db user: webapp_user password: secure_password
5.3 使用变量
基本变量引用
tasks: - name: 创建目录 file: path: "/var/www/{{ app_name }}" state: directory
引用字典变量
tasks: - name: 创建配置文件 template: src: config.j2 dest: "/etc/app/config.ini" vars: db_host: "{{ database_config.host }}" db_port: "{{ database_config.port }}"
引用列表变量
tasks: - name: 安装多个软件包 yum: name: "{{ required_packages }}" state: present
5.4 变量优先级
Ansible中变量的优先级顺序(从高到低):
- 命令行中通过
-e
或--extra-vars
指定的变量 - 在inventory中定义的连接变量
- 在play中定义的vars
- 在play中通过vars_files包含的变量
- 在role中定义的vars
- 在inventory中定义的变量
- 通过set_fact模块设置的变量
- 角色默认值(defaults/main.yml)
5.5 注册变量
使用register
关键字可以将任务的输出保存到变量中,以便在后续任务中使用。
- name: 检查服务状态 command: systemctl status nginx register: nginx_status ignore_errors: yes - name: 显示服务状态 debug: msg: "Nginx服务状态: {{ nginx_status.rc }}" when: nginx_status.rc is defined - name: 重启服务(如果失败) service: name: nginx state: restarted when: nginx_status.rc != 0
6. 条件判断和循环
条件判断和循环是Ansible Playbook中控制任务执行流程的重要机制。
6.1 条件判断
基本条件判断
- name: 安装Apache(仅适用于CentOS系统) yum: name: httpd state: present when: ansible_distribution == "CentOS" - name: 安装Nginx(仅适用于Ubuntu系统) apt: name: nginx state: present when: ansible_distribution == "Ubuntu"
多条件判断
- name: 安装特定版本的软件包(仅适用于CentOS 7) yum: name: httpd-2.4.6 state: present when: - ansible_distribution == "CentOS" - ansible_distribution_major_version == "7"
使用逻辑运算符
- name: 安装开发工具 yum: name: "@Development tools" state: present when: - (ansible_distribution == "CentOS" or ansible_distribution == "Red Hat Enterprise Linux") - ansible_distribution_major_version|int >= 7
检查变量是否定义
- name: 使用自定义配置文件(如果存在) copy: src: "{{ custom_config_file | default('/etc/app/default.conf') }}" dest: /etc/app/config.conf
6.2 循环
标准循环
- name: 创建多个用户 user: name: "{{ item }}" state: present loop: - alice - bob - charlie
循环字典列表
- name: 创建多个用户并设置属性 user: name: "{{ item.name }}" uid: "{{ item.uid }}" group: "{{ item.group }}" shell: "{{ item.shell }}" loop: - { name: 'alice', uid: 1001, group: 'users', shell: '/bin/bash' } - { name: 'bob', uid: 1002, group: 'developers', shell: '/bin/zsh' } - { name: 'charlie', uid: 1003, group: 'admins', shell: '/bin/bash' }
使用with_items(旧式循环)
- name: 安装多个软件包 yum: name: "{{ item }}" state: present with_items: - httpd - php - php-mysql - php-gd
使用with_dict(循环字典)
- name: 打印字典键值对 debug: msg: "Key: {{ item.key }}, Value: {{ item.value }}" with_dict: - { key: 'name', value: 'John' } - { key: 'age', value: 30 } - { key: 'city', value: 'New York' }
使用with_fileglob(循环文件)
- name: 复制所有配置文件 copy: src: "{{ item }}" dest: "/etc/app/{{ item | basename }}" with_fileglob: - "files/*.conf"
使用with_sequence(生成数字序列)
- name: 创建多个目录 file: path: "/tmp/dir{{ item }}" state: directory with_sequence: start=1 end=5
使用until循环(重试机制)
- name: 等待服务启动 command: systemctl status nginx register: nginx_status until: nginx_status.rc == 0 retries: 5 delay: 10
7. 模板和文件操作
7.1 使用template模块
template模块允许您使用Jinja2模板引擎生成动态配置文件。
基本模板使用
- name: 生成Apache配置文件 template: src: templates/httpd.conf.j2 dest: /etc/httpd/conf/httpd.conf owner: root group: root mode: '0644' backup: yes notify: 重启Apache
模板文件示例(templates/httpd.conf.j2)
# {{ ansible_managed }} ServerRoot "/etc/httpd" Listen {{ http_port }} User apache Group apache ServerAdmin {{ server_admin }} ServerName {{ server_name }} DocumentRoot "/var/www/html" <Directory "/var/www/html"> Options Indexes FollowSymLinks AllowOverride None Require all granted </Directory> {% if enable_ssl %} LoadModule ssl_module modules/mod_ssl.so Listen {{ https_port }} <VirtualHost *:{{ https_port }}> SSLEngine on SSLCertificateFile {{ ssl_cert_file }} SSLCertificateKeyFile {{ ssl_key_file }} </VirtualHost> {% endif %}
7.2 Jinja2模板高级用法
条件语句
{% if ansible_distribution == "CentOS" %} # CentOS specific configuration SyslogFacility AUTHPRIV {% elif ansible_distribution == "Ubuntu" %} # Ubuntu specific configuration SyslogFacility AUTH {% else %} # Default configuration SyslogFacility AUTH {% endif %}
循环
# Virtual hosts configuration {% for vhost in virtual_hosts %} <VirtualHost *:{{ vhost.port }}> ServerName {{ vhost.server_name }} DocumentRoot {{ vhost.document_root }} {% if vhost.custom_log is defined %} CustomLog {{ vhost.custom_log }} combined {% endif %} {% if vhost.error_log is defined %} ErrorLog {{ vhost.error_log }} {% endif %} </VirtualHost> {% endfor %}
过滤器
# 使用过滤器 ServerAdmin {{ admin_email | default("admin@example.com") }} MaxClients {{ max_clients | int }} ServerName {{ server_name | lower }} DocumentRoot "{{ document_root | quote }}"
7.3 行内文件内容
使用blockinfile模块
- name: 在配置文件中添加块 blockinfile: path: /etc/ssh/sshd_config block: | # Custom SSH settings PermitRootLogin no PasswordAuthentication no AllowUsers {{ allowed_users }} marker: "# {mark} ANSIBLE MANAGED BLOCK" backup: yes notify: 重启SSH服务
使用lineinfile模块
- name: 确保特定行存在于文件中 lineinfile: path: /etc/selinux/config regexp: '^SELINUX=' line: 'SELINUX=disabled' backup: yes notify: 重启系统 - name: 删除文件中的特定行 lineinfile: path: /etc/hosts regexp: '^192.168.1.100' state: absent
8. 错误处理
8.1 忽略错误
- name: 尝试删除可能不存在的文件 file: path: /tmp/old_config.conf state: absent ignore_errors: yes
8.2 错误处理与恢复
- name: 尝试执行可能失败的任务 command: /usr/bin/might_fail register: result ignore_errors: yes - name: 执行失败时的恢复操作 command: /usr/bin/recover_from_failure when: result is failed
8.3 使用failed_when控制失败条件
- name: 检查磁盘空间 shell: df / | tail -1 | awk '{print $5}' | sed 's/%//' register: disk_usage failed_when: disk_usage.stdout|int > 90 changed_when: false - name: 显示磁盘使用情况 debug: msg: "磁盘使用率: {{ disk_usage.stdout }}%"
8.4 使用rescue和block进行错误处理
- name: 尝试执行一系列任务,并在失败时执行恢复操作 block: - name: 安装软件包 yum: name: "{{ item }}" state: present loop: - package1 - package2 - package3 - name: 配置服务 template: src: service.conf.j2 dest: /etc/service/service.conf - name: 启动服务 service: name: myservice state: started enabled: yes rescue: - name: 记录错误 debug: msg: "安装或配置过程中出现错误,执行回滚操作" - name: 停止服务(如果已启动) service: name: myservice state: stopped ignore_errors: yes - name: 删除配置文件 file: path: /etc/service/service.conf state: absent ignore_errors: yes - name: 卸载软件包 yum: name: "{{ item }}" state: absent loop: - package1 - package2 - package3 ignore_errors: yes always: - name: 发送通知 debug: msg: "任务执行完成,无论成功或失败"
9. 角色和包含
9.1 使用include和import
include_tasks(动态包含)
- name: 包含任务列表 include_tasks: tasks/setup.yml vars: package_name: httpd - name: 条件包含任务 include_tasks: "tasks/{{ ansible_os_family }}.yml"
import_tasks(静态包含)
- name: 导入任务列表 import_tasks: tasks/common.yml - name: 条件导入任务(在解析时评估) import_tasks: tasks/firewall.yml when: enable_firewall | bool
include_role和import_role
- name: 包含角色 include_role: name: common tasks_from: main.yml vars_from: main.yml defaults_from: main.yml - name: 导入角色 import_role: name: webserver
9.2 创建和使用角色
角色目录结构
site.yml webservers.yml fooservers.yml roles/ common/ tasks/ handlers/ files/ templates/ vars/ defaults/ meta/ webservers/ tasks/ defaults/ meta/
角色任务示例(roles/webservers/tasks/main.yml)
--- - name: 安装Web服务器软件包 package: name: "{{ web_server_package }}" state: present - name: 创建Web服务器配置目录 file: path: "{{ web_server_config_dir }}" state: directory owner: root group: root mode: '0755' - name: 生成Web服务器配置文件 template: src: webserver.conf.j2 dest: "{{ web_server_config_path }}" owner: root group: root mode: '0644' notify: 重启Web服务器 - name: 确保Web服务器正在运行 service: name: "{{ web_server_service }}" state: started enabled: yes
角色变量示例(roles/webservers/defaults/main.yml)
--- # 默认变量 web_server_package: apache2 web_server_service: apache2 web_server_config_dir: /etc/apache2 web_server_config_path: /etc/apache2/apache2.conf web_server_port: 80 web_server_user: www-data web_server_group: www-data
角色处理器示例(roles/webservers/handlers/main.yml)
--- - name: 重启Web服务器 service: name: "{{ web_server_service }}" state: restarted - name: 重新加载Web服务器 service: name: "{{ web_server_service }}" state: reloaded
在Playbook中使用角色
--- - name: 配置Web服务器 hosts: webservers become: yes roles: - common - { role: webservers, web_server_port: 8080 } - { role: firewall, when: enable_firewall | bool }
10. 最佳实践
10.1 Playbook结构最佳实践
使用版本控制
# 始终在Playbook顶部添加注释,说明用途和作者 --- # 作者: John Doe # 描述: 配置Web服务器和数据库服务器 # 版本: 1.0 - name: 配置Web服务器 hosts: webservers # ... 其余内容 ...
使用有意义的名称
# 不好的做法 - name: 安装包 yum: name: httpd state: present # 好的做法 - name: 安装Apache Web服务器 yum: name: httpd state: present
模块化Playbook
--- - name: 配置Web服务器 hosts: webservers become: yes pre_tasks: - name: 预检查系统状态 include_tasks: tasks/pre_check.yml roles: - common - webserver tasks: - name: 部署应用程序 include_tasks: tasks/deploy_app.yml post_tasks: - name: 验证部署 include_tasks: tasks/verify_deployment.yml
10.2 变量管理最佳实践
使用变量文件而非硬编码
# 不好的做法 - name: 配置数据库连接 template: src: database.conf.j2 dest: /etc/app/database.conf # 好的做法 - name: 配置数据库连接 template: src: database.conf.j2 dest: /etc/app/database.conf vars: db_host: "{{ database_host }}" db_port: "{{ database_port }}" db_name: "{{ database_name }}" db_user: "{{ database_user }}" db_pass: "{{ database_password }}"
使用适当的变量作用域
--- - name: 配置应用程序 hosts: app_servers vars: # 全局变量 app_version: "2.3.1" tasks: - name: 设置应用程序特定变量 set_fact: app_config_dir: "/etc/app-{{ app_version }}" - name: 创建配置目录 file: path: "{{ app_config_dir }}" state: directory - name: 生成配置文件 template: src: app.conf.j2 dest: "{{ app_config_dir }}/app.conf" vars: # 任务级别变量 debug_mode: "{{ debug_mode_enabled | default(false) }}"
10.3 安全最佳实践
使用Ansible Vault加密敏感数据
# 创建加密的变量文件 ansible-vault create secrets.yml
# 在Playbook中使用加密的变量文件 --- - name: 安全部署应用程序 hosts: app_servers vars_files: - secrets.yml tasks: - name: 配置数据库连接 template: src: database.conf.j2 dest: /etc/app/database.conf vars: db_host: "{{ database_host }}" db_port: "{{ database_port }}" db_name: "{{ database_name }}" db_user: "{{ database_user }}" db_pass: "{{ database_password }}" # 此值来自加密的secrets.yml
避免在命令行中传递敏感信息
# 不好的做法 ansible-playbook deploy.yml --extra-vars "db_password=secret123" # 好的做法 ansible-playbook deploy.yml --ask-vault-pass
10.4 性能优化最佳实践
使用fact缓存
# ansible.cfg [defaults] gathering = smart fact_caching = jsonfile fact_caching_connection = /tmp/ansible_facts_cache fact_caching_timeout = 86400
使用异步任务
- name: 执行长时间运行的任务 command: /usr/bin/long_running_operation async: 3600 poll: 0 register: long_operation_result - name: 等待长时间运行的任务完成 async_status: jid: "{{ long_operation_result.ansible_job_id }}" register: job_result until: job_result.finished retries: 300 delay: 10
使用策略插件并行执行
--- - name: 在多台主机上并行执行任务 hosts: webservers strategy: free tasks: - name: 更新所有软件包 yum: name: "*" state: latest
10.5 调试和测试最佳实践
使用check模式
ansible-playbook deploy.yml --check
使用diff模式查看更改
ansible-playbook deploy.yml --check --diff
使用debug模块进行调试
- name: 调试变量值 debug: msg: "数据库主机: {{ database_host }}, 端口: {{ database_port }}" - name: 调试复杂变量结构 debug: var: database_config
使用assert模块进行验证
- name: 验证服务是否正在运行 assert: that: - "'running' in service_status.status" success_msg: "服务正在运行" fail_msg: "服务未运行"
结论
Ansible Playbook是自动化配置管理的强大工具,掌握其语法和核心技巧对于构建高效、可维护的自动化解决方案至关重要。通过本速查表,您可以快速了解和参考Ansible Playbook的主要语法元素和使用方法,从基础结构到高级技巧,包括变量使用、条件判断、循环、模板、错误处理、角色和最佳实践等方面。
随着您对Ansible的深入了解,您将能够构建更加复杂和强大的自动化解决方案,提高IT基础设施的效率和可靠性。记住,实践是掌握Ansible Playbook的最佳方式,不断尝试和应用这些技巧将帮助您成为Ansible自动化专家。