企业级自动化运维工具-ansible

目录

简介

ansible是自动化运维工具,基于Python开发,集合了众多运维工具(puppet、cfengine、chef、func、fabric)的优点,实现了批量系统配置、批量程序部署、批量运行命令等功能。

ansible是基于模块工作的,本身没有批量部署的能力。真正具有批量部署的是ansible所运行的模块,ansible只是提供一种框架。主要包括:

(1)、连接插件connection plugins:负责和被监控端实现通信;

(2)、host inventory:指定操作的主机,是一个配置文件里面定义监控的主机;

(3)、各种模块核心模块、command模块、自定义模块;

(4)、借助于插件完成记录日志邮件等功能;

(5)、playbook:剧本执行多个任务时,非必需可以让节点一次性运行多个任务。

ansible架构图 

企业级自动化运维工具-ansible_第1张图片

 上图中我们看到的主要模块如下:

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

ansible 任务执行模式

Ansible 系统由控制主机对被管节点的操作方式可分为两类,即adhocplaybook

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

ansible执行流程

企业级自动化运维工具-ansible_第2张图片

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

ansible 命令执行过程

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

ansible 配置详解

ansible 安装方式

  ansible安装常用两种方式,yum安装pip程序安装。下面我们来详细介绍一下这两种安装方式。

使用 pip(python的包管理模块)安装

  首先,我们需要安装一个python-pip包,安装完成以后,则直接使用pip命令来安装我们的包,具体操作过程如下:

	yum install python-pip
	pip install ansible

使用 yum 安装

  yum 安装是我们很熟悉的安装方式了。我们需要先安装一个epel-release包,然后再安装我们的 ansible 即可。

	yum install epel-release -y
	yum install ansible –y

ansible 程序结构

安装目录如下(yum安装):
  配置文件目录:/etc/ansible/
  执行文件目录:/usr/bin/
  Lib库依赖目录:/usr/lib/pythonX.X/site-packages/ansible/
  Help文档目录:/usr/share/doc/ansible-X.X.X/
  Man文档目录:/usr/share/man/man1/

/etc/ansible
/etc/ansible/ansible.cfg
/etc/ansible/hosts
/etc/ansible/roles
/usr/bin/ansible
/usr/bin/ansible-2
/usr/bin/ansible-2.7
/usr/bin/ansible-config
/usr/bin/ansible-connection
/usr/bin/ansible-console
/usr/bin/ansible-console-2
/usr/bin/ansible-console-2.7
/usr/bin/ansible-doc
/usr/bin/ansible-doc-2
/usr/bin/ansible-doc-2.7
/usr/bin/ansible-galaxy
/usr/bin/ansible-galaxy-2
/usr/bin/ansible-galaxy-2.7
/usr/bin/ansible-inventory
/usr/bin/ansible-playbook
/usr/bin/ansible-playbook-2
/usr/bin/ansible-playbook-2.7
/usr/bin/ansible-pull
/usr/bin/ansible-pull-2
/usr/bin/ansible-pull-2.7
/usr/bin/ansible-vault
/usr/bin/ansible-vault-2
/usr/bin/ansible-vault-2.7

ansible配置文件查找顺序

  ansible与我们其他的服务在这一点上有很大不同,这里的配置文件查找是从多个地方找的,顺序如下:

  1. 检查环境变量ANSIBLE_CONFIG指向的路径文件(export ANSIBLE_CONFIG=/etc/ansible.cfg);
  2. ~/.ansible.cfg,检查当前目录下的ansible.cfg配置文件;
  3. /etc/ansible.cfg检查etc目录的配置文件。

配置文件

  1. /etc/ansible/ansible.cfg 主配置文件,配置ansible工作特性
  2. /etc/ansible/hosts  主机清单
  3. /etc/ansible/roles/  存放角色的目录
程序:

        /usr/bin/ansible 主程序,临时命令执行工具

        /usr/bin/ansible-doc 查看配置文档,模块功能查看工具

        /usr/bin/ansible-galaxy 下载/上传优秀代码或Roles模块的官网平台

         /usr/bin/ansible-playbook 定制自动化任务,编排剧本工具。

        /usr/bin/ansible-vault 文件加密工具

        /usr/bin/ansible-console 基于console界面与用户交互的执行工具

ansible配置文件

  ansible 的配置文件为/etc/ansible/ansible.cfg,ansible 有许多参数,下面我们列出一些常见的参数:
 

inventory = /etc/ansible/hosts #这个参数表示资源清单inventory文件的位置

library = /usr/share/ansible #指向存放Ansible模块的目录,支持多个目录方式,只要用冒号(:)隔开就可以

forks = 5 #并发连接数,默认为5
remote_tmp = $HOME/.ansible/tmp #临时py命令文件存放在远程主机目录

sudo_user = root #设置默认执行命令的用户

remote_port = 22 #指定连接被管节点的管理端口,默认为22端口,建议修改,能够更加安全

host_key_checking = False #设置是否检查SSH主机的密钥,值为True/False。关闭后第一次连接不会提示配置实例

timeout = 60 #设置SSH连接的超时时间,单位为秒

log_path = /var/log/ansible.log #指定一个存储ansible日志的文件(默认不记录日志)

ansuble主机清单

  在配置文件中,我们提到了资源清单,这个清单就是我们的主机清单,里面保存的是一些 ansible 需要连接管理的主机列表。我们可以来看看他的定义方式:

1、 直接指明主机地址或主机名:
	## green.example.com#
	# blue.example.com#
	# 192.168.100.1
	# 192.168.100.10
2、 定义一个主机组[组名]把地址或主机名加进去
	[mysql_test]
	192.168.253.159
	192.168.253.160
	192.168.253.153

  需要注意的是,这里的组成员可以使用通配符来匹配,这样对于一些标准化的管理来说就很轻松方便了。
  我们可以根据实际情况来配置我们的主机列表,具体操作如下:

[root@server ~]# vim /etc/ansible/hosts
	[web]
	192.168.37.122
	192.168.37.133

ansible 常用命令

ansible 命令集

/usr/bin/ansible  Ansibe AD-Hoc 临时命令执行工具,常用于临时命令的执行
/usr/bin/ansible-doc   Ansible 模块功能查看工具
/usr/bin/ansible-galaxy  下载/上传优秀代码或Roles模块 的官网平台,基于网络的
/usr/bin/ansible-playbook  Ansible 定制自动化的任务集编排工具
/usr/bin/ansible-pull  Ansible远程执行命令的工具,拉取配置而非推送配置(使用较少,海量机器时使用,对运维的架构能力要求较高)
/usr/bin/ansible-vault  Ansible 文件加密工具
/usr/bin/ansible-console  Ansible基于Linux Consoble界面可与用户交互的命令执行工具

ansible-doc 命令

  ansible-doc 命令常用于获取模块信息及其使用帮助,一般用法如下:

	ansible-doc -l				#获取全部模块的信息
	ansible-doc -s MOD_NAME		#获取指定模块的使用帮助

  我们也可以查看一下ansible-doc的全部用法:

[root@server ~]# ansible-doc
Usage: ansible-doc [options] [module...]

Options:
  -h, --help            show this help message and exit  # 显示命令参数API文档
  -l, --list            List available modules  #列出可用的模块
  -M MODULE_PATH, --module-path=MODULE_PATH  #指定模块的路径
                        specify path(s) to module library (default=None)
  -s, --snippet         Show playbook snippet for specified module(s)  #显示playbook制定模块的用法
  -v, --verbose         verbose mode (-vvv for more, -vvvv to enable  # 显示ansible-doc的版本号查看模块列表:
                        connection debugging)
  --version             show program's version number and exit

  我们可以来看一下,以mysql相关的为例:

