5.0 组织Playbook角色

概览

掌握Ansible一些基础模块以及一些高级用法,再配合简单的Ansible复用知识,我们已经能管理一些基础的服务。不过如果我们决定生产环境服务部署全套都通过Ansible来管理,那么简单靠上面这些知识去组织Ansible Playbook目录结构是比较乱的,搞不好类似俄罗斯套娃那样,一层又一层,没什么规律,难以维护。组织管理大批量playbook,这就需要用到Ansible Roles

一个简单易上手的实例

Ansible Roles本身并没有引入太多新的知识,相当于一套合理的组织我们的playbook的方式,事实上在Ansible Roles没有出现之前,很多人已经开始形成自己的playbook组织方式,后来Ansible推出了Roles功能,这就有了统一的规范

# https://gitee.com/as4k/ysansible/tree/master/lamp_simple_rhel7
➜  ysansible git:(master) tree lamp_simple_rhel7 
lamp_simple_rhel7
├── group_vars
│   ├── all
│   └── dbservers
├── hosts
├── roles
│   ├── common
│   │   ├── handlers
│   │   │   └── main.yml
│   │   ├── tasks
│   │   │   └── main.yml
│   │   └── templates
│   │       └── ntp.conf.j2
│   ├── db
│   │   ├── handlers
│   │   │   └── main.yml
│   │   ├── tasks
│   │   │   └── main.yml
│   │   └── templates
│   │       └── my.cnf.j2
│   └── web
│       ├── tasks
│       │   ├── copy_code.yml
│       │   ├── install_httpd.yml
│       │   └── main.yml
│       └── templates
│           └── index.php.j2
└── site.yml

观察上面的目录结构,我们看到有一个hosts文件,这个是主机清单,为方便测试我们直接放到当前文件夹,使用-i参数即可指定主机清单文件

site.yml这份playbook是入口文件,里面调用了相关角色,执行该playbook的方法是,移动到当前目录,并执行下面的命令

ansible-playbook -i hosts site.yml --limit 192.168.31.101

我们前面讲过的 主机变量和组变量 Host and Group variables ,在这里依然适用

├── group_vars  #该目录名字是固定的,位置和主机清单在同一个目录
│   ├── all     #all表示所有分组(即所有机器)都可使用的变量
│   └── dbservers  #分组是dbservers可以使用的变量

roles里面的目录结构相似,每一个目录名表示一个角色,目录名既可以认为是角色名称,我们举一个例子来说

├── roles #该目录固定
│   ├── common #角色名称,可以任意起
│   │   ├── handlers #该目录固定
│   │   │   └── main.yml #该文件名固定,里面专门存放需要触发执行的操作,在tasks/main.yml可直接使用
│   │   ├── tasks #该目录固定
│   │   │   └── main.yml #该文件名固定,是一个角色的入口,角色其它资源都从这里调用,里面的内容跟普通的playbook一样,不过可以看到已经没有类似匹配主机这样的,已经被抽出去的指令了
│   │   └── templates #该目录固定,里面存放的都是模板原始文件,在tasks/main.yml可直接使用
│   │       └── ntp.conf.j2 #模板文件

有了上面这些文字对目录结构的解释,如果大家也有仔细去看每个文件里的内容,相信上面这套playbook(其中包含角色)的功能已经很清晰了,即安装LHMP(httpd、mysql、php)

上面的角色服务我已在CentOS7执行验证过,大家也可以自己操作去看看 Ansible的角色、主机清单位置都可以在配置文件中配置,这个我们后面说

大家如果成功执行上面的playbook,基本对Ansible角色有个初步的概念了,可以看到角色本身并没有多少内容要学习,要想读懂、用好一套使用角色来书写的playbook服务,更多的还是要熟悉相关的模块、模板等这些playbook本身的内容

Ansible Roles非常重要,一坨playbook堆在一块没有用角色管理、复用起来,那基本没法维护了,也非常不专业

角色目录结构

上面我们列举了一个简单的Ansible实例,可以看到从形式上来说,Ansible Roles就是一套行之有效的目录结构,目录的名称和目录的第一个文件main.yml都是固定的,本质来就是定义了一套通用的规范,来帮助我们更好的复用playbook

那么我们不仅想找到,一共有哪些目录我们可以用?使用下面的命令可以直接生成一份完整的Ansible Roles模板

[root@192_168_31_106 /tmp/xtest]# ansible-galaxy init my_role_name
- Role my_role_name was created successfully
[root@192_168_31_106 /tmp/xtest]# tree my_role_name/
my_role_name/
├── defaults
│   └── main.yml #这里放变量,这里的变量优先级最低
├── files  #放普通文件,如脚本文件等
├── handlers 
│   └── main.yml  #顾名思义,handlers放这里 
├── meta
│   └── main.yml #定义了一些元数据信息,方便在ansible galaxy上分享
├── README.md
├── tasks
│   └── main.yml #入口文件
├── templates    #模板文件
├── tests #顾名思义,测试用
│   ├── inventory 
│   └── test.yml
└── vars
    └── main.yml #这里也是放变量,这里的变量优先级比较高,通常是我们不希望被轻易改动的变量
8 directories, 8 files

上面的目录是最全的,如果说最小的话拥有一个tasks目录即可 ansible galaxy是官方提供的存放roles的仓库,方便大家分享,我们后面还会说到 vars/main.yml 与 defaults/main.yml 都可以存放变量,它们的区别不是强制性的,只是一般惯例

