自动化运维工具—ansible详解

1、ansible 是什么?

  ansible是目前最受运维欢迎的自动化运维工具,基于Python开发,集合了众多运维工具(SaltStack puppet、chef、func、fabric)的优点,实现了批量系统配置、批量程序部署、批量运行命令等功能。   ansible是基于 paramiko 开发的,并且基于模块化工作,本身没有批量部署的能力。真正具有批量部署的是ansible所运行的模块,ansible只是提供一种框架。ansible不需要在远程主机上安装client/agents,因为它们是基于ssh来和远程主机通讯的。ansible目前已经已经被红帽官方收购,是自动化运维工具中大家认可度最高的,并且上手容易,学习简单。是每位运维工程师必须掌握的技能之一。

2、ansible 特点

部署简单,只需在主控端部署Ansible环境,被控端无需做任何操作;
默认使用SSH协议对设备进行管理;
有大量常规运维操作模块,可实现日常绝大部分操作;
配置简单、功能强大、扩展性强;
支持API及自定义模块,可通过Python轻松扩展;
通过Playbooks来定制强大的配置、状态管理;
轻量级,无需在客户端安装agent,更新时,只需在操作机上进行一次更新即可;
提供一个功能强大、操作性强的Web管理界面和REST API接口——AWX平台。

3、ansible 架构图

上图中我们看到的主要模块如下:
Ansible:Ansible核心程序。
HostInventory:记录由Ansible管理的主机信息,包括端口、密码、ip等。
Playbooks:“剧本”YAML格式文件,多个任务定义在一个文件中,定义主机需要调用哪些模块来完成的功能。
CoreModules:核心模块,主要操作是通过调用核心模块来完成管理任务。
CustomModules:自定义模块,完成核心模块无法完成的功能,支持多种语言。
ConnectionPlugins:连接插件,Ansible和Host通信使用


1、ansible 任务执行模式

  Ansible 系统由控制主机对被管节点的操作方式可分为两类,即ad-hoc和playbook:
    ad-hoc模式(点对点模式)使用单个模块,支持批量执行单条命令。ad-hoc 命令是一种可以快速输入的命令,而且不需要保存起来的命令。就相当于bash中的一句话shell。
    playbook模式(剧本模式)是Ansible主要管理方式,也是Ansible功能强大的关键所在。playbook通过多个task集合完成一类功能,如Web服务的安装部署、数据库服务器的批量备份等。可以简单地把playbook理解为通过组合多条ad-hoc操作的配置文件。

2、ansible 执行流程

简单理解就是Ansible在运行时, 首先读取ansible.cfg中的配置, 根据规则获取Inventory中的管理主机列表, 并行的在这些主机中执行配置的任务, 最后等待执行返回的结果。

3、ansible 命令执行过程

加载自己的配置文件,默认/etc/ansible/ansible.cfg;
查找对应的主机配置文件,找到要执行的主机或者组;
加载自己对应的模块文件,如 command;
通过ansible将模块或命令生成对应的临时py文件(python脚本), 并将该文件传输至远程服务器;
对应执行用户的家目录的.ansible/tmp/XXX/XXX.PY文件;
给文件 +x 执行权限;
执行并返回结果;
删除临时py文件,sleep 0退出;


1、 准备环境----关闭防护墙和selinux
环境:主机:4台  一个控制节点 3个被控制节点
解析:本地互相解析(所有机器)
# vim /etc/hosts
192.168.1.10 ansible-web1
192.168.1.11 ansible-web2
192.168.1.12 ansible-web3
192.168.1.9  ansible-server  (控制节点服务器端)
配置ssh公钥认证:控制节点需要发送ssh公钥给所有非被控制节点
[root@ansible-server ~]# ssh-keygen
[root@ansible-server ~]# ssh-copy-id -i 192.168.1.10  #所有机器
所有机器:
systemctl stop firewalld && setenforce 0

