ansible

Ansible

内容:

1.软件发布环境机制优势对比

2.Linux上的Ansible应用

Ansible的相关的文档:
非常实用的中文版功能查询手册,Ansible的中文权威指南:ansible中文指南
Github上的ansible-galaxy示例:ansible-galaxy
本文只列出一些常用的功能,更多功能以后遇到再进行更新

其他相关运维管理工具使用方法:
pssh的使用方法参照链接文章:PSSH
saltstack介绍及使用参照链接文章:Saltstack
puppet介绍及使用参照链接文章:puppet

本文主要讲解Ansible在linux服务器上的管理
windows下的ansible使用方法链接:ansible-windows

当下有许多的运维自动化工具( 配置管理 ),例如:Ansible、SaltStack、Puppet、Fabric
常用自动化运维工具
    PSSH:适用于主机数量很少的环境(基础ssh的key验证)
    Ansible:python,Agentless,中小型应用环境(自带代理功能)
    Saltstack:python,一般需部署agent,执行效率更高
    Puppet:ruby, 功能强大,配置复杂,重型,适合大型环境
    Fabric:python,agentless

发布更新环境

灰度发布:又叫金丝雀发布(核心概念:一次只发布一部分主机)

比如:共100台生产服务器,先发布其中的10台服务器,这10台服务器就是灰度服务器
    而软件更新实际上是将旧版本或者新版本创建一个软链接指向软件的工具路径
     如:
     软件路径为:/data/app
     正在用的软件版本V1.0:/data/app1.0
     更新的软件版本V2.0:/data/app2.0
    则需要把删除原来的软链接:/data/app1.0--->/data/app
    创建新的软链接:/data/app2.0--->/data/app
10台机器升级软件版本后,先上线进行,然后再逐渐把剩余的90台主机升级上线
发布步骤:
    1.准备好部署各个阶段的工件,包括:构建工件,测试脚本,配置文件和部署清单文件。
    2.从负载均衡列表中移除掉「金丝雀」服务器。
    3.升级「金丝雀」应用(排掉原有流量并进行部署)。
    4.对应用进行自动化测试。
    5.将「金丝雀」服务器重新添加到负载均衡列表中(连通性和健康检查)。
    6.如果「金丝雀」在线使用测试成功,升级剩余的其他服务器(否则就回滚)。
A/B Testing
    A/B测试是用来测试应用功能表现的方法,例如可用性、受欢迎程度、可见性等等。 A/B 测试通常用在应用的前端上,不过当然需要后端来支持。
优势与不足:
    优势:用户体验影响小,灰度发布过程出现问题只影响少量用户
    不足:发布自动化程度不够,发布期间可引发服务中断
预发布验证:
    新版本的代码先发布到服务器,和线上环境配置相同,只是未接入调度器
灰度发布:
    可以基于主机,用户或者业务,又细分为地区,VIP和普通用户

蓝绿发布:核心:主备两套环境

定义:不停老版本,升级备环境版本然后进行测试。确认OK后将流量切到新版本,然后老版本同     时也升级到新版本
主:绿色环境-活动环境:负责对外提供服务,版本:v1.0
备:绿色环境-非活动环境:版本:v2.0
工作机制:
    先把备环境升级v1.0--->v2.0版本,然后上线
    把主环境的v1.0版本下线,已经升级的备环境进行替换
特点:
    蓝绿部署无需停机,并且风险较小.
注意事项:
    1.需要提前考虑数据库与应用部署同步迁移/回滚的问题
    2.蓝绿部署需要有基础设施支持
    3.在非隔离基础架构( VM 、 Docker 等)上执行蓝绿部署,蓝色环境
      和绿色环境有被摧毁的风险.
优势与不足:
    优势:升级切换和回退速度非常快
    不足:需要有2套基础设施,v2.0版本有问题,则对用户体验有直接影响

滚动发布:在灰度发布的基础上进行进一步优化

定义:
    一般是取出一个或者多个服务器停止服务,执行更新,并重新将其投入使用。周而复始,直到集群中所有的实例都更新成新版本,是自动化程度较高的发布方式.
特点:
    1.这种部署方式相对于蓝绿部署,更加节约资源——它不需要运行两个集群、两倍的实例数.  可以部分部署,例如每次只取出集群的20%进行升级。
    2.滚动式发布需要比较复杂的发布工具和智能LB,支持平滑的版本替换和流量拉入拉出
优势和不足:
    优势:用户体验影响小,体验较平滑
    不足:发布和回退时间比较缓慢。
         发布工具比较复杂,LB需要平滑的流量摘除和拉入能力
滚动发布目前成熟型技术组织所采用的主流发布方式

Ansible

ansible架构.png

ansible特性:-最多管理500台主机,更多效率会降低

1.模块化:调用特定的模块,完成特定任务   -类似linux中的小命令
2.有Paramiko,PyYAML,Jinja2(模板语言)三个关键模块
3.支持自定义模块
4.基于Python语言实现
5.部署简单,基于python和SSH(默认已安装),agentless(没有自己的代理服务)
6.安全,基于OpenSSH
7.支持playbook编排任务   -类似于脚本功能,多个脚本的集合成为Roles
8.幂等性: 一个任务执行1遍和执行n遍效果一样,不因重复执行带来意外情况
9.无需代理不依赖PKI(无需ssl)
10.可使用任何编程语言写模块
11.YAML格式,编排任务,支持丰富的数据结构
12.较强大的多层解决方案

