ansible使用jinja2管理配置文件以及jinja2语法简介
一、Jinja2介绍
Jinja2是基于python的模板引擎,功能比较类似于PHP的smarty,J2ee的Freemarker和velocity。它能完全支持unicode,并具有集成的沙箱执行环境,应用广泛。jinja2使用BSD授权
Jinja2的语法是由variables(变量)和statement(语句)组成,如下;
1、variables:可以输出数据
{{ my_variables }}
{{ some_dudes_name | capitalize }}
2、statements: 可以用来创建条件和循环等
1
2
3
4
5
6
7
8
9
|
if 语句: {% if my_conditional %} ... {% endif %} for 语句: {% for item in all_items %} {{item}} …… {% endfor %} |
从上面第二个variables的例子中可以看出,jinja2支持使用带过滤器的Unix型管道操作符,有很多的内置过滤器可供使用。我们可以仅仅用一堆简单if和for就可以建立几乎任何的常规配置文件,不过如果你有意更进一步,jinja2 documentation (http://jinja.pocoo.org/docs/dev/)包含了很多有趣的东西可供了解。我们可以看到ansible允许在模板中使用诸如绘制时间此类的一些额外的模板变量
第一个例子:引用变量
1
2
3
4
5
6
7
8
9
10
11
|
#cd roles/template/ . ├── meta │ └── main.yml ├── tasks │ ├── template.yml │ └── main.yml ├── templates │ ├── order.j2 └── vars └── main.yml |
总调度yml文件:
1
2
3
4
5
6
7
|
#cat templates.yml --- - hosts: 10.0.90.27 user: root gather_facts: false roles: - role: template |
注意:这里 - role: template 和 - template 是一样的!
其他yml文件,如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
|
#cat tasks/main.yml - include: template.yml #cat tasks/template.yml - name: create {{ PROJECT }} directory file : dest= /data/ {{ PROJECT }} state=directory - name: template transfor java dir template: src=order.j2 dest= /data/ {{ PROJECT }} /order .conf #cat templates/order.j2 project: {{ PROJECT }} switch: {{ SWITCH }} dbport: {{ DBPORT }} #cat vars/main.yml PROJECT: "JAVA" SWITCH: "ON" DBPORT: "8080" 测试: # ansible-playbook templates.yml --syntax-check playbook: templates.yml 执行: # ansible-playbook templates.yml PLAY [10.0.90.27] ************************************************************** TASK [template : include] *************************************************** included: /etc/ansible/roles/template/tasks/template .yml for 10.0.90.27 TASK [template : create JAVA directory] ************************************* changed: [10.0.90.27] TASK [template : template transfor java dir ] ******************************** changed: [10.0.90.27] PLAY RECAP ********************************************************************* 10.0.90.27 : ok=3 changed=2 unreachable=0 failed=0 到10.0.90.27查看结果 #cat /data/JAVA/order.conf project: JAVA switch: ON dbport: 8080 |
第二个例子:for 语句
为远程主机生成服务器列表,加入该列表从192.168.13.201 web01.test.com 到192.168.13.211 web11.test.com 结束,如果手动添加就很不科学了,这里需要使用jinja2语法的for循环通过模板批量生成对应的配置文件,如下:
ansible目录结构:
1
2
3
4
5
6
7
8
9
10
11
|
#cd /etc/ansible/roles/test_hosts . ├── meta │ └── main.yml ├── tasks │ ├── file1.yml │ └── main.yml ├── templates │ └── test1.j2 └── vars └── main.yml |
各个目录下yml文件内容:
1
2
3
4
5
6
7
8
9
10
11
12
13
|
# cat tasks/file1.yml - name: ansible jinja2 template for hosts config template: src=test1.j2 dest= /etc/httpd/conf/httpd .conf. test # cat tasks/main.yml - include: file1.yml # cat templates/test1.j2 {% for id in range(201,212) %} 192.168.13.{{ id }} web{{ "%03d" | format ( id -200) }}. test .com {% endfor %} 解释: {{ id }} 提取 for 循环中对应的变量 id 值 "%02d" 调用的是python内置的字符串格式化输出(%d格式化整数)因为是01,02这种格式,所以是保留2位,故用02 然后将结果通过管道符 “|” 传递给 format 函数做二次处理。 |
执行结果:
1
2
3
4
5
6
7
8
9
10
11
12
|
#cat httpd.conf.test 192.168.13.201 web01. test .com 192.168.13.202 web02. test .com 192.168.13.203 web03. test .com 192.168.13.204 web04. test .com 192.168.13.205 web05. test .com 192.168.13.206 web06. test .com 192.168.13.207 web07. test .com 192.168.13.208 web08. test .com 192.168.13.209 web09. test .com 192.168.13.210 web10. test .com 192.168.13.211 web11. test .com |
第三个例子:if语句
说明:如果定义端口号,就绑定定义的端口号,如果不定义端口号,就绑定默认端口号
1
2
3
4
5
6
7
8
9
10
11
|
ansible目录结果 #cd /etc/ansible/roles/mysql_cnf #tree . ├── meta │ └── main.yml ├── tasks │ └── main.yml ├── templates │ └── test3.j2 └── vars |
主要的yml文件是templates目录下面的test3.j2
1
2
3
4
5
6
|
# cat templates/test3.j2 {% if PORT %} bind_address=10.0.90.27:{{ PORT }} {% else %} bind_address=10.0.90.27:3306 {% endif %} |
playbook主文件
1
2
3
4
5
6
7
8
9
10
|
# cat jinj2_test.yml --- - hosts: 10.0.90.27 user: root gather_facts: false vars: PORT: 3136 tasks: - name: copy file to client template: src= /etc/ansible/roles/mysql_cnf/templates/test3 .j2 dest= /root/my .cnf |
执行:
1
2
3
4
5
6
|
# ansible-playbook jinj2_test.yml PLAY [10.0.90.27] ************************************************************** TASK [copy file to client] ***************************************************** changed: [10.0.90.27] PLAY RECAP ********************************************************************* 10.0.90.27 : ok=1 changed=1 unreachable=0 failed=0 |
查看
1
2
|
# cat my.cnf bind_address=10.0.90.27:3136 |
如果将vars变量去掉,执行结果:
1
2
3
4
5
6
7
8
9
10
|
# cat jinj2_test.yml --- - hosts: 10.0.90.27 user: root gather_facts: false vars: PORT: false tasks: - name: copy file to client template: src= /etc/ansible/roles/mysql_cnf/templates/test3 .j2 dest= /root/my .cnf |
查看:
1
2
|
# cat my.cnf bind_address=10.0.90.27:3306 |
3、Jinja default()设定
精通程序编码的朋友皆知,default()默认值的设定有助于程序的健壮性和简洁性。所幸Jinja也支持该功能,上面的例子中生成Mysql配置文件中的端口定义,如果指定则PORT=3136,否则PORT=3306,我们将该案例改造为使用default()试试
编辑/etc/ansible/roles/mysql_cnf/templates/test3.j2内容如下,这种方法更简介。
bind_address=10.0.90.27:{{ PORT | default(3306) }}
二、ansible使用jiaja2生成apache多主机配置
1、创建目录,创建好之后如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
#cd /etc/ansible/roles/apache_conf # tree ./ ./ ├── meta │ └── main.yml ├── tasks │ ├── file .yml │ └── main.yml ├── templates │ └── apache.config.j2 └── vars └── main.yml 4 directories, 5 files |
2、创建tasks调度文件,如下:
1
2
3
4
5
|
#cat file.yml - name: ansible jinja2 template for apache config template: src=apache.config.j2 dest= /etc/httpd/conf/httpd .conf.template #cat main.yml - include: file .yml |
3、创建apache的jinja2模板文件,如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
#cat apache.config.j2 NameVirtualHost *:80 {% for vhost in apache_vhost %} <VirtualHost *:80> ServerName {{ vhost.servername }} DocumentRoot {{ vhost.documentroot }} {% if vhost.serveradmin is defined %} ServerAdmin {{ vhost.serveradmin }} {% endif %} <Directory "{{ vhost.documentroot }}" > AllowOverride All Options -Indexes FollowSymLinks Order allow,deny Allow from all </Directory> </VirtualHost> {% endfor %} |
4、创建变量,如下:
1
2
3
4
|
#cat vars/main.yml apache_vhost: - {servername: "apache.test1.com" , documentroot: "/data/test1/" } - {servername: "apache.test2.com" , documentroot: "/data/test2/" } |
5、创建总调度yml文件,如下:
1
2
3
4
5
6
7
|
#cat /etc/ansible/apache_test.yml --- - hosts: 10.0.90.27 user: root gather_facts: no roles: - { role: apache_conf } |
6、测试:
1
2
3
|
#ansible-playbook apache_test.yml --syntax-check playbook: apache_test.yml |
7、执行测试
1
2
3
4
5
6
7
8
|
#ansible-playbook apache_test.yml PLAY [10.0.90.27] ************************************************************** TASK [apache_conf : include] *************************************************** included: /etc/ansible/roles/apache_conf/tasks/file .yml for 10.0.90.27 TASK [apache_conf : ansible jinja2 template for apache config] ***************** changed: [10.0.90.27] PLAY RECAP ********************************************************************* 10.0.90.27 : ok=2 changed=1 unreachable=0 failed=0 |
8、到客户端查看
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
|
#cat httpd.conf.template NameVirtualHost *:80 <VirtualHost *:80> ServerName apache.test1.com DocumentRoot /data/test1/ <Directory "/data/test1/" > AllowOverride All Options -Indexes FollowSymLinks Order allow,deny Allow from all < /Directory > < /VirtualHost > <VirtualHost *:80> ServerName apache.test2.com DocumentRoot /data/test2/ <Directory "/data/test2/" > AllowOverride All Options -Indexes FollowSymLinks Order allow,deny Allow from all < /Directory > < /VirtualHost > |
三、ansible使用jiaja2生成nginx一个模板多种不同配置
说明:为2台Nginx Proxy,1台Nginx Web通过一套模板生成对应的配置
1、ansible目录结构:
1
2
3
4
5
6
7
8
9
10
11
12
13
|
# cd roles/nginx_conf/ #tree . ├── files ├── meta │ └── main.yml ├── tasks │ ├── file .yml │ └── main.yml ├── templates │ └── nginx.conf.j2 └── vars └── main.yml |
2、tasks目录下文件内容:
1
2
3
4
5
|
#cat tasks/file.yml - name: nginx.j2 template transfer example template: src=nginx.conf.j2 dest= /etc/nginx/nginx .conf.template #cat tasks/main.yml - include: file .yml |
3、nginx模板文件
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
|
#cat templates/nginx.conf.j2 {% if nginx_use_proxy %} {% for proxy in nginx_proxies %} upstream {{ proxy.name }} #server 127.0.0.1:{{ proxy.port }}; server {{ ansible_eth0.ipv4.address }}:{{ proxy.port }}; } {% endfor %} {% endif%} server { listen 80; servername {{ nginx_server_name }}; access_log off; error_log /etc/nginx/nginx_error .log; rewrite ^ https: // $server_name$request_uri? permanent; } server { listen 443 ssl; server_name {{ nginx_server_name }}; ssl_certificate /etc/nginx/ssl/ {{ nginx_ssl_cert_name }}; ssl_certificate_key /etc/nginx/ssl/ {{ nginx_ssl_cert_key }}; root {{ nginx_web_root }}; index index.html index.html; {% if nginx_use_auth %} auth_basic "Restricted" ; auth_basic_user_file /etc/nginx/ {{ project_name }}.htpasswd; {% endif %} {% if nginx_use_proxy %} {% for proxy in nginx_proxies %} location {{ proxy.location }} { proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-Proto http; proxy_set_header X-Url-Scheme $scheme; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header Host $http_host; proxy_set_header X-NginX-Proxy true ; proxy_redirect off; proxy_pass http: // {{ proxy.name }}; break ; } {% endfor %} {% endif %} {% if nginx_server_static %} location / { try_files $url $url/ =404; } {% endif %} } |
4、ansible变量文件
1
2
3
4
5
6
7
8
9
10
|
cat vars /main .yml nginx_server_name: www.testnginx.com nginx_web_root: /data/html/ nginx_proxies: - name: suspicious location: / port: 1234 - name: suspicious-api location: /api port: 4567 |
ansible主playbook文件
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
|
#cat nginx_test.yml ##The first roles - name: Nginx Proxy Server's Config Dynamic Create hosts: "10.0.90.25:10.0.90.26" remote_user: root vars: nginx_use_proxy: true nginx_ssl_cert_name: ifa.crt nginx_ssl_cert_key: ifa.key nginx_use_auth: true project_name: suspicious nginx_server_static: true gather_facts: true roles: - role: nginx_conf ##The second roles - name: Nginx WebServer's Config Dynamic Create hosts: 10.0.90.27 remote_user: root vars: nginx_use_proxy: false nginx_ssl_cert_name: ifa.crt nginx_ssl_cert_key: ifa.crt nginx_use_auth: false project_name: suspicious nginx_server_static: false gather_facts: false roles: - role: nginx_conf |
5、测试并执行:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
|
#ansible-playbook nginx_test.yml --syntax-check playbook: nginx_test.yml 执行: # ansible-playbook nginx_test.yml PLAY [Nginx Proxy Server's Config Dynamic Create] ****************************** TASK [setup] ******************************************************************* ok: [10.0.90.25] ok: [10.0.90.26] TASK [nginx_conf : include] **************************************************** included: /etc/ansible/roles/nginx_conf/tasks/file .yml for 10.0.90.25, 10.0.90.26 TASK [nginx_conf : nginx.j2 template transfer example] ************************* changed: [10.0.90.26] changed: [10.0.90.25] PLAY [Nginx WebServer's Config Dynamic Create] ********************************* TASK [nginx_conf : include] **************************************************** included: /etc/ansible/roles/nginx_conf/tasks/file .yml for 10.0.90.27 TASK [nginx_conf : nginx.j2 template transfer example] ************************* changed: [10.0.90.27] PLAY RECAP ********************************************************************* 10.0.90.25 : ok=3 changed=1 unreachable=0 failed=0 10.0.90.26 : ok=3 changed=1 unreachable=0 failed=0 10.0.90.27 : ok=2 changed=1 unreachable=0 failed=0 |
6、查看检测执行结果
到Nginx Proxy 服务器查看配置文件
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
|
#cat nginx.conf.template upstream suspicious #server 127.0.0.1:1234; server 10.0.90.26:1234; } upstream suspicious-api #server 127.0.0.1:4567; server 10.0.90.26:4567; } server { listen 80; servername www.testnginx.com; access_log off; error_log /etc/nginx/nginx_error .log; rewrite ^ https: // $server_name$request_uri? permanent; } server { listen 443 ssl; server_name www.testnginx.com; ssl_certificate /etc/nginx/ssl/ifa .crt; ssl_certificate_key /etc/nginx/ssl/ifa .key; root /data/html/ ; index index.html index.html; auth_basic "Restricted" ; auth_basic_user_file /etc/nginx/suspicious .htpasswd; location / { proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-Proto http; proxy_set_header X-Url-Scheme $scheme; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header Host $http_host; proxy_set_header X-NginX-Proxy true ; proxy_redirect off; proxy_pass http: //suspicious ; break ; } location /api { proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-Proto http; proxy_set_header X-Url-Scheme $scheme; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header Host $http_host; proxy_set_header X-NginX-Proxy true ; proxy_redirect off; proxy_pass http: //suspicious-api ; break ; } location / { try_files $url $url/ =404; } } |
到Nginx Web 服务器上查看配置文件
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
#cat nginx.conf.template server { listen 80; servername www.testnginx.com; access_log off; error_log /etc/nginx/nginx_error .log; rewrite ^ https: // $server_name$request_uri? permanent; } server { listen 443 ssl; server_name www.testnginx.com; ssl_certificate /etc/nginx/ssl/ifa .crt; ssl_certificate_key /etc/nginx/ssl/ifa .crt; root /data/html/ ; index index.html index.html; } |
到这里,就结束了。用同样的模板通过简单的if和变量设置就可以完成不同类型主机的Nginx conf配置,所以一方面在了解Ansible强大的模板功能的同时,也需要看到模板质量的重要性。