2.安装:控制节点
1. 配置EPEL网络yum源
[root@ansible-server ~]# yum install -y epel-release
2. 安装ansible
[root@ansible-server ~]# yum install -y ansible
3.查看版本
[root@ansiable-server ~]# ansible --version
4.看帮助
[root@ansible-server ~]# ansible --help


3、ansible基础----inventory主机清单
官方文档:  http://docs.ansible.com/ansible/intro_inventory.html#>
inventory文件通常用于定义要管理主机的认证信息,例如ssh登录用户名、密码以及key相关信息。
查看配置文件:
[root@ansible-server ~]# rpm  -qc ansible
/etc/ansible/ansible.cfg
/etc/ansible/hosts
-q:---query查询
1.主配置文件:
inventory = /etc/ansible/ansible.cfg  #主要设置一些ansible初始化的信息,比如日志存放路径、模块、等配置信息 -i
library = /usr/share/ansible #指向存放Ansible模块的目录,支持多个目录方式,只要用冒号(:)隔开就可以
forks = 5      #并发连接数,默认为5
sudo_user = root        #设置默认执行命令的用户
remote_port = 22        #指定连接被管节点的管理端口,默认为22端口,建议修改,能够更加安全
host_key_checking = False #设置是否检查SSH主机的密钥,值为True/False。关闭后第一次连接不会提示配置实例
timeout = 60        #设置SSH连接的超时时间,单位为秒
log_path = /var/log/ansible.log    #指定一个存储ansible日志的文件(默认不记录日志)

2.主机清单文件:
默认位置/etc/ansible/hosts
1.添加主机或者主机组:
[root@ansible-server ~]# vim /etc/ansible/hosts  #在最后追加被管理端的机器
ansible-web1                      #单独指定主机,可以使用主机名称或IP地址
2.添加主机组:
[webservers]        #使用[]标签指定主机组 ----标签自定义
192.168.10.11        #如果未解析添加ip
ansible-web2      #解析添加主机名
3.组可以包含其他组:
[webservers1]    #组一
ansible-web1
[webservers2]    #组二
ansible-web2
[weball:children]      #children-照写 #weball包括两个子组
webservers1        #组一
webservers2        #组二
4.为一个组指定变量,组内每个主机都可以使用该变量:
[weball:vars]        #设置变量,vars--照写
ansible_ssh_port=22    
ansible_ssh_user=root
ansible_ssh_private_key_file=/root/.ssh/id_rsa  
#ansible_ssh_pass=1      #也可以定义密码,如果没有互传秘钥可以使用密码。

查看组内主机列表:
语法:ansible  组名  --list-hosts
[root@ansible-server ~]# ansible  weball --list-hosts
hosts (2):
    ansible-web1
    ansible-web2
====================================
扩展:自定义主机列表使用密码登录:(了解)
[root@ansible-server ~]# vim /opt/hostlist
[all:vars]
ansible_ssh_port=22
ansible_ssh_user=root
#ansible_ssh_private_key_file=/root/.ssh/id_rsa
ansible_ssh_pass=test

[all]
ansible-web1
ansible-web2
使用:
[root@ansible-server ~]# ansible -i /opt/hostlist all -m ping -o
-i:指定清单文件
注意:这里的ping并不是真正意义上的ping而是探测远程主机ssh是否可以连接!判断ssh端口是否存活

4.测试    ansible web -m ping -o语法:# ansible  <pattern>  -m <module_name>  -a <arguments>
pattern--主机清单里定义的主机组名,主机名,IP,别名等,all表示所有的主机,支持通配符,正则

