第174集:Ansible Playbook

核心知识点讲解

1. Ansible Playbook 概述

Ansible Playbook是Ansible的核心功能之一,它是一种使用YAML格式编写的配置文件,用于定义和执行一系列有序的自动化任务。Playbook可以实现复杂的配置管理、应用部署和任务编排,是Ansible实现自动化运维的重要工具。

2. Playbook 的基本结构

一个完整的Playbook文件通常包含以下几个部分:

  • 主机和用户信息:指定执行任务的目标主机和远程用户
  • 任务列表:定义要执行的具体任务
  • 变量定义:设置Playbook中使用的变量
  • 模板文件:使用Jinja2模板生成配置文件
  • 处理程序:响应特定事件的任务
  • 标签:为任务添加标签,便于选择性执行

3. Playbook 的基本语法

3.1 主机和用户信息

---
- name: 部署Web服务
  hosts: webservers
  remote_user: root
  become: yes
  become_method: sudo
  • name:Playbook的名称,用于标识Playbook的目的
  • hosts:指定目标主机或主机组
  • remote_user:指定远程执行用户
  • become:是否切换用户身份
  • become_method:切换用户身份的方法

3.2 任务定义

tasks:
  - name: 安装Nginx
    apt:
      name: nginx
      state: present
      update_cache: yes

  - name: 启动Nginx服务
    service:
      name: nginx
      state: started
      enabled: yes

  - name: 复制网站配置文件
    copy:
      src: files/nginx.conf
      dest: /etc/nginx/nginx.conf
    notify: 重启Nginx服务
  • tasks:任务列表,包含多个任务
  • name:任务的名称,用于标识任务的目的
  • 模块名:指定使用的Ansible模块
  • 参数:模块的具体参数
  • notify:触发处理程序

3.3 变量定义

vars:
  nginx_version: "1.18.0"
  web_root: "/var/www/html"
  server_name: "example.com"

vars_files:
  - vars/web_vars.yml
  • vars:直接在Playbook中定义变量
  • vars_files:从外部文件加载变量

3.4 处理程序

handlers:
  - name: 重启Nginx服务
    service:
      name: nginx
      state: restarted
  • handlers:处理程序列表,响应notify触发的事件
  • 处理程序只有在任务执行成功后才会运行
  • 相同的处理程序只会运行一次

3.5 标签

tasks:
  - name: 安装Nginx
    apt:
      name: nginx
      state: present
    tags: install

  - name: 配置Nginx
    copy:
      src: files/nginx.conf
      dest: /etc/nginx/nginx.conf
    tags: config
  • tags:为任务添加标签
  • 可以使用--tags选项选择性执行特定标签的任务

4. Playbook 中的变量

4.1 变量的定义方式

  • 在Playbook中直接定义:使用vars关键字
  • 从外部文件加载:使用vars_files关键字
  • 从命令行传递:使用-e选项
  • 从主机清单文件加载:在inventory中定义主机变量和组变量
  • 使用 Facts:Ansible自动收集的主机信息

4.2 变量的使用方式

tasks:
  - name: 创建网站根目录
    file:
      path: "{{ web_root }}"
      state: directory

  - name: 配置Nginx虚拟主机
    template:
      src: templates/vhost.conf.j2
      dest: /etc/nginx/sites-available/{{ server_name }}
  • 使用双大括号{{ }}包围变量名
  • 变量可以在模块参数、文件路径、模板文件中使用

5. Playbook 中的条件判断

5.1 when 语句

tasks:
  - name: 安装Apache(CentOS)
    yum:
      name: httpd
      state: present
    when: ansible_os_family == "RedHat"

  - name: 安装Apache(Ubuntu)
    apt:
      name: apache2
      state: present
    when: ansible_os_family == "Debian"
  • when:指定任务执行的条件
  • 条件可以使用比较运算符、逻辑运算符和测试函数

5.2 常用条件表达式

# 比较运算
when: var1 == var2
when: var1 != var2
when: var1 > var2
when: var1 < var2
when: var1 >= var2
when: var1 <= var2

# 逻辑运算
when: condition1 and condition2
when: condition1 or condition2
when: not condition

# 测试函数
when: var is defined
when: var is not defined
when: var is true
when: var is false
when: var is none
when: var in list

6. Playbook 中的循环

6.1 with_items 循环

tasks:
  - name: 安装多个软件包
    apt:
      name: "{{ item }}"
      state: present
    with_items:
      - nginx
      - mysql-server
      - php-fpm

6.2 with_dict 循环

vars:
  users:
    alice:
      uid: 1001
      group: admin
    bob:
      uid: 1002
      group: users

tasks:
  - name: 创建用户
    user:
      name: "{{ item.key }}"
      uid: "{{ item.value.uid }}"
      group: "{{ item.value.group }}"
    with_dict: "{{ users }}"

6.3 with_fileglob 循环

