layout: post
title: Ansible-playbook的Templates
date: 2018-01-16
tags: [“Ansible”,”自动化运维工具”]


一、 templates功能

文本文件,嵌套有脚本,使用 Jinja2语言,使用字面量,有下面形式:

字符串:使用单引号或双引号
数字:整数,浮点数
列表:[item1, item2, …]
元组:(item1, item2, …)
字典:{key1:value1, key2:value2, …}
布尔型:true/false
算术运算:+, -, , /, //, %, *
比较操作:==, !=, >, >=, <, <=
逻辑运算:and, or, not
流表达式:For If When

根据模块文件动态生成对应的配置文件, templates文件必须存放于templates目录下,且命名为 .j2 结尾yaml/yml 文件需和templates目录平级,目录结构如下:

./
├── temnginx.yml
└── templates
└── nginx.conf.j2

二、Templates示例

1)利用templates同步nginx配置文件

  1. 准备templates/nginx.conf.j2文件
  2. [root@ansible ~]# ansible 172.18.30.1 -m fetch -a 'src=/usr/local/nginx/conf/nginx.conf dest=/app' #因为之前已经安装过nginx,我把远端的nginx配置文件拉到本地做一个模板。
  3. [root@ansible ~]# cp /app/172.18.30.1/usr/local/nginx/conf/nginx.conf /app/ansible/playbook/templates/nginx.conf.j2
  4.  
  5. [root@ansible ~]# vim /app/ansible/playbook/templates/nginx.conf.j2
  6.  
  7. #worker_processes 1; 修改这一项
  8. worker_processes {{ansible_processor_vcpus}}; #可以通过ansible localhost -m setup ' grep cpu 找到这个内建变量,代表的是cpu个数
  9.  

因为只是实验,为了简介,我们将配置文件的其他选项直接删除

现在我们开始编写playbook,并使用templates

  1. vim templates_example.yml
  2. ---
  3. - hosts: webserver
  4. remote_user: root
  5. tasks:
  6. - name: template config to web hosts
  7. template: src=nginx.conf.j2 dest=/app/nginx.conf
  8. 调用剧本
  9. ansible-playbook templates_example.yml
  10. PLAY [webserver] ****************************************************************************
  11. TASK [Gathering Facts] **********************************************************************
  12. ok: [172.18.30.2]
  13. ok: [172.18.30.1]
  14. TASK [template config to web hosts] *********************************************************
  15. changed: [172.18.30.2]
  16. changed: [172.18.30.1]
  17. PLAY RECAP **********************************************************************************
  18. 172.18.30.1 : ok=2 changed=1 unreachable=0 failed=0
  19. 172.18.30.2 : ok=2 changed=1 unreachable=0 failed=0
  20. 执行成功,我们现在去web服务器,去看一下传递过去的配置文件
  21. @172.18.30.1
  22. [root@localhost /]# cat /app/nginx.conf
  23. #这是一个测试文件
  24. #user nobody;
  25. worker_processes 1;
  26. 成功应用了变量的值。这就是使用templates替换配置文件关键值的方法。

2)templates的算术演示

还借用上一个模版

  1. 我们修改模版
  2. vim templates/nginx.conf.j2
  3. worker_processes {{ansible_processor_vcpus*2}};
  4.  
  5. 再次执行playbook
  6.  
  7. ansible-playbook templates_example.yml
  8.  
  9. PLAY [webserver] ****************************************************************************
  10.  
  11. TASK [Gathering Facts] **********************************************************************
  12. ok: [172.18.30.2]
  13. ok: [172.18.30.1]
  14.  
  15. TASK [template config to web hosts] *********************************************************
  16. changed: [172.18.30.2]
  17. changed: [172.18.30.1]
  18.  
  19. PLAY RECAP **********************************************************************************
  20. 172.18.30.1 : ok=2 changed=1 unreachable=0 failed=0
  21. 172.18.30.2 : ok=2 changed=1 unreachable=0 failed=0
  22.  
  23. 我们去172.18.30.1去查看一下传递过去的配置文件
  24. @172.18.30.1
  25. cat /app/nginx.conf
  26. #这是一个测试文件
  27. #user nobody;
  28. worker_processes 2;
  29.  
  30. 直接进行了算术运算

3)when的使用:

条件测试:如果需要根据变量、facts或此前任务的执行结果来做为某task执行与否的前提时要用到条件测试,通过when语句实现,在task中使用,jinja2的语法格式

在task后添加when子句即可使用条件测试;when语句支持Jinja2表达式语法

