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配置文件
- 准备templates/nginx.conf.j2文件
- [root@ansible ~]# ansible 172.18.30.1 -m fetch -a 'src=/usr/local/nginx/conf/nginx.conf dest=/app' #因为之前已经安装过nginx,我把远端的nginx配置文件拉到本地做一个模板。
- [root@ansible ~]# cp /app/172.18.30.1/usr/local/nginx/conf/nginx.conf /app/ansible/playbook/templates/nginx.conf.j2
- [root@ansible ~]# vim /app/ansible/playbook/templates/nginx.conf.j2
- #worker_processes 1; 修改这一项
- worker_processes {{ansible_processor_vcpus}}; #可以通过ansible localhost -m setup ' grep cpu 找到这个内建变量,代表的是cpu个数
因为只是实验,为了简介,我们将配置文件的其他选项直接删除
现在我们开始编写playbook,并使用templates
vim templates_example.yml
---
- hosts: webserver
remote_user: root
tasks:
- name: template config to web hosts
template: src=nginx.conf.j2 dest=/app/nginx.conf
调用剧本
ansible-playbook templates_example.yml
PLAY [webserver] ****************************************************************************
TASK [Gathering Facts] **********************************************************************
ok: [172.18.30.2]
ok: [172.18.30.1]
TASK [template config to web hosts] *********************************************************
changed: [172.18.30.2]
changed: [172.18.30.1]
PLAY RECAP **********************************************************************************
172.18.30.1 : ok=2 changed=1 unreachable=0 failed=0
172.18.30.2 : ok=2 changed=1 unreachable=0 failed=0
执行成功,我们现在去web服务器,去看一下传递过去的配置文件
@172.18.30.1
[root@localhost /]# cat /app/nginx.conf
#这是一个测试文件
#user nobody;
worker_processes 1;
成功应用了变量的值。这就是使用templates替换配置文件关键值的方法。
2)templates的算术演示
还借用上一个模版
- 我们修改模版
- vim templates/nginx.conf.j2
- worker_processes {{ansible_processor_vcpus*2}};
- 再次执行playbook
- ansible-playbook templates_example.yml
- PLAY [webserver] ****************************************************************************
- TASK [Gathering Facts] **********************************************************************
- ok: [172.18.30.2]
- ok: [172.18.30.1]
- TASK [template config to web hosts] *********************************************************
- changed: [172.18.30.2]
- changed: [172.18.30.1]
- PLAY RECAP **********************************************************************************
- 172.18.30.1 : ok=2 changed=1 unreachable=0 failed=0
- 172.18.30.2 : ok=2 changed=1 unreachable=0 failed=0
- 我们去172.18.30.1去查看一下传递过去的配置文件
- @172.18.30.1
- cat /app/nginx.conf
- #这是一个测试文件
- #user nobody;
- worker_processes 2;
- 直接进行了算术运算
3)when的使用:
条件测试:如果需要根据变量、facts或此前任务的执行结果来做为某task执行与否的前提时要用到条件测试,通过when语句实现,在task中使用,jinja2的语法格式
在task后添加when子句即可使用条件测试;when语句支持Jinja2表达式语法
我们使用centos6和centos7两种操作系统来做演示:
- ssh-copy-id 172.18.30.254 这台机器是centos6
- 现在我们配置ansible的Iventory, 我们为centos6添加到webserver组内
- vim /etc/ansible/hosts
- [webserver]
- 172.18.30.[1:2]
- 172.18.30.254
- 回到/app/ansible/playbook/下编写剧本
- cd /app/ansible/playbook/
- touch when_example.yml
- vim when_example.yml
- ---
- - hosts: webserver
- remote_user: root
- tasks:
- - name: yum install ftp
- yum: name=ftp,vsftp state=latest
- when: ansible_distribution_major_version=='6'
- #ansible_distribution_major_version这个变量可以通过 ansible localhost -m setup ' grep version 获得
- 执行剧本
- ansible-playbook when_example.yml
- PLAY [webserver] ***************************************************************************************************************************
- TASK [Gathering Facts] *********************************************************************************************************************
- ok: [172.18.30.2]
- ok: [172.18.30.1]
- ok: [172.18.30.254]
- TASK [yum install ftp] *********************************************************************************************************************
- skipping: [172.18.30.1]
- skipping: [172.18.30.2]
- changed: [172.18.30.254]
- PLAY RECAP *********************************************************************************************************************************
- 172.18.30.1 : ok=1 changed=0 unreachable=0 failed=0
- 172.18.30.2 : ok=1 changed=0 unreachable=0 failed=0
- 172.18.30.254 : ok=2 changed=1 unreachable=0 failed=0
- 通过执行结果可以看出,在执行时,跳过了两台centos7,只在centos6上安装了软件包,ansible_distribution_major_version这个变量的含义是系统的主版本号,这就是when的语法,主要用在剧本中。
4)when的实例2:
根据不通的系统版本复制不通的配置文件
(1)创建两个模板文件
- vim /app/ansible/playbook/templates/c6_nginx.conf
- #这是c6的模版文件
- vim /app/ansible/playbook/templates/c7.nginx.conf
- #这是c7的模版文件
(2)编写playbook
vim /app/ansible/playbook/when_example2.yml
---
- hosts: webserver
remote_user: root
tasks:
- name: cp nginx cfg of c6 to remote hosts
template: src=templates/c6_nginx.conf dest=/app/nginx.conf
when: ansible_distribution_major_version=='6'
- name: cp nginx cfg of c7 to remote hosts
template: src=templates/c7_nginx.conf dest=/app/nginx.conf
when: ansible_distribution_major_version=='7'</pre>
(3)执行这段脚本
<pre class="EnlighterJSRAW" data-enlighter-language="null">[root@ansible playbook]# ansible-playbook when_example2.yml
PLAY [webserver] ***************************************************************************
TASK [Gathering Facts] *********************************************************************
ok: [172.18.30.1]
ok: [172.18.30.2]
ok: [172.18.30.254]
TASK [cp nginx cfg of c6 to remote hosts] **************************************************
skipping: [172.18.30.1]
skipping: [172.18.30.2]
changed: [172.18.30.254]
TASK [cp nginx cfg of c7 to remote hosts] **************************************************
skipping: [172.18.30.254]
changed: [172.18.30.1]
changed: [172.18.30.2]
PLAY RECAP *********************************************************************************
172.18.30.1 : ok=2 changed=1 unreachable=0 failed=0
172.18.30.2 : ok=2 changed=1 unreachable=0 failed=0
172.18.30.254 : ok=2 changed=1 unreachable=0 failed=0</pre>
执行是成功的,下面我们分别查看c6和c7的文件
(4)查看传递的配置文件
<pre class="EnlighterJSRAW" data-enlighter-language="null">@172.18.30.1
cat /app/nginx.conf
#这是c7的模版文件
@172.18.30.254
#这是c6的模版文件
when的用法就写到这里
5)with_items迭代
迭代:当有需要重复性执行的任务时,可以使用迭代机制
对迭代项的引用,固定变量名为”item”,要在task中使用with_items给定要迭代的元素列表
列表格式:
字符串
字典
下面做一个批量添加用户的演示
(1)编写playbook
- vim /app/ansible/playbook/with_items_add_user_example.yml
- ---
- - hosts: mysql
- remote_user: root
- tasks:
- - name: with_items_example add user
- user: name={{item}} state=present groups=apache shell=/sbin/nologin createhome=no comment=test
- with_items:
- - aabb
- - bbcc
- - ccee
- #这里有个坑,在添加用户时,如果直接使用group 来给用户添加 与用户名同名的主组会报错。
现在我们调用这个playbook
- [root@ansible playbook]# ansible-playbook with_items_add_user_example.yml
- PLAY [mysql] *******************************************************************************
- TASK [Gathering Facts] *********************************************************************
- ok: [172.18.30.3]
- TASK [with_items_example add user] *********************************************************
- changed: [172.18.30.3] => (item=aabb)
- changed: [172.18.30.3] => (item=bbcc)
- changed: [172.18.30.3] => (item=ccee)
- PLAY RECAP *********************************************************************************
- 172.18.30.3 : ok=2 changed=1 unreachable=0 failed=0
- 执行成功,我们去目标主机查看,新添加的用户
(2)查看新添加的用户
- @172.18.30.3
- [root@mysql ~]# tail -n 5 /etc/passwd
- ntp:x:38:38::/etc/ntp:/sbin/nologin
- ddd:x:1000:1000::/home/ddd:/bin/bash
- aabb:x:1001:1002:test:/home/aabb:/sbin/nologin
- bbcc:x:1002:1003:test:/home/bbcc:/sbin/nologin
- ccee:x:1003:1004:test:/home/ccee:/sbin/nologin
- 已经成功添加
6)要想删除这些用户,也简单,再写个剧本
- vim /app/ansible/playbook/absent_user_example.yml
- ---
- - hosts: mysql
- remote_user: root
- tasks:
- - name:absent users
- user: name={{item}} state=absent
- with_itmes:
- - aabb
- - bbcc
- - ccee
脚本的执行结果就是把这几个用户删除了
7)迭代嵌套子变量
(1) 编写一个创建用户的案例:
- vim /app/ansible/playbook/add_user_example.yml
- ---
- - hosts: webserver
- remote_user: root
- tasks:
- - name: add users
- user: name={{item.name}} groups={{item.group}}
- with_items:
- - {name: 'ok',group: 'nginx'}
- - {name: 'nice',group: 'nginx'}
(2)执行这段剧本
- [root@ansible playbook]# ansible-playbook add_user_example.yml
- PLAY [webserver] ***************************************************************************
- TASK [Gathering Facts] *********************************************************************
- ok: [172.18.30.2]
- ok: [172.18.30.1]
- TASK [add users] ***************************************************************************
- changed: [172.18.30.2] => (item={u'group': u'nginx', u'name': u'ok'})
- changed: [172.18.30.1] => (item={u'group': u'nginx', u'name': u'ok'})
- changed: [172.18.30.1] => (item={u'group': u'nginx', u'name': u'nice'})
- changed: [172.18.30.2] => (item={u'group': u'nginx', u'name': u'nice'})
- PLAY RECAP *********************************************************************************
- 172.18.30.1 : ok=2 changed=1 unreachable=0 failed=0
- 172.18.30.2 : ok=2 changed=1 unreachable=0 failed=0
8)templates中的for 和 if
这两个关键词使用在模版文件中,而不是用在剧本中的。
我们来编辑一个nginx的配置文件
(1)创建nginx模板配置文件并进行编辑
- vim /app/ansible/playbook/templates/nginx_temp_example_for_if.conf
- worker_processes {{ansible_processor_vcpus}};
- events {
- use epoll;
- multi_accept on;
- worker_connections 65535;
- }
- error_log /log/nginx/error/error.log notice;
- http {
- include mime.types;
- default_type application/octet-stream;
- access_log /log/nginx/access/access.log new_log;
- upstream php_page{
- server 172.18.30.1:18150 weight=1 max_fails=1 fail_timeout=60s;
- server 172.18.30.2:18150 weight=1 max_fails=1 fail_timeout=60s;
- }
- upstream html_page{
- server 172.18.30.3:18150 weight=1 max_fails=1 fail_timeout=60s;
- server 172.18.30.4:18150 weight=1 max_fails=1 fail_timeout=60s;
- }
- {% for vhost in nginx_hosts %}
- server {
- listen {{vhost.listen}};
- server_name {{vhost.server_name}};
- location / {
- index index.jhtml index.html index.htm index.php;
- proxy_pass http://php_page;
- client_max_body_size 30m;
- client_body_buffer_size 5280k;
- keepalive_requests 1000;
- }
- }
- {% endfor %} #这段对server循环配置
- }
(2)编写playbook,在playbook中定义在模板文件中需要的变量
vim nginx_conf_exmaple.yml
---
- hosts: webserver
remote_user: root
vars:
nginx_hosts:
- ok1:
listen: 8080
server_name: php
- ok2:
listen: 80
server_name: html
tasks:
- name: nginx file
template: src=templates/nginx_temp_example_for_if.conf dest=/app/nginx/nginx.conf.2
(3)执行这段playbook,并查看复制的配置文件
[root@ansible playbook]# ansible-playbook nginx_conf_example.yml
PLAY [webserver] ***************************************************************************************************************************
TASK [Gathering Facts] *********************************************************************************************************************
ok: [172.18.30.1]
ok: [172.18.30.2]
ok: [172.18.30.254]
TASK [nginx file] **************************************************************************************************************************
changed: [172.18.30.254]
changed: [172.18.30.1]
changed: [172.18.30.2]
PLAY RECAP *********************************************************************************************************************************
172.18.30.1 : ok=2 changed=1 unreachable=0 failed=0
172.18.30.2 : ok=2 changed=1 unreachable=0 failed=0
172.18.30.254 : ok=2 changed=1 unreachable=0 failed=0
查看配置文件
@172.18.30.1
[root@localhost nginx]# cat /app/nginx/nginx.conf.2
worker_processes 1;
events {
use epoll;
multi_accept on;
worker_connections 65535;
}
error_log /log/nginx/error/error.log notice;
http {
include mime.types;
default_type application/octet-stream;
access_log /log/nginx/access/access.log new_log;
upstream php_page{
server 172.18.30.1:18150 weight=1 max_fails=1 fail_timeout=60s;
server 172.18.30.2:18150 weight=1 max_fails=1 fail_timeout=60s;
}
upstream html_page{
server 172.18.30.3:18150 weight=1 max_fails=1 fail_timeout=60s;
server 172.18.30.4:18150 weight=1 max_fails=1 fail_timeout=60s;
}
server {
listen 8080;
server_name php;
location / {
index index.jhtml index.html index.htm index.php;
proxy_pass http://php_page;
client_max_body_size 30m;
client_body_buffer_size 5280k;
keepalive_requests 1000;
}
}
server {
listen 80;
server_name html;
location / {
index index.jhtml index.html index.htm index.php;
proxy_pass http://php_page;
client_max_body_size 30m;
client_body_buffer_size 5280k;
keepalive_requests 1000;
}
}
#这段对server循环配置
}
生成了两个不同的server
(4)if的套用
(1)我们还是还用nginx的配置文件作为模板
vim /app/ansible/playbook/templates/nginx_if_example.conf.j2
worker_processes {{ansible_processor_vcpus}};
events {
use epoll;
multi_accept on;
worker_connections 65535;
}
error_log /log/nginx/error/error.log notice;
http {
include mime.types;
default_type application/octet-stream;
access_log /log/nginx/access/access.log new_log;
upstream php_page{
server 172.18.30.1:18150 weight=1 max_fails=1 fail_timeout=60s;
server 172.18.30.2:18150 weight=1 max_fails=1 fail_timeout=60s;
}
upstream html_page{
server 172.18.30.3:18150 weight=1 max_fails=1 fail_timeout=60s;
server 172.18.30.4:18150 weight=1 max_fails=1 fail_timeout=60s;
}
{% for vhost in nginx_hosts %}
server {
listen {{vhost.listen}};
{% if vhost.server_name is defined %}
server_name {{vhost.server_name}};
{% endif %}
location / {
index index.jhtml index.html index.htm index.php;
proxy_pass http://php_page;
client_max_body_size 30m;
client_body_buffer_size 5280k;
keepalive_requests 1000;
}
}
{% endfor %} #这段对server循环配置
}
(2)编写playbook
---
- hosts: webserver
remote_user: root
vars:
nginx_hosts:
- {listen: 80,server_name: php_page}
- {listen: 8080}
tasks:
- name: use if
template: src=nginx_if_example.conf.j2 dest=/app/nginx/nginx_if.conf
(3)执行这段,并查看目标主机的文件
[root@ansible playbook]# ansible-playbook nginx_if.yml
PLAY [webserver] ***************************************************************************************************************************
TASK [Gathering Facts] *********************************************************************************************************************
ok: [172.18.30.1]
ok: [172.18.30.2]
ok: [172.18.30.254]
TASK [use if] ******************************************************************************************************************************
changed: [172.18.30.254]
changed: [172.18.30.2]
changed: [172.18.30.1]
PLAY RECAP *********************************************************************************************************************************
172.18.30.1 : ok=2 changed=1 unreachable=0 failed=0
172.18.30.2 : ok=2 changed=1 unreachable=0 failed=0
172.18.30.254 : ok=2 changed=1 unreachable=0 failed=0
执行成功
查看受控主机生成的配置文件
@172.18.30.1
[root@localhost nginx]# cat nginx_if.conf
worker_processes 1;
events {
use epoll;
multi_accept on;
worker_connections 65535;
}
error_log /log/nginx/error/error.log notice;
http {
include mime.types;
default_type application/octet-stream;
access_log /log/nginx/access/access.log new_log;
upstream php_page{
server 172.18.30.1:18150 weight=1 max_fails=1 fail_timeout=60s;
server 172.18.30.2:18150 weight=1 max_fails=1 fail_timeout=60s;
}
upstream html_page{
server 172.18.30.3:18150 weight=1 max_fails=1 fail_timeout=60s;
server 172.18.30.4:18150 weight=1 max_fails=1 fail_timeout=60s;
}
server {
listen 80;
server_name php_page; #通过if,这个有server_name
location / {
index index.jhtml index.html index.htm index.php;
proxy_pass http://php_page;
client_max_body_size 30m;
client_body_buffer_size 5280k;
keepalive_requests 1000;
}
}
server {
listen 8080; #未定义server_name,这个没有
location / {
index index.jhtml index.html index.htm index.php;
proxy_pass http://php_page;
client_max_body_size 30m;
client_body_buffer_size 5280k;
keepalive_requests 1000;
}
}
#这段对server循环配置
}