-a MODULE_ARGS #模块的参数,如果执行默认COMMAND的模块,即是命令参数,如: “date”,“pwd”等等
-k,--ask-pass #ask for SSH password。登录密码,提示输入SSH密码而不是假设基于密钥的验证
--ask-su-pass #ask for su password。su切换密码
-K,--ask-sudo-pass #ask for sudo password。提示密码使用sudo,sudo表示提权操作
--ask-vault-pass #ask for vault password。假设我们设定了加密的密码,则用该选项进行访问
-B SECONDS #后台运行超时时间
-C #模拟运行环境并进行预运行,可以进行查错测试
-c CONNECTION #连接类型使用
-f FORKS #并行任务数,默认为5
-i INVENTORY #指定主机清单的路径,默认为/etc/ansible/hosts
--list-hosts #查看有哪些主机组-m MODULE_NAME #执行模块的名字,默认使用 command 模块,所以如果是只执行单一命令可以不用
 -m参数-o #压缩输出,尝试将所有结果在一行输出,一般针对收集工具使用
-S #用 su 命令-R SU_USER #指定 su 的用户,默认为 root 用户-s #用 sudo 命令
-U SUDO_USER #指定 sudo 到哪个用户,默认为 root 用户
-T TIMEOUT #指定 ssh 默认超时时间,默认为10s,也可在配置文件中修改
-u REMOTE_USER #远程用户,默认为 root 用户
-v #查看详细信息,同时支持-vvv,-vvvv可查看更详细信息


5、Ad-Hoc
ad hoc其实就是执行简单的命令——一条命令。对于复杂的命令则为 playbook。
帮助文档:
列出ansible支持的模块:
-l:获取列表
-s module_name:获取指定模块的使用信息
看所有模块(A10,华为,docker,EC2,aws等等广大厂商设备)
[root@ansible-server ~]# ansible-doc -l
查看模块使用信息,了解其功能:
[root@ansible-server ~]# ansible-doc -s modelname


常用模块

1.command 模块
这个模块可以直接在远程主机上执行命令,并将结果返回本主机。举例如下: ansible web -m command -a 'ss -ntl'
 命令模块接受命令名称,后面是空格分隔的列表参数。给定的命令将在所有选定的节点上执行。它不会通过shell进行处理,比如$HOME和操作如"<",">","|",";","&" 工作(需要使用(shell)模块实现这些功能)。注意,该命令不支持| 管道命令。   下面来看一看该模块下常用的几个命令:
chdir     # 在执行命令之前,先切换到该目录
executable    # 切换shell来执行命令,需要使用命令的绝对路径
free_form   # 要执行的Linux指令,一般使用Ansible的-a参数代替。
creates        # 一个文件名,当这个文件存在,则该命令不执行,可以用来做判断
removes        # 一个文件名,这个文件不存在,则该命令不执行
ansible web -m command -a 'chdir=/data/ ls' #先切换到/data/ 目录,再执行“ls”命令

2、shell 模块
  shell模块可以在远程主机上调用shell解释器运行命令,支持shell的各种功能,例如管道等。
ansible web -m shell -a 'cat /etc/passwd |grep "keer"'
只要是我们的shell命令,都可以通过这个模块在远程主机上运行,这里就不一一举例了。

3、copy 模块
  这个模块用于将文件复制到远程主机,同时支持给定内容生成文件和修改权限等。   其相关选项如下:

src     #被复制到远程主机的本地文件。可以是绝对路径,也可以是相对路径。如果路径是一个目录,则会递归复制,用法类似于"rsync"
content  #用于替换"src",可以直接指定文件的值
dest     #必选项,将源文件复制到的远程主机的绝对路径
backup   #当文件内容发生改变后,在覆盖之前把源文件备份,备份文件包含时间信息directory_mode    #递归设定目录的权限,默认为系统默认权限
force    #当目标主机包含该文件,但内容不同时,设为"yes",表示强制覆盖;设为"no",表示目标主机的目标位置不存在该文件才复制。默认为"yes"
others    #所有的 file 模块中的选项可以在这里使用
1.复制文件    ansible web -m copy -a 'src=~/hello dest=/data/hello' 
2. 给定内容生成文件,并制定权限    ansible web -m copy -a 'content="I am keer\n" dest=/data/name mode=666'
3.关于覆盖     ansible web -m copy -a 'content="I am keerya\n" backup=yes dest=/data/name mode=666'

4、file 模块
  该模块主要用于设置文件的属性,比如创建文件、创建链接文件、删除文件等。   下面是一些常见的命令:

force  #需要在两种情况下强制创建软链接,一种是源文件不存在,但之后会建立的情况下;另一种是目标软链接已存在,需要先取消之前的软链,然后创建新的软链,有两个选项:yes|no
group  #定义文件/目录的属组。后面可以加上mode:定义文件/目录的权限
owner  #定义文件/目录的属主。后面必须跟上path:定义文件/目录的路径
recurse  #递归设置文件的属性,只对目录有效,后面跟上src:被链接的源文件路径,只应用于state=link的情况
dest  #被链接到的路径,只应用于state=link的情况
state  #状态,有以下选项:
directory:如果目录不存在,就创建目录
file:即使文件不存在,也不会被创建
link:创建软链接
hard:创建硬链接
touch:如果文件不存在,则会创建一个新的文件,如果文件或目录已存在,则更新其最后修改时间
absent:删除目录、文件或者取消链接文件
1.创建目录:ansible web -m file -a 'path=/data/app state=directory'
2.创建链接文件    ansible web -m file -a 'path=/data/bbb.jpg src=aaa.jpg state=link'
3.删除文件    ansible web -m file -a 'path=/data/a state=absent'

5、fetch 模块
  该模块用于从远程某主机获取(复制)文件到本地。   有两个选项:

dest:用来存放文件的目录
src:在远程拉取的文件,并且必须是一个file,不能是目录
ansible web -m fetch -a 'src=/data/hello dest=/data'

6、cron 模块
  该模块适用于管理cron计划任务的。   其使用的语法跟我们的crontab文件中的语法一致,同时,可以指定以下选项:

day=      #日应该运行的工作( 1-31, , /2, )
hour=     # 小时 ( 0-23, , /2, )
minute= #分钟( 0-59, , /2, )
month=   # 月( 1-12, *, /2, )
weekday=      # 周 ( 0-6 for Sunday-Saturday,, )
job=       #指明运行的命令是什么
name=    #定时任务描述
reboot  # 任务在重启时运行,不建议使用,建议使用
special_timespecial_time #特殊的时间范围,参数:reboot(重启时),annually(每年),monthly(每月),weekly(每周),daily(每天),hourly(每小时)
state   #指定状态,present表示添加定时任务,也是默认设置,absent表示删除定时任务
user     # 以哪个用户的身份执行
1.添加计划任务    ansible web -m cron -a 'name="ntp update every 5 min" minute=*/5  job="/sbin/ntpdate 172.17.0.1 &> /dev/null"'
2.查看    ansible web -m shell -a 'crontab -l'
3.删除计划任务    ansible web -m cron -a 'name="df everyday" hour=15 job="df -lh >> /tmp/disk_total &> /dev/null" state=absent'

7.yum模块
name=   #所安装的包的名称
state=  #present--->安装, latest--->安装最新的, absent---> 卸载软件。
update_cache  #强制更新yum的缓存
conf_file  #指定远程yum安装时所依赖的配置文件(安装本地已有的包)。disable_pgp_check  #是否禁止GPG checking,只用于presentor latest。
disablerepo  #临时禁止使用yum库。 只用于安装或更新时。
enablerepo   #临时使用的yum库。只用于安装或更新时。
ansible web -m yum -a 'name=htop state=present'

8.service模块
arguments #命令行提供额外的参数
enabled #设置开机启动。
name= #服务名称
runlevel #开机启动的级别,一般不用指定。
sleep #在重启服务的过程中,是否等待。如在服务关闭以后等待2秒再启动。(定义在剧本中。)state #有四种状态,分别为:started--->启动服务, stopped--->停止服务, restarted--->重启服务, reloaded--->重载配置
1.开启服务并设置自启动    ansible web -m service -a 'name=nginx state=started enabled=true' 
2.关闭服务    ansible web -m service -a 'name=nginx state=stopped'

