Ansible 常用

2022-05-20 14:43:26 浏览数 (1)

一.前言

在企业中运维工作人员通常需要同时管理几十台甚至几百台主机(虚拟机),如果需要批量修改设置或者做更新操作的话,即便是事先编写好脚本,一台一台的去运行脚本也是非常耗时的,效率也十分低下。所以这时候我们需要可以在一台主机上,同时操作、控制多台其他主机的运维工具。

目前主流的工具很多,基本可以分为两类

1、agent:需要事先在被管控主机上安装一个小的程序,用于接受和控制远端主机,代表软件有puppet、func。这类软件运行起来比较安全,但是需要提前部署代理程序,当主机很多的时候会比较麻烦

2、agentless:不需要代理程序,而是直接使用ssh协议连接、控制被管控主机,后者只需要开启SSH服务就可以了,代表软件有farbic,ansible。这种软件比较方便,但是不太安全,毕竟要远程使用管理员账户登录,所以通常管控主机要使用有sudo权限的普通账户进行操作。

二.ansible的一些基础****概念

ansible的公司成立于2012年,目前已经被红帽以1.5亿美元的价格收购了。虽然ansible作为一款开源软件面世的时间不长,但是却十分好用,它既兼具了puppet的一部分功能,也有fabric的部分功能,而且,只要有SS协议,它就可以工作,非常的轻量化,但是正因为基于SSH工作,所以它无法同时处理过多的主机,一般用在千台以下的环境。

ansible有以下一些特性:

1、模块化,ansible本身非常轻量,通过调用特定的模块来完成不同的任务

2、基于Python语言实现,由Paramiko,PyYAML和jinja2三个关键模块实现。

3、部署简单、agentless

4、主从模式工作

5、支持自定义模块

6、支持playbook,批量执行一串任务

<wbr>而且ansible还要有幂等性:即同样的命令重复执行多次,不会出现问题。

ansible包含以下几个模块:

1、ansible core: ansible自己的核心

2、host inventory: 被管控主机列表,只要将能通信的主机列在这个文件里,ansible就可以管控

3、connection plugins:链接插件,用于与每一个被管控主机建立会话并发送控制指令

4、modules:包含两类模块:core modules 核心模块;custom modules 自定义模块。

5、playbooks: 设定一个流程化脚本,让多个ansible任务按顺序执行。

ansible可以通过yum自动安装,但是它在epel源中。

ansible的主配置文件是 /etc/ansible/ansible.cfg

Host inventory : /etc/ansible/hosts <wbr> <wbr> <wbr>用于定义被管控的主机列表,它的格式是这样的

这个文件使用的是INI风格的,可以直接写主机名,IP地址;也可以设置一个组,向组中加入多个主机,并且一个主机还可以同时属于不同的组;还可以在域名中直接调用组里的主机名。不过通常可以不用写的那么复杂。

三.ansible的常用命令

ansible-doc -l : 列出常用的模块文档列表。ansible支持超多的模块,可以使用这个命令找到自己想要使用的对应模块。

ansible-doc -s 模块名称: 查看某一个模块支持的具体参数 <wbr>

示例:

ansible-doc -s ping:查看ping命令的详细帮助

接下来写一些常用模块,在这之前先做一些准备工作

1、我的/etc/ansible/hosts配置是这样的

2.由于ansible是基于ssh管理被管控主机,所以需要配置ssh基于秘钥认证进行连接,否则每次发送一个管控命令都会提示输入ssh的用户密码。

ssh-keygen -t rsa -P '' <wbr>

ssh-copy-id -i .ssh/id_rsa.pub root@172.16.26.1

由于有7被管控个主机,同样的命令要敲7次,本来想弄个脚本解决,但是由于传送秘钥的时候需要交互输入对端用户密码,我不会解决这个问题,所以就没做 <wbr>- - # .....

<wbr> <wbr>

command模块:对被管控主机做一些操作命令,并将各主机上的结果输出回ansible主机上。

示例:ansible all -m command -a ‘ifconfig ’

