Ansible playbooks 使用介绍

环境信息

  • ansible-core 2.16
  • Docker image python:3.12.3
Ansible 安装部署参考 Ansible templates 使用介绍

Ansible Playbook 语法

Playbooks 使用 YAML 语法定义(描述)。一个 playbook 由一个或多个 play 依序组成。每个 play 运行一个或多个 tasks,每个 task 也成为一个 module

Ansible playbook 示例:

playbook.yml
---
- name: Update web servers
hosts: webservers
remote_user: root

tasks:
- name: Ensure apache is at the latest version
ansible.builtin.yum:
name: httpd
state: latest

- name: Write the apache config file
ansible.builtin.template:
src: /srv/httpd.j2
dest: /etc/httpd.conf

- name: Update db servers
hosts: databases
remote_user: root
vars:
port: 8080

tasks:
- name: Ensure postgresql is at the latest version
ansible.builtin.yum:
name: postgresql
state: latest

- name: Ensure that postgresql is started
ansible.builtin.service:
name: postgresql
state: started

---
- name: Install multiple packages
hosts: webservers
tasks:
- name: Install packages
apt:
name: "{{ item }}"
state: present
loop:
- nginx
- git
- curl

一个 Ansible playbook 由一个或多个 plays 组成,每个 play 包含以下部分:

  • name : 描述性的名称
  • hosts : 指定目标主机
  • become : 提升权限(默认是使用 sudo 提升到 root 用户)
  • remote_user : 用于连接到远程主机的账户。(如果 Inventory 中定义了远程连接的用户,会覆盖此处的配置)
  • tasks : 要执行的一系列任务列表
  • vars : 用于定义变量,便于管理和重用
  • gather_facts : 收集 Facts, 默认值为 yes

tasks 是一个任务列表,每个任务执行特定的操作。任务包含以下元素:

  • name : 描述任务的目的。
  • module_name : Ansible 模块名称,如 aptservice 等。
  • module_options : 模块的参数,以键值对的形式提供。
  • when : 条件语句,控制任务是否执行。
  • loop : 循环执行任务

执行以下命令运行 playbook.yml

ansible-playbook playbook.yml -f 10

常用选项说明

选项 说明 示例
-f
--forks
指定并发执行的数量,默认为 5
-v
--verbose
-vvvvvv
打印 debug 信息,详细程度从 -v-vvvvvv
-C
--check
Check mode,不执行任何实际操作,而是对要执行的操作进行验证
-D
--diff
- 只使用 --diff 会执行 play 定义的实际操作,并对所有受影响的文件或者模板显示其变更前后的具体差异
- --check 一起使用,不会执行 play 定义的实际操作,只显示变更前后的差异,可以在实际执行前,调试/预览将要进行的变更,防止意外配置变更或文件修改
主要用于文件或者模板的变更,对于其他类型的任务(如包安装、服务管理、修改主机名等),不会显示具体的差异( 配合 --check 使用时,结果会显示为 skipping,实际执行时结果为 changed )。
--list-hosts 不执行任何实际操作,只列出符合 pattern 的目标主机
--list-tasks 不执行任何实际操作,只列出将要执行的 task
--syntax-check 不执行任何实际操作,只检查 playbook 文件是否有语法错误

when 语句

在 Ansible playbook 中,when 关键字用于条件执行任务。它允许你根据特定的条件来决定是否执行某个任务。这个功能非常强大,可以帮助你在不同的主机、不同的环境或不同的配置下灵活地执行任务。

when 表达式基于 Jinja2 模板语言,其中的变量主要来自: [1]

变量优先级 参考说明

when 关键字后面跟随一个条件表达式,当条件为真时,任务会执行;当条件为假时,任务会被跳过。

tasks:
- name: Install nginx on Debian
apt:
name: nginx
state: present
when: ansible_facts['os_family'] == 'Debian'