9.script模块
该模块用于将本机的脚本在被管理端的机器上运行。   
该模块直接指定脚本的路径即可,我们通过例子来看一看到底如何使用的:  
首先,我们写一个脚本,并给其加上执行权限:
[root@server ~]# vim /tmp/df.sh
  #!/bin/bash
  date >> /tmp/disk_total.log
  df -lh >> /tmp/disk_total.log 
[root@server ~]# chmod +x /tmp/df.sh 
ansible web -m script -a '/tmp/df.sh'


ansible-playbook 剧本(1)
Playbook介绍
playbook是ansible用于配置,部署,和管理被控节点的剧本。通过playbook的详细描述,执行其中的tasks,可以让远端主机达到预期的状态。playbook是由一个或多个”play”组成的列表。  当对一台机器做环境初始化的时候往往需要不止做一件事情,这时使用playbook会更加适合。通过playbook你可以一次在多台机器执行多个指令。通过这种预先设计的配置保持了机器的配置统一,并很简单的执行日常任务。

ansible通过不同的模块实现相应的管理,管理的方式通过定义的清单文件(hosts)所管理的主机包括认证的方式连接的端口等。所有的功能都是通过调用不同的模块(modules)来完成不同的功能的。不管是执行单条命令还是p   lay-book都是基于清单文件。

playbook格式
playbook由YMAL语言编写。YMAL格式是类似于JSON的文件格式,便于人理解和阅读,同时便于书写。 1、文件的第一行应该以 "---" (三个连字符)开始,表明YMAL文件的开始。  2、在同一行中,#之后的内容表示注释,类似于shell,python和ruby。  3、YMAL中的列表元素以”-”开头然后紧跟着一个空格,后面为元素内容。  4、同一个列表中的元素应该保持相同的缩进。否则会被当做错误处理。  5、play中hosts,variables,roles,tasks等对象的表示方法都是键值中间以":"分隔表示,":"后面还要增加一个空格。

 我们的文件名称应该以.yml结尾,像我们上面的例子就是mysql.yml。其中,有三个部分组成:

host部分:使用 hosts 指示使用哪个主机或主机组来运行下面的 tasks ,每个 playbook 都必须指定 hosts ,hosts也可以使用通配符格式。主机或主机组在 inventory 清单中指定,可以使用系统默认的/etc/ansible/hosts,也可以自己编辑,在运行的时候加上-i选项,指定清单的位置即可。在运行清单文件的时候,–list-hosts选项会显示那些主机将会参与执行 task 的过程中。remote_user:指定远端主机中的哪个用户来登录远端系统,在远端系统执行 task 的用户,可以任意指定,也可以使用 sudo,但是用户必须要有执行相应 task 的权限。
tasks:指定远端主机将要执行的一系列动作。tasks 的核心为 ansible 的模块,前面已经提到模块的用法。tasks 包含 name 和要执行的模块,name 是可选的,只是为了便于用户阅读,不过还是建议加上去,模块是必须的,同时也要给予模块相应的参数。

  使用ansible-playbook运行playbook文件,得到如下输出信息,输出内容为JSON格式。并且由不同颜色组成,便于识别。一般而言
| 绿色代表执行成功,系统保持原样
| 黄色代表系统代表系统状态发生改变
|红色代表执行失败,显示错误输出  
执行有三个步骤:1、收集facts  2、执行tasks  3、报告结果

一个剧本里面可以有多个play,每个play只能有一个tasks,每个tasks可以有多个name

核心元素:
Hosts:主机组;
Tasks:任务列表;
Variables:变量,设置方式有四种;
Templates:包含了模板语法的文本文件;
Handlers:由特定条件触发的任务;

基本组件
Hosts:运行指定任务的目标主机
remoute_user:在远程主机上执行任务的用户;
sudo_user:
tasks:任务列表
  格式:
    tasks:
      – name: TASK_NAME
       module: arguments
       notify: HANDLER_NAME 
      handlers:
      – name: HANDLER_NAME
       module: arguments

模块,模块参数:
  格式:    (1) action: module arguments    (2) module: arguments
  注意:shell和command模块后面直接跟命令,而非key=value类的参数列表;