[root@server ~]# ansible-doc -l |grep mysql
mysql_db                           Add or remove MySQL databases from a remote...
mysql_replication                  Manage MySQL replication                   
mysql_user                         Adds or removes a user from a MySQL databas...
mysql_variables                    Manage MySQL global variables      
[root@server ~]# ansible-doc -s mysql_user

ansible 命令详解

  命令的具体格式如下:

ansible  [-f forks] [-m module_name] [-a args]

  也可以通过ansible -h来查看帮助,下面我们列出一些比较常用的选项,并解释其含义:

-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可查看更详细信息

ansible 配置公私钥

  上面我们已经提到过 ansible 是基于 ssh 协议实现的,所以其配置公私钥的方式与 ssh 协议的方式相同,具体操作步骤如下:

#1.生成私钥
[root@server ~]# ssh-keygen 
#2.向主机分发私钥
[root@server ~]# ssh-copy-id [email protected]
[root@server ~]# ssh-copy-id [email protected]

  这样的话,就可以实现无密码登录,我们的实验过程也会顺畅很多。
  注意,如果出现了一下报错:

	-bash: ssh-copy-id: command not found

  那么就证明我们需要安装一个包:

	yum -y install openssh-clientsansible

  把包安装上即可。

ansible 常用模块

1)主机连通性测试

  我们使用ansible web -m ping命令来进行主机连通性测试,效果如下:

[root@ansible ~]# ansible dbserver -m ping
192.168.245.129 | SUCCESS => {
    "ansible_facts": {
        "discovered_interpreter_python": "/usr/libexec/platform-python"
    }, 
    "changed": false, 
    "ping": "pong"
}

  这样就说明我们的主机是连通状态的。接下来的操作才可以正常进行。

这里的ping模块不是走的ICMP协议,可以打开关闭ICMP协议测试

关闭ICMP协议(echo 1 > /proc/sys/net/ipv4/icmp_echo_ignore_all)

打开ICMP协议(echo 0 > /proc/sys/net/ipv4/icmp_echo_ignore_all)

2)command 模块

  这个模块可以直接在远程主机上执行命令,并将结果返回本主机。
  举例如下:

 

[root@ansible ~]# ansible web -m command -a "ss -ntl"
192.168.245.130 | CHANGED | rc=0 >>
State      Recv-Q Send-Q Local Address:Port               Peer Address:Port              
LISTEN     0      128          *:22                       *:*                  
LISTEN     0      100    127.0.0.1:25                       *:*                  
LISTEN     0      128       [::]:22                    [::]:*                  
LISTEN     0      100      [::1]:25                    [::]:*  

  命令模块接受命令名称,后面是空格分隔的列表参数。给定的命令将在所有选定的节点上执行。它不会通过shell进行处理,比如$HOME和操作如"<",">","|",";","&" 工作(需要使用(shell)模块实现这些功能)。注意,该命令不支持| 管道命令
  下面来看一看该模块下常用的几个命令:

chdir       # 在执行命令之前,先切换到该目录
executable             # 切换shell来执行命令,需要使用命令的绝对路径
free_form            # 要执行的Linux指令,一般使用Ansible的-a参数代替。
creates                # 一个文件名,当这个文件存在,则该命令不执行,可以用来做判断,不存在则执行
removes                 # 一个文件名,这个文件不存在,则该命令不执行,存在则执行。

  下面我们来看看这些命令的执行效果:

[root@ansible ~]# ansible web -m command -a "chdir=/tmp/ ls"
192.168.245.131 | CHANGED | rc=0 >>
ansible_command_payload_zKgszH
[root@ansible ~]# ansible web -m command -a "creates=/etc/fstab touch /etc/fstab"
192.168.245.132 | SUCCESS | rc=0 >>
skipped, since /etc/fstab exists
[root@ansible ~]# ansible web -m command -a "creates=/etc/fstabtest touch /etc/fstabtest"
rid of this message.
192.168.245.131 | CHANGED | rc=0 >>

[root@ansible ~]# ansible web -m command -a "ls -l /etc/fstabtest"
192.168.245.131 | CHANGED | rc=0 >>
-rw-r--r--. 1 root root 0 12月  7 01:38 /etc/fstabtest
[root@ansible ~]# ansible web -m command -a "removes=/etc/fstab cat  /etc/fstab"
192.168.245.133 | CHANGED | rc=0 >>

#
# /etc/fstab
# Created by anaconda on Tue Nov 23 21:29:45 2021
#
# Accessible filesystems, by reference, are maintained under '/dev/disk'
# See man pages fstab(5), findfs(8), mount(8) and/or blkid(8) for more info
#
/dev/mapper/centos-root /                       xfs     defaults        0 0
UUID=bad63c62-92c6-49ff-9040-28dbc52d1c23 /boot                   xfs     defaults        0 0
/dev/mapper/centos-home /home                   xfs     defaults        0 0
/dev/mapper/centos-var  /var                    xfs     defaults        0 0

3)shell 模块

  shell模块可以在远程主机上调用shell解释器运行命令,支持shell的各种功能,例如管道等。

[root@server ~]# ansible web -m shell -a 'cat /etc/passwd |grep "keer"'
192.168.37.122 | SUCCESS | rc=0 >>
keer:x:10001:1000:keer:/home/keer:/bin/sh

192.168.37.133 | SUCCESS | rc=0 >>
keer:x:10001:10001::/home/keer:/bin/sh

4)copy 模块

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

src    #被复制到远程主机的本地文件。可以是绝对路径,也可以是相对路径。如果路径是一个目录,则会递归复制,用法类似于"rsync"
content   #用于替换"src",可以直接指定文件的值
dest    #必选项,将源文件复制到的远程主机的绝对路径
backup   #当文件内容发生改变后,在覆盖之前把源文件备份,备份文件包含时间信息
directory_mode    #递归设定目录的权限,默认为系统默认权限
force    #当目标主机包含该文件,但内容不同时,设为"yes",表示强制覆盖;设为"no",表示目标主机的目标位置不存在该文件才复制。默认为"yes"
others    #所有的 file 模块中的选项可以在这里使用

用法举例如下:
① 复制文件:

[root@ansible tmp]# ansible web -m copy -a 'src=/tmp/lsblk.sh dest=/tmp/'
192.168.245.131 | CHANGED => {
    "ansible_facts": {
        "discovered_interpreter_python": "/usr/bin/python"
    }, 
    "changed": true, 
    "checksum": "e1655e430bc0d0bb97dea7e9a7ea8711786279f6", 
    "dest": "/tmp/lsblk.sh", 
    "gid": 0, 
    "group": "root", 
    "md5sum": "531c25d2ad160eaa4fb01e0cc91a5c97", 
    "mode": "0644", 
    "owner": "root", 
    "secontext": "unconfined_u:object_r:admin_home_t:s0", 
    "size": 37, 
    "src": "/root/.ansible/tmp/ansible-tmp-1638814130.7-78317-182378212980552/source", 
    "state": "file", 
    "uid": 0
}

② 给定内容生成文件,并制定权限,(如果文件存在则直接覆盖)