注:all的含义是:操作对象为所有hosts文件中的主机和组,-m的含义是调用模块,而command是默认模块,如果不添加-m选项的话默认就为command,而且command只支持一些简单的命令,不支持管道符,如果想用管道符,要使用shell模块

user模块:可以快速在被管控主机上批量添加用户

示例:ansible all -m user -a 'name=ly state=present' <wbr>

常用参数:

state=present <wbr> : 创建用户

home= <wbr> <wbr> :来指定用户家目录路径;

system=true <wbr> :创建系统用户

uid= ** <wbr>:** 来指定用户uid

shell= <wbr> <wbr> <wbr> :指定用户的默认shell

如果执行成功如上图,其中changed为被控主机确实发生了更改,即,之前没有该用户,现在已经创建。如果同样的命令再执行一次会怎么样?

虽然当前执行结果也成功了,但是两台被控主机并未发生任何变化,即,他们之前就已经存在了ly用户

删除用户:

ansible all -m user -a 'name=ly state=absent remove=true'

state=absent : 删除用户

remove=true : 删除用户家目录!

group模块

和user类似,用于创建系统组

示例:ansible all -m group -a ‘name=go state=present gid=5001 system=true’

system=true <wbr>: <wbr> 创建一个系统组

如果要删除该组,只需要将state=present改成absent就可以了

cron模块

为被管控主机在crontab -e列表中添加计划任务

示例:ansible all -m cron -a “minute='/5' job='/usr/sbin/ntpdate 172.16.0.1 &> /dev/null' name='sync time' state='present'"*

为所有被管控主机添加一条计划任务,每5分钟向172.16.0.1同步一次系统时间

name= <wbr> <wbr> <wbr> <wbr> :表示工作名称

job= <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> :表示具体运行什么命令

hour=* <wbr> <wbr> <wbr> <wbr> <wbr>: 每小时

day=* <wbr> <wbr> <wbr>: <wbr> 每天

month=3 <wbr> <wbr>: 3月

weekday=3 <wbr> : 周三

file模块

为被管控主机创建新文件

示例:ansible all -m file -a 'path=/tmp/test.txt state=touch owner=user1 mode=600'

在/tmp下创建一个叫test.txt的普通文件,属主为user1,权限为600

mode= <wbr> <wbr> <wbr> : 文件权限

group= <wbr> <wbr> <wbr>: 文件属组

state=touch:创建普通文件

state=directory: 创建目录

state=link <wbr> :创建一个软连接,还要使用src=/etc/passwd参数来指定源文件。

state=hard <wbr>: 创建一个硬链接,和上面一样也要使用src参数

state=absent:删除文件

yum模块

为被管控主机用yum安装软件

示例:ansible all -m yum -a 'name=httpd state=present'

为所有管控主机安装httpd,各管控主机默认从自己的base源中进行安装

state=latest <wbr> <wbr> : 为某个包做更新操作

enablerepo= <wbr> <wbr> :启动某个仓库源

disablerepo= <wbr> <wbr> :禁用某个仓库源

copy模块

为被管控主机执行复制操作

示例:ansible all -m copy -a 'src=/etc/fstab dest=/tmp/fstab owner=ly group=ly mode=600'

让所有被管控主机复制管控主机的/etc/fstab文件到被管控主机的/tmp/fstab,属主属组为ly,权限为600

content=123 <wbr> :将‘123’复制到dest=字段指定的文件中,会覆盖目标文件的所有内容,基本就是远程输出重定向的意思。而且和src=参数不能一起用。

service

可以管理被管控主机上的各种服务程序,从简单的开启和关闭,到 在不同级别下是否开机自动启动等都可以操作

示例:ansbile all -m service -a 'name=httpd state=started ' <wbr>

这个主机启动失败的原因是80端口被占用了,我在上面跑着haproxy

另一个示例

ansible all -m service -a 'name=httpd runlevel=5 enabled=true'

在级别5下,自动启动httpd服务

script

