目录

ansible

Ansible简介

当下有许多的运维自动化工具(配置管理),例如:ansible、SaltStack、Puppet、Fabric等。Ansible是一种集成IT系统的配置管理、应用部署、执行特定任务的开源平台,是ansibleWorks公司名下的项目。

Ansible是基于python语言实现的。有Paramiko和PyYaml、jinja2三个关键模块构建。

特性

  1. 模块化: 调用特定的模块,完成特定的任务
  2. 有Paramiko、PyYaml、Jinja2(模块语言)三个关键模块
  3. 支持自定义模块
  4. 基于python语言实现
  5. 部署简单,基于python和ssh(默认已安装)
  6. 安全,基于openssh
  7. 支持playbook编排任务
  8. 冥等性:一个任务执行1遍和执行n遍效果一样,不会因为重复执行带来意外情况
  9. 无需代理不依赖PKI(无需SSL)
  10. 可使用任何编程语言写模块
  11. YAML格式,编排任务,支持丰富的数据结构
  12. 较强大的多层解决方案
  13. 提供一个功能强大、操作性强的web管理界面和RESTAPI接口 - AWX平台

ansible架构

https://xieys.club/images/posts/image-20210616145747869.png

工作原理

https://xieys.club/images/posts/image-20210616145835259.png

主要组成部分

  1. Ansible playbooks:任务剧本(任务集),编排定义Ansible任务集的配置文件,由Ansible顺序依次执行,通常是JSON格式的YAML文件
  2. Inventory:ansible管理主机的清单 /etc/ansible/hosts
  3. Modules:Ansible执行命令的功能模块,多数为内置核心模块,也可以自定义
  4. Plugins:模块功能的补充,如连接类型插件、循环插件、变量插件、过滤插件等,该功能不常用
  5. API:供第三方程序调用的应用程序编程接口
  6. Ansible:组合Inventory、API、Modules、Plugins的绿框,可以理解为是ansible命令工具,其为核心执行工具

ansible命令执行来源

  1. User,普通用户,即System Administrator
  2. CMDB(配置管理数据库)API调用
  3. Public/Private Cloud Api调用

利用ansible实现管理的方式

  1. Ad-Hoc 即ansible命令,主要用于临时命令使用场景
  2. Ansible-playbook 主要用于长期规划好的,大型项目的场景,需要有提前的规划

Ansible-playbook(剧本)执行过程

  1. 将已有编排好的任务集写入Ansible-Playbook
  2. 通过ansible-playbook命令拆分任务集至逐条ansible命令,按预定规则逐条执行

ansible主要操作对象

  1. Hosts主机
  2. Networking网络设备

注意事项

  1. 执行ansible的主机一般称为主控端,中控、master或堡垒机
  2. 主控端python版本需要2.6或以上
  3. 被控端python版本小于2.4需要安装python-simplejson
  4. 被控端如开启SELinux需要安装libselinux-python
  5. 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界面与用户交互的执行工具

主机清单

  1. Inventory 主机清单,ansible的主要功能用于批量主机操作,为了便捷地使用其中的部分主机,可以再inventory file中将其分组命名
  2. 默认的inventory file为/etc/ansible/hosts
  3. 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文件中进行配置的内置变量,如下:

  1. ansible_ssh_host:定义host ssh地址
  2. ansible_ssh_port:定义host ssh端口
  3. ansible_ssh_user:定义host ssh 认证用户
  4. ansible_ssh_pass:定义ssh认证密码
  5. ansible_sudo:定义sudo用户
  6. ansible_sudo_pass:定义sudu密码
  7. ansible_ssh_connection 目标主机连接类型,可以是local/ssh或者paramiko
  8. 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执行命令过程

  1. 加载自己的配置文件,默认/etc/ansible/ansible.cfg
  2. 加载自己对应的模板文件,如command
  3. 通过ansible将模块或命令生成对应的临时py文件,并将该文件传输至远程服务器的对应执行用户$HOME/.ansible/tmp/ansible-tmp-数字/xxx.py文件
  4. 给文件+x执行权限
  5. 执行并返回结果
  6. 删除临时py文件,sleep 0 退出

执行状态:

  1. 绿色:执行成功并且不需要做改变的操作
  2. 黄色:执行成功并且对目标主机做出了变更
  3. 红色:执行失败

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

  1. Playbook是由一个或多个“play”组成的列表
  2. Play的主要功能在于将事先归并为一组的主机装扮成事先通过ansible中的task定义好的角色。从根本上来讲,所谓task无非是调用ansible的一个module。将多个play组织在一个playbook中,即可以让它们联同起来按事先编排的机制同唱一台大戏
  3. Playbook采用yaml语言编写

核心元素

  1. Hosts 执行的远程主机列表

  2. Tasks 任务集

  3. Varniables 内置变量或自定义变量在playbook中调用

  4. Templates 模板,可替换模板文件中的变量并实现一些简单逻辑的文件

  5. Handlers 和notify结合使用,由特定条件触发的操作,满足条件方才执行,否则不执行

  6. 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

  1. Play的主体部分是task list。Task list中的各任务按次序逐个在hosts中指定的所有主机上执行,即在所有主机上完成第一个任务后再开始第二个。在运行自上而下某playbook时,如果中途发生错误,所有已执行任务都将回滚,因此在更正playbook后重新执行一次即可
  2. Task的目的是使用指定的参数执行模块,而在模块参数中可以使用变量。模块执行时幂等的,这意味着多次执行时安全的,因为其结果一致
  3. 每个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

  1. 运行playbook的方式 ansible-playbook <filename.yml> … [options]
  2. 常见选项

-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

playbook中tags的使用

比如上面示例,我只想运行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中变量的使用

变量名:仅能由字母、数字和下划线组成,且只能以字母开头

变量来源:

  1. ansible setup facts远程主机的所有变量都可直接调用

  2. 在/etc/ansible/hosts中定义

    普通变量:主机组中主机单独定义,优先级高于公共变量

    公共(组)变量:针对主机组中所有主机定义统一变量

  3. 在playbook中定义

    vars:

    - var1: value1

    - var2: value2

  4. 通过命令行指定变量,优先级最高

  5. 在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,代码复用度高

  1. 变更指定主机或主机组
  2. 如命名不规范维护和传参成本大
  3. 某些功能需要多个playbook,通过includes即可实现

Roles目录结构

  1. 每个角色,以特定的层级目录结构进行组织

  2. 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}

roles playbook tags使用

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同时执行