Ansible的主要功能简介:

1.ansible基本命令使用
2.ansible常用模块详解,介绍ansible单个命令的使用
3.YAML语法介绍
4.ansible playbook基础:剧本初体验,类似于写脚本
5.playbook中的变量:tags,handlers使用
6.plsybook模板:templates
7.playbook的条件判断:when
8.playbook的字典:with_items
9.Ansible Roles -多个playbook的组合,类似于多个脚本的集合

如果执行playbook时有错误信息,则会在playbook的同目录下生成一个*.retry的文件记录会记录执行时的错误IP地址,可以查看具体是什么原因产生的错误。

ansible命令执行过程(可以参照下面的playbook的执行流程图)

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退出
执行状态:(颜色定义在/etc/ansible/ansible.cfg中)
    绿色:执行成功并且不需要做改变的操作
    黄色:执行成功并且对目标主机做变更
    红色:执行失败

CMDB作用介绍:

CMDB:Configuration Management Database 配置管理数据库
        将服务器的配置,网络配置写到数据库里
CMDB即配置管理数据库,通过识别、控制、维护,检查企业的IT资源,从而高效控制与管理不
断变化的IT基础架构与IT服务,并为其它流程,例如事故管理、问题管理、变更管理、发布管
理等流程提供准确的配置信息.

了解更多CMDB可参照文章:CMDB

1.ansible基本命令使用

ansible软件安装:多种安装方法

1.基于epel源安装:
    yum install ansible,非服务,只是一个管理工具
2.编译安装:
3.Github方式安装:可以同步安装
4.pip安装:pip是安装Python包的管理器,类似yum

ansible的重要&主要文件

配置文件:
    /etc/ansible/ansible.cfg  配置ansible的工作特性
    /etc/ansible/hosts  主机清单
    /etc/ansible/roles  存放的角色目录
程序文件:
    /usr/bin/ansible   ansible的可执行命令-->2.7的软链接,都是软链接的思想
    /usr/bin/ansible-doc 查看配置文档,模块功能查看工具,man帮助
    /usr/bin/ansible-galaxy 下载/上传优秀代码或Roles模块的官网平台
    /usr/bin/ansible-playbook 管理执行编排的playbook剧本任务
    /usr/bin/ansible-vault 文件加密工具
    /usr/bin/ansible-console 基于Console界面与用户交互的执行工具

ansible主机清单配置:/etc/ansible/hosts,第一步(下文中介绍主机清单的多种表示方法)

支持不分组,分组,等方式
    如:
        192.168.34.100
        [webservers]
        192.168.34.101
        192.168.34.102
        [dbservers]
        192.168.34.[1:6]7 (17,27..67)
        db[01:100].cenntos.com

ansible配置文件:/etc/ansible/ansible.cfg (一般保持默认)

配置文件只提供默认值,但可以通过playbook的设置进行覆盖
配置文件可以放在/etc/ansible/ansible.cfg中
也可以放到一个工作目录下命名为.ansible.cfg

[defaults]
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命令是否询问ssh密码
ask_pass = True
remote_port = 22
host_key_checking = False  -检查对应服务器的host_key,建议取消注释
log_path=/var/log/ansible.log -建议启用日志文件,利于排错
[color] 定义ansible命令的执行结果颜色的

配置文件说明和建议修改的项:

local_tmp和remote_tmp:
    本地临时文件和远程临时文件:把playbook转化成python程序,先放在本地
    家目录的.ansible/tmp下,然后再通过ssh协议复制到远程主机的.ansible/tmp下,执行完毕后自动删除.
host_key_checking = False -检查对应服务器的host_key,建议取消注释
log_path=/var/log/ansible.log -建议启用日志文件,利于排错
module_name = command   -默认使用的命令模块,可以修改成shell
    建议修改为:module_name = shell

2.ansible常用模块详解,介绍ansible单个命令的使用

ansible模块的使用查询方法

ansible-doc: 显示模块帮助
ansible-doc [options] [module...]
    -a 显示所有模块的文档
    -l, --list 列出可用模块
    -s, --snippet显示指定模块的playbook片段
示例:
    ansible-doc –l 列出所有功能模块
    ansible-doc ping 查看ansible中的ping用法
    ansible-doc -s shell 查看shell模块的使用方法

ansible的常用基本选项

ansible通过ssh实现配置管理、应用部署、任务执行等功能,建议配置ansible
    端能基于密钥认证的方式联系各被管理节点
ansible语法:
    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.All :表示所有Inventory中的所有主机
    如:ansible all -m ping
        ansible all --list-hosts列出所有主机清单
        ansible "dbservers" --list-hosts列出db组中的所有主机IP
2.* :通配符
    如:ansible "*" = ansible all
        ansible 192.168.34.* 表示34网段的所有IP
3.或的关系
    如:ansible "websrvs:appsrvs" 对两个组的主机执行操作
        ansible "192.168.1.10:192.168.1.20"对两个主机执行操作