tasks:
  - name: 复制配置文件
    copy:
      src: "{{ item }}"
      dest: "/etc/nginx/conf.d/"
    with_fileglob:
      - files/conf.d/*.conf

6.4 循环控制

tasks:
  - name: 重试任务
    command: some-command
    register: result
    retries: 3
    delay: 2
    until: result.rc == 0

7. Playbook 中的模板

7.1 创建模板文件

templates/vhost.conf.j2

server {
    listen 80;
    server_name {{ server_name }};
    root {{ web_root }};
    
    location / {
        index index.html index.php;
    }
    
    location ~ \.php$ {
        fastcgi_pass unix:/run/php/php7.4-fpm.sock;
        fastcgi_index index.php;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        include fastcgi_params;
    }
}

7.2 使用模板模块

tasks:
  - name: 配置虚拟主机
    template:
      src: templates/vhost.conf.j2
      dest: "/etc/nginx/sites-available/{{ server_name }}"

8. 执行 Playbook

# 执行完整的Playbook
ansible-playbook playbook.yml

# 执行指定标签的任务
ansible-playbook playbook.yml --tags "install"

# 跳过指定标签的任务
ansible-playbook playbook.yml --skip-tags "config"

# 检查Playbook但不执行
ansible-playbook playbook.yml --check

# 详细输出执行过程
ansible-playbook playbook.yml -v

# 更详细的输出
ansible-playbook playbook.yml -vv

# 最详细的输出
ansible-playbook playbook.yml -vvv

实用案例分析

案例1:部署 LAMP 环境

场景描述:需要在多台服务器上部署 LAMP(Linux + Apache + MySQL + PHP)环境。

解决方案

  1. 创建 Playbook 文件 lamp.yml
---
- name: 部署 LAMP 环境
  hosts: webservers
  remote_user: root
  
  vars:
    http_port: 80
    mysql_root_password: "your_password"
    php_packages:
      - php
      - php-mysql
      - php-cli
      - php-fpm
  
  tasks:
    - name: 更新软件包列表
      apt:
        update_cache: yes
    
    - name: 安装 Apache
      apt:
        name: apache2
        state: present
    
    - name: 启动 Apache 服务
      service:
        name: apache2
        state: started
        enabled: yes
    
    - name: 安装 MySQL 服务器
      apt:
        name: mysql-server
        state: present
    
    - name: 启动 MySQL 服务
      service:
        name: mysql
        state: started
        enabled: yes
    
    - name: 设置 MySQL root 密码
      mysql_user:
        name: root
        password: "{{ mysql_root_password }}"
        host_all: yes
    
    - name: 安装 PHP 相关包
      apt:
        name: "{{ item }}"
        state: present
      with_items: "{{ php_packages }}"
    
    - name: 创建测试页面
      copy:
        content: "<?php phpinfo(); ?>"
        dest: /var/www/html/info.php
    
  handlers:
    - name: 重启 Apache
      service:
        name: apache2
        state: restarted
    
    - name: 重启 MySQL
      service:
        name: mysql
        state: restarted
  1. 执行 Playbook:
ansible-playbook lamp.yml

实施效果

  • 批量完成了 LAMP 环境的部署
  • 确保了所有服务器的配置一致性
  • 简化了部署流程,减少了人工操作

案例2:配置防火墙规则

场景描述:需要在多台服务器上配置统一的防火墙规则。

解决方案

  1. 创建 Playbook 文件 firewall.yml
---
- name: 配置防火墙规则
  hosts: all
  remote_user: root
  
  vars:
    firewall_rules:
      - port: 22
        protocol: tcp
        state: enabled
      - port: 80
        protocol: tcp
        state: enabled
      - port: 443
        protocol: tcp
        state: enabled
  
  tasks:
    - name: 安装 ufw
      apt:
        name: ufw
        state: present
    
    - name: 启用 ufw
      ufw:
        state: enabled
        policy: deny
    
    - name: 配置防火墙规则
      ufw:
        rule: allow
        port: "{{ item.port }}"
        proto: "{{ item.protocol }}"
      with_items: "{{ firewall_rules }}"
    
    - name: 查看防火墙状态
      command: ufw status
      register: firewall_status
    
    - name: 显示防火墙状态
      debug:
        var: firewall_status.stdout
  1. 执行 Playbook:
ansible-playbook firewall.yml

实施效果

  • 批量配置了统一的防火墙规则
  • 确保了所有服务器的网络安全
  • 简化了防火墙管理流程

课后练习

  1. 编写一个 Ansible Playbook,实现以下功能:

    • 在目标服务器上创建一个新的用户
    • 为该用户配置 SSH 密钥登录
    • 安装并配置 Nginx 服务
    • 部署一个简单的静态网站
  2. 编写一个 Ansible Playbook,实现以下功能:

    • 安装并配置 MySQL 数据库
    • 创建数据库和用户
    • 导入数据库初始数据
    • 配置 MySQL 安全选项
  3. 研究 Ansible 的角色(Role)功能,了解如何使用角色组织 Playbook

  4. 学习 Ansible Galaxy,了解如何使用和分享社区贡献的角色

  5. 尝试使用 Ansible 配置管理一个多节点的应用集群

总结

本集详细介绍了Ansible Playbook的概念、结构、语法规则和核心功能,包括变量使用、条件判断、循环控制、模板使用等。Playbook是Ansible实现自动化运维的核心工具,通过编写和执行Playbook,可以实现复杂的配置管理、应用部署和任务编排。通过本集的学习,你应该能够掌握编写和执行Ansible Playbook的技能,为实现自动化运维打下坚实的基础。

« 上一篇 Ansible 基础 下一篇 » Puppet 基础