角色搜索路径

  • roles目录里找(相对于当前playbook)
  • /etc/ansible/roles目录里找(可以改动配置文件修改)

继续上实例

https://gitee.com/as4k/ysansible/tree/master/wordpress-nginx-rhel7
https://gitee.com/as4k/ysansible/tree/master/geerlingguy_nginx/roles/nginx
#这两个实例,都是我亲测,可以在CentOS7上执行的

生产环境playbook目录架构

如果我们准备把公司全套的软件部署、更新,全都通过Ansible管理,显然我们需要有一个整体的目录规划,不能随意的写一个playbook,加几个文件直接就跑,这样时间一常基本就无法维护

首先我们得使用代码管理工具,如git,全面对Ansible的playbook等资源文件进行管理,每次先提交git,再执行部署,这样我们后人或者说过一段时间我们自己只要检查类似git log,即可了解自己之前干了啥,改了什么东西,从而方便问题的定位和追踪

对于太大的二进制文件,尽量做成RPM包,或者放到专门的地方管理

关于规划我们Ansible Playbook的目录结构,最根本的问题是解决,资源合理复用的问题,比如在很多企业里,拿到一台新机器,都要进行初始化,都需要配置一些很基础的操作,诸如SSH配置、软件仓库配置、相关用户创建、定时任务时间同步等,这一类操作显然需要抽象出来单独放到一个roles里,以供其它playbook调用

在定义一个角色供后面的playbook复用的时候,我们需要考虑这个角色的功能哪些可以变动,哪些不能变动,用编程语言来说,就是暴露出哪些接口给用户使用,比如我们定义一个角色用来安装docker,为保证统一我们把docker的版本号做成变量,放到vars/main.yml里,含义就是docker版本号,尽量不要改动,而把docker的数据存放目录,也定义为一个变量,放到defaults/main.yml,表示这里的变量可以被覆盖

回顾前面我们讲到的角色目录结构,介绍了每个角色每个目录大致的功能

下面我们看下,整体的一个目录结构参考

#https://gitee.com/as4k/ysansible/tree/master/nginx_core
#这是nginx官方提供的,nginx Ansible 部署
➜  ysansible git:(master) tree  -L 2 nginx_core
nginx_core
├── LICENSE
├── README.md
├── docs
├── playbooks  #这里的playbook,去调用roles目录里的角色
│   ├── deploy-nginx-app-protect.yml 
│   ├── deploy-nginx-plus-app-protect-web-server-proxy.yml
│   ├── deploy-nginx-plus-app-protect.yml
│   ├── deploy-nginx-plus.yml
│   ├── deploy-nginx-web-server-proxy.yml
│   ├── deploy-nginx-web-server.yml
│   └── deploy-nginx.yml
├── plugins
└── roles
    ├── nginx
    ├── nginx_app_protect
    └── nginx_config

我们再来看下,具体一个playbook如何引入变量,去覆盖默认值,已达到更好的复用角色

# cat deploy-nginx-app-protect.yml
---
- hosts: all
  roles:
    - role: nginx_app_protect
      vars:
        nginx_app_protect_license:
          certificate: <path/to/certificate>
          key: <path/to/key>
        nginx_app_protect_remove_license: false
        nginx_app_protect_install_signatures: true
        nginx_app_protect_install_threat_campaigns: true
        nginx_app_protect_configure: true
        nginx_app_protect_security_policy_template_enable: true
        nginx_app_protect_security_policy_enforcement_mode: blocking
        nginx_app_protect_log_policy_template_enable: true
        nginx_app_protect_log_policy_filter_request_type: all
        nginx_app_protect_conf_template_enable: false

再来看一份完整的全目录架构参考

inventories/
   production/
      hosts               # inventory file for production servers
      group_vars/
         group1.yml       # here we assign variables to particular groups
         group2.yml
      host_vars/
         hostname1.yml    # here we assign variables to particular systems
         hostname2.yml

   staging/
      hosts               # inventory file for staging environment
      group_vars/
         group1.yml       # here we assign variables to particular groups
         group2.yml
      host_vars/
         stagehost1.yml   # here we assign variables to particular systems
         stagehost2.yml

library/
module_utils/
filter_plugins/

playbooks/
  site.yml
  webservers.yml
  dbservers.yml

roles/
    common/
    webtier/
    monitoring/
    fooapp/

Ansible Pull 工作模式

Ansible 默认工作模式是Push,即主机通过SSH远程推送相关资源到目标机器,目标机器执行

具体示例参考如下:

*/20 * * * * root /usr/local/bin/ansible-pull -o -C 2.1.0 -d /srv/www/king-gw/ -i /etc/ansible/hosts -U git:// git.kingifa.com/king-gw-ansiblepull >> /var/log/ansible-pull.log 2>&1

ansible-pull通常在配置大批量机器的场景下会使用,灵活性稍有欠缺,但效率几乎可以无限提升,对运维人员的技术水平和前瞻性规划有较高要求

参考资料

https://docs.ansible.com/ansible/latest/user_guide/playbooks_reuse_roles.html
https://docs.ansible.com/ansible/latest/user_guide/playbooks_reuse.html
https://docs.ansible.com/ansible/latest/user_guide/sample_setup.html
https://docs.ansible.com/ansible/latest/cli/ansible-pull.html
https://medium.com/splunkuserdeveloperadministrator/using-ansible-pull-in-ansible-projects-ac04466643e8
https://github.com/vincesesto/ansible-pull-example