4.与的关系(且)
    如:ansible "websrvs:&dbsrvs"既在websrvs组并且在dbsrvs组中的主机
5.非,取反
    如:ansible 'websrvs:!dbsrvs'
        在websrvs组,但不在dbsrvs组中的主机;注意:此处为单引号
6.正则表达式
    如:ansible "~(web|db).*\.centos\.com" 

ansible的常见模块(第二步:具有很多模块,先列出比较常见且重要的,遇到再更新新的模块)

ansible-doc +模块名 可以查看具体使用方法:显示都有哪些选项
1.Command:在远程主机执行命令,默认模块,可忽略-m选项
    可以在ansible.cfg中修改默认模块项
    支持:chdir(切换目录)
    command模块不支持 $ < > | ; & 等,可以用shell模块实现
使用示例:
    ansible all -a 'rm -f /data/f1' 删除远程所有主机下f1文件,类似pssh
    ansible all -a 'useradd test' 所有主机上创建test用户

2.Shell:和command相似,用shell执行命令,执行时要加-m shell选项
    支持功能:支持$ < > | ; & 等
            chdir 执行前,先切换到该文件夹
示例:ansible appsrvs -m shell -a 'echo $HOSTNAME'
        显示appsrvs组的主机名
    ansible all -m shell -a 'chdir=/data rm -rf *'
    先切换到/data目录下,再执行删除命令

3.Script: 批量运行脚本
    可以现在管理机上先把复杂命令写成脚本,再通过script去批量管理
    功能:creates:远程主机的文件存在,则不运行
        removes:远程主机的文件不存在,则也不运行==即文件存在,则执行命令
示例:ansible all -m script -a "/data/test.sh"
    ansible all -a "creats=/etc/fstab rm -rf /data/*命令"
        因为fstab文件存在,则不执行rm -rf /data/*命令
    ansible all -a "removes=/etc/fstab rm -rf /data/*"
        因为fstab文件存在,则执行rm -rf /data/*命令

4.Copy:从服务器复制文件到目标主机
    src,dest,mode,owner,content,backup,mode 
示例:1.nsible all -m copy -a 'src=/etc/fstab dest=/data/fstab2 backup=yes owner=test' 将fstab拷贝到主机被改名为fstab2,如果存在先备份,所有者改为test用户
2.ansible all -m copy -a 'content="selinux1\nselinux2" dest=/data/selinux1'
    根据自己写的字符串生成文件

5.Fetch:从目标主机抓取文件至服务器端,copy相反,目录可先tar再抓取
    src,dest(抓取到本机目录)
示例:ansible all -m fetch -a 'src=/data/fstab2 dest=/data/'
        将远程主机fstab2文件抓取到本机/data下
    如果抓取的是目录,先打包再抓取
    打包:ansible all -a 'tar cf /root/data.tar /data' 
    抓取:ansible all -m fetch -a 'src=/data/fstab2 dest=/data/'

6.File:设置文件属性,创建/删除文件
    src(创建链接文件),path=dest,state:(touch,absent,link,direcotory) 
示例:创建文件:ansible all -m file -a 'dest=/data/f10 state=touch'
     创建文件夹:ansible all -m file -a 'dest=/data/haha state=directory'
     删除文件夹/目录:ansible all -m file -a 'dest=/data/haha state=absent'

7.Hostname:管理主机名
     可以通过后面的变量来实现
    a.先在hosts后定义hostname变量名
        [centos6]
        192.168.34.106 hostname=mini6-2
        192.168.34.101 hostname=node6-1 
        [centos7]
        192.168.34.107 hostname=mini7-1
    b.再通过hostname模块批量修改
        ansible all -m hostname -a 'name={{hostname}}'

8.Cron:计划任务
    支持:minute,hour,day,month,weekday
示例:ansible all -m cron -a 'minute=*/5 job="/usr/sbin/ntpdate
        172.18.0.1 &>/dev/null" name=Synctime' 创建计划任务
     ansible srv -m cron -a 'name=Synctime state=absent' 删除指定的计划任务名
     ansible srv -m cron -a 'name=Synctime disable=true' 禁用指定的计划任务名

9.Yum:管理包
    支持:name,state=(started stopped reloaded restarted),absent
    更新缓存:update_cache=yes,
示例:ansible all -m yum -a 'name=httpd,samba,vsftpd'安装多个包
      ansible all -m yum -a 'name=httpd,samba,vsftpd state=absent'删除包

10.Service:管理服务(同一systemctl&service)
    name,state(stopped,started,reloaded,restarted) enable(设置开启启动)
示例:ansible srv -m service -a 'name=httpd state=stopped' 停止服务
     ansible srv –m service –a 'name=httpd state=reloaded' 重新加载服务
     ansible srv -m service -a 'name=httpd state=restarted' 重启服务
     ansible srv -m service -a 'name=httpd enable=yes' 设置开机启动

11.User:管理用户
    name,comment(描述),group(主组),groups(附加组),uid,home,shell,system(系统用户) (absent,remove删除用户及家目录)
示例:ansible all -m user -a 'name=user1 uid=234 home=/data/user1 system=yes group=root groups=bin shell=/sbin/nologin comment'
    创建用户,指定uid,家目录,主组,附加组,shell类型,指定为系统用户