这个模块非常有用,可以把本地的脚本在各被管控主机上跑一遍,我可以现在本地主机的/root目录下建立一个脚本123.sh,然后运行:

ansible <wbr>all -m script -a '/root/123.sh'

shell : <wbr>

直接在被管控主机上启动一个子shell进程来运行命令,可以支持绝大多数的shell命令,包括管道符

ansible all -m shell -a "echo $RANDOM | tr <wbr>'0-9' 'a-z' > /root/123"

其实上面大多数操作都可以直接使用shell完成,不过用shell返回的信息并不太详细。

四.ansible的playbook

虽然ansible可以同时操作很多个主机,但是如果有些命令可以批量执行,而不用一条一条的打的话其实会更加理想,而ansible的playbook就提供了这样的功能,它其实也是一种类型的脚本,核心元素有这几个:

1、Tasks <wbr>: 任务

2、varibales :变量

3、Templates:模板

4、Handlers:触发器

5、Roles:规则

而它的代码组织格式为YAML,它是一种编程语言,诞生于2001年,类似于xml这种半结构化语句,但是它并不需要那么多标签,所以很适合用于配置。

playbook的基本格式:

  • hosts:172.16.26.1 <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr># <wbr>指定要操作的主机

<wbr> <wbr> <wbr> <wbr>vars : <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr># <wbr>指定变量

<wbr> <wbr> <wbr> <wbr> <wbr> <wbr> var1:

<wbr> <wbr> <wbr> <wbr> <wbr> <wbr> var2:

<wbr> <wbr> <wbr> <wbr>tasks: <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> # <wbr>指定任务

<wbr> <wbr> <wbr> <wbr> <wbr> <wbr> - name: <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr># <wbr>指定任务名字

<wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> shell : <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> # 具体的操作命令

<wbr> <wbr> <wbr> <wbr> <wbr> <wbr> - name:

<wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> command <wbr>: <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr>

<wbr> <wbr> <wbr> <wbr>handlers: <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr>

<wbr> <wbr> <wbr> <wbr> <wbr> <wbr>- name :

<wbr> <wbr> <wbr> <wbr>remote_user: <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr># 在被管控主机上执行这些任务的用户,也可以使用sudo

  • host:172.16.26.2
  • host:172.16.26.3

举个栗子

-name 后是自定义的名字,用来标识不同的任务。

定义好playbook后,使用ansible-playbook 123.yml 来启动

ansible会先获取主机上的FACTS变量。然后开始一项一项的执行定义好的任务。OK则说明

其中OK则代表有三项任务执行成功,但是没发生任何改变;

changed则也表示成功,但是被管控主机做出了变化,比如本来没有httpd,通过剧本安装了httpd,状态就会发生改变,则为changed。

failed=1 就是某个task执行失败了,这里失败的原因是我的playbook中的命令写错了 - -# 。

上面的playbook中只有一个hosts字段,我们也可以设置多个hosts,分别设置不同的任务,如果一台主机在多个hosts字段中都存在,会按hosts字段的顺序执行,即最后task中做的设置会生效。

刚才的playbook中只是最基本的一些设置,其实还有一个重要的元素是变量,playbook中的变量和其他语言中的变量类似,只能使用字母、数字和下划线组成,并仅能以字母开头。

ansible中包含以下几种变量:

1、facts变量

2、自定义变量

3、主机变量

4、组变量

5、一些启动参数

什么是facts变量呢?

facts简单来说就是由被管控主机返回来的自身的一些属性信息,比如ip地址,系统版本,硬件信息等,他们被存在ansible的facts变量中,可以使用 ansbile all -m setup 命令来手动查看facts变量

facts是系统变量,不需要声明就可以直接调用,如果要使用自定义变量的话,需要提前声明,声明有两种方法,命令行和roles:

可以用playbook命令时,使用参数的方式来来声明,比如

ansible-playbook 123.yml --extra-vars "host=www user=ly"

这就声明了两个变量:host与user

roles的话,下小节再说吧。

主机变量:定义在host inventory中(就是/etc/ansible/hosts) 中的主机之后的变量,