我们使用centos6和centos7两种操作系统来做演示:

  1. ssh-copy-id 172.18.30.254 这台机器是centos6
  2.  
  3. 现在我们配置ansibleIventory, 我们为centos6添加到webserver组内
  4.  
  5. vim /etc/ansible/hosts
  6.  
  7. [webserver]
  8. 172.18.30.[1:2]
  9. 172.18.30.254
  10.  
  11. 回到/app/ansible/playbook/下编写剧本
  12. cd /app/ansible/playbook/
  13.  
  14. touch when_example.yml
  15.  
  16. vim when_example.yml
  17.  
  18. ---
  19. - hosts: webserver
  20. remote_user: root
  21. tasks:
  22. - name: yum install ftp
  23. yum: name=ftp,vsftp state=latest
  24. when: ansible_distribution_major_version=='6'
  25. #ansible_distribution_major_version这个变量可以通过 ansible localhost -m setup ' grep version 获得
  26.  
  27. 执行剧本
  28. ansible-playbook when_example.yml
  29.  
  30. PLAY [webserver] ***************************************************************************************************************************
  31.  
  32. TASK [Gathering Facts] *********************************************************************************************************************
  33. ok: [172.18.30.2]
  34. ok: [172.18.30.1]
  35. ok: [172.18.30.254]
  36.  
  37. TASK [yum install ftp] *********************************************************************************************************************
  38. skipping: [172.18.30.1]
  39. skipping: [172.18.30.2]
  40. changed: [172.18.30.254]
  41.  
  42. PLAY RECAP *********************************************************************************************************************************
  43. 172.18.30.1 : ok=1 changed=0 unreachable=0 failed=0
  44. 172.18.30.2 : ok=1 changed=0 unreachable=0 failed=0
  45. 172.18.30.254 : ok=2 changed=1 unreachable=0 failed=0
  46.  
  47. 通过执行结果可以看出,在执行时,跳过了两台centos7,只在centos6上安装了软件包,ansible_distribution_major_version这个变量的含义是系统的主版本号,这就是when的语法,主要用在剧本中。

4)when的实例2:

根据不通的系统版本复制不通的配置文件

(1)创建两个模板文件

  1. vim /app/ansible/playbook/templates/c6_nginx.conf
  2.  
  3. #这是c6的模版文件
  1. vim /app/ansible/playbook/templates/c7.nginx.conf
  2.  
  3. #这是c7的模版文件

(2)编写playbook

  1. vim /app/ansible/playbook/when_example2.yml
  2. ---
  3. - hosts: webserver
  4. remote_user: root
  5. tasks:
  6. - name: cp nginx cfg of c6 to remote hosts
  7. template: src=templates/c6_nginx.conf dest=/app/nginx.conf
  8. when: ansible_distribution_major_version=='6'
  9. - name: cp nginx cfg of c7 to remote hosts
  10. template: src=templates/c7_nginx.conf dest=/app/nginx.conf
  11. when: ansible_distribution_major_version=='7'</pre>
  12. (3)执行这段脚本
  13. <pre class="EnlighterJSRAW" data-enlighter-language="null">[root@ansible playbook]# ansible-playbook when_example2.yml
  14. PLAY [webserver] ***************************************************************************
  15. TASK [Gathering Facts] *********************************************************************
  16. ok: [172.18.30.1]
  17. ok: [172.18.30.2]
  18. ok: [172.18.30.254]
  19. TASK [cp nginx cfg of c6 to remote hosts] **************************************************
  20. skipping: [172.18.30.1]
  21. skipping: [172.18.30.2]
  22. changed: [172.18.30.254]
  23. TASK [cp nginx cfg of c7 to remote hosts] **************************************************
  24. skipping: [172.18.30.254]
  25. changed: [172.18.30.1]
  26. changed: [172.18.30.2]
  27. PLAY RECAP *********************************************************************************
  28. 172.18.30.1 : ok=2 changed=1 unreachable=0 failed=0
  29. 172.18.30.2 : ok=2 changed=1 unreachable=0 failed=0
  30. 172.18.30.254 : ok=2 changed=1 unreachable=0 failed=0</pre>
  31. 执行是成功的,下面我们分别查看c6c7的文件
  32. 4)查看传递的配置文件
  33. <pre class="EnlighterJSRAW" data-enlighter-language="null">@172.18.30.1
  34. cat /app/nginx.conf
  35. #这是c7的模版文件
  36. @172.18.30.254
  37. #这是c6的模版文件