ansible all -m user -a 'name=user1 state=absent remove=yes'删除用户及家目录

12.Group:管理组
    支持:group,name,gid,system,state=(absent)
示例:ansible srv -m group -a 'name=testgroup system=yes' 创建系统组
    ansible srv -m group -a 'name=testgroup state=absent' 删除组 

ansible系列的一些模块(用的不多)

简单介绍与了解:
ansible-galaxy 互联网上的角色分享
ansible-pull  
    推送命令至远程,效率无限提升,对运维要求较高  
Ansible-vault管理yaml文件
    功能:管理加密解密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 new.yml 创建新文件
Ansible-console

ansible重要知识之playbook(上面的各种模块的组合)

playbook执行原理.png

YAML语言(编写playbook的专门语言)

YAML语法:
     在单一档案中,可用连续三个连字号(——)区分多个档案。另外,还有选择性的连续三
    个点号( ... )用来表示档案结尾
    次行开始正常写Playbook的内容,一般建议写明该Playbook的功能
    使用#号注释代码
    缩进必须是统一的,不能空格和tab混用
    缩进的级别也必须是一致的,同样的缩进代表同样的级别,程序判别配置的级别是通过
    缩进结合换行来实现的
    YAML文件内容是区别大小写的,k/v的值均需大小写敏感
    k/v的值可同行写也可换行写。同行使用:分隔
    v可是个字符串,也可是另一个列表
    一个完整的代码块功能需最少元素需包括 name: task
    一个name只能包括一个task
    YAML文件扩展名通常为yml或yaml
    List:列表,其所有元素均使用“-”打头
    Dictionary:字典,通常由多个key与value构成

Playbook中的核心元素:

    1.Hosts 执行的远程主机列表
    2.remote_user: 可用于Host和task中。也可以通过指定其通过sudo的方式在远
        程主机上执行任务,其可用于play全局或某任务;此外,甚至可以在sudo时使
        用sudo_user指定sudo时切换的用户
    3.Tasks 任务集
    4.Varniables 内置变量或自定义变量在playbook中调用
    5.Templates 模板,可替换模板文件中的变量并实现一些简单逻辑的文件
    6.Handlers 和notity结合使用,由特定条件触发的操作,满足条件方才执行,否
    则不执行
    7.tags 标签 指定某条任务执行,用于选择运行playbook中的部分代码。ansible
    具有幂等性,因此会自动跳过没有变化的部分,即便如此,有些代码为测试其
    确实没有发生变化的时间依然会非常地长。此时,如果确信其没有变化,就可
    以通过tags跳过此些代码片断
    8.handlers和notify  

运行playbook

运行playbook的方式
ansible-playbook <filename.yml> ... [options]
常见选项
    -C|--check 只检测可能会发生的改变,但不真正执行操作,建议执行前先检测
    --list-hosts 列出运行任务的主机
    --limit 主机列表 只针对主机列表中的主机执行
    -v 显示过程 -vv -vvv 更详细
 备注:
    执行前建议 ansible-plsybook -C install_httpd.yml检查语法错误
    ansible-playbook install_httpd.yml --list-hosts可以查看对哪些主机执行

执行playbook时,更改正确的是绿色的,更改的显示黄色的,错误信息显示红色,可以根据颜色变化判断是否更改,或者是否更改成功了。

示例:以下实验均在centos7管理centos7集群,因为6&7配置文件不同,均在7上实验

将centos7的httpd.conf复制到centos7主机,6上的配置文件不同

示例1:写一个安装启动httpd的playbook:install_httpd.yml
        包括创建用户,安装httpd包,开启服务,并设置开机启动
- hosts: all
  remote_user: root
  tasks:
    - name: creat user
      user: name=httpd shell=/sbin/nologin uid=1234 home=/data/httpd
    - name: copy config
      copy: src=/data/httpd.conf dest=/etc/httpd/conf/httpd.conf
    - name: install package
      yum: name=httpd
    - name: service
      service: name=httpd state=started enabled=yes
备注:
    执行完通过以下命令判断每个任务都否都执行成功了
    1.ansible all -a 'getent passwd httpd'
    2.ansible all -a 'rpm -q httpd'
    3..ansible all -a 'ss -ntlp|grep 80'

示例2:写一个删除上面的playbook:remove_httpd.yml
        包括:删除用户,卸载httpd包
- hosts: all
  remote_user: root
  tasks:
    - name: del user
      user: name=httpd state=absent remove=yes
    - name: remove package
      yum: name=httpd state=absent
备注:
    如果只删除特定主机的httpd,而不是全部,需要加--limit选项
    ansible-playbook --limit 192.168.34.105 remove_httpd.yml
        只限制在192.168.34.105的主机执行

上面的playbook只是实现了简单的安装配置功能,但是不能根据在更改配置文件后,再次执行,因为服务设置是start,不合理,所以要用到下面触发条件,来达到更改控制的目的。

handlers和notify结合使用触发条件:当达到某个条件时,触发执行对应的task任务。

Handlers:
    是task列表,这些task与前述的task并没有本质上的不同,用于当关注的资源发生
        变化时,才会采取一定的操作
