# template-debugging.yml
---
- name: 模板调试示例
  hosts: localhost
  
  vars:
    debug_template: true
    complex_data:
      users:
        - name: alice
          role: admin
          permissions: [read, write, delete]
        - name: bob
          role: user
          permissions: [read]
      settings:
        timeout: 30
        retries: 3
        endpoints:
          api: "https://api.example.com"
          auth: "https://auth.example.com"
  
  tasks:
    # 调试变量内容
    - name: 显示复杂数据结构
      debug:
        var: complex_data
      when: debug_template
    
    # 调试模板渲染结果
    - name: 预览模板渲染结果
      debug:
        msg: |
          {% for user in complex_data.users %}
          用户: {{ user.name }}
          角色: {{ user.role }}
          权限: {{ user.permissions | join(', ') }}
          {% endfor %}
      when: debug_template
    
    # 使用临时文件调试模板
    - name: 生成调试模板
      template:
        src: debug-template.j2
        dest: /tmp/debug-output.txt
      when: debug_template
    
    - name: 显示调试模板内容
      slurp:
        src: /tmp/debug-output.txt
      register: debug_content
      when: debug_template
    
    - name: 输出调试内容
      debug:
        msg: "{{ debug_content.content | b64decode }}"
      when: debug_template
    
    # 验证模板语法
    - name: 验证模板语法
      template:
        src: complex-config.j2
        dest: /tmp/syntax-check.conf
      check_mode: yes
      register: template_syntax
    
    - name: 报告语法检查结果
      debug:
        msg: "模板语法检查通过"
      when: template_syntax is succeeded
    
    # 条件调试输出
    - name: 条件调试信息
      debug:
        msg: |
          环境: {{ environment | default('未设置') }}
          调试模式: {{ debug_mode | default(false) }}
          主机组: {{ group_names | join(', ') }}
          变量定义状态:
          - app_name: {{ 'defined' if app_name is defined else 'undefined' }}
          - database: {{ 'defined' if database is defined else 'undefined' }}
          - cache: {{ 'defined' if cache is defined else 'undefined' }}
      when: debug_template or debug_mode | default(false)
{# templates/debug-template.j2 #}
{# 调试模板示例 #}
=== 模板调试输出 ===
生成时间: {{ ansible_date_time.iso8601 }}
主机信息: {{ inventory_hostname }} ({{ ansible_default_ipv4.address | default('N/A') }})

=== 变量信息 ===
{% for key, value in vars.items() %}
{% if not key.startswith('ansible_') and not key.startswith('hostvars') %}
{{ key }}: {{ value | to_nice_json }}
{% endif %}
{% endfor %}

=== 主机事实 ===
操作系统: {{ ansible_distribution }} {{ ansible_distribution_version }}
CPU 核心数: {{ ansible_processor_vcpus }}
内存总量: {{ ansible_memtotal_mb }} MB
磁盘信息:
{% for mount in ansible_mounts %}
  {{ mount.mount }}: {{ mount.size_total | filesizeformat }} ({{ mount.fstype }})
{% endfor %}

=== 网络信息 ===
{% for interface in ansible_interfaces %}
{% set interface_facts = hostvars[inventory_hostname]['ansible_' + interface] %}
{% if interface_facts.ipv4 is defined %}
{{ interface }}: {{ interface_facts.ipv4.address }}/{{ interface_facts.ipv4.netmask }}
{% endif %}
{% endfor %}

=== 复杂数据处理 ===
{% if complex_data is defined %}
用户列表:
{% for user in complex_data.users %}
  - {{ user.name }} ({{ user.role }}): {{ user.permissions | join(', ') }}
{% endfor %}

设置信息:
{% for key, value in complex_data.settings.items() %}
  {{ key }}: {{ value }}
{% endfor %}
{% endif %}

=== 条件测试 ===
{% set test_conditions = [
    ('environment == "production"', environment == 'production'),
    ('debug_mode is true', debug_mode | default(false)),
    ('ansible_memtotal_mb > 1024', ansible_memtotal_mb > 1024),
    ('"webservers" in group_names', 'webservers' in group_names)
] %}
{% for condition, result in test_conditions %}
{{ condition }}: {{ result }}
{% endfor %}

=== 过滤器测试 ===
{% set test_string = "Hello World" %}
原始字符串: {{ test_string }}
大写: {{ test_string | upper }}
小写: {{ test_string | lower }}
反转: {{ test_string | reverse }}
长度: {{ test_string | length }}
Base64: {{ test_string | b64encode }}

{% set test_list = [3, 1, 4, 1, 5, 9, 2, 6] %}
原始列表: {{ test_list }}
排序: {{ test_list | sort }}
去重: {{ test_list | unique | sort }}
最大值: {{ test_list | max }}
最小值: {{ test_list | min }}
平均值: {{ (test_list | sum / test_list | length) | round(2) }}

=== 模板结束 ===

6.7 高级变量技巧

6.7.1 动态变量生成

# dynamic-variables.yml
---
- name: 动态变量生成示例
  hosts: all
  
  vars:
    base_config:
      app_name: myapp
      version: "1.0.0"
      port: 8080
    
    environment_overrides:
      development:
        debug: true
        log_level: debug
        workers: 1
      production:
        debug: false
        log_level: warning
        workers: "{{ ansible_processor_vcpus * 2 }}"
  
  tasks:
    # 动态合并配置
    - name: 生成环境特定配置
      set_fact:
        app_config: "{{ base_config | combine(environment_overrides[environment]) }}"
      vars:
        environment: "{{ target_environment | default('development') }}"
    
    # 基于主机信息动态生成变量
    - name: 生成主机特定配置
      set_fact:
        host_config:
          hostname: "{{ inventory_hostname }}"
          ip_address: "{{ ansible_default_ipv4.address }}"
          memory_mb: "{{ ansible_memtotal_mb }}"
          cpu_cores: "{{ ansible_processor_vcpus }}"
          disk_space: "{{ ansible_mounts | selectattr('mount', 'equalto', '/') | map(attribute='size_total') | first }}"
          recommended_workers: "{{ [ansible_processor_vcpus * 2, 8] | min }}"
          max_memory_usage: "{{ (ansible_memtotal_mb * 0.8) | int }}M"
    
    # 动态生成服务发现配置
    - name: 生成服务发现配置
      set_fact:
        service_discovery:
          web_servers: |
            {%- set servers = [] -%}
            {%- for host in groups['webservers'] | default([]) -%}
              {%- set _ = servers.append({
                'name': host,
                'ip': hostvars[host]['ansible_default_ipv4']['address'],
                'port': hostvars[host]['app_port'] | default(8080)
              }) -%}
            {%- endfor -%}
            {{ servers }}
          database_servers: |
            {%- set servers = [] -%}
            {%- for host in groups['databases'] | default([]) -%}
              {%- set _ = servers.append({
                'name': host,
                'ip': hostvars[host]['ansible_default_ipv4']['address'],
                'port': hostvars[host]['db_port'] | default(3306),
                'role': hostvars[host]['db_role'] | default('replica')
              }) -%}
            {%- endfor -%}
            {{ servers }}
    
    # 动态生成负载均衡配置
    - name: 生成负载均衡器配置
      set_fact:
        load_balancer_config:
          upstream_servers: |
            {%- set upstreams = {} -%}
            {%- for group_name in ['webservers', 'api_servers', 'worker_servers'] -%}
              {%- if groups[group_name] is defined -%}
                {%- set servers = [] -%}
                {%- for host in groups[group_name] -%}
                  {%- set server_config = {
                    'server': hostvars[host]['ansible_default_ipv4']['address'] + ':' + (hostvars[host]['app_port'] | default(8080) | string),
                    'weight': hostvars[host]['server_weight'] | default(1),
                    'max_fails': hostvars[host]['max_fails'] | default(3),
                    'fail_timeout': hostvars[host]['fail_timeout'] | default('30s')
                  } -%}
                  {%- set _ = servers.append(server_config) -%}
                {%- endfor -%}
                {%- set _ = upstreams.update({group_name: servers}) -%}
              {%- endif -%}
            {%- endfor -%}
            {{ upstreams }}
    
    # 显示动态生成的变量
    - name: 显示动态配置
      debug:
        msg: |
          应用配置: {{ app_config | to_nice_json }}
          主机配置: {{ host_config | to_nice_json }}
          服务发现: {{ service_discovery | to_nice_json }}
          负载均衡: {{ load_balancer_config | to_nice_json }}

6.7.2 变量继承和覆盖

# variable-inheritance.yml
---
- name: 变量继承和覆盖示例
  hosts: all
  
  vars:
    # 基础配置(最低优先级)
    default_config:
      app:
        name: myapp
        version: "1.0.0"
        port: 8080
        workers: 4
        timeout: 30
      database:
        host: localhost
        port: 3306
        pool_size: 10
      cache:
        enabled: false
        ttl: 300
      logging:
        level: info
        format: standard
    
    # 环境特定配置(中等优先级)
    environment_config:
      development:
        app:
          workers: 1
          timeout: 60
        database:
          host: dev-db.example.com
          pool_size: 5
        cache:
          enabled: false
        logging:
          level: debug
      production:
        app:
          workers: 8
          timeout: 15
        database:
          host: prod-db.example.com
          pool_size: 20
        cache:
          enabled: true
          ttl: 3600
        logging:
          level: warning
    
    # 主机特定配置(最高优先级)
    host_specific_config:
      web1.example.com:
        app:
          port: 8081
          workers: 6
      web2.example.com:
        app:
          port: 8082
          workers: 4
      db1.example.com:
        database:
          port: 3307
          pool_size: 30
  
  tasks:
    # 多层配置合并
    - name: 合并配置层次
      set_fact:
        final_config: |
          {%- set config = default_config -%}
          {%- if environment is defined and environment in environment_config -%}
            {%- set config = config | combine(environment_config[environment], recursive=True) -%}
          {%- endif -%}
          {%- if inventory_hostname in host_specific_config -%}
            {%- set config = config | combine(host_specific_config[inventory_hostname], recursive=True) -%}
          {%- endif -%}
          {{ config }}
      vars:
        environment: "{{ target_environment | default('development') }}"
    
    # 显示最终配置
    - name: 显示最终配置
      debug:
        msg: "{{ final_config | to_nice_json }}"
    
    # 基于角色的配置继承
    - name: 基于角色的配置
      set_fact:
        role_config: |
          {%- set config = {} -%}
          {%- for role in group_names -%}
            {%- if role in role_configurations -%}
              {%- set config = config | combine(role_configurations[role], recursive=True) -%}
            {%- endif -%}
          {%- endfor -%}
          {{ config }}
      vars:
        role_configurations:
          webservers:
            nginx:
              worker_processes: "{{ ansible_processor_vcpus }}"
              worker_connections: 1024
            php:
              memory_limit: 256M
              max_execution_time: 30
          databases:
            mysql:
              innodb_buffer_pool_size: "{{ (ansible_memtotal_mb * 0.7) | int }}M"
              max_connections: 200
          loadbalancers:
            haproxy:
              maxconn: 4096
              timeout_connect: 5000
              timeout_client: 50000
              timeout_server: 50000
    
    # 条件配置覆盖
    - name: 条件配置覆盖
      set_fact:
        conditional_config: |
          {%- set config = final_config -%}
          {%- if ansible_memtotal_mb < 2048 -%}
            {%- set memory_config = {
              'app': {'workers': 2},
              'database': {'pool_size': 5}
            } -%}
            {%- set config = config | combine(memory_config, recursive=True) -%}
          {%- endif -%}
          {%- if ansible_processor_vcpus < 2 -%}
            {%- set cpu_config = {
              'app': {'workers': 1}
            } -%}
            {%- set config = config | combine(cpu_config, recursive=True) -%}
          {%- endif -%}
          {{ config }}

6.8 本章总结

本章深入介绍了 Ansible 的变量和模板系统,主要内容包括:

  • 变量系统概述:变量类型、优先级和作用域
  • 变量文件管理:组织结构和环境特定配置
  • 变量过滤器和测试:内置过滤器、自定义过滤器和变量测试
  • Jinja2 模板系统:基础语法、控制结构和宏定义
  • 模板使用实践:最佳实践、调试技巧和实际应用
  • 高级变量技巧:动态生成、继承和覆盖

掌握变量和模板是编写灵活、可维护的 Ansible Playbook 的关键技能。

6.9 练习题

基础练习

  1. 变量定义和使用

    • 创建多层次的变量结构
    • 实现变量的条件赋值
    • 使用变量过滤器处理数据
  2. 模板编写

    • 编写 Nginx 配置模板
    • 创建应用程序配置模板
    • 实现条件和循环逻辑

进阶练习

  1. 复杂模板

    • 设计可重用的模板宏
    • 实现模板继承和包含
    • 创建动态配置生成
  2. 变量管理

    • 设计环境特定的变量结构
    • 实现变量加密和安全管理
    • 创建动态变量生成逻辑

实战练习

  1. 完整配置管理
    • 设计多环境配置管理方案
    • 实现配置模板的版本控制
    • 创建配置验证和测试机制

下一章第7章:Inventory 管理详解

返回目录Ansible 自动化运维教程