Ansible进阶
# Ansible进阶
# 掌握要点
(1)掌握 Ansible 中 includes 使用。
(2)掌握 Ansible 中 roles 的使用。
(3)掌握 Jinja2 实现模板自定义。
# includes模块的使用
include 简单用法在进行编程时,运维人员都会将可以重复利用的代码提取出来,将提取出的代码作为一个逻辑单元,这个逻辑单元通常被称为“函数”或者“方法”,函数可以让用户更加方便、重复地调用一段代码,并且如果需要更改这段代码的逻辑,只要更改函数本身即可,所有调用函数之处的逻辑都会随之改变。
在 Ansible 中,其实也有类似的功能,这种功能被称之为“include”,通过 include,运维人员可以在一个 PlayBook 中包含另一个文件,以便实现刚才所描述的效果,接下来就来了解一下 include 的用法。
先来看一个小示例,假设运维人员想要编写 2 个 PlayBook,这 2 个 PlayBook 分别用于安装 LAMP 和 LNMP 环境,2 个 PlayBook 的大致内容如下:
# cat lamp.yaml
---
- hosts: node1
remote_user: root
tasks:
- name: install mysql
yum: name=mysql state=present
- name: install php
yum: name=php-fpm state=present
- name: install httpd
yum: name=httpd state=present
# cat lnmp.yaml
---
- hosts: node1
remote_user: root
tasks:
- name: install mysql
yum: name=mysql state=present
- name: install php
yum: name=php-fpm state=present
- name: install nginx
yum: name=nginx state=present
注意:
无论在 lamp.yaml 中还是在 lnmp.yaml 中,安装 MySQL 和 PHP 部分的任务是完全相同的,所以可以把这两个任务提取出来,作为一个逻辑单元。把安装 MySQL 和 PHP 部分的任务提取到 install_MysqlAndPhp.yaml 文件中,文件内容如下:
# cat install_MysqlAndPhp.yaml
- name: install mysql
yum: name=mysql state=present
- name: install php
yum: name=php-fpm state=present
如上例所示,2 个 task 被提取到了 install_MysqlAndPhp.yaml 文件中,当需要安装 MySQL 和 php-fpm 时,只需要调用此 YAML 文件即可。那么怎样调用这个文件呢?方法只要把 lamp.yaml 和 lnmp.yaml 修改为如下模样即可:
# cat lamp.yaml
---
- hosts: node1
remote_user: root
tasks:
- include: install_MysqlAndPhp.yaml
- name: install httpd
yum: name=httpd state=present
# cat lnmp.yaml
---
- hosts: node1
remote_user: root
tasks:
- include: install_MysqlAndPhp.yaml
- name: install nginx
yum: name=nginx state=present
此处使用了 include 模块,引用了 install_MysqlAndPhp.yaml 文件,当引用此文件时,
install_MysqlAndPhp.yaml 文件中的 tasks 都会在被引用处执行
,这就是 include 的用法。include 模块可以指定一个文件,这个文件中的内容是一个任务列表(一个或多个任务),当使用 include 模块引用对应的文件时,文件中的任务会在被引用处执行,就好像写在被引用处一样。
# include_tasks模块使用
include_tasks 模块。在理解了 include 以后,再来理解 include_tasks 就很简单了。众所周知,include 模块可以用来包含一个任务列表, include_tasks 模块的作用也是用来包含一个任务列表。在之后的版本中,如果想要包含一个任务列表,那么就可以使用 include_tasks 关键字代替 include 关键字。
示例如下:
[root@ansible test]# cat intest.yaml
---
- hosts: web
remote_user: root
tasks:
- debug:
msg: "test task1"
- include_tasks: in.yaml
- debug:
msg: "test task2"
[root@ansible test]# cat in.yaml
- debug:
msg: "test1 in in.yaml"
- debug:
msg: "test2 in in.yaml"
如上例所示,当需要包含一个任务列表时,include_tasks 关键字的用法与 include 完全相同,看看执行效果如何
[root@ansible test]# ansible-playbook intest.yaml
PLAY [webserver] *****************************************************************************************************
TASK [Gathering Facts] ***********************************************************************************************
ok: [192.168.1.6]
TASK [debug] *********************************************************************************************************
ok: [192.168.1.6] => {
"msg": "test task1"
}
TASK [include_tasks] *************************************************************************************************
included: /root/lnmp/test/in.yaml for 192.168.1.6
TASK [debug] *********************************************************************************************************
ok: [192.168.1.6] => {
"msg": "test1 in in.yaml"
}
TASK [debug] *********************************************************************************************************
ok: [192.168.1.6] => {
"msg": "test2 in in.yaml"
}
TASK [debug] *********************************************************************************************************
ok: [192.168.1.6] => {
"msg": "test task2"
}
PLAY RECAP ***********************************************************************************************************
192.168.1.6 : ok=6 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
如上面执行结果所示,当使用 include_tasks 时,include_tasks 本身会被当做一个 task,这个 task 会把被 include 的文件的路径输出在控制台中(即 included: /root/test/in.yaml for node1 这个语句),这就是 include_tasks 模块与 include 模块之间的区别之处。如果将上例中的 include_tasks 关键字替换成 include,控制台中则不会显示 included: /root/test/in.yaml for node1 信息,由此可见 include 是透明的,include_tasks 是可见的。include_tasks 更像是一个任务,这个任务包含了其他的一些任务。
# Ansible roles的使用
⚫roles 使用场景 roles 适合大规模使用,PlayBook 如果文件较多时,不清楚哪些主机执行了哪些状态的 YAML 文件,roles 能清楚哪些主机应用哪些角色。
⚫下面使用一个小案例,来学习 roles 的使用。假如现在有 3 个被管理主机,第一个要配置成 httpd 服务器,第二个要配置成 PHP 服务器,第三个要配置成MySQL 服务器。如何来定义 PlayBook?若使用以前的方法,第一个 play 用到第一个主机上,用来构建 httpd,第二个 play 用到第二个主机上,用来构建 PHP,第三个 play 用到第三个主机上,用来构建 MySQL。这些 play 定义在 PlayBook 中比较麻烦,将来也不利于模块化调用和多次调用。比如,后期又加进来一个主机,这第 4 个主机既是 httpd 服务器,又是 PHP 服务器,这时只能写第 4 个 play,上面写安装 httpd 和 PHP。这样 PlayBook 中的代码就重复了。
⚫为了避免代码重复,roles 能够实现代码重复被调用。定义一个角色叫webserver,第二个角色叫 dbserver。
[root@ansible anasible_playbook]# cat role.yaml
---
- hosts: webserver
roles:
- webserver
- hosts: dbserver
roles:
- dbserver
# 规划节点
IP | 主机名 | 节点 |
---|---|---|
192.168.1.7 | ansible | Ansible 节点 |
192.168.1.6 | node1 | Node1 节点 |
192.168.1.5 | node2 | Node2 节点 |
192.168.1.15 | node3 | Node3 节点 |
ansible的hosts主机清单
[root@ansible ~]# cat /etc/ansible/hosts
[webserver]
192.168.1.6
[phpserver]
192.168.1.5
[dbserver]
192.168.1.15
# 1.创建roles文件夹
roles 实战准备使用 3 台主机,192.168.1.6 主机上安装 httpd,192.168.1.5 上安装 MySQL,192.168.1.15 上安装 MySQL 和 httpd。然后,建立两个角色 webserver 和 dbserver,并应用到这几个主机上。首先创建项目目录,在/opt 下创建项目目录 ansible_playbook,然后在 ansible_playbook 下创建 roles 下的必要目录。
[root@ansible ~]# mkdir -pv /opt/ansible_playbook/roles/{webserver,dbserver}/{tasks,files,templates,meta,handlers,vars}
mkdir: created directory ‘/opt/ansible_playbook’
mkdir: created directory ‘/opt/ansible_playbook/roles’
mkdir: created directory ‘/opt/ansible_playbook/roles/webserver’
mkdir: created directory ‘/opt/ansible_playbook/roles/webserver/tasks’
mkdir: created directory ‘/opt/ansible_playbook/roles/webserver/files’
mkdir: created directory ‘/opt/ansible_playbook/roles/webserver/templates’
mkdir: created directory ‘/opt/ansible_playbook/roles/webserver/meta’
mkdir: created directory ‘/opt/ansible_playbook/roles/webserver/handlers’
mkdir: created directory ‘/opt/ansible_playbook/roles/webserver/vars’
mkdir: created directory ‘/opt/ansible_playbook/roles/dbserver’
mkdir: created directory ‘/opt/ansible_playbook/roles/dbserver/tasks’
mkdir: created directory ‘/opt/ansible_playbook/roles/dbserver/files’
mkdir: created directory ‘/opt/ansible_playbook/roles/dbserver/templates’
mkdir: created directory ‘/opt/ansible_playbook/roles/dbserver/meta’
mkdir: created directory ‘/opt/ansible_playbook/roles/dbserver/handlers’
mkdir: created directory ‘/opt/ansible_playbook/roles/dbserver/vars’
# 2.查看文件目录
⚫安装 tree 工具,Ansible 节点配置好域名后,使用网络 Yum 源自行下载 tree工具
⚫创建目录和安装完 tree 工具之后,查看 ansible_playbook 中的目录结构
[root@ansible ~]# yum install tree -y
[root@ansible opt]# tree ansible_playbook/ ansible_playbook/
└── roles
├── dbserver │ ├── files
│ ├── handlers
│ ├── meta
│ ├── tasks
│ ├── templates
│ └── vars
└── webserver
├── files
├── handlers
├── meta
├── tasks
├── templates
└── vars
15 directories, 0 files
可以看见在每个 roles 下,又创建了好多目录,下面详细讲一下每个目录的作用:
⚫files 目录:
角色可能会用到的一些其他文件可以放置在此目录中,比如,当定义 Nginx 角色时,需要配置 https,那么相关的证书文件即可放置在此目录中。
⚫handlers目录:
当角色需要调用handlers时,默认会在此目录中的main.yaml 文件中查找对应的 handler。
⚫meta 目录:
如果想要赋予这个角色一些元数据,则可以将元数据写入到 meta/main.yaml 文件中,这些元数据用于描述角色的相关属性。比如作者信息、角色主要作用等等,也可以在 meta/main.yml 文件中定义这个角色依赖于哪些其他角色,或者改变角色的默认调用设定。
⚫tasks 目录:
角色需要执行的主任务文件放置在此目录中,默认的主任务文件名为 main.yaml。当调用角色时,默认会执行 main.yaml 文件中的任务,也可以将其他需要执行的任务文件通过 include 的方式包含在 tasks/main.yaml 文件中。
⚫templates 目录:
角色相关的模板文件可以放置在此目录中。当使用角色相关的模板时,如果没有指定路径,会默认从此目录中查找对应名称的模板文件。
⚫vars 目录:
角色会使用到的变量可以写入到此目录中的 main.yml 文件中,那 vars/main.yaml 文件和 defaults/main.yaml 文件的区别在哪里呢?区别就是, defaults/main.yaml 文件中变量的优先级是最低的,而 vars/main.yaml 文件中变量的优先级非常高。如果用户只是想提供一个默认的配置,那么可以把对应的变量定义在 defaults/main.yaml 中;如果用户想要确保别人在调用角色时,使用的值就是自己指定的值,则可以将变量定义在 vars/main.yaml 中。因为定义在 vars/main.yaml 文件中的变量的优先级非常高,所以其值比较难以覆盖。
# 3.配置角色 webserver
⚫在 Ansible 节点,首先进入/opt/ansible_playbook/roles/webserver/files/目录
⚫在 files 目录下创建 httpd.conf 文件
⚫静态文件都放在 files 目录下。如果打算用模板文件,则应该把模板文件放在 templates 目录下。
⚫然后编写任务列表 tasks,安装httpd服务,中途修改配置文件触发handlers
[root@ansible opt]# cd ansible_playbook/roles/webserver/files/
[root@ansible files]# touch httpd.conf
[root@ansible files]# cd ../tasks
[root@ansible tasks]# cat main.yaml
- name: install httpd package
yum: name=httpd state=present
- name: install configuration file
copy: src=httpd.conf dest=/opt/httpd.conf
tags:
- conf
notify:
- restart httpd
- name: start httpd
service: name=httpd state=started
⚫由于上面的 tasks 中定义了 notify,所以要定义 handlers。
[root@ansible tasks]# cd ..
[root@ansible webserver]# vi handlers/main.yaml
[root@ansible webserver]# cat handlers/main.yaml
- name: restart httpd
service: name=httpd state=restarted
# 4.配置角色 dbserver
⚫进入 dbserver 角色目录,将数据库配置文件 my.cnf 上传至 files 目录下
⚫编写任务列表 tasks,安装mariadb-server,中途替换配置文件,触发handlers。
[root@ansible roles]# cd dbserver/
[root@ansible dbserver]# ls
files handlers meta tasks templates vars
[root@ansible dbserver]# cd files/
[root@ansible files]# touch my.cnf
[root@ansible files]# cd ..
[root@ansible dbserver]# vi tasks/main.yaml
- name: install_mariadb-server
yum: name=mariadb-server state=present
- name: install configuration file
copy: src=my.cnf dest=/opt/my.cnf
tags:
- conf
notify:
- restart mariadb
- name: start mariadb
service: name=mariadb enabled=yes state=started
⚫如果同样定义了 notify,需要定义 handlers。
[root@ansible dbserver]# vi handlers/main.yaml
[root@ansible dbserver]# cat handlers/main.yaml
- name: restart mariadb
service: name=mariadb state=restarted
# 5.配置role的playbook
⚫配置 PlayBook 需要在 roles 目录同级创建 PlayBook。
⚫编排包含两个role,一个是webserver的一个是dbserver,也可以单独两个role写开,再两role个写一起。分别执行。
[root@ansible ansible_playbook]# vi role.yaml
---
- hosts: webserver
roles:
- webserver
- hosts: dbserver
roles:
- dbserver
# 6.执行playbook
[root@ansible ansible_playbooks]# ansible-playbook role.yaml
# Ansible Jinja2的使用
**Jinja2 是一个现代的、设计者友好的、仿照 Django 模板的 Python 模板语言。**它速度快,被广泛使用,并且提供了可选的沙箱模板,执行环境保证安全。
**Ansible 使用 Jinja2 模板,也就是 template 模块。**该模块和 copy 模块一样,都是将文件复制到目标机器,但是区别在于 template 模块可以获取要复制文件中的变量的值,而 copy 模块则是原封不动地把文件内容复制过去。实际运用时,针对不同的主机定义不同的变量,template 会在文件分发前读取变量到 Jinja2 模板,之后再分发到不同的被管理主机上。
下面来看一个 Jinja2 模板使用的案例。假如为 2 台 webserver 安装 httpd 服务,而它们的配置文件,第一台节点上的 httpd 需要监听 80 端口,第二台节点上需要监听 8080 端口,两个节点的 ServerName 也是不一样的,所以就需要 2 个配置文件,这样管理起来极为不便。在这种情况下,可以考虑在配置文件中使用变量来定义。
# 1.修改tasks
⚫修改webserver角色的清单列表。
⚫进入 Ansible 节点的/opt/ansible_playbook 目录下,修改 roles/webserver/tasks/main.yaml 文件
⚫将原来的 copy 模块替换成 template 模块,将 httpd.conf 改成 httpd.conf.j2。然后将提供的 httpd.conf.j2 文件放到在 roles/webserver/templates/目录下
[root@ansible tasks]# cat main.yaml
- name: install httpd package
yum: name=httpd state=present
- name: install configuration file
template: src=httpd.conf.j2 dest=/etc/httpd/conf/httpd.conf #注意这里的j2文件
tags:
- conf
notify:
- restart httpd
- name: start httpd
service: name=httpd state=started
[root@ansible ansible_playbook]# cd roles/webserver/templates/
[root@ansible templates]# ll total 4
-rw-r--r--. 1 root root 49 Aug 24 02:20 httpd.conf.j2
[root@ansible templates]# cat httpd.conf.j2
...
Listen {{http_port}} #j2 文件中主要修改了该行
...
ServerName {{ansible_fqdn}} #这是主机报告中的信息,直接使用
...
# 2.添加变量
⚫在vars/下添加main.yaml文件。
⚫添加http_port: 88的变量。
[root@ansible webserver]# cd vars/
[root@ansible vars]# cat main.yaml
http_port: 88
#或者使用如下方法添加变量
#[root@ansible ~]# cat /etc/ansible/hosts
#[hosts]
#192.168.1.6 http_port=80
#192.168.1.5 http_port=81
#192.168.1.15 http_port=82
# 3.执行role
[root@ansible ansible_playbooks]# ansible-playbook role.yaml