Notify:
    此action可用于在每个play的最后被触发,这样可避免多次有改变发生
    时每次都执行指定的操作,仅在所有的变化发生完成后一次性地执行指定操作。
    在notify中列出的操作称为handler,也即notify中调用handler中定义的操作

示例:

示例3:将memcached的配置文件的端口更改后再复制到各主机上,服务需要重启,则用到了handlers和notify功能 (端口11211改成11200)
- hosts: all
  remote_user: root
  tasks:
    - name: creat user
      user: name=memcached shell=/sbin/nologin uid=2345
    - name: install package
      yum: name=memcached
    - name: copy config
      copy: src=/data/memcached dest=/etc/sysconfig/memcached
      notify: restart service   和handlers名称一致
    - name: service
      service: name=memcached state=started enabled=yes
  handlers:
    - name: restart service  和notify名称一致
      service: name=memcached state=restarted 
备注:停止并删除用户和安装包
    ansible all -a 'service memcached stop'
    ansible all -a 'ss -ntl'
    ansible all -a 'rpm -q memcached'
    ansible all -a 'getent passwd memcached'

可以多个notify对应一个handlers,也可以多个motify对应多个handlers

示例4:多个notify对应一个handlers
- hosts: websrvs
  remote_user: root
  tasks:
    - name: Install httpd
      yum: name=httpd state=present
    - name: Install configure file
      copy: src=files/httpd.conf dest=/etc/httpd/conf/
      notify: restart httpd  第一个notify
    - name: ensure apache is running
      service: name=httpd state=started enabled=yes
      notify: restart httpd  第二个notify
  handlers:  
    - name: restart httpd   对应一个handlers
      service: name=httpd status=restarted

示例5:多个notify对应多个handlers

  - hosts: websrvs
    remote_user: root
    tasks:
      - name: config
        copy: src=/root/config.txt dest=/etc/nginx/nginx.conf
        notify:
          - Restart Nginx
          - Check Nginx Process  多个notify的写法
     
    handlers:
      - name: Restart Nginx     对应写多个handlers
        service: name=nginx state=restarted enabled=yes
      - name: Check Nginx process
        shell: killall -0 nginx > /tmp/nginx.log

tags的用法:作用:挑选某一段的task来执行

将安装memcached的yml,在拷贝的动作后加一个标签,执行时指定标签运行
然后执行:ansible-plsybook -t ceshi install_memcached.yml
        只会触发拷贝文件和handlers的动作
---
#test yaml file
- hosts: all
  remote_user: root
  tasks:
    - name: creat user
      user: name=memcached shell=/sbin/nologin uid=2345
    - name: install package
      yum: name=memcached
    - name: copy config
      copy: src=/data/memcached dest=/etc/sysconfig/memcached
      notify: restart service   和handlers名称一致
      tags: ceshi   对拷贝动作加一个标签
    - name: service
      service: name=memcached state=started enabled=yes
  handlers:
    - name: restart service  和notify名称一致
      service: name=memcached state=restarted

Playbook中变量使用:可以多出定义,但是存在优先级

优先级的顺序为:-e var > yaml中的var > hosts中的普通变量 > hosts公共变量

变量名:仅能由字母、数字和下划线组成,且只能以字母开头
变量来源:
1 ansible setup facts 远程主机的所有变量都可直接调用
    setup是一个模块,收集所有主机的各种信息,如果要用变量,需要先在里面找出对应的
        代码块,然后用代码块当变量
    比如:ansible all -m setup | grep "version" 过滤和版本有关的
          ansible all -m setup | grep "name" 过滤和主机名有关的
2 在/etc/ansible/hosts中定义
 普通变量:主机组中主机单独定义,优先级高于公共变量
 公共(组)变量:针对主机组中所有主机定义统一变量
3 通过命令行指定变量,优先级最高
    可以对单个变量赋值:ansible-playbook –e varname=value 
    也可以对多个变量赋值:ansible-playbook –e "var1=1 var2=2"
4 在playbook中定义
    vars:
         - var1: value1
         - var2: value2
5 在独立的变量YAML文件中定义,即roles下的var目录下的var.yml文件
            很适合在roles中进行单独定义
6 在role中定义(下文中有介绍)

从setup模块中查找到的有用的变量;可以通过判断变量的值,然后执行不同的操作,类似于shell中,先判断version==7?然后再执行不同的命令

先列出setup中几个有用的变量,然后在plsybook中执行不同操作
    ansible_fqdn 主机名的变量
    ansible_hostname 主机名
    ansible_distribution_major_version: "6" 版本名变量
    ansible_processor_vcpus 虚拟cpu个数变量
    ansible_memtotal_mb 内存的变量
示例:   
ansible all -m setup -a "filter=ansible_memtotal_mb" 
    用此命令来查看系统内变量的值

调用不同变量来源的示例:得出变量的优先级顺序

示例1:调用setup中的ansible_hostname主机名变量,来生成对应文件 var.yml
- hosts: all
  remote_user: root
  tasks:
    - name: touch file
      file: name=/data/{{ ansible_hostname }}.log state=touch 