when 关键字支持多种表达式,包括:

  • 简单条件

    • 基于变量 的条件:when: variable == 'value'

      - name: Install nginx only if nginx_install is true
      apt:
      name: nginx
      state: present
      when: nginx_install

      在这个示例中,nginx_install 是一个布尔变量。当 nginx_install 为真时,任务将执行。

    • 基于事实(facts) 的条件:when: ansible_facts['os_family'] == 'Debian'

      - name: Install nginx on Debian systems
      apt:
      name: nginx
      state: present
      when: ansible_facts['os_family'] == 'Debian'
  • 逻辑操作

    • 与操作when: condition1 and condition2
      - name: Install nginx on Debian systems
      apt:
      name: nginx
      state: present
      when: ansible_facts['os_family'] == 'Debian' or ansible_facts['os_family'] == 'Ubuntu'
      当使用多个条件时,也先当于 and 操作
      tasks:
      - name: Shut down CentOS 6 systems
      ansible.builtin.command: /sbin/shutdown -t now
      when:
      - ansible_facts['distribution'] == "CentOS"
      - ansible_facts['distribution_major_version'] == "6"
    • 或操作when: condition1 or condition2
    • 非操作when: not condition
  • 列表和字典操作

    • 列表包含when: 'item' in mylist
      - name: Ensure package is installed if it is in the list
      apt:
      name: "{{ item }}"
      state: present
      loop:
      - nginx
      - git
      when: item in packages_to_install
    • 字典键存在when: 'key' in mydict
      - name: Run only if the key 'run_task' is present in mydict and its value is true
      debug:
      msg: "Running task"
      when: mydict.get('run_task', False)

      这个任务仅在 mydict 中存在键 run_task 且其值为真时执行。

      when: mydict.get('run_task', False)False 为默认值,如果 mydict 字典中不存在 run_task 键,mydict.get('run_task', False) 将返回 False。这种用法确保了在键不存在时,条件判断不会抛出错误。

  • 复杂条件

    • 组合多个条件when: (condition1 and condition2) or condition3

以下是一个完整的示例

---
- name: Example playbook using when conditions
hosts: all
become: yes

vars:
nginx_install: true
packages_to_install:
- nginx
- git
mydict:
run_task: true

tasks:
- name: Install nginx only if nginx_install is true
apt:
name: nginx
state: present
when: nginx_install

- name: Install nginx on Debian or Ubuntu
apt:
name: nginx
state: present
when: ansible_facts['os_family'] == 'Debian' or ansible_facts['os_family'] == 'Ubuntu'

- name: Ensure package is installed if it is in the list
apt:
name: "{{ item }}"
state: present
loop: "{{ packages_to_install }}"
when: item in packages_to_install

- name: Run only if the key 'run_task' is present in mydict and its value is true
debug:
msg: "Running task"
when: mydict.get('run_task', False)

引用 Facts 变量值

Ansible-playbook 运行过程中,默认会收集目标主机的 Facts 信息。可以在 Playbook 定义中引用这些值 [2]

原始的 facts 信息可以通过 setup 模块获取

ansible <hostname> -m ansible.builtin.setup

要在 playbook 或者 template 中引用,可以参考以下方法:

{{ ansible_facts['devices']['xvda']['model'] }}

{{ ansible_facts['nodename'] }}

playbook 示例

修改主机名

以下示例展示修改主机名可使用的 playbook,主机名称修改为 Inventory 中主机的主机名(Alias)

假设 Inventory 文件内容如下:

/etc/ansible/inventory/hosts
test_target1:
hosts:
ansible-target-centos79-1:
ansible_host: ansible-target-centos79-1
ansible_user: root
ansible-target-centos79-2:
ansible_host: ansible-target-centos79-2
ansible_port: 22
ansible_user: root

Playbook 内容如下

change_hostname.yml
---
- name: Change hostname based on inventory alias
hosts: test_target1
become: yes
tasks:
- name: Set hostname from alias
hostname:
name: "{{ inventory_hostname }}"

- name: Update /etc/hosts file with new hostname
lineinfile:
path: /etc/hosts
regexp: '^(127\.0\.1\.1\s+).*'
line: "127.0.1.1 {{ inventory_hostname }}"
state: present
when: ansible_facts['distribution'] == 'Ubuntu'

- name: Update /etc/sysconfig/network with new hostname (CentOS/RedHat)
lineinfile:
path: /etc/sysconfig/network
regexp: '^HOSTNAME=.*'
line: "HOSTNAME={{ inventory_hostname }}"
state: present
when: ansible_facts['distribution'] in ['CentOS', 'RedHat']

- name: Set hostname using hostnamectl
command: "hostnamectl set-hostname {{ inventory_hostname }}"
when: ansible_facts['distribution'] in ['CentOS', 'RedHat', 'Ubuntu']

- name: Reboot the system to apply changes
reboot:
msg: "Rebooting to apply hostname changes"
pre_reboot_delay: 5
post_reboot_delay: 30
reboot_timeout: 300

相关模板变量说明

模板变量 说明 示例
inventory_hostname 引用 Inventory 中的主机名称(Alias) {{ inventory_hostname }}

相关模块使用参考

模块 参考链接 示例
hostname hostname
lineinfile lineinfile
reboot reboot
command command

参考链接

Ansible playbooks

脚注