组变量:定义在host inventory中(就是/etc/ansible/hosts) 中的组后面的变量

启动参数:也是定义在定义在host inventory中(就是/etc/ansible/hosts) 中的主机之后的,但是并不是自定义的变量,更像一些参数。

其中NUM是我自己定义的变量,后边三个则是ansible内置的一些参数

ansible_ssh_user=root <wbr> <wbr> <wbr> <wbr> <wbr> # 用于连接ssh的账户

ansible_ssh_pass= <wbr> <wbr> <wbr> <wbr> <wbr> <wbr># <wbr> <wbr>连接ssh时使用的密码,如果事先没有设置秘钥认证,这个选项就很必要!

ansible_ssh_port= <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> # 有些主机更改了ssh监听的端口,这个选项就很有用。

如何在playbook中定义并使用变量?

只需要加入vars字段,并在下面直接声明就可以了;调用的时候要加双大括号

这时候又有一个问题:如果我在命令行中传递了一样的变量username,和playbook中的变量冲突了,哪个生效?肯定是命令行中定义的变量生效,命令行定义的值会覆盖playbook中写死的变量值。

playbook中除了变量以外,还可以添加条件变量,在某task后面添加when子句即可实现条件测试功能;when语句支持jinja2语法;

ansible_os_family : 内置变量,保存了呗管控主机的系统类型。

当被管控主机是Debian时,才执行install web package这个tasks。

skipping表示任务直接跳过了,没有执行,因为我的c6组中的主机都是CentOS 6。

ansible中还有一种迭代变量,用起来也十分简单:

httpd、php、php-mysql会按顺序轮流替换上方的item变量进行安装。

handlers:类似一个触发器,可以监控在某一个tasks中的name字段上,一旦这个name在执行发生了改变,即标注了change,则就会触发handlers,并执行handlers中定义的命令。

notify字段类似一个监控器,可以监控某个任务,一旦该任务状态为change,则触发handlers,注意notify后的名字一定要和handlers的名字对应上,然后执行handlers里预先定义的任务,图中为重启httpd服务。

图中的大体含义是:首先安装httpd,然后复制管控主机上的定制好的配置文件到所有被管控主机上,如果复制配置文件这一步为changed,就会触发handlers,即重启httpd服务让复制过去的配置文件生效。然后无论是否触发了handler,都要尝试启动httpd服务。

这样设置的好处就在于,只有修改了配置文件的主机才会重启httpd服务,而不会影响到其他未发生变化的主机。

templates <wbr>

刚才我们有一步复制了一个本地已经定义好的配置文件到被管控主机上作为被管控主机上的,但是如果被管控主机各自需要的配置不相同怎么办?比如说,4台被管控主机都是httpd服务器,但是需要监听的端口不一样,我们如果把本地的配置文件复制给它们,那它们的配置文件都一样,势必监听的端口也都一样,这时要如何处理?这时候就可以使用templates功能。

templates使用jinja2风格的语法,我们可以先在/etc/ansible/hosts上为不同的主机各自定义不同的变量,比如:

然后修改本地/root/httpd.conf的listen字段,并给他改名为?/root/httpd.conf.j2,把它做成一个真正的模板文件。

接下来再修改b.yml,把copy任务换成template字段,把源改为/root/httpd.conf.j2

接下来运行ansible-playbook b.yml, 每个主机会自动用httpd.conf.j2这个模板文件生成自己的配置文件,并用自己的port变量替换掉模板中的{{ port }}字段。

这里172.16.26.104这台主机失败了,是由于我之前并没有为它配置port变量导致的。另外3个则配置成功了。让我们看一下另外三台主机监听的端口。

和我们刚才设定的变量值一模一样,我们也可以使用更多的变量来替换模板中的固定内容,让同一批被管控主机可以分别拥有自己的个性化配置。

=======================================================

五.roles <wbr>

roles可以把一个完整playbook中的元素分拆,以层级结构分别放到磁盘中特定的位置保存起来,然后可以让不同的hosts灵活的调用这些被分拆的元素代码,重新组合成一个新的临时playbook来运行。