[root@ansible tmp]# ansible web -m copy -a 'content="I an keer \n" dest=/tmp/lsblk.sh 
mode=600 owner=usertest'
192.168.245.132 | CHANGED => {
    "ansible_facts": {
        "discovered_interpreter_python": "/usr/bin/python"
    }, 
    "changed": true, 
    "checksum": "62c6cfacc06b9cb29635c49dfee4cc6d6e8088e6", 
    "dest": "/tmp/lsblk.sh", 
    "gid": 0, 
    "group": "root", 
    "md5sum": "dad17665841753e7c8ea7fc32f40e467", 
    "mode": "0644", 
    "owner": "root", 
    "secontext": "unconfined_u:object_r:admin_home_t:s0", 
    "size": 11, 
    "src": "/root/.ansible/tmp/ansible-tmp-1638814262.52-80986-149502365496099/source", 
    "state": "file", 
    "uid": 0
}


③ 关于覆盖
  我们把文件的内容修改一下,然后选择覆盖备份:

[root@server ~]# ansible web -m copy -a 'content="I am keerya\n" backup=yes dest=/data/name mode=666'
192.168.37.122 | SUCCESS => {
    "backup_file": "/data/name.4394.2017-12-06@09:46:25~", 
    "changed": true, 
    "checksum": "064a68908ab9971ee85dbc08ea038387598e3778", 
    "dest": "/data/name", 
    "gid": 0, 
    "group": "root", 
    "md5sum": "8ca7c11385856155af52e560f608891c", 
    "mode": "0666", 
    "owner": "root", 
    "size": 12, 
    "src": "/root/.ansible/tmp/ansible-tmp-1512438383.78-228128616784888/source", 
    "state": "file", 
    "uid": 0
}

5)file 模块

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

force  #需要在两种情况下强制创建软链接,一种是源文件不存在,但之后会建立的情况下;另一种是目标软链接已存在,需要先取消之前的软链,然后创建新的软链,有两个选项:yes|no
group  #定义文件/目录的属组。后面可以加上mode:定义文件/目录的权限
owner  #定义文件/目录的属主。后面必须跟上path:定义文件/目录的路径
recurse  #递归设置文件的属性,只对目录有效,后面跟上src:被链接的源文件路径,只应用于state=link的情况
dest  #被链接到的路径,只应用于state=link的情况
state  #状态,有以下选项:

directory:如果目录不存在,就创建目录
file:即使文件不存在,也不会被创建
link:创建软链接
hard:创建硬链接
touch:如果文件不存在,则会创建一个新的文件,如果文件或目录已存在,则更新其最后修改时间
absent:删除目录、文件或者取消链接文件

  用法举例如下:
 创建文件:

# 创建文件
# ansible web -m file -a 'path=/tmp/testfile state=touch mode=600 owner=yzg'
# 创建链接
# ansible web -m file -a 'src=/tmp/testfile path=/tmp/testfile-link state=link'
# 创建文件夹
# ansible web -m file -a 'path=/tmp/dir1 state=directory'
# 删除文件
# ansible web -m file -a 'path=/tmp/testfile state=absent'
# 删除目录
# ansible web -m file -a 'path=/tmp/ state=absent'

6)fetch 模块

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

dest:用来存放文件的目录
src:在远程拉取的文件,并且必须是一个file,不能是目录

  具体举例如下:

[root@ansible tmp]# ansible all -m fetch -a 'src=/tmp/lsblk.sh dest=/tmp/'
192.168.245.132 | CHANGED => {
    "changed": true, 
    "checksum": "62c6cfacc06b9cb29635c49dfee4cc6d6e8088e6", 
    "dest": "/tmp/192.168.245.132/tmp/lsblk.sh", 
    "md5sum": "dad17665841753e7c8ea7fc32f40e467", 
    "remote_checksum": "62c6cfacc06b9cb29635c49dfee4cc6d6e8088e6", 
    "remote_md5sum": null
}

  我们可以在本机上查看一下文件是否复制成功。要注意,文件保存的路径是我们设置的接收目录下的被管制主机ip目录下:

[root@ansible tmp]# tree .
.
├── 192.168.245.130
│   └── tmp
│       └── lsblk.sh

7)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_time
special_time #特殊的时间范围,参数:reboot(重启时),annually(每年),monthly(每月),weekly(每周),daily(每天),hourly(每小时)
state #指定状态,present表示添加定时任务,也是默认设置,absent表示删除定时任务
user # 以哪个用户的身份执行

  举例如下:
① 添加计划任务

[root@ansible tmp]# ansible centos8 -m cron -a 'minute=*/5 weekday=0,6 job="/usr/bin/wall cron job " name=testcron'
192.168.245.129 | CHANGED => {
    "ansible_facts": {
        "discovered_interpreter_python": "/usr/libexec/platform-python"
    }, 
    "changed": true, 
    "envs": [], 
    "jobs": [
        "testcron"
    ]
}
[root@ansible tmp]# ansible centos8 -m shell -a 'crontab -l'
192.168.245.129 | CHANGED | rc=0 >>
#Ansible: testcron
*/5 * * * 0,6 /usr/bin/wall cron job 


② 删除计划任务  如果我们的计划任务添加错误,想要删除的话,则执行以下操作:首先我们查看一下现有的计划任务:

[root@ansible tmp]# ansible centos8 -m shell -a 'crontab -l'
192.168.245.129 | CHANGED | rc=0 >>
#Ansible: testcron
#*/5 * * * 0,6 /usr/bin/wall cron job 
# state=absent  删除掉计划任务
# disabled=true 注释掉计划任务,true /false yes/no
[root@ansible tmp]# ansible centos8 -m cron -a 'state=absent minute=*/5 weekday=0,6 job="/usr/bin/wall cron job " name=testcron'192.168.245.129 | CHANGED => {
    "ansible_facts": {
        "discovered_interpreter_python": "/usr/libexec/platform-python"
    }, 
    "changed": true, 
    "envs": [], 
    "jobs": [
        "testcron"
    ]
}
[root@ansible tmp]# ansible centos8 -m shell -a 'crontab -l'
192.168.245.129 | CHANGED | rc=0 >>
#Ansible: testcron
#*/5 * * * 0,6 /usr/bin/wall cron job 
 
  
[root@ansible tmp]# ansible centos8 -m cron -a 'disabled=true minute=*/5 weekday=0,6 job="/usr/bin/wall cron job " name=testcron'
192.168.245.129 | CHANGED => {
    "ansible_facts": {
        "discovered_interpreter_python": "/usr/libexec/platform-python"
    }, 
    "changed": true, 
    "envs": [], 
    "jobs": [
        "testcron"
    ]
}
[root@ansible tmp]# ansible centos8 -m shell -a 'crontab -l'
192.168.245.129 | CHANGED | rc=0 >>
#Ansible: testcron
#*/5 * * * 0,6 /usr/bin/wall cron job 

8)yum 模块

  顾名思义,该模块主要用于软件的安装。
  其选项如下:

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

  下面我们就来安装一个包试试看:

# 安装软件包
[root@ansible ~]# ansible web -m yum -a 'name=dstat state=present'
192.168.245.133 | CHANGED => {
    "ansible_facts": {
        "discovered_interpreter_python": "/usr/bin/python"
    }, 
    "changed": true, 
    "changes": {
        "installed": [
            "dstat"
        ]
    }, 
    "msg": "", 
    "rc": 0, 
    "results": [
        "Loaded plugins: fastestmirror\nLoading mirror speeds from cached hostfile\n * base: mirrors.ustc.edu.cn\n * extras: mirrors.ustc.edu.cn\n * updates: mirrors.163.com\nResolving Dependencies\n--> Running transaction check\n---> Package dstat.noarch 0:0.7.2-12.el7 will be installed\n--> Finished Dependency Resolution\n\nDependencies Resolved\n\n================================================================================\n Package         Arch             Version                  Repository      Size\n================================================================================\nInstalling:\n dstat           noarch           0.7.2-12.el7             base           163 k\n\nTransaction Summary\n================================================================================\nInstall  1 Package\n\nTotal download size: 163 k\nInstalled size: 752 k\nDownloading packages:\nRunning transaction check\nRunning transaction test\nTransaction test succeeded\nRunning transaction\n  Installing : dstat-0.7.2-12.el7.noarch                                    1/1 \n  Verifying  : dstat-0.7.2-12.el7.noarch                                    1/1 \n\nInstalled:\n  dstat.noarch 0:0.7.2-12.el7                                                   \n\nComplete!\n"
    ]
}
# 删除软件包
[root@ansible ~]# ansible web -m yum -a 'name=dstat state=absent'
192.168.245.130 | CHANGED => {
    "ansible_facts": {
        "discovered_interpreter_python": "/usr/bin/python"
    }, 
    "changed": true, 
    "changes": {
        "removed": [
            "dstat"
        ]
    }, 
    "msg": "", 
    "rc": 0, 
    "results": [
        "已加载插件:fastestmirror\n正在解决依赖关系\n--> 正在检查事务\n---> 软件包 dstat.noarch.0.0.7.2-12.el7 将被 删除\n--> 解决依赖关系完成\n\n依赖关系解决\n\n================================================================================\n Package         架构             版本                    源               大小\n================================================================================\n正在删除:\n dstat           noarch           0.7.2-12.el7            @base           752 k\n\n事务概要\n================================================================================\n移除  1 软件包\n\n安装大小:752 k\nDownloading packages:\nRunning transaction check\nRunning transaction test\nTransaction test succeeded\nRunning transaction\n  正在删除    : dstat-0.7.2-12.el7.noarch                                   1/1 \n  验证中      : dstat-0.7.2-12.el7.noarch                                   1/1 \n\n删除:\n  dstat.noarch 0:0.7.2-12.el7                                                   \n\n完毕!\n"
    ]
}
# 查看是否安装
[root@ansible ~]# ansible web -m shell -a 'rpm -q dstat'
192.168.245.132 | FAILED | rc=1 >>
未安装软件包 dstat non-zero return code
192.168.245.131 | FAILED | rc=1 >>
未安装软件包 dstat non-zero return code
192.168.245.130 | FAILED | rc=1 >>
未安装软件包 dstat non-zero return code
192.168.245.133 | FAILED | rc=1 >>
未安装软件包 dstat non-zero return code

9)service 模块

  该模块用于服务程序的管理。
  其主要选项如下:

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

  下面是一些例子:
① 开启服务并设置自启动

# 启动服务
[root@ansible ~]# ansible web -m service -a 'name=httpd state=started enabled=true'
192.168.245.130 | CHANGED => {
    "ansible_facts": {
        "discovered_interpreter_python": "/usr/bin/python"
    }, 
...
# 查看服务是否启动
[root@ansible ~]# ansible web -m shell -a 'ss -ntl '
192.168.245.131 | CHANGED | rc=0 >>
State      Recv-Q Send-Q Local Address:Port               Peer Address:Port              
LISTEN     0      128          *:22                       *:*                  
LISTEN     0      100    127.0.0.1:25                       *:*                  
LISTEN     0      128       [::]:80                    [::]:*                  
LISTEN     0      128       [::]:22                    [::]:*                  
LISTEN     0      100      [::1]:25                    [::]:*              


② 关闭服务

# 关闭服务
[root@ansible ~]# ansible web -m service -a 'name=httpd state=stopped'
192.168.245.133 | CHANGED => {
    "ansible_facts": {
        "discovered_interpreter_python": "/usr/bin/python"
    }, 
...
# 查看端口
[root@ansible ~]# ansible web -m shell -a 'ss -ntl'
192.168.245.131 | CHANGED | rc=0 >>
State      Recv-Q Send-Q Local Address:Port               Peer Address:Port              
LISTEN     0      128          *:22                       *:*                  
LISTEN     0      100    127.0.0.1:25                       *:*                  
LISTEN     0      128       [::]:22                    [::]:*                  
LISTEN     0      100      [::1]:25                    [::]:*             

10)user 模块

  该模块主要是用来管理用户账号。
  其主要选项如下:

comment  # 用户的描述信息
createhome  # 是否创建家目录
force  # 在使用state=absent时, 行为与userdel –force一致.
group  # 指定基本组
groups  # 指定附加组,如果指定为(groups=)表示删除所有组
home  # 指定用户家目录
move_home  # 如果设置为home=时, 试图将用户主目录移动到指定的目录
name  # 指定用户名
non_unique  # 该选项允许改变非唯一的用户ID值
password  # 指定用户密码
remove  # 在使用state=absent时, 行为是与userdel –remove一致,会产出家目录
shell=  # 指定默认shell
state  # 设置帐号状态,不指定为创建,指定值为absent表示删除
system=yes  # 当创建一个用户,设置这个用户是系统用户。这个设置不能更改现有用户
uid  # 指定用户的uid

  举例如下:
① 添加一个用户并指定其 uid

# 创建用户
[root@ansible ~]# ansible web -m user -a 'name=test1 comment="testuser 1" uid=2000 home=/tmp/test1 group=yzg groups=root,bin' 
192.168.245.132 | CHANGED => {
    "ansible_facts": {
        "discovered_interpreter_python": "/usr/bin/python"
    }, 
    "changed": true, 
    "comment": "testuser 1", 
    "create_home": true, 
    "group": 1000, 
    "groups": "root,bin", 
    "home": "/tmp/test1", 
    "name": "test1", 
    "shell": "/bin/bash", 
    "state": "present", 
    "system": false, 
    "uid": 2000
}

# 查看用户
[root@ansible ~]# ansible web -m shell -a 'getent passwd test1'
192.168.245.131 | CHANGED | rc=0 >>
test1:x:2000:1000:testuser 1:/tmp/test1:/bin/bash

# 删除用户
[root@ansible ~]# ansible web -m user -a 'name=test1 state=absent'
192.168.245.130 | CHANGED => {
    "ansible_facts": {
        "discovered_interpreter_python": "/usr/bin/python"
    }, 
    "changed": true, 
    "force": false, 
    "name": "test1", 
    "remove": false, 
    "state": "absent"
}

11)group 模块

  该模块主要用于添加或删除组。
  常用的选项如下:

gid=  #设置组的GID号
name=  #指定组的名称
state=  #指定组的状态,默认为创建,设置值为absent为删除
system=  #设置值为yes,表示创建为系统组

  举例如下:
 

# 创建组
[root@ansible ~]# ansible web -m group -a 'name=grouptest gid=1234'
192.168.245.130 | CHANGED => {
    "ansible_facts": {
        "discovered_interpreter_python": "/usr/bin/python"
    }, 
    "changed": true, 
    "gid": 1234, 
    "name": "grouptest", 
    "state": "present", 
    "system": false
}

# 查看组
[root@ansible ~]# ansible web -a 'getent group grouptest'
192.168.245.131 | CHANGED | rc=0 >>
grouptest:x:1234:

# 删除组
[root@ansible ~]# ansible web -m group -a 'name=grouptest state=absent'
192.168.245.132 | CHANGED => {
    "ansible_facts": {
        "discovered_interpreter_python": "/usr/bin/python"
    }, 
    "changed": true, 
    "name": "grouptest", 
    "state": "absent"
}

12)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 

[root@server ~]# ansible web -m script -a '/tmp/df.sh'
192.168.37.122 | SUCCESS => {
    "changed": true, 
    "rc": 0, 
    "stderr": "Shared connection to 192.168.37.122 closed.\r\n", 
    "stdout": "", 
    "stdout_lines": []
}

13)setup 模块

  该模块主要用于收集信息,是通过调用facts组件来实现的。
  facts组件是Ansible用于采集被管机器设备信息的一个功能,我们可以使用setup模块查机器的所有facts信息,可以使用filter来查看指定信息。整个facts信息被包装在一个JSON格式的数据结构中,ansible_facts是最上层的值。
  facts就是变量,内建变量 。每个主机的各种信息,cpu颗数、内存大小等。会存在facts中的某个变量中。调用后返回很多对应主机的信息,在后面的操作中可以根据不同的信息来做不同的操作。如redhat系列用yum安装,而debian系列用apt来安装软件。
① 查看信息
  我们可以直接用命令获取到变量的值,具体我们来看看例子:

# 查看所有变量
# ansible web -m setup -a 
# ansible web -m setup -a  'filter=*hostname*'
# ansible web -m setup -a  'filter=ansible_hostname'
# 显示完整地主机名,如yzg-101.com.cn,ansible_hostname只显示yzg-101,ansible_nodename则可以显示完整主机名。
# ansible web -m setup -a  'filter=ansible_nodename'
# 显示完整地主机名
# ansible web -m setup -a  'filter=ansible_fqdn'
# 查看内存
[root@ansible ~]# ansible web -m setup -a 'filter="*mem*"'
192.168.245.130 | SUCCESS => {
    "ansible_facts": {
        "ansible_memfree_mb": 1521, 
        "ansible_memory_mb": {
            "nocache": {
                "free": 1619, 
                "used": 223
            }, 
            "real": {
                "free": 1521, 
                "total": 1842, 
                "used": 321
            }, 
            "swap": {
                "cached": 0, 
                "free": 0, 
                "total": 0, 
                "used": 0
            }
        }, 
        "ansible_memtotal_mb": 1842, 
        "discovered_interpreter_python": "/usr/bin/python"
    }, 
    "changed": false
}


② 保存信息
  我们的setup模块还有一个很好用的功能就是可以保存我们所筛选的信息至我们的主机上,同时,文件名为我们被管制的主机的IP,这样方便我们知道是哪台机器出的问题。
  我们可以看一看例子:

# 结果保存到facts文件,方便查看
[root@ansible ~]# ansible web -m setup -a 'filter="*mem*"' --tree /tmp/facts
192.168.245.131 | SUCCESS => {
    "ansible_facts": {
        "ansible_memfree_mb": 1521, 
        "ansible_memory_mb": {
            "nocache": {
                "free": 1621, 
                "used": 221
            }, 
            "real": {
                "free": 1521, 
                "total": 1842, 
                "used": 321
            }, 
            "swap": {
                "cached": 0, 
                "free": 0, 
                "total": 0, 
                "used": 0
            }
        }, 
        "ansible_memtotal_mb": 1842, 
        "discovered_interpreter_python": "/usr/bin/python"
    }, 
    "changed": false
}

[root@ansible ~]# cat /tmp/facts/192.168.245.132 
{"ansible_facts": {"ansible_memfree_mb": 1516, "ansible_memory_mb": {"nocache": {"free": 1616, "used": 226}, "real": {"free": 1516, "total": 1842, "used": 326}, "swap": {"cached": 0, "free": 0, "total": 0, "used": 0}}, "ansible_memtotal_mb": 1842, "discovered_interpreter_python": "/usr/bin/python"}, "changed": false}

下载角色

ansible-galaxy

ansible-galaxy collection install nginxinc.nginx_core

ansible-galaxy install geerlingguy.nginx 

Ansible-vault

功能:管理加密解密yml文件

ansible-vault [create|decrypt|edit|encrypt|rekey|view]
 

# 加密yml文件
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:

2.0+新增,可交互执行命令,支持tab

root@test (2)[f:10] $ 执行用户@当前操作的主机组 (当前组的主机数量)[f:并发数]$

设置并发数: forks n 例如: forks 10

切换组: cd 主机组 例如: cd web

列出当前组主机列表: list

列出所有的内置命令: ?或help

示例:

root@all (2)[f:5]$ list

root@all (2)[f:5]$ cd appsrvs

root@appsrvs (2)[f:5]$ list

root@appsrvs (2)[f:5]$ yum name=httpd state=present

root@appsrvs (2)[f:5]$ service name=httpd state=started

Ansible playbook格式

1)格式简介

  playbook由YMAL语言编写。YAML( /ˈjæməl/ )参考了其他多种语言,包括:XML、C语言、Python、Perl以及电子邮件格式RFC2822,Clark Evans在2001年5月在首次发表了这种语言,另外Ingy döt Net与OrenBen-Kiki也是这语言的共同设计者。
  YMAL格式是类似于JSON的文件格式,便于人理解和阅读,同时便于书写。首先学习了解一下YMAL的格式,对我们后面书写playbook很有帮助。以下为playbook常用到的YMAL格式:
  1、文件的第一行应该以 "---" (三个连字符)开始,表明YMAL文件的开始。
  2、在同一行中,#之后的内容表示注释,类似于shell,python和ruby。
  3、YMAL中的列表元素以”-”开头然后紧跟着一个空格,后面为元素内容。
  4、同一个列表中的元素应该保持相同的缩进。否则会被当做错误处理。
  5、play中hosts,variables,roles,tasks等对象的表示方法都是键值中间以":"分隔表示,":"后面还要增加一个空格。

  下面是一个举例:

---
#安装与运行mysql服务
- hosts: node1
  remote_user: root
  tasks:
  
    - name: install mysql-server package
      yum: name=mysql-server state=present
    - name: starting mysqld service
      service: name=mysql state=started

我们的文件名称应该以.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、报告结果

企业级自动化运维工具-ansible_第3张图片

2)核心元素

  Playbook的核心元素:

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

3)基本组件

  Playbooks配置文件的基础组件:

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指定进行调用;

举例

[root@ansible ansible]# cat test1.yml 
---
- hosts: centos8
  remote_user: root
  tasks: 
    - name: install pack
      yum: 
        name: httpd 
        state: present
    - name: start service 
      service: 
        name: httpd 
        state: started
        enabled: true
          
[root@ansible ansible]# cat nginx.yml
---
- hosts: web
  remote_user: root
  tasks:
    - name: install nginx
        yum: 
          name: nginx 
          state: present
    - name: copy nginx.conf
        copy: 
          src: /tmp/nginx.conf 
          dest: /etc/nginx/nginx.conf 
          backup: yes
      notify: reload    #当nginx.conf发生改变时,通知给相应的handlers
      tags: reloadnginx   #打标签
    - name: start nginx service
        service: 
          name: nginx 
          state: started
      tags: startnginx   #打标签

  handlers:  #注意,前面没有-,是两个空格
    - name: reload
        service: 
          name: nginx 
          state: restarted  #为了在进程中能看出来