handlers:任务,在特定条件下触发;接收到其它任务的通知时被触发;
  (1) 某任务的状态在运行后为changed时,可通过“notify”通知给相应的handlers;
  (2) 任务可以通过“tags“打标签,而后可在ansible-playbook命令上使用-t指定进行调用;

举例

① 定义playbook

检测语法:--syntax-check
[root@ansible-server ansible]# ansible-playbook --syntax-check test.yml 
playbook: test.yml
运行Playbook:
[root@ansible-server ansible]# ansible-playbook test.yml #加剧本名称

③ 测试标签
  我们在里面已经打上了一个标签,所以可以直接引用标签。但是我们需要先把服务关闭,再来运行剧本并引用标签:
[root@server ansible]# ansible web -m shell -a 'systemctl stop nginx'
[root@server ansible]# ansible-playbook nginx.yml -t startnginx

5、模板 templates

  模板是一个文本文件,嵌套有脚本(使用模板编程语言编写)。  Jinja2:Jinja2是python的一种模板语言,以Django的模板语言为原本。模板支持:

通常来说,模板都是通过引用变量来运用的。举例

① 定义模板  我们直接把之前定义的/tmp/nginx.conf改个名,然后编辑一下,就可以定义成我们的模板文件了:

② 修改剧本  我们现在需要去修改剧本来定义变量:vim nginx.yml

copy修改为template

角色订制:roles
① 简介

  对于以上所有的方式有个弊端就是无法实现复用假设在同时部署Web、db、ha 时或不同服务器组合不同的应用就需要写多个yml文件。很难实现灵活的调用。
  roles 用于层次性、结构化地组织playbook。roles 能够根据层次型结构自动装载变量文件、tasks以及handlers等。要使用roles只需要在playbook中使用include指令即可。简单来讲,roles就是通过分别将变量(vars)、文件(file)、任务(tasks)、模块(modules)及处理器(handlers)放置于单独的目录中,并可以便捷地include它们的一种机制。角色一般用于基于主机构建服务的场景中,但也可以是用于构建守护进程等场景中。

② 角色集合
角色集合:roles/
mysql/
httpd/
nginx/
files/:存储由copy或script等模块调用的文件;
tasks/:此目录中至少应该有一个名为main.yml的文件,用于定义各task;其它的文件需要由main.yml进行“包含”调用;
handlers/:此目录中至少应该有一个名为main.yml的文件,用于定义各
handler;其它的文件需要由main.yml进行“包含”调用;
vars/:此目录中至少应该有一个名为main.yml的文件,用于定义各
variable;其它的文件需要由main.yml进行“包含”调用;
templates/:存储由template模块调用的模板文本;
meta/:此目录中至少应该有一个名为main.yml的文件,定义当前角色的特殊设定及其依赖关系;其它的文件需要由main.yml进行“包含”调用;
default/:此目录中至少应该有一个名为main.yml的文件,用于设定默认变量;

③ 角色定制实例
1. 在roles目录下生成对应的目录结构

2. 定义配置文件  我们需要修改的配置文件为/tasks/main.yml,下面,我们就来修改一下:

3. 放置我们所需要的文件到指定目录  因为我们定义的角色已经有了新的组成方式,所以我们需要把文件都放到指定的位置,这样,才能让配置文件找到这些并进行加载。  rpm包放在files目录下,模板放在templates目录下:

4. 修改变量文件  我们在模板中定义的变量,也要去配置文件中加上
[root@server nginx]# vim vars/main.yml
nginxprot: 9999

5. 定义handlers文件  我们在配置文件中定义了notify,所以我么也需要定义handlers,我们来修改配置文件:

6. 定义剧本文件  接下来,我们就来定义剧本文件,由于大部分设置我们都单独配置在了roles里面,所以,接下来剧本就只需要写一点点内容即可:

7. 启动服务  剧本定义完成以后,我们就可以来启动服务了:

推荐阅读更多精彩内容