Ansible简介
当下有许多的运维自动化工具(配置管理),例如:ansible、SaltStack、Puppet、Fabric等。Ansible是一种集成IT系统的配置管理、应用部署、执行特定任务的开源平台,是ansibleWorks公司名下的项目。
Ansible是基于python语言实现的。有Paramiko和PyYaml、jinja2三个关键模块构建。
特性
- 模块化: 调用特定的模块,完成特定的任务
- 有Paramiko、PyYaml、Jinja2(模块语言)三个关键模块
- 支持自定义模块
- 基于python语言实现
- 部署简单,基于python和ssh(默认已安装)
- 安全,基于openssh
- 支持playbook编排任务
- 冥等性:一个任务执行1遍和执行n遍效果一样,不会因为重复执行带来意外情况
- 无需代理不依赖PKI(无需SSL)
- 可使用任何编程语言写模块
- YAML格式,编排任务,支持丰富的数据结构
- 较强大的多层解决方案
- 提供一个功能强大、操作性强的web管理界面和RESTAPI接口 - AWX平台
ansible架构
工作原理
主要组成部分
- Ansible playbooks:任务剧本(任务集),编排定义Ansible任务集的配置文件,由Ansible顺序依次执行,通常是JSON格式的YAML文件
- Inventory:ansible管理主机的清单 /etc/ansible/hosts
- Modules:Ansible执行命令的功能模块,多数为内置核心模块,也可以自定义
- Plugins:模块功能的补充,如连接类型插件、循环插件、变量插件、过滤插件等,该功能不常用
- API:供第三方程序调用的应用程序编程接口
- Ansible:组合Inventory、API、Modules、Plugins的绿框,可以理解为是ansible命令工具,其为核心执行工具
ansible命令执行来源
- User,普通用户,即System Administrator
- CMDB(配置管理数据库)API调用
- Public/Private Cloud Api调用
利用ansible实现管理的方式
- Ad-Hoc 即ansible命令,主要用于临时命令使用场景
- Ansible-playbook 主要用于长期规划好的,大型项目的场景,需要有提前的规划
Ansible-playbook(剧本)执行过程
- 将已有编排好的任务集写入Ansible-Playbook
- 通过ansible-playbook命令拆分任务集至逐条ansible命令,按预定规则逐条执行
ansible主要操作对象
- Hosts主机
- Networking网络设备
注意事项
- 执行ansible的主机一般称为主控端,中控、master或堡垒机
- 主控端python版本需要2.6或以上
- 被控端python版本小于2.4需要安装python-simplejson
- 被控端如开启SELinux需要安装libselinux-python
- Windows不能作为主控端
ansible与SaltStack的区别
最大区别是Ansible无需在被监控主机部署任何客户端代理,默认通过ssh通道进行远程命令执行或下发配置(相对而言,Saltstack有自己的agent端,速度会比ansible更快)
相同点是都具备功能强大、灵活的系统管理、状态配置,都使用YAML格式来描述配置,两者都提供丰富的模板及API,对云计算平台、大数据都有很好的支持
Ansible安装与配置
安装ansible
1
2
3
4
5
6
7
8
9
10
11
12
|
#安装wget
[root@ansible ~]# yum -y install wget
#添加阿里云yum源以及epel源
[root@ansible ~]# wget -O /etc/yum.repos.d/CentOS-Base.repo http://mirrors.aliyun.com/repo/Centos-7.repo
[root@ansible ~]# wget -O /etc/yum.repos.d/epel.repo http://mirrors.aliyun.com/repo/epel-7.repo
#重新建立yum缓存
[root@ansible ~]# yum clean all && yum makecache fast
#安装ansible
[root@ansible ~]# yum -y install ansible
|
相关文件
配置文件
文件 |
作用 |
/etc/ansible/ansible.cfg |
主配置文件,配置ansible工作特性 |
/etc/ansible/hosts |
主机清单 |
/etc/ansible/roles |
存放角色的目录 |
程序
文件 |
作用 |
/usr/bin/ansible |
主程序,临时命令执行工具 |
/usr/bin/ansible-doc |
查看配置文档,模块功能查看工具 |
/usr/bin/ansible-galaxy |
下载/上传优秀代码或Roles模块的官网平台 |
/usr/bin/ansible-playbook |
定制自动化任务,编排剧本工具 |
/usr/bin/ansible-pull |
远程执行命令的工具 |
/usr/bin/ansible-vault |
文件加密工具 |
/usr/bin/ansible-console |
基于console界面与用户交互的执行工具 |
主机清单
- Inventory 主机清单,ansible的主要功能用于批量主机操作,为了便捷地使用其中的部分主机,可以再inventory file中将其分组命名
- 默认的inventory file为/etc/ansible/hosts
- Inventory file文件可以有多个,且也可以通过Dynamic Inventory来动态生成
/etc/ansible/hosts文件格式
Inventory文件遵循INI文件风格,中括号中的字符为组名。可以将同一个主机同时归并到多个不同的组中;此外,当如若目标主机使用了非默认的ssh端口,还可以在主机名称之后使用冒号加端口号来标明
1
2
3
4
5
6
7
|
[webservers]
www1.lingcb.com:222
www2.lingcb.com
[dbservers]
db1.lingcb.com
db2.lingcb.com
db3.lingcb.com
|
如果主机名称遵循相似的命名模式,还可以使用列表的方式标识各主机
1
2
3
4
5
|
[webservs]
www[01:100].example.com
[dbservs]
db-[a:f].example.com
|
Ansible配置文件
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
Ansible配置文件/etc/ansible/ansible.cfg(一般保持默认)
[default]
#inventory = /etc/ansible/hosts #主机列表配置文件
#library = /usr/share/my_modules/ #库文件存放目录
#remote_tmp = $HOME/.ansible/tmp #临时py命令文件存放在远程主机目录
#local_tmp = $HOME/.ansible/tmp #本机的临时命令执行目录
#forks = 5 #默认并发数
#sudo_user = root #默认sudo用户
#ask_sudo_pass = True #每次执行ansible命令是否询问sudo密码
#ask_pass = True #每次执行ansible命令是否询问ssh密码
#remote_port = 22 #远程主机默认端口
#host_key_checking = False #检查对应服务器的host_key,建议取消注释
#log_path = /var/log/ansible.log #日志文件
建议修改host_key_checking以及log_path
|
Ansible系列命令
ansible
1
2
3
4
5
6
7
8
9
10
11
12
|
ansible <host-pattern> [-m module_name] [-a args]
--version 显示版本
-m module 指定模块,默认为command
-v 详细过程 -vv -vvv 更详细
--list-hosts 显示主机列表,可简写 --list
-k,--ask-pass 提示输入ssh连接密码,默认key验证
-K,--ask-become-pass 提示输入sudo时口令
-C,--check 检查,并不执行
-T,--timeout=TIMEOUT 执行命令的超时时间,默认10s
-u,--user=REMOTE_USER 远程执行命令的用户
-b,--become 代替旧版sudo切换
|
ansible的Host-pattern
匹配主机的列表
1
2
3
4
5
6
|
ALL : 表示所有Inventory中的所有主机
[root@ansible ~]# ansible all -m ping
* : 通配符
[root@ansible ~]# ansible "*" -m ping
[root@ansible ~]# ansible 192.168.116.* -m ping
[root@ansible ~]# ansible *serv -m ping
|
逻辑或
1
2
|
[root@ansible ~]# ansible webserv:dbserv -m ping
在webserv组中或者在dbserv组中
|
逻辑与
1
2
|
[root@ansible ~]# ansible 'webserv:&dbserv' -m ping
在webserv组并且在dbserv组中的主机,注意因为&在shell中有特殊意义,所以这里需要用引号引起来
|
逻辑非
1
2
|
[root@ansible ~]# ansible 'webserv:!dbserv' -m ping
在webserv组中,但是不在dbserv组中的主机,注意需要使用引号引起来
|
综合逻辑
1
2
|
[root@ansible ~]# ansible 'webserv:dbserv:&appserv:!ftpserv' -m ping
在webserv组中或者在dbserv组中并且在appserv组中但不在ftpserv组中的主机
|
正则表达式
1
2
3
|
[root@ansible ~]# ansible 'webserv:dbserv' -m ping
等同于
[root@ansible ~]# ansible '~(web|db)serv' -m ping
|
Ansible inventory内置变量
可以再hosts文件中进行配置的内置变量,如下:
- ansible_ssh_host:定义host ssh地址
- ansible_ssh_port:定义host ssh端口
- ansible_ssh_user:定义host ssh 认证用户
- ansible_ssh_pass:定义ssh认证密码
- ansible_sudo:定义sudo用户
- ansible_sudo_pass:定义sudu密码
- ansible_ssh_connection 目标主机连接类型,可以是local/ssh或者paramiko
- ansible_ssh_private_key_file 连接目标主机的ssh私钥 ansible_*_interpreter 指定采用非python的其他语言脚本,如ruby/perl解释器
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
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
|
示例:
[root@ansible ~]# cat /etc/ansible/hosts
[webserv]
192.168.116.2[0:1] ansible_ssh_user='root' ansible_ssh_pass='123456'
[dbserv]
192.168.116.2[1:2]
#给dbserv组定义内置变量
[dbserv:vars]
ansible_ssh_user='root'
ansible_ssh_pass='123456'
测试:
[root@ansible ~]# ansible webserv -m ping
192.168.116.20 | SUCCESS => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/bin/python"
},
"changed": false,
"ping": "pong"
}
192.168.116.21 | SUCCESS => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/bin/python"
},
"changed": false,
"ping": "pong"
}
[root@ansible ~]# ansible dbserv -m ping
192.168.116.21 | SUCCESS => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/bin/python"
},
"changed": false,
"ping": "pong"
}
192.168.116.22 | SUCCESS => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/bin/python"
},
"changed": false,
"ping": "pong"
}
|
ansible-doc
1
2
3
4
5
6
7
8
9
10
|
ansible-doc [options] [module...]
-a 显示所有模块的文档
-l,--list 列出可用模块
-s,--snippet 显示指定模块的playbook片段
示例:
[root@ansible ~]# ansible-doc -l 列出所有模块
[root@ansible ~]# ansible-doc ping 查看指定ping模块的帮助用法
[root@ansible ~]# ansible-doc -s ping 查看指定模块的帮助用法
Ansible通过ssh实现配置管理、应用部署、任务执行等功能,建议配置ansible端能基于秘钥认证的方式联系各被管理节点。
|
Ansible执行命令过程
- 加载自己的配置文件,默认/etc/ansible/ansible.cfg
- 加载自己对应的模板文件,如command
- 通过ansible将模块或命令生成对应的临时py文件,并将该文件传输至远程服务器的对应执行用户$HOME/.ansible/tmp/ansible-tmp-数字/xxx.py文件
- 给文件+x执行权限
- 执行并返回结果
- 删除临时py文件,sleep 0 退出
执行状态:
- 绿色:执行成功并且不需要做改变的操作
- 黄色:执行成功并且对目标主机做出了变更
- 红色:执行失败
ansible-galaxy
连接https://galaxy.ansible.com下载相应的roles
列出所有已安装的galaxy
ansible-galaxy list
安装galaxy
ansible-galaxy install geerlingguy.redis
刪除galaxy
ansible-galaxy remove geerlingguy.redis
ansible-pull
推送命令至远程,效率无限提升,对运维要求较高
ansible-playbook
ansible-playbook hello.yml
运行定制好的ansible-playbook剧本
ansible-console
2.0+新增,可交互执行命令,支持tab
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
|
[root@ansible ~]# ansible-console
Welcome to the ansible console.
Type help or ? to list commands.
root@all (3)[f:5]$
执行用户@当前操作的主机组(当前组的主机数量)[f:并发数]$
root@all (3)[f:5]$ forks 10
设置并发数为10
root@all (3)[f:10]$ cd webserv
切换至webserv组
root@webserv (2)[f:10]$ list
192.168.116.20
192.168.116.21
列出当前组主机列表
root@webserv (2)[f:10]$ ?
列出所有内置命令
root@webserv (2)[f:10]$ yum name=httpd
安装httpd包
root@webserv (2)[f:10]$ yum name=httpd state=absent
卸载httpd包
|
ansible-vault
功能:管理加密解密yml文件
ansible-vault [create|decrypt|edit|encrypt|rekey|view]
ansible-vault encrypt hello.yml 加密
ansible-vault decrypt hello.yml 解密
ansible-vault view hello.yml 查看
ansible-vault edit hello.yml 编辑加密文件
ansible-vault rekey hello.yml 修改口令
ansible-vault create hello.yml 创建新文件
Ansible常用模块
Command模块
在远程主机执行命令,默认模块,可以忽略-m选项
1
2
|
[root@ansible ~]# ansible webserv -m command -a 'ls /root'
需要注意的是,command模块不支持特殊符号,比如重定向以及管道,如果需要用到这些,可以使用shell模块实现
|
shell模块
1
2
3
|
和command相似,用shell执行命令
[root@ansible ~]# ansible webserv -m shell -a 'findmnt | grep /dev'
调用bash执行命令 ,但是一些复杂命令,即使使用shell也可能会失败,解决办法:写到脚本,使用script模块
|
script模块
1
2
3
4
5
|
运行脚本
[root@ansible ~]# cat a.sh
#!/bin/bash
hostname
[root@ansible ~]# ansible webserv -m script -a a.sh
|
Copy模块
1
2
3
4
5
6
|
从服务器复制文件到客户端
[root@ansible ~]# ansible webserv -m copy -a 'src=/root/a.sh dest=/tmp/f1.sh owner=root mode=600 backup=yes'
将/root/a.sh拷贝到被控端的/tmp/f1.sh 所有者、所属组为root,权限为600,如果目标存在,默认覆盖,此处指定先备份
[root@ansible ~]# ansible webserv -m copy -a 'content="test content\n" dest=/tmp/f1.txt'
利用content内容,直接生成目标文件
|
fetch模块
1
2
3
4
5
6
|
从客户端取文件到服务器端,与copy相反
[root@ansible ~]# ansible webserv -m fetch -a 'src=/tmp/f1.txt dest=/mnt'
[root@ansible ~]# ll /mnt/
total 0
drwxr-xr-x. 3 root root 17 Feb 1 15:06 192.168.116.20
drwxr-xr-x. 3 root root 17 Feb 1 15:06 192.168.116.21
|
file模块
1
2
3
4
5
6
7
8
9
10
11
12
13
|
设置文件属性
[root@ansible ~]# ansible webserv -u root -m file -a 'path=/data mode=755 state=directory'
创建/data目录,权限为755
[root@ansible ~]# ansible webserv -u root -m file -a 'path=/data/f1.txt mode=644 owner=root state=touch'
创建一个/data/f1.txt,所有者所属组为root,文件权限为644
[root@ansible ~]# ansible webserv -m file -a 'src=/etc/fstab path=/data/fstab state=link'
创建一个/etc/fstab的软连接到/data目录下。
[root@ansible ~]# ansible webserv -m file -a 'path=/data state=absent'
删除/data目录
|
stat模块
1
2
|
获取在远程文件状态信息,atime/ctime/mtime/MD5/uid/gid等信息
[root@ansible ~]# ansible webserv -m stat -a 'path=/tmp/f1.sh'
|
yum模块
1
2
3
4
5
|
软件包管理模块
安装
[root@ansible ~]# ansible webserv -m yum -a 'name=curl'
卸载
[root@ansible ~]# ansible webserv -m yum -a 'name=httpd state=absent'
|
get_url模块
1
2
|
实现在远程主机下载指定url到本地,支持sha256sum文件校验
[root@ansible ~]# ansible webserv -m get_url -a 'url=http://www.baidu.com dest=/tmp/index.html mode=0440 force=yes'
|
cron模块
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
远程主机crontab配置,支持时间:minute、hour、day、month、weekday
[root@ansible ~]# ansible webserv -m cron -a 'name="check dirs" hour="5,2" job="ls -alh > /dev/null"'
效果如下:
[root@node1 ~]# crontab -l
#Ansible: check dirs
* 5,2 * * * ls -alh > /dev/null
关闭上面定时任务:
[root@ansible ~]# ansible webserv -m cron -a 'name="check dirs" hour="5,2" job="ls -alh > /dev/null" disabled=yes'
效果如下:
[root@node1 ~]# crontab -l
#Ansible: check dirs
#* 5,2 * * * ls -alh > /dev/null
彻底删除上面定时任务
[root@ansible ~]# ansible webserv -m cron -a 'name="check dirs" state=absent'
|
mount模块
1
2
3
|
远程主机分区挂载模块
[root@ansible ~]# ansible webserv -m mount -a 'name=/mnt src=/dev/sd0 fstype=ext4 opts=ro state=mounted'
具体其他参数参考 ansible-doc -s mount
|
service模块
1
2
3
4
5
|
远程主机系统服务管理
ansible node -m service -a "name=httpd state=restarted"
ansible node -m service -a "name=httpd state=reloaded"
ansible node -m service -a "name=httpd state=stopped"
ansible node -m service -a "name=httpd state=started"
|
group模块
1
2
|
远程主机用户组管理
[root@ansible ~]# ansible webserv -m group -a 'name=nginx gid=88 system=yes'
|
user模块
1
2
3
4
5
6
|
远程主机用户管理
添加用户
[root@ansible ~]# ansible webserv -m user -a 'name=nginx uid=88 group=nginx shell=/sbin/nologin system=yes'
递归删除用户以及用户组以及家目录等数据
[root@ansible ~]# ansible webserv -m user -a 'name=nginx state=absent remove=yes'
|
hostname模块
1
2
|
管理主机名
[root@ansible ~]# ansible 192.168.116.22 -m hostname -a 'name=a-node3'
|
setup模块
1
2
|
查看ansible所有的内置变量
[root@ansible ~]# ansible webserv -m setup -a 'filter=*process*'
|
Playbook
- Playbook是由一个或多个“play”组成的列表
- Play的主要功能在于将事先归并为一组的主机装扮成事先通过ansible中的task定义好的角色。从根本上来讲,所谓task无非是调用ansible的一个module。将多个play组织在一个playbook中,即可以让它们联同起来按事先编排的机制同唱一台大戏
- Playbook采用yaml语言编写
核心元素
-
Hosts 执行的远程主机列表
-
Tasks 任务集
-
Varniables 内置变量或自定义变量在playbook中调用
-
Templates 模板,可替换模板文件中的变量并实现一些简单逻辑的文件
-
Handlers 和notify结合使用,由特定条件触发的操作,满足条件方才执行,否则不执行
-
Tags 标签,指定某条任务执行,用于选择运行playbook中的部分代码。Ansible具有幂等性。因此会自动跳过没有变化的部分,即便如此,有些代码为测试其确实没有发生变化的时间依然会非常地长。此时,如果确信其没有变化,就可以通过tags跳过此些代码片段。
ansible-playbook -t tagsname useradd.yml
playbook基础组件
hosts
Hosts:playbook中的每一个play的目的都是为了让某个或某些主机以某个指定的用户身份执行任务。Hosts用于指定要执行指定任务的主机列表,须事先定义在主机清单中
可以是如下形式:
1
2
3
4
5
6
7
8
9
10
11
12
13
|
One.example.com
One.example.com:two.example.com
192.168.150
192.168.1.*
两个组的并集: webserv :dbserv
两个组的交集: webserv:&dbserv
两个组的非集: webserv:!dbserv
|
remote_user
用于hosts和task中,也可以通过指定其通过sudo的方式在远程主机上执行任务,其可用于play全局或某个任务;此外,甚至可以在sudo时使用sudo_user指定sudo时切换的用户
tasks列表和action
- Play的主体部分是task list。Task list中的各任务按次序逐个在hosts中指定的所有主机上执行,即在所有主机上完成第一个任务后再开始第二个。在运行自上而下某playbook时,如果中途发生错误,所有已执行任务都将回滚,因此在更正playbook后重新执行一次即可
- Task的目的是使用指定的参数执行模块,而在模块参数中可以使用变量。模块执行时幂等的,这意味着多次执行时安全的,因为其结果一致
- 每个task都应该有其name,用于playbook的执行结果输出,建议其内容尽可能清晰地描述任务执行步骤,如果未提供name,则action的结果将用于输出。
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
27
28
29
30
31
32
33
34
35
36
37
38
|
tasks: 任务列表
格式:
1、action: module arguments
2、module: arguments 建议使用
注意:shell和command模块后面跟命令,而非key=value
某任务的状态在运行后为changed时,可以通过notify 通知给相应的handlers。
任务可以通过tags打标签,而后可以再ansible-playbook 命令上使用 -t 指定标签进行调用
示例:
[root@ansible ~]# cat test.yaml
---
- hosts: all
remote_user: root
tasks:
- name: disable selinux
command: /sbin/setenforce 0
- name: replace selinux config
replace: path=/etc/selinux/config regexp=^(SELINUX=).* replace=\1disabled backup=yes
如果让遇到某个task错误后不停止,继续往后执行,可以使用如下方式:
[root@ansible ~]# cat test.yaml
---
- hosts: all
remote_user: root
tasks:
- name: disable selinux
shell: sss || /bin/true
或者使用ignore_errors来忽略错误信息
[root@ansible ~]# cat test.yaml
---
- hosts: all
remote_user: root
tasks:
- name: disable selinux
shell: sss
ignore_errors: True
|
运行palybook
- 运行playbook的方式 ansible-playbook <filename.yml> … [options]
- 常见选项
-C , –check 只检测可能会发生的改变,但不真正执行操作
–list-hosts , –list 列出运行任务的主机列表
–limit 主机列表,只针对主机列表中的主机执行
-v 显示过程 -vv -vvv更详细
handlers和notify结合使用触发条件
Handlers 是task列表,这些task与前述的task并没有本质上的不同,同于当关注的资源发生变化时,才会采取一定的操作
Notify此action可用于在每个play的最后被触发,这样可避免多次有改变发生时每次都执行指定的操作,仅在所有的变化发生完成后一次性地执行指定操作。在notify列出的操作称为handler,也即notify中调用handler中定义的操作。
比如,nginx服务,当配置文件发生改变后,触发重新加载操作
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
[root@ansible ~]# cat nginx.yml
---
- hosts: webserv
remote_user: root
tasks:
- name: copy repo config
copy: src=/etc/yum.repos.d/nginx.repo dest=/etc/yum.repos.d/
- name: install nginx
yum: name=nginx
- name: copy nginx config
copy: src=/etc/nginx/nginx.conf dest=/etc/nginx/
notify: reload nginx
- name: start nginx
service: name=nginx state=started enabled=yes
handlers:
- name: reload nginx
service: name=nginx state=reloaded
检查语法
[root@ansible ~]# ansible-playbook -C nginx.yml
执行playbook
[root@ansible ~]# ansible-playbook nginx.yml
|
比如上面示例,我只想运行copy nginx config这个task,这时候就可以使用tag来做(不同task中的标签可以相同),首先添加在task中添加tag
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
27
28
|
[root@ansible ~]# cat nginx.yml
---
- hosts: webserv
remote_user: root
tasks:
- name: copy repo config
copy: src=/etc/yum.repos.d/nginx.repo dest=/etc/yum.repos.d/
- name: install nginx
yum: name=nginx
- name: copy nginx config
copy: src=/etc/nginx/nginx.conf dest=/etc/nginx/
tags: [nginx,copyconfig]
notify: reload nginx
- name: start nginx
service: name=nginx state=started enabled=yes
tags: [nginx,startservice]
handlers:
- name: reload nginx
service: name=nginx state=reloaded
查看此playbook中存在的标签
[root@ansible ~]# ansible-playbook nginx.yml --list-tags
或者 用查看所有的任务也能看到标签信息
[root@ansible ~]# ansible-playbook nginx.yml --list-tasks
指定标签执行playbook
[root@ansible ~]# ansible-playbook -t copyconfig nginx.yml
|
playbook中变量的使用
变量名:仅能由字母、数字和下划线组成,且只能以字母开头
变量来源:
-
ansible setup facts远程主机的所有变量都可直接调用
-
在/etc/ansible/hosts中定义
普通变量:主机组中主机单独定义,优先级高于公共变量
公共(组)变量:针对主机组中所有主机定义统一变量
-
在playbook中定义
vars:
- var1: value1
- var2: value2
-
通过命令行指定变量,优先级最高
-
在role中定义
变量优先级
命令行 > playbook(role) > /etc/ansible/hosts(普通变量) > /etc/ansible/hosts(公共变量)
变量定义
key = value
示例: http_port = 80
变量调用方式
通过{{ variable_name }}调用变量,且变量名前后必须有空格,有时需要用引号”{{ variable_name }}”才生效
templates
templates功能:根据模块文件动态生成对应的配置文件,使用的是jinja2模板语法
1、templates文件必须存放于templates目录下,且命名为.j2结尾
2、Yaml/yml文件需和templates目录平级
例如:
[root@ansible ansible]# tree
.
├── templates
│ └── nginx.conf.j2
└── template.yml
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
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
|
[root@ansible ansible]# grep worker_pro templates/nginx.conf.j2
worker_processes {{ ansible_processor_vcpus*2 }};
[root@ansible ansible]# cat template.yml
---
- hosts: webserv
remote_user: root
tasks:
- name: copy template
template: src=nginx.conf.j2 dest=/etc/nginx/nginx.conf backup=yes
notify: reload nginx
handlers:
- name: reload nginx
service: name=nginx state=reloaded
此时会根据变量ansible_processor_vcpus 动态替换模板的值
此外在template中还可以使用for循环或者if判断
例如:我想根据模板生成类似于这样的配置文件
#官网
server {
listen 80;
server_name www.lingcb1.com;
location / {
root /data/web/www.lingcb.com;
index index.html index.htm;
try_files $uri $uri/ /index.html;
proxy_cache lingcb;
proxy_cache_valid 200 302 10m;
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root html;
}
}
#收银台升级包
server {
listen 80;
server_name upg.lingcb1.com;
location / {
root /data/web/upg.lingcb.com;
index index.html index.htm;
proxy_cache lingcb;
proxy_cache_valid 200 302 10m;
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root html;
}
}
第一步 编写template模板文件
[root@ansible ansible]# cat templates/www.conf.j2
{% for item in items %}
server {
listen {{ item.listen | default('80') }};
{% if item.server_name is defined %}
server_name {{ item.server_name }};
{% endif %}
location / {
{% if item.root is defined %}
root /data/web/{{ item.root }};
{% endif %}
index index.html index.htm;
try_files $uri $uri/ /index.html;
proxy_cache lingcb;
proxy_cache_valid 200 302 10m;
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root html;
}
}
{% endfor %}
第二步编写playbook文件
[root@ansible ansible]# cat template1.yml
---
- hosts: webserv
remote_user: root
vars:
items:
- listen: 80
server_name: "www.lingcb1.com"
root: "www.lingcb.com"
- listen: 80
server_name: "upg.lingcb1.com"
root: "upg.lingcb.com"
tasks:
- name: copy nginx conf template
template: src=www.conf.j2 dest=/tmp/www.conf backup=yes
[root@ansible ansible]# ansible-playbook template1.yml
生成文件如下:
[root@node1 ~]# cat /tmp/www.conf
#官网
server {
listen 80;
server_name www.lingcb1.com;
location / {
root /data/web/www.lingcb.com;
index index.html index.htm;
try_files $uri $uri/ /index.html;
proxy_cache lingcb;
proxy_cache_valid 200 302 10m;
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root html;
}
}
server {
listen 80;
server_name upg.lingcb1.com;
location / {
root /data/web/upg.lingcb.com;
index index.html index.htm;
try_files $uri $uri/ /index.html;
proxy_cache lingcb;
proxy_cache_valid 200 302 10m;
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root html;
}
}
|
when 条件判断
条件测试:如果需要根据变量、facts或此前任务的执行结果来做为某task执行与否的前提时要用到条件测试,通过when语句实现,在task中使用,jinja2的语法格式
在task后添加when子句即可使用条件测试
例如:
只有4核cpu的机器,我才把nginx.conf这个文件拷贝过去
1
2
3
4
5
6
7
8
9
|
[root@ansible ansible]# cat when.yml
---
- hosts: webserv
remote_user: root
tasks:
- name: test when
copy: src=/etc/nginx/nginx.conf dest=/tmp
when: ansible_processor_vcpus == 4
|
with_items 循环
迭代:当有需要重复性执行的任务时,可以使用迭代机制
1、对迭代项的引用,固定变量名为 “item”
2、要在task中使用with_items给定要迭代的元素列表
3、列表格式:
字符串
字典
例如:
示例1:拷贝多个文件
1
2
3
4
5
6
7
8
9
10
11
12
13
|
[root@ansible ansible]# cat items1.yml
---
- hosts: webserv
remote_user: root
tasks:
- name: copy files
copy: src={{ item }} dest=/tmp
with_items:
- /etc/fstab
- /etc/passwd
- /etc/shadow
|
示例2:添加多个用户组,并把用户添加到对应的用户组中
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
[root@ansible ansible]# cat items2.yml
---
- hosts: webserv
remote_user: root
tasks:
- name: add groups
group: name={{ item }} state=present
with_items:
- group1
- group2
- group3
- name: add user
user: name={{ item.name }} group={{ item.group }}
with_items:
- {name: 'user1',group: 'group1'}
- {name: 'user2',group: 'group2'}
- {name: 'user3',group: 'group3'}
|
roles
Ansible自1.2版本引入的新特性,用于层次性,结构化地组织playbook。Roles能根据层次型结构自动装载变量文件、tasks以及handlers等。要使用roles只需要在playbook中使用include指令即可。简单来讲,roles就是通过分别将变量、文件、任务、模板及处理器放置于单独的目录中,并可以便捷地include它们的一种机制。角色一般用于基于主机构建服务的场景中,但也可以是用于构建守护进程等场景
复杂场景:建议使用roles,代码复用度高
- 变更指定主机或主机组
- 如命名不规范维护和传参成本大
- 某些功能需要多个playbook,通过includes即可实现
Roles目录结构
-
每个角色,以特定的层级目录结构进行组织
-
Roles目录结构
Playbook.yml (playbook文件,要跟roles根在同级目录)
roles/ (roles根目录)
project/ (roles项目)
tasks/ (任务目录,定义task,role的基本元素,至少应该包含一个名为main.yml的文件;其他的文件需要在此文件中通过include进行包含)
files/ (文件目录,存放由copy或script模块等调用的文件)
vars/ (变量目录,不常用,定义变量,至少应该包含一个名为main.yml文件,其他的文件需要在此文件中通过include进行包含)
default (不常用,设定默认变量时使用此目录中的main.yml文件)
templates/ (模板目录,template模块查找所需要模板文件的目录)
handlers/ (handlers目录,至少应该包含一个名为main.yml文件,其他的文件需要在此文件中通过include进行包含)
meta/ (不常用,定义当前角色的特殊设定及其依赖关系,至少应该包含一个名为main.yml文件,其他的文件需要在此文件中通过include进行包含)
playbook 调用角色
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
|
方法1
---
- hosts: webserv
remote_user: root
roles:
- role: nginx
#- role: http #可以多个role同时执行
方法2
传递变量给角色
- hosts: webserv
remote_user: root
roles:
- {role: nginx,username:nginx}
键role用于指定角色名称
后续的k/v用于传递变量给角色
方法3
还可以基于条件测试实现角色调用,比如
roles:
- {role: nginx,username:nginx,when: ansible_distribution_major_version == 7}
|
1
2
3
4
5
6
|
- hosts: webserv
remote_user: root
roles:
- {role: nginx,tags: [‘nginx’,’web’]}
- {role: nginx,tags: [‘httpd,’web’]}
|
示例 创建一个简单的nginx的roles
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
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
|
[root@ansible ansible]# mkdir roles
[root@ansible ansible]# mkdir roles/nginx
[root@ansible ansible]# cd !$
[root@ansible nginx]# mkdir {tasks,templates,handlers,files}
[root@ansible nginx]# cp /etc/yum.repos.d/nginx.repo files/
[root@ansible nginx]# cat tasks/copy_repofile.yml
- name: copy yum repo file
copy: src=nginx.repo dest=/etc/yum.repos.d/ backup=yes
[root@ansible nginx]# cat tasks/install.yml
- name: install nginx package
yum: name=nginx
[root@ansible nginx]# cp /etc/nginx/nginx.conf templates/nginx.conf.j2
[root@ansible nginx]# cat templates/nginx.conf.j2
user nginx;
worker_processes {{ ansible_processor_vcpus*2 }};
...
[root@ansible nginx]# cat tasks/template.yml
- name: template nginx.conf
template: src=nginx.conf.j2 dest=/etc/nginx/nginx.conf backup=yes
notify: reload nginx service
[root@ansible nginx]# cat tasks/cron.yml
- name: delete repos backup file
cron: name='delete repo backup file' hour=2 minute=0 job='rm -rf /etc/yum.repos.d/nginx.repo.*'
- name: delete nginx config backup file
cron: name='delete nginx conf backup file' hour=2 minute=0 job='rm -rf /etc/nginx/nginx.conf.*'
[root@ansible nginx]# cat tasks/start.yml
- name: start nginx service
service: name=nginx state=started enabled=yes
[root@ansible nginx]# cat tasks/main.yml
- include: copy_repofile.yml
- include: install.yml
- include: template.yml
- include: cron.yml
- include: start.yml
[root@ansible nginx]# cat handlers/reload.yml
- name: reload nginx service
service: name=nginx state=reloaded
[root@ansible nginx]# cat handlers/main.yml
- include: reload.yml
[root@ansible nginx]# cd ..
[root@ansible roles]# cd ..
[root@ansible ansible]# cat nginx.yml
---
- hosts: webserv
remote_user: root
roles:
- role: nginx
#- role: http #可以多个role同时执行
|