[root@ansible ansible]# ansible-playbook test1.yml --list-hosts

playbook: test1.yml

  play #1 (centos8): centos8    TAGS: []
    pattern: [u'centos8']
    hosts (1):
      192.168.245.129
[root@ansible ansible]# ansible-playbook test1.yml --list-tasks

playbook: test1.yml

  play #1 (centos8): centos8    TAGS: []
    tasks:
      install pack      TAGS: []
      start service     TAGS: []

# 指定某台机器执行
 ansible-playbook --limit 192.168.245.131 httpd.yml

案例

# 安装httpd ,拷贝配置文件,启动服务
[root@ansible ansible]# cat httpd.yml 
--- 
- hosts: web
  remote_user: root
  tasks: 
    - name: install httpd
      yum:
        name: httpd
    - name: copy config
      copy: 
        src: /app/httpd.conf 
        dest: /etc/httpd/conf/
        backup: yes
    - name: start httpd
      service: 
        name: httpd
        state: started
        enabled: yes

Handlers

是task列表,这些task与前述的task并没有本质上的不同,用于当关注的资源发生变化时,才会采取一定的操作。

notify这个action可用于在每个play的最后被触发,这样可以避免多次有改变发生时每次都执行指定的操作,仅在所有的变化发生完成后一次性地执行指定操作。在notify中列出的操作称为handler,也即notify中调用handler中定义的操作。

# 当copy模块发生变化时执行notify任务,hadlers
[root@ansible ansible]# cat httpd.yml 
--- 
- hosts: web
  remote_user: root
  tasks: 
    - name: install httpd
      yum:
        name: httpd
    - name: copy config
      copy: 
        src: /app/httpd.conf 
        dest: /etc/httpd/conf/
        backup: yes
      notify: restart httpd
    - name: start httpd
      service: 
        name: httpd
        state: started
        enabled: yes
    
  handlers:
    - name: restart httpd
      service: 
        name: httpd 
        state: restarted
          

remote_root: 可用于host和task中,也可以通过指定其通过sudo的方式在远程主机上执行任务,其可用于play全局或某任务;此外,甚至可以在sudo时使用sudo_user指定sudo时切换的用户。

- hosts: web
  remote_user: root
  tasks:
  - name: test connection
    ping:
    remote_user: yzg
    sudu: yes    #默认sudo为root
    sudo_user: testuser  # sudo为testuser

    
# 如果命令或脚本的退出码不为零,可以使用如下方式替代
     tasks: 
       - name: run this command and ignore the result
         shell: /usr/bin/somecommand || /bin/true
# 或者使用ignore_errors来忽略错误信息
     tasks:
       - name: run this command and ignore the result
         shell: /usr/bin/somecommand 
         ignore_errors: True

 tags标签的使用(标签名可以重复)

[root@ansible ansible]# cat httpd.yml 
--- 
- hosts: web
  remote_user: root
  tasks: 
    - name: install httpd
      yum:
        name: httpd
    - name: copy config
      copy: 
        src: /app/httpd.conf 
        dest: /etc/httpd/conf/
        backup: yes
      notify: restart httpd
      tags: conf
    - name: start httpd
      service: 
        name: httpd
        state: started
        enabled: yes
      tags: service
  handlers:
    - name: restart httpd
      service: 
        name: httpd 
        state: restarted

# 执行时指定标签,则单独执行标签内的语句
# ansible-playbook -t conf httpd.yml

playbook 中变量使用

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

变量来源:

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

在/etc/ansible/hosts中定义
    普通变量:主机组中主机单独定义,优先级高于公共变量
    公共(组)变量:针对主机组中所有主机定义统一变量

通过命令行指定变量,优先级最高
 ansible-playbook -e varname-value

在playbook中定义
    vars:
    - var1: value1
    - var2: value2

在role中定义

变量应用

[root@ansible ansible]# cat pack.yml 
---
- hosts: web
  remote_user: root
  
  tasks:
    - name: install package
      yum: 
        name: "{{ pkname }}"
    - name: copyfile
      copy: 
        src: /app/{{ filename }}
        dest: /app/

# ansible-playbook -e "pkname=vsftpd filename=httpd.conf"  pack.yml
[root@ansible ansible]# cat v.yml 
---
- hosts: web
  remote_user: root
  vars:   
    - username: user1
    - groupname: group1
  tasks: 
    - name: create group
      group: 
        name: "{{ groupname }}"
    - name: create user
      user:
        name: "{{ username }}"
        group: "{{ groupname }}"
        home: /app/{{ username }}dir


#执行
# ansible-playbook v.yml 
# ansible web -a 'getent passwd user1'
# ansible web -a 'id user1'
# ansible web -m shell -a 'ls /app/user1dir/'
# 利用setup变量
[root@ansible ansible]# cat file.yml 
---
- hosts: web
  remote_user: root
  tasks:
    - name: create file
      file:
        name: /app/{{ ansible_hostname }}.txt 
        state: touch 
# ansible-playbook file.yml
# cat /etc/ansible/hosts
[web]
192.168.245.130   http_port=80
192.168.245.131   http_port=81
192.168.245.132   http_port=82
192.168.245.133   http_port=83

# ansible web -m hostname -a 'name=web{{ http_port }}'
# cat /etc/ansible/hosts 
[web]
192.168.245.130   http_port=80 hname=httpd
192.168.245.131   http_port=81 hname=nginx
192.168.245.132   http_port=82 hname=firefox
192.168.245.133   http_port=83 hname=chrome

[root@ansible ansible]# cat name.yml 
---
- hosts: web
  remote_user: root
  tasks: 
    - name: set hostname
      hostname: 
        name: '{{ hname }}-{{ http_port }}'

# ansible-playbook  name.yml 
#  vim /etc/ansible/hosts
[web]
192.168.245.130   http_port=80 
192.168.245.131   http_port=81 
192.168.245.132   http_port=82 
192.168.245.133   http_port=83 
[web:vars]
hname=web
#定义web组公共变量

[root@ansible ansible]# cat name.yml 
---
- hosts: web
  remote_user: root
  tasks: 
    - name: set hostname
      hostname: 
        name: '{{ hname }}-{{ http_port }}'

# ansible-playbook  name.yml 
# 定义和调用变量yml文件
[root@ansible ansible]# cat vars.yml 
var1: httpd
var2: nginx

[root@ansible ansible]# cat var1.yml 
--- 
- hosts: web
  remote_user: root
  vars_files:
    - vars.yml
  tasks: 
    - name: create file
      file: 
        name: /app/{{ var1 }}-{{ var2 }}.log
        state: touch
        mode: 600 
        owner: yzg

# ansible-playbook  var1.yml 
# playbook和变量文件在同一个目录内

[root@ansible ansible]# ansible web -m shell -a 'ls /app/'
192.168.245.132 | CHANGED | rc=0 >>
httpd-nginx.log

模板 templates

文本文件,嵌套有脚本(使用模板编程语言编写)

Jinja2语言,使用字面量,有下面形式

  字符串:使用单引号或双引号

  数字:整数,浮点数

   列表:[item1, item2, ...]

  元组:(item1, item2, ...)

  字典:{key1:value1, key2:value2, ...}

  布尔型:true/false

算术运算:+, -, *, /, //, %, **

                   // 除取整数,** 指数(4**2,4的2次方16   )

比较操作:==, !=, >, >=, <, <=

逻辑运算:and, or, not