示例2:将变量定义在/etc/ansible/hosts中(濮普通变量和公共变量),然后调用变量
    /etc/ansible/hosts:中定义的变量:
        [websrvs]
        192.168.34.105 port1=80
        192.168.34.106 port1=90   -普通变量
        [websrvs:vars]   -公共组变量
        mark="-"
        [appsrvs]
        192.168.34.101 port1=100
        [appsrvs:vars]
        mark="="
    vars.yml中书写格式:
        - hosts: all
          remote_user: root
          tasks:
            - name: touch file
              file: name=/data/app{{mark}}{{ port1 }}.log state=touch
最后生成的文件为:
            app=100.log,app-80.logapp-90.log

示例3:在示例1的基础上,再通过命令行中定义变量:
    在外部定义ansible_hostname="hahaha",对比示例1的执行结果:
    ansible-playbook -e ansible_hostname="hahaha" vars.yml
    可以看出,最后新建的文件名为hahaha.log

示例4:在playbook中定义变量
    - hosts: all
      remote_user: root
      vars:
        - port1: 200
        - mark: +++
      tasks:
        - name: touch file
          file: name=/data/app{{mark}}{{ port1 }}.log state=touch
    生成的文件:
        app+++200.log

示例5:先写在var.yml中定义变量,
    1.先准备cat vars.yml:文件内容格式
        var1: httpd
        var2: nginx
    2.在cat var.yml,中调用准备好的vars.yml文件这种方式适用于在roles中单独定义
        - hosts: web
          remote_user: root
          vars_files:
            - vars.yml
         tasks:
           - name: create httpd log
             file: name=/app/{{ var1 }}.log state=touch
           - name: create nginx log
             file: name=/app/{{ var2 }}.log state=touch

模板templates,作用:

文本文件,嵌套有脚本(使用模板编程语言编写)
Jinja2语言,使用字面量,有下面形式
字符串:使用单引号或双引号
数字:整数,浮点数
列表:[item1, item2, ...]
元组:(item1, item2, ...)
字典:{key1:value1, key2:value2, ...}
布尔型:true/false
算术运算:+, -, *, /, //, %, **
比较操作:==, !=, >, >=, <, <=
逻辑运算:and, or, not
流表达式:For If When

templates功能:根据模块文件动态生成对应的配置文件

templates文件必须存放于templates目录下,且命名为 .j2 结尾,而*.yml是和templates同一层目录。

 yaml/yml 文件需和templates目录平级,目录结构如下:
 ./
 ├── temnginx.yml
 └── templates
    └── nginx.conf.j2

示例1:通过templates模板配置文件nginx,安装nginx

1.先生成nginx.conf.j2模板
cp /etc/nginx/nginx.conf templates/nginx.conf.j2
2.创建playbook
- hosts: all
  remote_user: root
  tasks:
    - name: inastll nginx
      yum: name=nginx
    - name: template
      template: src=nginx.conf.j2 dest=/etc/nginx/nginx.conf                                 
      notify: service
    - name: start service
      service: name=nginx state=started
  handlers:
    - name: service
      service: name=nginx state=restarted

when配合templates实现根据不同版本执行不同的功能

条件测试:
    如果需要根据变量、facts或此前任务的执行结果来做为某task执行与
    否的前提时要用到条件测试,通过when语句实现,在task中使用,jinja2的语法
    格式
when语句
    在task后添加when子句即可使用条件测试;when语句支持Jinja2表达式语法
示例:
tasks:
     - name: "shutdown RedHat flavored systems"
     command: /sbin/shutdown -h now
     when: ansible_os_family == "RedHat" 非赋值,而是比较是否为某个值

示例2:通过templates模板根据不同的centos版本,安装不同的httpd,就用到了when功能

步骤:涉及到多个notify对应一个handlers,定义端口变量
1.hosts文件配置:修改了4台主机httpd的端口
    [centos6]
    192.168.34.105 http_port=86
    192.168.34.106 http_port=87
    192.168.34.101 http_port=88
    [centos7]
    192.168.34.107 http_port=89 
2.将centos6&centos7的httpd配置文件复制到templates/并改名为*.j2文件
    httpd_6.conf.j2  
    httpd_7.conf.j2
3.将端口都自定义:修改httpd_6.conf.j2和httpd_7.conf.j2的
    Listen {{http_port}} 调用hosts列表中的端口变量
4.plsybook如下:
---
- hosts: all
  remote_user: root
  tasks:
    - name: install httpd
      yum: name=httpd
    - name: templates 6
      template: src=httpd_6.conf.j2 dest=/etc/httpd/conf/httpd.conf
      notify: restart service
      when: ansible_distribution_major_version == "6"
    - name: templates 7
      template: src=httpd_7.conf.j2 dest=/etc/httpd/conf/httpd.conf                          
      when: ansible_distribution_major_version == "7"
      notify: restart service
    - name: service
      service: name=httpd state=started
  handlers:
    - name: restart service
      service: name=httpd state=restarted

迭代:with_items,类似于shell中的for循环

迭代:当有需要重复性执行的任务时,可以使用迭代机制
对迭代项的引用,固定变量名为”item“
要在task中使用with_items给定要迭代的元素列表
列表格式:
    字符串
    字典   字典构成一个键值对{key:vavul},如示例3

