目录
[1 流程控制概述](#1 流程控制概述)
[1.1 什么是流程控制](#1.1 什么是流程控制)
[1.2 流程控制的类型](#1.2 流程控制的类型)
[1.3 流程控制的重要性](#1.3 流程控制的重要性)
[2 条件判断(if/elif/else)](#2 条件判断(if/elif/else))
[2.1 基本语法](#2.1 基本语法)
[2.2 简单条件判断](#2.2 简单条件判断)
[2.3 比较运算符](#2.3 比较运算符)
[2.4 逻辑运算符](#2.4 逻辑运算符)
[2.5 实际应用案例:根据操作系统类型配置Nginx](#2.5 实际应用案例:根据操作系统类型配置Nginx)
[3 循环(for循环)](#3 循环(for循环))
[3.1 基本语法](#3.1 基本语法)
[3.2 遍历列表](#3.2 遍历列表)
[3.3 遍历字典](#3.3 遍历字典)
[3.4 循环控制变量](#3.4 循环控制变量)
[3.5 实际应用案例:配置多个Nginx虚拟主机](#3.5 实际应用案例:配置多个Nginx虚拟主机)
[3.6 带条件的循环](#3.6 带条件的循环)
[3.7 循环中的else语句](#3.7 循环中的else语句)
[4 嵌套循环与复杂场景](#4 嵌套循环与复杂场景)
[4.1 嵌套循环](#4.1 嵌套循环)
[4.2 循环中的特殊语法](#4.2 循环中的特殊语法)
[4.3 实际应用案例:配置多个负载均衡后端服务器](#4.3 实际应用案例:配置多个负载均衡后端服务器)
[5 宏(Macro)的高级应用](#5 宏(Macro)的高级应用)
[5.1 宏的定义与调用](#5.1 宏的定义与调用)
[5.2 带默认参数的宏](#5.2 带默认参数的宏)
[5.3 实际应用案例:使用宏简化虚拟主机配置](#5.3 实际应用案例:使用宏简化虚拟主机配置)
[6 总结](#6 总结)
在Ansible模板管理中,我们经常需要根据不同条件生成不同的配置内容,或者对列表、字典等复杂数据结构进行迭代处理。Jinja2模板引擎提供了强大的流程控制功能,包括for循环和if条件判断,使得模板能够根据实际情况动态生成配置内容。
1 流程控制概述
1.1 什么是流程控制
流程控制是编程语言中的基本概念,它允许程序根据条件执行不同的代码分支或重复执行某些代码块。在Ansible模板中,流程控制使我们能够根据变量值、主机 facts 或其他条件动态生成配置内容。
1.2 流程控制的类型

1.3 流程控制的重要性
流程控制使得Ansible模板能够:
- 根据不同环境生成差异化配置
- 处理复杂数据结构(如列表、字典)
- 实现配置的逻辑判断和条件应用
- 减少重复代码,提高模板的可维护性
2 条件判断(if/elif/else)
2.1 基本语法
{% if condition %}
<!-- 条件为真时执行的代码 -->
{% elif another_condition %}
<!-- 另一个条件为真时执行的代码 -->
{% else %}
<!-- 所有条件都为假时执行的代码 -->
{% endif %}
2.2 简单条件判断
{% if debug %}
debug = true
{% else %}
debug = false
{% endif %}
2.3 比较运算符
{% if value > 10 %}
<!-- value大于10 -->
{% endif %}
{% if version == "1.0" %}
<!-- version等于"1.0" -->
{% endif %}
{% if name in ["nginx", "apache", "httpd"] %}
<!-- name在列表中 -->
{% endif %}
2.4 逻辑运算符
{% if condition1 and condition2 %}
<!-- condition1和condition2都为真 -->
{% endif %}
{% if condition1 or condition2 %}
<!-- condition1或condition2至少一个为真 -->
{% endif %}
{% if not condition %}
<!-- condition为假 -->
{% endif %}
2.5 实际应用案例:根据操作系统类型配置Nginx
---
- hosts: webservers
vars:
nginx_config:
user: "{{ ansible_user | default('nginx') }}"
worker_processes: "{{ ansible_processor_vcpus }}"
keepalive_timeout: 65
tasks:
- name: Configure nginx
template:
src: nginx.conf.j2
dest: /etc/nginx/nginx.conf
-
模板文件 nginx.conf.j2 :
user {{ nginx_config.user }};
worker_processes {{ nginx_config.worker_processes }};{% if ansible_distribution == "CentOS" %}
error_log /var/log/nginx/error.log warn;
pid /var/run/nginx.pid;
{% elif ansible_distribution == "Ubuntu" %}
error_log /var/log/nginx/error.log;
pid /run/nginx.pid;
{% endif %}events {
worker_connections 1024;
multi_accept on;
}http {
include /etc/nginx/mime.types;
default_type application/octet-stream;sendfile on; tcp_nopush on; tcp_nodelay on; keepalive_timeout {{ nginx_config.keepalive_timeout }}; types_hash_max_size 2048; {% if ansible_distribution_major_version == "7" %} # CentOS 7 specific configuration ssl_protocols TLSv1 TLSv1.1 TLSv1.2; {% elif ansible_distribution_major_version == "8" %} # CentOS 8 specific configuration ssl_protocols TLSv1.2 TLSv1.3; {% endif %} # ... 其他配置
}
3 循环(for循环)
3.1 基本语法
{% for item in sequence %}
<!-- 对序列中的每个item执行的代码 -->
{% endfor %}
3.2 遍历列表
{% for server in servers %}
server {{ server }};
{% endfor %}
3.3 遍历字典
{% for key, value in config.items() %}
{{ key }} = {{ value }}
{% endfor %}
3.4 循环控制变量
- Jinja2提供了多个循环控制变量:
|----------------|-----------------|
| 变量 | 描述 |
| loop.index | 当前循环的索引(从1开始) |
| loop.index0 | 当前循环的索引(从0开始) |
| loop.revindex | 当前循环的倒序索引(从1开始) |
| loop.revindex0 | 当前循环的倒序索引(从0开始) |
| loop.first | 是否是第一次循环 |
| loop.last | 是否是最后一次循环 |
| loop.length | 序列的长度 |
| loop.depth | 当前循环的嵌套深度 |
| loop.depth0 | 当前循环的嵌套深度(从0开始) |
3.5 实际应用案例:配置多个Nginx虚拟主机
---
- hosts: webservers
vars:
virtual_hosts:
- name: "example.com"
root: "/var/www/example.com"
server_name: "example.com www.example.com"
index: "index.html index.htm"
- name: "test.com"
root: "/var/www/test.com"
server_name: "test.com www.test.com"
index: "index.html"
tasks:
- name: Configure virtual hosts
template:
src: virtual_hosts.conf.j2
dest: /etc/nginx/conf.d/virtual_hosts.conf
-
模板文件 virtual_hosts.conf.j2 :
{% for host in virtual_hosts %}
server {
listen 80;
server_name {{ host.server_name }};
root {{ host.root }};
index {{ host.index }};location / { try_files $uri $uri/ =404; } {% if host.name == "example.com" %} location /status { stub_status on; access_log off; allow 127.0.0.1; deny all; } {% endif %}
}
{% endfor %}
3.6 带条件的循环
{% for host in virtual_hosts if host.enabled %}
server {
# 配置内容
}
{% endfor %}
3.7 循环中的else语句
{% for item in items %}
{{ item }}
{% else %}
<!-- 如果items为空或未定义,则执行此代码 -->
No items found
{% endfor %}
4 嵌套循环与复杂场景
4.1 嵌套循环
{% for category in categories %}
[{{ category.name }}]
{% for product in category.products %}
{{ product.name }} = {{ product.price }}
{% endfor %}
{% endfor %}
4.2 循环中的特殊语法
{% for user in users %}
{{ user.name }}{% if not loop.last %},{% endif %}
{% endfor %}
4.3 实际应用案例:配置多个负载均衡后端服务器
---
- hosts: load_balancers
vars:
upstreams:
- name: "app_servers"
servers:
- name: "app1"
address: "192.168.10.10:8080"
weight: 3
- name: "app2"
address: "192.168.10.11:8080"
weight: 2
- name: "app3"
address: "192.168.10.12:8080"
weight: 1
- name: "api_servers"
servers:
- name: "api1"
address: "192.168.2.10:8080"
weight: 1
tasks:
- name: Configure upstreams
template:
src: upstreams.conf.j2
dest: /etc/nginx/conf.d/upstreams.conf
-
模板文件 upstreams.conf.j2 :
{% for upstream in upstreams %}
upstream {{ upstream.name }} {
{% for server in upstream.servers %}
server {{ server.address }} weight={{ server.weight }}{% if not loop.last %};{% endif %}
{% endfor %}
}
{% endfor %}server {
listen 80;
server_name example.com;location / { proxy_pass http://app_servers; } location /api { proxy_pass http://api_servers; }
}
5 宏(Macro)的高级应用
5.1 宏的定义与调用
{% macro server_block(name, port) %}
server {
listen {{ port }};
server_name {{ name }};
# ... 其他配置
}
{% endmacro %}
{% for server in servers %}
{{ server_block(server.name, server.port) }}
{% endfor %}
5.2 带默认参数的宏
{% macro server_block(name, port=80, root="/var/www") %}
server {
listen {{ port }};
server_name {{ name }};
root {{ root }};
# ... 其他配置
}
{% endmacro %}
5.3 实际应用案例:使用宏简化虚拟主机配置
{% macro virtual_host(name, root, server_names, port=80) %}
server {
listen {{ port }};
server_name {{ server_names }};
root {{ root }};
index index.html index.htm;
location / {
try_files $uri $uri/ =404;
}
location /status {
stub_status on;
access_log off;
allow 127.0.0.1;
deny all;
}
}
{% endmacro %}
{{ virtual_host(
name="example.com",
root="/var/www/example.com",
server_names="example.com www.example.com",
port=80
) }}
{{ virtual_host(
name="test.com",
root="/var/www/test.com",
server_names="test.com www.test.com",
port=80
) }}
6 总结
本文介绍了Ansible模板中的流程控制功能,包括条件判断(if/elif/else)和循环(for循环),以及宏的高级应用。通过这些流程控制语句,我们能够创建更加智能、灵活的配置模板,根据不同条件生成差异化的配置内容。
条件判断使我们能够根据变量值、主机 facts 或其他条件动态应用配置,而循环则允许我们高效处理列表、字典等复杂数据结构,避免重复代码。宏的使用则可以进一步提高模板的可重用性和可维护性。
在实际应用中,我们应该遵循最佳实践,保持模板简洁,合理使用注释,避免过度嵌套,并通过变量简化复杂逻辑。