when的用法就写到这里

5)with_items迭代

迭代:当有需要重复性执行的任务时,可以使用迭代机制

对迭代项的引用,固定变量名为”item”,要在task中使用with_items给定要迭代的元素列表

列表格式:

字符串
字典

下面做一个批量添加用户的演示

(1)编写playbook

  1. vim /app/ansible/playbook/with_items_add_user_example.yml
  2.  
  3. ---
  4. - hosts: mysql
  5. remote_user: root
  6. tasks:
  7. - name: with_items_example add user
  8. user: name={{item}} state=present groups=apache shell=/sbin/nologin createhome=no comment=test
  9. with_items:
  10. - aabb
  11. - bbcc
  12. - ccee
  13.  
  14. #这里有个坑,在添加用户时,如果直接使用group 来给用户添加 与用户名同名的主组会报错。
  15.  

现在我们调用这个playbook

  1. [root@ansible playbook]# ansible-playbook with_items_add_user_example.yml
  2.  
  3. PLAY [mysql] *******************************************************************************
  4.  
  5. TASK [Gathering Facts] *********************************************************************
  6. ok: [172.18.30.3]
  7.  
  8. TASK [with_items_example add user] *********************************************************
  9. changed: [172.18.30.3] => (item=aabb)
  10. changed: [172.18.30.3] => (item=bbcc)
  11. changed: [172.18.30.3] => (item=ccee)
  12.  
  13. PLAY RECAP *********************************************************************************
  14. 172.18.30.3 : ok=2 changed=1 unreachable=0 failed=0
  15.  
  16. 执行成功,我们去目标主机查看,新添加的用户

(2)查看新添加的用户

  1. @172.18.30.3
  2. [root@mysql ~]# tail -n 5 /etc/passwd
  3. ntp:x:38:38::/etc/ntp:/sbin/nologin
  4. ddd:x:1000:1000::/home/ddd:/bin/bash
  5. aabb:x:1001:1002:test:/home/aabb:/sbin/nologin
  6. bbcc:x:1002:1003:test:/home/bbcc:/sbin/nologin
  7. ccee:x:1003:1004:test:/home/ccee:/sbin/nologin
  8.  
  9. 已经成功添加

6)要想删除这些用户,也简单,再写个剧本

  1. vim /app/ansible/playbook/absent_user_example.yml
  2.  
  3. ---
  4. - hosts: mysql
  5. remote_user: root
  6. tasks:
  7. - name:absent users
  8. user: name={{item}} state=absent
  9. with_itmes:
  10. - aabb
  11. - bbcc
  12. - ccee

脚本的执行结果就是把这几个用户删除了

7)迭代嵌套子变量

(1) 编写一个创建用户的案例:

  1. vim /app/ansible/playbook/add_user_example.yml
  2.  
  3. ---
  4. - hosts: webserver
  5. remote_user: root
  6. tasks:
  7. - name: add users
  8. user: name={{item.name}} groups={{item.group}}
  9. with_items:
  10. - {name: 'ok',group: 'nginx'}
  11. - {name: 'nice',group: 'nginx'}

(2)执行这段剧本

  1. [root@ansible playbook]# ansible-playbook add_user_example.yml
  2.  
  3. PLAY [webserver] ***************************************************************************
  4.  
  5. TASK [Gathering Facts] *********************************************************************
  6. ok: [172.18.30.2]
  7. ok: [172.18.30.1]
  8.  
  9. TASK [add users] ***************************************************************************
  10. changed: [172.18.30.2] => (item={u'group': u'nginx', u'name': u'ok'})
  11. changed: [172.18.30.1] => (item={u'group': u'nginx', u'name': u'ok'})
  12. changed: [172.18.30.1] => (item={u'group': u'nginx', u'name': u'nice'})
  13. changed: [172.18.30.2] => (item={u'group': u'nginx', u'name': u'nice'})
  14.  
  15. PLAY RECAP *********************************************************************************
  16. 172.18.30.1 : ok=2 changed=1 unreachable=0 failed=0
  17. 172.18.30.2 : ok=2 changed=1 unreachable=0 failed=0
  18.  

8)templates中的for 和 if

这两个关键词使用在模版文件中,而不是用在剧本中的。

我们来编辑一个nginx的配置文件