迭代的示例:

示例1:比如创建user1.user2.user3个用户
    - hosts: all
      remote_user: root
      tasks:
        - name: touch users
          user: name={{item}}
          with_items:
            - haha1
            - haha2
            - haha3
示例2:拷贝3个文件,file1 file2 file3
    - hosts: all 
    remote_user: root
    tasks:
      - name: copy files
        copy: src=/data/playbook/{{item}} dest=/data/
        with_items:
          - file1
          - file2
          - file3

迭代嵌套子变量:涉及到多个键值对的表达方式

示例3:创建3个组,再创建3个用户,指定加入一一对应的组
    - hosts: all
      remote_user: root
      tasks:
        - name: creat groups
          group: name={{item}}
          with_items:
            - group1
            - group2
            - group3
        - name: creat users
          user: name={{item.name}} group={{item.group}}
          with_items:
            - { name: 'haha1', group: 'group1' }
            - { name: 'haha2', group: 'group2' }
            - { name: 'haha3', group: 'group3' }
备注:注意创建用户时,键值对的表达和使用方法
    上面的执行结果是:先用单个迭代创建多个组,再通过多个键值对创建用户和组的一一对应关系:即:haha1属于group1;haha2属于group2;haha3属于group3;

Playbook中template结合for循环生成具有重复性的代码段