我们可以在/etc/ansible/roles目录下建立多个不同的目录,给它们取上不同的名字,每个roles目录下可以以文件的方式存放不同的元素(tasks,variables,handlers等),然后在playbook中直接调用roles目录的名字,就可以自动执行roles目录下的所有元素。roles目录类似于一个存放在磁盘上的函数,里面包含了很多元素,需要使用的时候,直接调用roles目录的目录名就可以运行目录下的所有元素。

比如,我们在/etc/ansible/roles目录下建立一个目录,叫test,然后在test目录下建立多个子目录:files/,

tasks/,handlers,vars,meta。

files/:此roles下用到的所有文件均可放置于此目录中

templates/: jinja2模板文件存放位置

tasks/:任务列表文件; 可以有多个文件,但至少有一个叫做main.yml的文件。

vars/:变量字典文件,用于自定义多个变量,上小节说的通过role传递变量就是指这里; <wbr>可以有多个文件,但至少有一个叫做main.yml的文件。

handlers/ : 处理器列表文件; <wbr>可以有多个文件,但至少有一个叫做main.yml的文件。

meta/ : 此roles的特殊设定及依赖关系等

我们可以现在/etc/ansible/roles下创建几个目录:

mkdir testrole/{meta,files,templates,tasks,vars,handlers} <wbr> <wbr> #这些目录并非都是必须的

如果我们需要定义变量的话,可以在vars目录下创建一个main.yml的文件,然后进行定义

定义两个变量,user=ly <wbr>group=ly

然后在tasks目录下创建main.yml来定义任务列表。

图例的配置和刚才的b.yml剧本几乎一样,但是注意在roles中,handler不能再和tasks放在一起了,要单独定义在handlers目录中;而且template处指定的源是一个相对路径,相对路径就是roels/testrole/templates这个目录中,所以我们把所有的j2配置模板放在这里就好。

我们在handlers目录中建立一个文件main.yml

ansible常用技巧

注意这里的name还是要和notify监控字段指定的名字要一样,否则当我们有多个handler的时候,notify不知道我们要激活哪一个handler。

然后把之前的/root/httpd.conf.j2复制到roles/testrole/templates目录下,然后修改一下这个j2模板文件,让他们能利用上我们之前在vars/main.yml中定义的两个变量:

现在一个role就设置完毕了,我们如果想要调用这个role,需要在/etc/ansible下创建一个playbook文件

testrole是我们之前在roles目录下创建的那个子目录名字,调用这个目录名字,就可以调用这个目录下所有我们刚才定义好的元素。

注意:如果确定要调用roles话,playbook文件尽量放在/etc/ansible目录下,否则容易出现一些小问题。

然后运行我们刚刚创建好的脚本文件

运行基本没有问题。

注意,roles下的层级结构一定要遵循规范,否则无法成功调用

tags:标签

有的role中可能有很多个task任务,如果我们只想运行role中的某一个task,而不想所有task都运行一遍怎么办?

可以给task加上不同的标签,用来标识不同的task,然后我们在运行playbook的时候,可以用-t 选项指定标签,来运行我们指定的任务,而不是所有role中的任务全都跑一遍。比如,修改testrole/tasks/main.yml

给修改配置文件的步骤添加一个标签,然后运行

ansible-playbook -t conf abc.yml

此时只会运行role中的其中一个task,而不会所有的task全跑一遍。

六.总结

1、ansible安装包在epel源中,如果想通过yum安装,需要配置好epel源

2、ansible装好后需要先配置被管控主机列表/etc/ansible/hosts;而且最好先把管控主机的秘钥传给所有被管控主机

3、除了shell模块以外,大多数的模块最基本的格式都是name=XX state=present|absent <wbr>

4、playbook和roles用法很类似,只不过roles要分散设置各各不同的元素。而且同一个playbook可以调用多个roles,所以当很多tasks等元素需要大量复用时可以考虑roles

0 人点赞