(1)创建nginx模板配置文件并进行编辑

  1. vim /app/ansible/playbook/templates/nginx_temp_example_for_if.conf
  2.  
  3. worker_processes {{ansible_processor_vcpus}};
  4.  
  5. events {
  6. use epoll;
  7. multi_accept on;
  8. worker_connections 65535;
  9. }
  10.  
  11. error_log /log/nginx/error/error.log notice;
  12. http {
  13. include mime.types;
  14. default_type application/octet-stream;
  15. access_log /log/nginx/access/access.log new_log;
  16.  
  17. upstream php_page{
  18. server 172.18.30.1:18150 weight=1 max_fails=1 fail_timeout=60s;
  19. server 172.18.30.2:18150 weight=1 max_fails=1 fail_timeout=60s;
  20. }
  21. upstream html_page{
  22. server 172.18.30.3:18150 weight=1 max_fails=1 fail_timeout=60s;
  23. server 172.18.30.4:18150 weight=1 max_fails=1 fail_timeout=60s;
  24. }
  25.  
  26. {% for vhost in nginx_hosts %}
  27. server {
  28. listen {{vhost.listen}};
  29. server_name {{vhost.server_name}};
  30. location / {
  31. index index.jhtml index.html index.htm index.php;
  32. proxy_pass http://php_page;
  33. client_max_body_size 30m;
  34. client_body_buffer_size 5280k;
  35. keepalive_requests 1000;
  36.  
  37. }
  38. }
  39.  
  40. {% endfor %} #这段对server循环配置
  41. }

(2)编写playbook,在playbook中定义在模板文件中需要的变量

  1. vim nginx_conf_exmaple.yml
  2. ---
  3. - hosts: webserver
  4. remote_user: root
  5. vars:
  6. nginx_hosts:
  7. - ok1:
  8. listen: 8080
  9. server_name: php
  10. - ok2:
  11. listen: 80
  12. server_name: html
  13. tasks:
  14. - name: nginx file
  15. template: src=templates/nginx_temp_example_for_if.conf dest=/app/nginx/nginx.conf.2

(3)执行这段playbook,并查看复制的配置文件

  1. [root@ansible playbook]# ansible-playbook nginx_conf_example.yml
  2. PLAY [webserver] ***************************************************************************************************************************
  3. TASK [Gathering Facts] *********************************************************************************************************************
  4. ok: [172.18.30.1]
  5. ok: [172.18.30.2]
  6. ok: [172.18.30.254]
  7. TASK [nginx file] **************************************************************************************************************************
  8. changed: [172.18.30.254]
  9. changed: [172.18.30.1]
  10. changed: [172.18.30.2]
  11. PLAY RECAP *********************************************************************************************************************************
  12. 172.18.30.1 : ok=2 changed=1 unreachable=0 failed=0
  13. 172.18.30.2 : ok=2 changed=1 unreachable=0 failed=0
  14. 172.18.30.254 : ok=2 changed=1 unreachable=0 failed=0
  1. 查看配置文件
  2. @172.18.30.1
  3. [root@localhost nginx]# cat /app/nginx/nginx.conf.2
  4. worker_processes 1;
  5. events {
  6. use epoll;
  7. multi_accept on;
  8. worker_connections 65535;
  9. }
  10. error_log /log/nginx/error/error.log notice;
  11. http {
  12. include mime.types;
  13. default_type application/octet-stream;
  14. access_log /log/nginx/access/access.log new_log;
  15. upstream php_page{
  16. server 172.18.30.1:18150 weight=1 max_fails=1 fail_timeout=60s;
  17. server 172.18.30.2:18150 weight=1 max_fails=1 fail_timeout=60s;
  18. }
  19. upstream html_page{
  20. server 172.18.30.3:18150 weight=1 max_fails=1 fail_timeout=60s;
  21. server 172.18.30.4:18150 weight=1 max_fails=1 fail_timeout=60s;
  22. }
  23. server {
  24. listen 8080;
  25. server_name php;
  26. location / {
  27. index index.jhtml index.html index.htm index.php;
  28. proxy_pass http://php_page;
  29. client_max_body_size 30m;
  30. client_body_buffer_size 5280k;
  31. keepalive_requests 1000;
  32. }
  33. }
  34. server {
  35. listen 80;
  36. server_name html;
  37. location / {
  38. index index.jhtml index.html index.htm index.php;
  39. proxy_pass http://php_page;
  40. client_max_body_size 30m;
  41. client_body_buffer_size 5280k;
  42. keepalive_requests 1000;
  43. }
  44. }
  45. #这段对server循环配置
  46. }
  47. 生成了两个不同的server

(4)if的套用