语法:
for的写法:
    {% for vhost in nginx_vhosts %}
    server {
    listen {{ vhost.listen | default('80 default_server') }}

Playbook中template结合for循环生成具有重复性的代码段

if的写法和表达的意思:如果键值对中的vhost.server_name被定义了,则使用
                    如果没定义,则不执行接下来的代码:示例2
    {% if vhost.server_name is defined %}
            server_name {{ vhost.server_name }};
    {% endif %}
    {% if vhost.root is defined %}
            root {{ vhost.root }};
    {% endif %}

for和if的示例,帮助理解其要执行语句的含义

示例2:生成listen加不同端口的和fqdn文件,由多个键值对组成
先创建for.j2文件:
            {% for i in ports %}
            server{
                    listen {{i.listen}}
                    name {{i.name}}
                    root {{i.root}}
            }
            {% endfor %}
        创建playbook:再其中调用for.j2文件
            - hosts: all
              remote_user: root
              vars:
                ports:
                  - web1:
                    listen: 81
                    name: www.baidu.com
                    root: /data/web1
                  - web2:
                    listen: 82
                    name: www.baidu1.com
                    root: /data/web2
              tasks:
                - name: test for
                  template: src=for.j2 dest=/data/for1.conf
    效果为:
        server{
            listen 81
            name www.baidu.com
            root /data/web1
        }
        server{
            listen 82
            name www.baidu1.com
            root /data/web2
        }

示例2:template配合if的涵义:
    在示例1中的playbook中,把name注释掉,即不定义name的值
            - web1:
                    listen: 81
                   # name: www.baidu.com
                    root: /data/web1
    然后playbook:再调用for.j2文件
        {% for i in ports %}
        server{
                listen {{i.listen}}
        {% if i.name is defined%} 表示:如果i.name的值定义了,就用,没定义不用
                name {{i.name}}
        {% endif %}
                root {{i.root}}
        }
        {% endfor %}
    结果:则web1没有name的值,即可以理解if的用法
        server{
            listen 81
            root /data/web1  少了web1的name的值
        }
        server{
            listen 82
            name www.baidu1.com
            root /data/web2
        }

Roles:什么是roles,为什么要用roles?什么场景适合于roles?roles的结构?

ansible重要内容之Roles;playbook的集合和拆分

 ansilbe自1.2版本引入的新特性,用于层次性、结构化地组织playbook。roles
    能够根据层次型结构自动装载变量文件、tasks以及handlers等。要使用roles只需
    要在playbook中使用include指令即可。简单来讲,roles就是通过分别将变量、
    文件、任务、模板及处理器放置于单独的目录中,并可以便捷地include它们的一
    种机制。角色一般用于基于主机构建服务的场景中,但也可以是用于构建守护进程
    等场景中
复杂场景:建议使用roles,代码复用度高
变更指定主机或主机组
如命名不规范维护和传承成本大
某些功能需多个Playbook,通过Includes即可实现

roles的意义和适用场景:

角色(roles):角色集合
    适用场景:如系统内有多台数据库服务器,httpd服务器,nginx服务器,可以事先把
    同一类的服务器所需的软件,数据库等写成各自的角色roles,然后就可以批量部署了,
    当需要临时增加扩容一台服务器时,就可以使用事先编排好的role来对一台或多台服务器进行部署,从而提高了安装部署的效率。
        如系统内会存在如下的各类服务,可以先编排好角色
        roles/
        ├── httpd/
        ├── memcached/
        ├── mysql/
        └── nginx/

roles的目录结构(一般分成以下目录进行存放一类的文件)

Roles各目录作用:
/roles/project/ :项目名称,有以下子目录
    如创建http,memcached,nginx等目录
files/ :存放由copy或script模块等调用的文件
    保存需要拷贝的配置文件
templates/:template模块查找所需要模板文件的目录
    保存通过template的jinja2模板调用的配置文件
tasks/:定义task,role的基本元素,至少应该包含一个名为main.yml的文件;
        其它的文件需要在此文件中通过include进行包含
handlers/:至少应该包含一个名为main.yml的文件;其它的文件需要在此
           文件中通过include进行包含
vars/:定义变量,至少应该包含一个名为main.yml的文件;其它的文件需要
       在此文件中通过include进行包含,可以单独定义变量的目录
meta/:定义当前角色的特殊设定及其依赖关系,至少应该包含一个名为

main.yml的文件,其它文件需在此文件中通过include进行包含
            tasks目录下,组合任务顺序的文件
default/:设定默认变量时使用此目录中的main.yml文件

roles playbook的tags的标签的作用:通过标签可以更灵活的调用playbook的角色.

- hosts: all
  remote_user: root
  roles:
    - {role: httpd,tags: ['httpd','web']}   
    - {role: memcached,tags: ['memcached','web']}
    - {role: nginx,tags: ['nginx','web1']}

playbook调用角色:介绍前文提到的变量来源第六条:来自于roles的变量

方法一:把需要调用的角色写在一个playbook里
    - hosts: all
      remote_user: root
      roles:
        - role: httpd
        - role: memcached
        - role: nginx
    弊端:如果要执行次playbook,三个角色都会执行一遍,不灵活

方法二;可以把变量在角色中定义
    传递变量给角色
    - hosts:
      remote_user:
      roles:
        - mysql
        - { role: nginx, username: nginx }
          键role用于指定角色名称
          后续的k/v用于传递变量给角色
          调用角色方法3:还可基于条件测试实现角色调用

方法三:还可基于条件测试实现角色调用
    roles:
      - { role: nginx, username: nginx, when: ansible_distribution_major_version == ‘7’ }

roles示例:

以httpd&nginxmemcached三个role为例,下面为整个roles的目录结构和调用角色的playbook:role_playbook.yml
roles的目录结构下的httpd&nginx&memcached
    roles
    ├── httpd
    │   ├── files
    │   │   ├── index_6.html
    │   │   └── index_7.html
    │   ├── handlers
    │   │   └── main.yml
    │   ├── tasks
    │   │   ├── copyhtml_6.yml
    │   │   ├── copyhtml_7.yml
    │   │   ├── group.yml
    │   │   ├── main.yml
    │   │   ├── package.yml
    │   │   ├── service.yml
    │   │   ├── tempconfig_6.yml
    │   │   ├── tempconfig_7.yml
    │   │   └── user.yml
    │   ├── templates
    │   │   ├── httpd_6.conf.j2
    │   │   └── httpd_7.conf.j2
    │   └── vars
    ├── memcached
    │   ├── files
    │   ├── handlers
    │   │   └── main.yml
    │   ├── tasks
    │   │   ├── group.yml
    │   │   ├── main.yml
    │   │   ├── package.yml
    │   │   ├── service.yml
    │   │   ├── tempconfig.yml
    │   │   └── user.yml
    │   ├── templates
    │   │   └── memcached.j2
    │   └── vars
    └── nginx
        ├── files
        │   ├── index_6.html
        │   └── index_7.html
        ├── handlers
        │   └── main.yml
        ├── tasks
        │   ├── copyhtml_6.yml
        │   ├── copyhtml_7.yml
        │   ├── group.yml
        │   ├── main.yml
        │   ├── package.yml
        │   ├── service.yml
        │   ├── tempconfig.yml
        │   └── user.yml
        ├── templates
        │   └── nginx.conf.j2
        └── vars
           └── main.yml

调用角色的playbook: roles.yml

可以通过加变量和标签和条件测试调用更灵活的调用各种角色)
    vim /data/roles.yml    
        - hosts: all  
          remote_user: root
          roles:
        - {role: httpd,tags: ['httpd','web'],when: ansible_distribution_major_version == "6“}
        - {role: memcached,tags: ['memcached','web']}
        - {role: nginx,tags: ['nginx','web1']}
比如:
     1.ansible-playbook -C -t httpd roles.yml 选择测试安装httpd,检查语法
     2.ansible-playbook -t httpd roles.yml 只选择安装httpd
     3.ansible-playbook -t nginx roles.yml 只选择安装nginx
     4.ansible-playbook -t web roles.yml 安装httpd和memcached
     5.ansible-playbook -t web1 roles.yml 只选择安装nginx

下图为每个role的各个文件内容:

图一:参照roles的httpd的目录各个文件内容
roles_http.png
图二:参照roles的nginx的目录各个文件内容
涉及到跨角色调用配置文件,避免产生多余的垃圾文件:截图上也有
    跨角色调用配置文件写法:   
- name: copy index6
  copy: src=roles/httpd/files/index_6.html dest=/usr/share/nginx/html/index.html
roles_nginx.png
图三:参照roles的memcached的目录各个文件内容
roles_memcached.png
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
禁止转载,如需转载请通过简信或评论联系作者。
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,362评论 5 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,330评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,247评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,560评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,580评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,569评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,929评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,587评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,840评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,596评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,678评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,366评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,945评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,929评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,165评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,271评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,403评论 2 342