流表达式:For If When

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

        templates文件必须存放于templates目录下,且命名为.j2 结尾

        yaml/yml 文件需和templates目录平级,目录结构如下:

[root@ansible temp]# tree ./
./
├── templates
│   └── test.conf.j2
└── temptest.yml

实例

# templates 目录里httpd.conf.j2是httpd的配置文件,把配置文件拷贝到web组主机

[root@ansible ansible]# cat temphttpd.yml 
---
- hosts: web
  remote_user: root
  
  tasks: 
    - name: template
      template: 
        src: httpd.conf.j2
        dest: /etc/httpd/conf/httpd.conf

实例

# cat /etc/ansible/hosts  #定义变量,每台机器的端口
[web]
192.168.245.130   http_port=80
192.168.245.131   http_port=81
192.168.245.132   http_port=82 
192.168.245.133   http_port=83

# 模板文件配置,进程数根据cpu核心数*2,端口号来自hosts文件定义的变量
[root@ansible ansible]# cat templates/nginx.conf.j2
worker_processes {{ ansible_processor_vcpus*2 }};
server {
        listen       {{http_port}};
        listen       [::]:{{http_port}};
        server_name  _;
        root         /usr/share/nginx/html;
        ...


# 安装、修改配置,启动服务
[root@ansible ansible]# cat temnginx.yml
--- 
- hosts: web
  remote_user: root
  #vars: 
  #  - http_port: 8080
  tasks:
    - name: install
      yum: 
        name: nginx
        state: present
    - name: copytmp
      template:
        src: nginx.conf.j2
        dest: /etc/nginx/nginx.conf
      tags: copytmp
      notify: restart nginx    
    - name: service start
      service:
        name: nginx
        state: started
        enabled: yes
  handlers:
    - name: restart nginx
      service: 
        name: nginx
        state: started   

when 

条件测试:如果需要根据变量、facts或此前任务的执行结果来做为某task执行与否的前提时要做到条件测试,通过when语句实现,在task中使用,jinja2的语句格式。

when语句

在task后添加when字句即可使用条件测试;when语句支持jinja2表达式语法

实例:

# templates 目录里httpd.conf.j2是httpd的配置文件,把配置文件拷贝到web组主机

[root@ansible ansible]# cat temphttpd.yml 
---
- hosts: web
  remote_user: root
  
  tasks: 
    - name: template 7
      template: 
        src: httpd_7.conf.j2
        dest: /etc/httpd/conf/httpd.conf
      when: ansible_distribution_major_version=="7"
    - name: template 8
      template: 
        src: httpd_8.conf.j2
        dest: /etc/httpd/conf/httpd.conf
      when: ansible_distribution_major_version=="8"
    - name: start
      service: 
        name: httpd
        state: started

迭代:with_items

迭代:当有需要重复性执行的任务时,可以使用迭代机制

        对迭代项的引用,固定变量名为“item”

        要在task中使用with_items给定要迭代的元素列表

        列表格式:

                字符串

                字典

# 实例:

#  创建用户,复制文件
---
- hosts: web
  remote_root: root
  tasks:
    - name: add users
      user:
        name: {{ item }} 
        state: present
        groups: wheel
      with_items:
        - testuser1
        - testuser2
    - name: copyfile
      copy:
        src: /app/{{ item }} 
        dest: /etc/{{ item }}
      with_items:
        - file1
        - file2
    - name: copyfile2
      copy:
        src: {{ item }} 
        dest: /app/
      with_items:
        - /app/file1
        - /app/file2
    - name: install 
      yum: 
        name: {{ item }}
        state: present
      with_items:
        - httpd
        - vsftpd
        - apr
# 等同于下面的语句
    - name: add users
      user:
        name: testuser1 
        state: present
        groups: wheel
    - name: add users
      user:
        name: testuser2 
        state: present
        groups: wheel
    - name: copyfile1
      copy:
        src: /app/file1 
        dest: /etc/file1
    - name: copyfile2
      copy:
        src: /app/file2 
        dest: /etc/file2

迭代嵌套子变量

# 实例
---
- hosts: web
  remote_user: root
  
  tasks:
    - name: create groups
      group: 
        user: {{ item }}
      with_items:
        - newgoups1
        - newgoups2
        - newgoups3
    - name: create user
      user: 
        name: {{ item.newuser }}
        group: {{ item.groups }}
      with_items:
        - {newuser:'newuser1',groups:'newgroups1'}
        - {newuser:'newuser2',groups:'newgroups2'}       
        - {newuser:'newuser3',groups:'newgroups3'}

 Playbook中template for if

# Playbook中template for if
{% for vhost in nginx_vhosts %}
server {
listen {{ vhost.listen | default('80 default_server') }};
{% endfor %}

{% if vhost.server_name is defined %}
server_name {{ vhost.server_name }};
{% endif %}

{% if vhost.root is defined %}
root {{ vhost.root }};
{% endif %}
# 实例
[root@ansible ansible]# cat templates/for1.conf.j2 
{%for port in ports%}
server{
        listen {{ port }};
}
{%endfor%}

[root@ansible ansible]# cat for1.yml 
---
- hosts: web
  remote_user: root
  vars: 
    ports:
      - 81
      - 82
      - 83
      - 84
  tasks: 
    - name: test for1
      template: 
        src: for1.conf.j2
        dest: /app/for1.conf
    

[root@ansible ansible]# cat templates/for2.conf.j2 
{%for vhost in vhosts%}
server{
        listen {{ vhost.port }};
        servername {{ vhost.name }};
        rootdir {{ vhost.root }};
}
{%endfor%}

[root@ansible ansible]# cat for2.yml 
---
- hosts: web
  remote_user: root
  vars: 
    vhosts:
      - web1:
        port: 82
        name: web1.yzg.com
        root: /app/webroot1
      - web2:
        port: 83
        name: web3.yzg.com
        root: /app/webroot3
      - web3:
        port: 84
        name: web4.yzg.com
        root: /app/webroot4
  tasks:
    - name: test for2
      template: 
        src: for2.conf.j2
        dest: /app/for2.conf
[root@ansible ansible]# cat templates/for3.conf.j2 
{%for vhost in vhosts%}
server{
        listen {{ vhost.port }};
# 判断vhost.name的值是否被定义,如果定义了就引用,没定义就不管
{%if vhost.name is defined%}
        servername {{ vhost.name }};
{%endif%}
        rootdir {{ vhost.root }};
}
{%endfor%}

[root@ansible ansible]# cat for3.yml 
---
- hosts: web
  remote_user: root
  vars: 
    vhosts:
      - web1:
        port: 82
        root: /app/webroot1
      - web2:
        port: 83
        root: /app/webroot3
      - web3:
        port: 84
        name: web4.yzg.com
        root: /app/webroot4
  tasks:
    - name: test for2
      template: 
        src: for3.conf.j2
        dest: /app/for3.conf

roles

ansilbe自1.2版本引入的新特性,用于层次性、结构化地组织playbook。

roles能够根据层次型结构自动装载变量文件、 tasks以及handlers等。

要使用roles只需要在playbook中使用 import_tasks指令即可。

简单来讲,roles就是通过分别将变量、文件 、任务、模板及处理器放置于单独的目录中,并可以便捷地 include它们的一种机制。

角色一般用于基于主机构建服务的场 景中,但也可以是用于构建守护进程等场景中

复杂场景:建议使用roles,代码复用度高

        变更指定主机或主机组

        如命名不规范维护和传承成本大

        某些功能需多个Playbook,通过Includes即可实现

角色(roles):角色集合
    roles/
      mysql/
      httpd/
      nginx/
      memcached/

企业级自动化运维工具-ansible_第4张图片

 roles目录结构

# 每个角色,以特定的层级目录结构进行组织
# roles目录结构:
  playbook.yml
  roles/
    project/
      tasks/
      files/
      vars/      #不常用
      default/   #不常用
      templates/
      handlers/
      meta/   #不常用

实例

# roles目录结构
[root@ansible ansible]# tree
.
├── filecopy_roles.yml
├── nginx_roles.yml
├── roles
│   ├── filecopy
│   │   ├── files
│   │   │   └── fstab
│   │   └── tasks
│   │       └── main.yml
│   ├── memcached
│   └── nginx
│       ├── tasks
│       │   ├── groupadd.yml
│       │   ├── install.yml
│       │   ├── main.yml
│       │   ├── start.yml
│       │   ├── stop.yml
│       │   └── useradd.yml
│       ├── templates
│       └── vars
└── roles-tags.yml

[root@ansible ansible]# cat roles/nginx/tasks/groupadd.yml 
- name: add group
  group:
    name: nginx
[root@ansible ansible]# cat roles/nginx/tasks/install.yml 
- name: install pack
  yum: 
    name: nginx
[root@ansible ansible]# cat roles/nginx/tasks/start.yml 
- name: install service
  service:  
    name: nginx
    state: started
    enabled: yes
[root@ansible ansible]# cat roles/nginx/tasks/stop.yml 
- name: stop service
  service: 
    name: nginx
    state: stopped
[root@ansible ansible]# cat roles/nginx/tasks/useradd.yml 
- name: add user
  user: 
    name: nginx
    group: nginx
    system: yes
    shell: /sbin/nologin

# 按执行顺序写
[root@ansible ansible]# cat roles/nginx/tasks/main.yml 
- import_tasks: groupadd.yml
- import_tasks: useradd.yml
- import_tasks: install.yml
- import_tasks: stop.yml
- import_tasks: start.yml

# 这里拷贝和创建文件写在一起了,拷贝的文件放在files文件夹内,src可以不写具体路径。
[root@ansible ansible]# cat roles/filecopy/tasks/main.yml 
- name: filecopy
  copy: 
    src: fstab
    dest: /app/
- name: create file
  file: 
    name: /app/testfile 
    mode: '600'
    state: touch
# 这里是在filecopy角色中调用了nginx的stop任务。跨角色调用
- import_tasks: roles/nginx/tasks/stop.yml


[root@ansible ansible]# cat nginx_roles.yml 
---
- hosts: web
  remote_user: root
  
  roles:
    - role: nginx
    - role: filecopy      #  这里还可以调用多个roles角色


[root@ansible ansible]# cat filecopy_roles.yml 
---
- hosts: web
  remote_user: root
  
  roles:
    - role: filecopy


# 给角色打标签,每个角色可以打多个标签,执行的时候可以写多个角色。
[root@ansible ansible]# cat roles-tags.yml 
---
- hosts: web
  remote_user: root
  
  roles:
    - { role: nginx, tags: ['nginx','web'] }
    - { role: httpd, tags: ['httpd','web'] }
    - { role: memcached, tags: 'cache' }
    - { role: mysql, tags: 'db' }
# 短格式写法 
  roles:
    - role: nginx
      tags: '"nginx" "web"'
    - role: httpd
      tags: '"httpd" "web"'
    - role: memcached 
      tags: cache
    - role: mysql
      tags: db

#
# 执行web标签角色,会执行nginx角色和httpd角色。
ansible-playbook -C -t web roles-tags.yml 
# 
ansible-playbook -C -t "web,db" roles-tags.yml

roles案例

# 安装nginx服务,拷贝模板、启动
# 目录结构
[root@ansible ansible]# tree roles/nginx/
roles/nginx/
├── handlers
│   └── main.yml
├── tasks
│   └── main.yml
├── templates
│   └── nginx.conf.j2
└── vars

[root@ansible ansible]# cat roles/nginx/tasks/main.yml 
- name: install package
  yum: 
    name: nginx
- name: template
  template: 
    src: nginx.conf.j2
    dest: /etc/nginx/nginx.conf
  notify: restart service
  tags: tempfile   # 给任务加标签 ,执行标签任务ansible-playbook -t tempfile test_roles.yml
- name: start service
  service: 
    name: nginx 
    state: started
# 
[root@ansible ansible]# cat roles/nginx/handlers/main.yml 
- name: restart service
  service: 
    name: nginx
    state: restarted

# 模板这里进程数引用ansible的变量来获取并乘以2
[root@ansible ansible]# cat roles/nginx/templates/nginx.conf.j2 | grep ansible
worker_processes {{ ansible_processor_vcpus*2}};

# 执行测试验证
ansible-playbook test_roles.yml

ansible web -m shell -a 'ps aux | grep nginx'
ansible web -m shell -a 'ss -ntlp'

# 加入变量测试
[root@ansible ansible]# cat roles/nginx/vars/main.yml 
http_port: 8080

[root@ansible ansible]# cat roles/nginx/templates/nginx.conf.j2 | grep -C3 listen
    include /etc/nginx/conf.d/*.conf;

    server {
        listen       {{ http_port }};
        listen       [::]:{{ http_port }};
        server_name  _;
        root         /usr/share/nginx/html;3

[root@ansible ansible]# cat test_roles.yml 
- hosts: web
  remote_user: root
    
  roles: 
    - role: nginx

# 执行测试验证
ansible-playbook test_roles.yml

ansible web -m shell -a 'ps aux | grep nginx'
ansible web -m shell -a 'ss -ntlp'

# 加入条件判断,只有centos7版本才执行
[root@ansible ansible]# cat test_roles.yml 
- hosts: all
  remote_user: root
    
  roles: 
    - role: nginx
      when: ansible_distribution_major_version=='7'
      http_port: 9090   # 这里还可以定义变量,会替代vars里定义的变量

# 执行测试验证
ansible-playbook test_roles.yml

# 执行多个角色
[root@ansible ansible]# cat test_roles.yml 
- hosts: all
  remote_user: root
    
  roles: 
    - role: nginx
      when: ansible_distribution_major_version=='7' 
      http_port: 9090
    - role: filecopy
      when: ansible_nodename=='yzg_01'  #条件为主机名为yzg_01才执行filecopy角色

实例:安装memcached

[root@ansible roles]# tree memcached/
memcached/
├── tasks
│   └── main.yml
└── templates
    └── memcached.j2

[root@ansible roles]# cat memcached/tasks/main.yml 
- name: install package
  yum: 
    name: memcached
- name: template
  template: 
    src: memcached.j2
    dest: /etc/sysconfig/memcached
- name: start service
  service: 
    name: memcached
    state: started
    enabled: yes
# 模板文件,缓存大小调整为内存大小的四分之一,取整
[root@ansible roles]# cat memcached/templates/memcached.j2 
PORT="11211"
USER="memcached"
MAXCONN="1024"
CACHESIZE="{{ ansible_memtotal_mb//4 }}"
OPTIONS=""


[root@ansible ansible]# cat test_roles1.yml 
- hosts: all
  remote_user: root
    
  roles: 
    - role: memcached
      when: ansible_distribution_major_version=='7'

你可能感兴趣的:(ansible,运维,自动化,devops)