(1)我们还是还用nginx的配置文件作为模板

  1. vim /app/ansible/playbook/templates/nginx_if_example.conf.j2
  2. worker_processes {{ansible_processor_vcpus}};
  3. events {
  4. use epoll;
  5. multi_accept on;
  6. worker_connections 65535;
  7. }
  8. error_log /log/nginx/error/error.log notice;
  9. http {
  10. include mime.types;
  11. default_type application/octet-stream;
  12. access_log /log/nginx/access/access.log new_log;
  13. upstream php_page{
  14. server 172.18.30.1:18150 weight=1 max_fails=1 fail_timeout=60s;
  15. server 172.18.30.2:18150 weight=1 max_fails=1 fail_timeout=60s;
  16. }
  17. upstream html_page{
  18. server 172.18.30.3:18150 weight=1 max_fails=1 fail_timeout=60s;
  19. server 172.18.30.4:18150 weight=1 max_fails=1 fail_timeout=60s;
  20. }
  21. {% for vhost in nginx_hosts %}
  22. server {
  23. listen {{vhost.listen}};
  24. {% if vhost.server_name is defined %}
  25. server_name {{vhost.server_name}};
  26. {% endif %}
  27. location / {
  28. index index.jhtml index.html index.htm index.php;
  29. proxy_pass http://php_page;
  30. client_max_body_size 30m;
  31. client_body_buffer_size 5280k;
  32. keepalive_requests 1000;
  33. }
  34. }
  35. {% endfor %} #这段对server循环配置
  36. }

(2)编写playbook

  1. ---
  2. - hosts: webserver
  3. remote_user: root
  4. vars:
  5. nginx_hosts:
  6. - {listen: 80,server_name: php_page}
  7. - {listen: 8080}
  8. tasks:
  9. - name: use if
  10. template: src=nginx_if_example.conf.j2 dest=/app/nginx/nginx_if.conf

(3)执行这段,并查看目标主机的文件

  1. [root@ansible playbook]# ansible-playbook nginx_if.yml
  2. PLAY [webserver] ***************************************************************************************************************************
  3. TASK [Gathering Facts] *********************************************************************************************************************
  4. ok: [172.18.30.1]
  5. ok: [172.18.30.2]
  6. ok: [172.18.30.254]
  7. TASK [use if] ******************************************************************************************************************************
  8. changed: [172.18.30.254]
  9. changed: [172.18.30.2]
  10. changed: [172.18.30.1]
  11. PLAY RECAP *********************************************************************************************************************************
  12. 172.18.30.1 : ok=2 changed=1 unreachable=0 failed=0
  13. 172.18.30.2 : ok=2 changed=1 unreachable=0 failed=0
  14. 172.18.30.254 : ok=2 changed=1 unreachable=0 failed=0
  15. 执行成功
  1. 查看受控主机生成的配置文件
  2. @172.18.30.1
  3. [root@localhost nginx]# cat nginx_if.conf
  4. worker_processes 1;
  5. events {
  6. use epoll;
  7. multi_accept on;
  8. worker_connections 65535;
  9. }
  10. error_log /log/nginx/error/error.log notice;
  11. http {
  12. include mime.types;
  13. default_type application/octet-stream;
  14. access_log /log/nginx/access/access.log new_log;
  15. upstream php_page{
  16. server 172.18.30.1:18150 weight=1 max_fails=1 fail_timeout=60s;
  17. server 172.18.30.2:18150 weight=1 max_fails=1 fail_timeout=60s;
  18. }
  19. upstream html_page{
  20. server 172.18.30.3:18150 weight=1 max_fails=1 fail_timeout=60s;
  21. server 172.18.30.4:18150 weight=1 max_fails=1 fail_timeout=60s;
  22. }
  23. server {
  24. listen 80;
  25. server_name php_page; #通过if,这个有server_name
  26. location / {
  27. index index.jhtml index.html index.htm index.php;
  28. proxy_pass http://php_page;
  29. client_max_body_size 30m;
  30. client_body_buffer_size 5280k;
  31. keepalive_requests 1000;
  32. }
  33. }
  34. server {
  35. listen 8080; #未定义server_name,这个没有
  36. location / {
  37. index index.jhtml index.html index.htm index.php;
  38. proxy_pass http://php_page;
  39. client_max_body_size 30m;
  40. client_body_buffer_size 5280k;
  41. keepalive_requests 1000;
  42. }
  43. }
  44. #这段对server循环配置
  45. }
文档更新时间: 2018-12-20 16:00   作者:张尚