模板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
Playbook中template 的 算术运算
.j2文件
server {
worker_connectios {{ ansible_processor_vcpus *2 }};
}
yml文件
- hosts: dns
remote_user: root
tasks:
- template: src=/app/1.conf.j2 dest=/app/2.conf
生成的配置文件
server {
worker_connectios 4; > ansible_processor_vcpus=2,所以2*2=4
}
Playbook中template 的 for 循环
语法:
{% for i in nginx_vhosts %}
语句块
{% endfor %}
{% if vhost.root is defined %}
root {{ vhost.root }};
{% endif %}
以实例来讲:
- hosts: web
remote_user: root
vars:
prot_list:
- 8080
- 8081
- 8082
tasks:
- name: create vhost
template: src=/app/1.conf.j2 dest=/app/2.conf > for 循环是写在.j2文件中的。
一般来讲是配合template模板来使用,文件的后缀名为.j2
先建立一个标准模板文件,这个文件需要跟dest使用的格式一致,只不过是将会变化的内容使用for循环的格式来写
{% for prot in prot_list %}
server {
listen prot;
}
{% endfor %}
是不是与shell编程的for循环很像?
#ansible-playbook for1.yml
结果:
#cat /app/2.conf
server {
listen 8080;
}
server {
listen 8081;
}
server {
listen 8082;
}
再来一个多行多主机的模板:
- hosts: web
remote_user: root
vars:
vhosts:
- web:
prot: 8080
server: web1.hunk.tech
root: /app/webroot1
- web:
prot: 8081
server: web2.hunk.tech
root: /app/webroot2
- web:
prot: 8082
server: web2.hunk.tech
root: /app/webroot2
tasks:
- name: create vhost
template: src=/app/1.conf.j2 dest=/app/2.conf
j2文件:
{% for vhost in vhost_list %}
server {
listen {{ vhost.prot }};
servername {{ vhost.server }};
root {{ vhost.root }};
}
{% endfor %}
执行:
#ansible-playbook for1.yml
结果:
#cat /app/2.conf
server {
listen 8080;
servername web1.hunk.tech;
root /app/webroot1;
}
server {
listen 8081;
servername web2.hunk.tech;
root /app/webroot2;
}
server {
listen 8082;
servername web2.hunk.tech;
root /app/webroot2;
}
Playbook中template 的 if 判断
语法:
{% if i is defined %}
语句块
{% endif %}
playbook文件:
- hosts: web
remote_user: root
vars:
vhost_list:
- web1:
prot: 8080
name: web1.hunk.tech > 注意,web1是定义了name的值
- web2: > 注意,web2是没有定义了name的值
prot: 8081
tasks:
- template: src=/app/1.conf.j2 dest=/app/2.conf
j2文件:
{% for vhost in vhost_list %}
server {
listen {{ vhost.prot }};
{% if vhost.name is defined %} > 如果vhost.name有应以,刚填入下面的内容
servername {{ vhost.name }};
{% endif %}
}
{% endfor %
执行:
#ansible-playbook if.yml
结果:
#cat /app/2.conf
server {
listen 8080;
servername web1.hunk.tech;
}
server {
listen 8081;
}
roles
用于层次性、结构化地组织playbook。 roles能够根据层次型结构自动装载变量文件、tasks以及handlers等。
要使用roles只需要在playbook中使用import_tasks指令即可。(include也可以用,官方明确声明此命令将会淘汰)
简单来讲,roles就是通过分别将变量、文件、任务、模板及处理器放置于单独的目录中,并可以便捷地
include它们的一种机制。角色一般用于基于主机构建服务的场景中,但也可以是用于构建守护进程等场景中
复杂场景:建议使用roles,代码复用度高
创建role的步骤
(1) 创建以roles命名的目录
(2) 在roles目录中分别创建以各角色名称命名的目录,如webservers等
(3) 在每个角色命名的目录中分别创建files、 handlers、meta、 tasks、 templates和vars目录;
用不到的目录可以创建为空目录,也可以不创建
(4) 在playbook文件中,调用各自角色
建议的目录结构
├── roles > 必须是这个名字
│ ├── git > 具体项目名称
│ │ ├── default > 设定默认变量时使用此目录中的main.yml文件
│ │ │ └── main.yml > 至少应该包含一个名为main.yml的文件
│ │ ├── files > 存放有copy或script模块等调用的文件
│ │ ├── handlers > 定义触发器
│ │ │ └── main.yml > 至少应该包含一个名为main.yml的文件
│ │ ├── meta > 定义当前角色的特殊设定及其依赖关系
│ │ │ └── main.yml > 至少应该包含一个名为main.yml的文件
│ │ ├── tasks > 定义任务
│ │ │ └── main.yml > 至少应该包含一个名为main.yml的文件
│ │ ├── templates > template模块查找所需要模板文件目录
│ │ │ └── main.yml > 至少应该包含一个名为main.yml的文件
│ │ └── vars > 定义变量;;其他的文件需要在此文件中通过include进行包含
│ │ └── main.yml > 至少应该包含一个名为main.yml的文件
还是拿一个实例来说:
如果要在一台初始化的主机上面安装httpd服务,有以下过程:(这里不考虑编译安装情况,假设yum脚本里不会创建组和用户)
1.创建用于httpd服务的组
2.创建用于httpd服务的用户
3.安装httpd软件包
4.启动httpd服务
把这些过程体现在ansible上面就是对应的具体的tasks,因此,将需要在roles/tasks/下面创建分别用于这些过程的独立yml文件
1.创建用于httpd服务的
#vim groupadd.yml
- name: groupadd apache
group: name=apache
2.创建用于httpd服务的用户
#vim useradd.yml
- name: useradd apache
user: name=apache group=apache shell=/sbin/nologin system=yes
3.安装httpd软件包
#vim install_httpd.yml
- name: yum install httpd
yum: name=httpd
4.启动httpd服务
#vim start_httpd.yml
- name: start httpd
service: name=httpd state=started
每个具体的小任务有了,那么就得有一个主的配置文件,默认剧本就会读取它,从而确定其他任务的关系。
注意,文件名必须是main.yml
注意,顺序不能颠倒,步骤是从上而下顺序执行,就像编排电影剧本一样。有没有当导演的感觉?
#vim main.yml
- import_tasks: groupadd.yml
- import_tasks: useradd.yml
- import_tasks: install_httpd.yml
- import_tasks: start_httpd.yml
最后,创建一个执行的playbook文件,这个文件与roles目录是同级目录。
#vim httpd_roles.yml
---
- hosts: web
remote_user: root
roles:
- httpd > 注意,这个- 后面跟就是roles目录下的子目录名称
当然,也可以写成
roles:
- role: httpd > 注意,这个- role: 是不可以改变名称的,后面跟就是roles目录下的子目录名称
至此,此时的目录结构为:
├── httpd_roles.yml > 执行的playbook文件
└── roles > roles角色目录
├── httpd > 项目文件夹
│ ├── default
│ ├── files
│ ├── handlers
│ ├── meta
│ ├── tasks > 任务文件夹
│ │ ├── groupadd.yml
│ │ ├── install_httpd.yml
│ │ ├── main.yml
│ │ ├── start_httpd.yml
│ │ └── useradd.yml
│ ├── templates
│ └── vars
#ansible web -m shell -a 'ss -nlt|grep 80'
6-web-1.hunk.tech | SUCCESS | rc=0 >>
LISTEN 0 128 :::80
7-web-2.hunk.tech | SUCCESS | rc=0 >>
LISTEN 0 128 :::80
7-web-0.hunk.tech | SUCCESS | rc=0 >>
LISTEN 0 128 :::80
调用其他任务
为了更好的复用代码,可以将一些公共的代码集中在一个目录里,按需要在以后的roles进行调用
├── pubtasks
│ └── create_nginx_user_and_group.yml
#cat create_nginx_user.yml
- name: create nginx group
group: name=nginx
- name: create nginx user
user: name=nginx shell=/usr/sbin/nologin comment="nginx service" group=nginx createhome=no
调用的时候,在tasks中引入即可
- hosts: dns
remote_user: root
tasks:
- name: test
import_tasks: /app/yml/pubtasks/create_nginx_user_and_group.yml
同理,在别的文件中引入import_role也是可以的。
roles中的tags
前面的章节针对tasks有tags,而roles中也可以运用此方法
- hosts: web
remote_user: root
roles:
- { role: httpd, tags: [ 'web', 'apache22' ] } > 其实,这是字典的一种写法,前面章节有讲到,只不过是写在一行里了。
所以,下面的写法是同等的
roles:
- role: httpd
tags:
- web
- apache22
基于条件判断的roles的tags
- { role: nginx, tags: [ 'nginx', 'web' ], when: ansible_distribution_major_version == "6" }
当roles中有了tags后,执行时候加上-t tags名称即可
# ansible-playbook httpd_roles.yml -t web
# ansible-playbook httpd_roles.yml -t apache22
也可以同时调用多个tags
# ansible-playbook httpd_roles.yml -t "web,db"
第 (五) 篇属于应用级别的。后续再更新了。