Ansible Advanced
# Ansible Jinja2
# 什么是jinja2
Jinja2是Python的全功能模板引擎
Ansible需要使用Jinja2模板来修改被管理主机的配置文件。
- 场景:给10台主机装上
Nginx服务,但是要求每台主机的端口都不一样,如何解决?
# Ansible如何使用jinja2
ansible使用jinja2模板需要借助template模块实现,那template模块是用来做什么的?
template模块和copy模块完全一样,都是拷贝文件至远程主机,区别在于template模块会解析要拷贝的文件中变量的值,而copy则是原封不动的将文件拷贝至被控端。
# jinja模板基本语法
- 要想在配置文件中使用
jinj2,playbook中的tasks必须使用template模块; - 配置文件里面使用变量,用双大括号括起来;
# jinja模板逻辑关系
循环表达式
{% for i in EXPR %}...{% endfor %}1判断表达式
{% if EXPR %}...{% elif EXPR %}...{% endif %}1注释
{# COMMENT #}1
# jinja模板示例
使用
Playbook推送文件[root@manager playbook]# cat jinja2.yml - hosts: webservers tasks: - name: Copy template File /etc/motd template: src=./motd.j2 dest=/etc/motd1
2
3
4
5准备
motd.j2文件[root@manager playbook]# cat motd.j2 Welcome to {{ ansible_hostname }} This system total Memory is: {{ ansible_memtotal_mb }} MB This system free Memory is: {{ ansible_memfree_mb }} MB1
2
3
4执行
playbook[root@manager playbook]# ansible-playbook jinja2.yml PLAY [webservers] ******************************************************************** TASK [Copy template File /etc/motd] ************************************************** changed: [10.0.0.13] changed: [10.0.0.12] PLAY RECAP *************************************************************************** 10.0.0.12 : ok=1 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0 10.0.0.13 : ok=1 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=01
2
3
4
5
6
7
8
9
10检查执行后的状态
[root@manager playbook]# ssh root@10.0.0.12 Welcome to slave-1 This system total Memory is: 972 MB This system free Memory is: 379 MB [root@manager playbook]# ssh root@10.0.0.13 Welcome to slave-2 This system total Memory is: 972 MB This system free Memory is: 379 MB1
2
3
4
5
6
7
8
9
上面的例子展示了如何使用facts变量,当playbook被执行后,ansible_hostname和ansible_memtotal_mb将会被替换成被管理主机上搜集的facts变量的值
# 案例1-Jinja2管理Nginx
ansible使用jinja2的for循环表达式渲染出nginx负载均衡的配置文件。
使用
Playbook推送文件[root@manager playbook]# cat proxy.yml - hosts: webservers vars: http_port: 80 server_name: www.bi.com tasks: - name: Copy template Nginx Configure template: src=./blog.conf.j2 dest=/etc/nginx/conf.d/blog.bi.com.conf notify: Reload Nginx Server handlers: - name: Reload Nginx Server service: name=nginx state=reloaded1
2
3
4
5
6
7
8
9
10
11
12
13
14准备
blog.conf.j2配置文件[root@manager playbook]# cat blog.conf.j2 upstream ansible_php { {% for i in groups['webservers'] %} server {{i}}:80; {% endfor %} } server { listen 80; server_name ansible.bi.com; location / { proxy_pass http://ansible_php; proxy_set_header Host $http_hosts; } }1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17执行
playbook[root@manager playbook]# ansible-playbook proxy.yml PLAY [webservers] ******************************************************************** TASK [Copy template Nginx Configure] ************************************************* changed: [10.0.0.12] changed: [10.0.0.13] RUNNING HANDLER [Reload Nginx Server] ************************************************ changed: [10.0.0.13] changed: [10.0.0.12] PLAY RECAP *************************************************************************** 10.0.0.12 : ok=2 changed=2 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0 10.0.0.13 : ok=2 changed=2 unreachable=0 failed=0 skipped=0 rescued=0 ignored=01
2
3
4
5
6
7
8
9
10
11
12
13
14检查
jinja模板渲染出来的配置文件[root@slave-1 ~]# cat /etc/nginx/conf.d/blog.bi.com.conf upstream ansible_php { #设置变量,并进行循环赋值,渲染配置 server 10.0.0.12:80; server 10.0.0.13:80; } server { listen 80; server_name ansible.bi.com; location / { proxy_pass http://ansible_php; proxy_set_header Host $http_hosts; } }1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# 案例2-Jinja2管理Keepalived
ansible使用jinja2的if判断表达式渲染出keepalived的Master和Slave的配置文件。
使用
playbook推送keeplaived配置文件[root@manager playbook]# cat keepalived.yml - hosts: lb tasks: - name: Copy template Keepalived Configure template: src=./keepalived.j2 dest=/etc/keepalived/keepalived.conf notify: Restart Keepalived Server handlers: - name: Restart Keepalived Server service: name=keepalived state=restarted1
2
3
4
5
6
7
8
9
10准备
keepalived.j2配置文件[root@manager playbook]# cat keepalived.j2 global_defs { router_id {{ ansible_fqdn }} } vrrp_instance VI_1 { {% if ansible_fqdn == 'lb01' %} #如果主机名为lb01则使用如下配置 state MASTER priority 150 {% elif ansible_fqdn == 'lb02' %} #如果主机名为lb02则使用如下配置 state Backup priority 100 {% endif %} #相同配置 interface eth0 virtual_router_id 51 advert_int 1 authentication { auth_type PASS auth_pass 1111 } virtual_ipaddress { 172.16.1.3 } }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执行
playbook[root@manager playbook]# ansible-playbook keepalived.yml PLAY [lb] ******************************************************************** TASK [Copy template Keepalived Configure] ************************************************* changed: [10.0.0.5] changed: [10.0.0.6] RUNNING HANDLER [Reload Keepalived Server] ************************************************ changed: [10.0.0.5] changed: [10.0.0.6] PLAY RECAP *************************************************************************** 10.0.0.5 : ok=2 changed=2 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0 10.0.0.6 : ok=2 changed=2 unreachable=0 failed=0 skipped=0 rescued=0 ignored=01
2
3
4
5
6
7
8
9
10
11
12
13
14检查
lb01 Master的keepalived配置文件[root@lb01 ~]# cat /etc/keepalived/keepalived.conf global_defs { router_id lb01 } vrrp_instance VI_1 { #如果主机名为lb01则使用如下配置 state MASTER priority 150 #相同配置 interface eth0 virtual_router_id 51 advert_int 1 authentication { auth_type PASS auth_pass 1111 } virtual_ipaddress { 172.16.1.3 } }1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21检查
lb02 Backup的keepalived配置文件[root@lb02 ~]# cat /etc/keepalived/keepalived.conf global_defs { router_id lb02 } vrrp_instance VI_1 { #如果主机名为lb02则使用如下配置 state Backup priority 150 #相同配置 interface eth0 virtual_router_id 51 advert_int 1 authentication { auth_type PASS auth_pass 1111 } virtual_ipaddress { 172.16.1.3 } }1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# Ansible Roles
# Roles基本概述
使用Roles组织playbook才是最好的方式。
Roles基于一个已知的文件结构,去自动的加载vars、tasks以及handlers以便playbook更好的调用。
roles相比playbook的结构更加的清晰有层次,但roles显然要比playbook更加复杂难理解!
比如:我们无论安装什么软件都会安装时间同步服务,那么每个playbook都要编写时间同步服务的task。此时我们可以将时间同步服务task任务编写好,等到需要使用的时候进行调用就行了。
# Roles目录结构
roles官方目录结构,必须按如下方式定义。在每个目录中必须有main.yml文件,这些属于强制要求。
[root@manager ~]# cd /etc/ansible/roles
[root@manager roles]# mkdir {nfs,rsync,web}/{vars,tasks,templates,handlers,files,meta} -p
[root@manager roles]# tree
[root@manager roles]# tree
.
├── nfs #角色名称
│ ├── files #存放文件
│ ├── handlers #触发任务
│ ├── meta #依赖关系
│ ├── tasks #具体任务
│ ├── templates #模板文件
│ └── vars #定义变量
2
3
4
5
6
7
8
9
10
11
12
# Roles依赖关系
roles允许在使用时自动引入其他role,role依赖关系存储在meta/main.yml文件中。- 例如: 安装
wordpress项目时:- 需要先确保
nginx与php-fpm的role都能正常运行 - 然后在
wordpress的role中定义,依赖关系 - 依赖的
role有nginx以及php-fpm
- 需要先确保
#wordpress依赖nginx与php-fpm的role [root@manager playbook]# cat /root/roles/wordpress/meta/main.yml dependencies: - { role: nginx } - { role: php-fpm }1
2
3
4
5- 例如: 安装
wordpress的role会先执行nginx、php-fpm的role,最后在执行wordpress本身
# Roles案例实战
- Roles三步走:
- 创建
roles目录结构,手动创建或使用ansible-galaxy init testroles - 编写
roles的功能,也就是tasks - 最后
playbook引用roles编写好的tasks
- 创建
# 案例-Roles部署NFS
目录结构如下
[root@manager roles]# tree /etc/ansible/roles ├── group_vars │ └── all ├── hosts ├── nfs │ ├── files │ ├── handlers │ │ └── main.yml │ ├── meta │ ├── tasks │ │ └── main.yml │ └── templates │ └── exports.j2 └── site.yml1
2
3
4
5
6
7
8
9
10
11
12
13
14定义
roles主机清单[root@manager roles]# cat /etc/ansible/roles/hosts [nfs] 10.0.0.121
2
3查看
nfs角色的tasks任务[root@manager roles]# cat /etc/ansible/roles/nfs/tasks/main.yml - name: Installed NFS Server yum: name: nfs-utils state: present - name: Configure NFS Server template: src: exports.j2 dest: /etc/exports notify: Restart NFS Server - name: Init NFS Server file: path: "{{ nfs_share_directory }}" state: directory owner: "{{ user }}" group: "{{ group }}" - name: Systemd NFS Server systemd: name: nfs state: started enabled: yes1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24查看
nfs角色的handlers[root@manager roles]# cat /etc/ansible/roles/nfs/handlers/main.yml - name: Restart NFS Server systemd: name: nfs state: restarted1
2
3
4
5查看
nfs角色的files目录[root@manager roles]# cat /etc/ansible/roles/nfs/templates/exports.j2 {{ nfs_share_directory }} {{ nfs_share_ip_pool }}(rw,sync,anonuid={{ user_id }},anongid={{ group_id }})1
2nfs对应的变量定义[root@manager roles]# cat /etc/ansible/roles/group_vars/all # all user: www group: www # nfs nfs_share_directory: /ansible_data nfs_share_ip_pool: 10.0.0.0/24 user_id: 666 group_id: 6661
2
3
4
5
6
7
8
9在
playbook中使用role,指定nfs主机组,执行nfs服务的roles[root@manager roles]# cat /etc/ansible/roles/site.yml - hosts: nfs roles: - nfs [root@manager roles]# ansible-playbook -i hosts site.yml PLAY [nfs] *************************************************************************** TASK [nfs : Installed NFS Server] **************************************************** ok: [10.0.0.12] TASK [nfs : Configure NFS Server] **************************************************** ok: [10.0.0.12] TASK [nfs : Init NFS Server] ********************************************************* changed: [10.0.0.12] TASK [nfs : Systemd NFS Server] ****************************************************** ok: [10.0.0.12] PLAY RECAP *************************************************************************** 10.0.0.12 : ok=4 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=01
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24