ansible批量管理服务

ansible.png

  1. 提高工作的效率
  2. 提高工作准确度
  3. 减少维护的成本
  4. 减少重复性工作
  5. 批量系统操作配置
  6. 批量软件服务部署
  7. 批量文件数据分发
  8. 批量系统信息收集

ansible批量管理服务部署

服务 主机名 eth0网卡IP eth1网卡IP 软件
防火墙服务器 firewalld 10.0.0.81 172.16.1.81 firewalld
负载均衡服务器 lb01 10.0.0.5 172.16.1.5 nginx,keepalived
负载均衡服务器 lb02 10.0.0.6 172.16.1.6 nginx,keepalived
web服务器 web01 10.0.0.7 172.16.1.7 nginx
web服务器 web02 10.0.0.8 172.16.1.8 nginx
web服务器 web03 10.0.0.9 172.16.1.9 nginx
存储服务器 nfs01 10.0.0.31 172.16.1.31 nfs
备份服务器 backup 10.0.0.41 172.16.1.41 rsync
数据库服务器 db01 10.0.0.51 172.16.1.51 mysql,mariaDB
批量管理服务器 m01 10.0.0.61 172.16.1.61 ansible
跳板机服务器 jumpserver 10.0.0.71 172.16.1.71 jumpserver
监控服务器 zabbix 10.0.0.72 172.16.1.72 zabbix
缓存服务器 暂无 暂无 暂无 暂无

安装部署软件

#需要配置epel的yum源
yum install -y ansible
  • /etc/ansible/ansible.cfg : ansible服务配置文件
  • /etc/ansible/hosts : 主机清单文件 定义可以管理的主机信息
  • /etc/ansible/roles : 角色目录

编写主机清单文件

vi /etc/ansible/hosts

#最后一行插入ip地址
172.16.1.7
172.16.1.31
172.16.1.41

ansible基于秘钥连接主机,如果客户端没有向服务端分发密钥,执行ansible命令会出现要求确认连接

[root@m01 roles]# ansible all -a "hostname"
The authenticity of host '172.16.1.41 (172.16.1.41)' can't be established.
ECDSA key fingerprint is SHA256:MC0ToP0sqGJFsc2R81Z2fhoSk51YznYRv6eskWERDg0.
ECDSA key fingerprint is MD5:e4:a3:00:75:0d:a3:39:a0:98:38:fe:5b:a8:62:04:f8.
Are you sure you want to continue connecting (yes/no)? The authenticity of host '172.16.1.31 (172.16.1.31)' can't be established.
ECDSA key fingerprint is SHA256:MC0ToP0sqGJFsc2R81Z2fhoSk51YznYRv6eskWERDg0.
ECDSA key fingerprint is MD5:e4:a3:00:75:0d:a3:39:a0:98:38:fe:5b:a8:62:04:f8.
Are you sure you want to continue connecting (yes/no)? The authenticity of host '172.16.1.7 (172.16.1.7)' can't be established.
ECDSA key fingerprint is SHA256:MC0ToP0sqGJFsc2R81Z2fhoSk51YznYRv6eskWERDg0.
ECDSA key fingerprint is MD5:e4:a3:00:75:0d:a3:39:a0:98:38:fe:5b:a8:62:04:f8.
Are you sure you want to continue connecting (yes/no)?

分发完密钥后执行结果

[root@m01 ~]# ansible all -a "hostname"
172.16.1.31 | CHANGED | rc=0 >>
nfs01
172.16.1.7 | CHANGED | rc=0 >>
web01
172.16.1.41 | CHANGED | rc=0 >>
backup

ansible模块应用

ansible命令语法格式.png

command模块(默认模块)

Executes a command on a remote node(在远程节点上执行命令)

command模块官方文档

文档中有一条概要是这样写的

  • The command(s) will not be processed through the shell, so variables like $HOME and operations like <, >, |, ; and & will not work. Use the shell module if you need these features.(命令不会通过shell处理,因此$HOME之类的变量和<,>,|,;&之类的操作将不起作用.如果需要这些特性,请使用shell模块.)
#在172.16.1.31上,执行hostname命令
ansible 172.16.1.31 -m command -a "hostname"

#运行结果
[root@m01 ~]# ansible 172.16.1.31 -m command -a "hostname"
172.16.1.31 | CHANGED | rc=0 >>
nfs01

扩展应用

  • chdir : Change into this directory before running the command.(在运行命令之前切换到此目录)
#在172.16.1.31上,切换到/目录,执行pwd命令
ansible 172.16.1.31 -m command -a "chdir=/ pwd"

#运行结果
[root@m01 ~]# ansible 172.16.1.31 -m command -a "chdir=/ pwd"
172.16.1.31 | CHANGED | rc=0 >>
/
  • creates : A filename or (since 2.0) glob pattern. If it already exists, this step won't be run.(文件名或(从2.0开始)全局模式.如果已经存在,此步骤将不运行)
#判断文件名/,执行pwd命令
ansible 172.16.1.31 -m command -a "creates=/ pwd"

#运行结果
[root@m01 ~]# ansible 172.16.1.31 -m command -a "creates=/ pwd"
172.16.1.31 | SUCCESS | rc=0 >>
skipped, since / exists
  • removes : A filename or (since 2.0) glob pattern. If it already exists, this step will be run.(文件名或(从2.0开始)全局模式.如果已经存在,则此步骤将运行)
#判断文件名/,执行pwd命令
ansible 172.16.1.31 -m command -a "removes=/ pwd"

#运行结果
[root@m01 ~]# ansible 172.16.1.31 -m command -a "removes=/ pwd"
172.16.1.31 | CHANGED | rc=0 >>
/root
  • free_form : The command module takes a free form command to run.There is no parameter actually named 'free form'. See the examples!(命令模块接受一个自由格式的命令来运行.没有实际命名为"free form"的参数.看看例子!)

shell模块

Executes a command on a remote node(在远程节点上执行命令)

shell模块官方文档

文档中有一条概要是这样写的

  • It is almost exactly like the command module but runs the command through a shell /bin/sh on the remote node.(它几乎与命令模块完全相同,但通过远程节点上的shell/bin/sh运行命令)
#在172.16.1.31上,执行hostname命令
ansible 172.16.1.31 -m shell -a "hostname"

#运行结果
[root@m01 ~]# ansible 172.16.1.31 -m shell -a "hostname"
172.16.1.31 | CHANGED | rc=0 >>
nfs01

扩展应用

  • chdir : Change into this directory before running the command.(在运行命令之前切换到此目录)
#在172.16.1.31上,切换到/目录,执行pwd命令
ansible 172.16.1.31 -m shell -a "chdir=/ pwd"

#运行结果
[root@m01 ~]# ansible 172.16.1.31 -m shell -a "chdir=/ pwd"
172.16.1.31 | CHANGED | rc=0 >>
/
  • creates : A filename or (since 2.0) glob pattern. If it already exists, this step won't be run.(文件名或(从2.0开始)全局模式.如果已经存在,此步骤将不运行)
#判断文件名/,执行pwd命令
ansible 172.16.1.31 -m shell -a "creates=/ pwd"

#运行结果
[root@m01 ~]# ansible 172.16.1.31 -m shell -a "creates=/ pwd"
172.16.1.31 | SUCCESS | rc=0 >>
skipped, since / exists
  • removes : A filename or (since 2.0) glob pattern. If it already exists, this step will be run.(文件名或(从2.0开始)全局模式.如果已经存在,则此步骤将运行)
#判断文件名/,执行pwd命令
ansible 172.16.1.31 -m shell -a "removes=/ pwd"

#运行结果
[root@m01 ~]# ansible 172.16.1.31 -m shell -a "removes=/ pwd"
172.16.1.31 | CHANGED | rc=0 >>
/root
  • free_form : The command module takes a free form command to run.There is no parameter actually named 'free form'. See the examples!(命令模块接受一个自由格式的命令来运行.没有实际命名为"free form"的参数.看看例子!)

script模块

Runs a local script on a remote node after transferring it(传输后在远程节点上运行本地脚本)

script模块官方文档

#在172.16.1.31上,执行本地的script.sh
ansible 172.16.1.31 -m script -a "/root/script.sh"

#运行结果
[root@m01 ~]# ansible 172.16.1.31 -m script -a "/root/script.sh"
172.16.1.31 | CHANGED => {
    "changed": true, 
    "rc": 0, 
    "stderr": "Shared connection to 172.16.1.31 closed.\r\n", 
    "stderr_lines": [
        "Shared connection to 172.16.1.31 closed."
    ], 
    "stdout": "127.0.0.1   localhost localhost.localdomain localhost4 localhost4.localdomain4\r\n::1         localhost localhost.localdomain localhost6 localhost6.localdomain6\r\n172.16.1.81 firewalld\r\n172.16.1.5 lb01\r\n172.16.1.6 lb02\r\n172.16.1.7 web01\r\n172.16.1.8 web02\r\n172.16.1.9 web03\r\n172.16.1.31 nfs01\r\n172.16.1.41 backup\r\n172.16.1.51 db01\r\n172.16.1.61 m01\r\n172.16.1.71 jumpserver\r\n172.16.1.72 zabbix\r\n", 
    "stdout_lines": [
        "127.0.0.1   localhost localhost.localdomain localhost4 localhost4.localdomain4", 
        "::1         localhost localhost.localdomain localhost6 localhost6.localdomain6", 
        "172.16.1.81 firewalld", 
        "172.16.1.5 lb01", 
        "172.16.1.6 lb02", 
        "172.16.1.7 web01", 
        "172.16.1.8 web02", 
        "172.16.1.9 web03", 
        "172.16.1.31 nfs01", 
        "172.16.1.41 backup", 
        "172.16.1.51 db01", 
        "172.16.1.61 m01", 
        "172.16.1.71 jumpserver", 
        "172.16.1.72 zabbix"
    ]
}
  • 查看/root/script.sh的内容
#!/bin/bash

cat /etc/hosts

copy模块

Copy files to remote locations(将文件复制到远程位置)

copy模块官方文档

#复制本地的script.sh到172.16.1.31上/root目录下
ansible 172.16.1.31 -m copy -a "src=/root/script.sh dest=/root/"

#运行结果
[root@m01 ~]# ansible 172.16.1.31 -m copy -a "src=/root/script.sh dest=/root/"
172.16.1.31 | CHANGED => {
    "ansible_facts": {
        "discovered_interpreter_python": "/usr/bin/python"
    }, 
    "changed": true, 
    "checksum": "037df21352f59ace8da103fc7fab50459bc53f40", 
    "dest": "/root/script.sh", 
    "gid": 0, 
    "group": "root", 
    "md5sum": "63900c21a6c7023dd4562669a57a1074", 
    "mode": "0644", 
    "owner": "root", 
    "size": 28, 
    "src": "/root/.ansible/tmp/ansible-tmp-1576583539.42-211104509645760/source", 
    "state": "file", 
    "uid": 0
}

扩展应用

  • owner : Name of the user that should own the file/directory, as would be fed to chown.(应该拥有该文件/目录的用户的名称,该名称将被馈送给chown.)
#复制本地的script.sh到172.16.1.31上/tmp目录下,属主改为www
ansible 172.16.1.31 -m copy -a "src=/root/script.sh dest=/tmp/ owner=www"

#运行结果
[root@m01 ~]# ansible 172.16.1.31 -m copy -a "src=/root/script.sh dest=/tmp/ owner=www"
172.16.1.31 | CHANGED => {
    "ansible_facts": {
        "discovered_interpreter_python": "/usr/bin/python"
    }, 
    "changed": true, 
    "checksum": "037df21352f59ace8da103fc7fab50459bc53f40", 
    "dest": "/tmp/script.sh", 
    "gid": 0, 
    "group": "root", 
    "md5sum": "63900c21a6c7023dd4562669a57a1074", 
    "mode": "0644", 
    "owner": "www", 
    "size": 28, 
    "src": "/root/.ansible/tmp/ansible-tmp-1576584020.46-212675252356939/source", 
    "state": "file", 
    "uid": 1000
}
  • group : Name of the group that should own the file/directory, as would be fed to chown.(应该拥有文件/目录的组的名称,该组将被馈送给chown.)
#复制本地的script.sh到172.16.1.31上/tmp目录下,属组改为www
ansible 172.16.1.31 -m copy -a "src=/root/script.sh dest=/tmp/ group=www"

#运行结果
[root@m01 ~]# ansible 172.16.1.31 -m copy -a "src=/root/script.sh dest=/tmp/ group=www"
172.16.1.31 | CHANGED => {
    "ansible_facts": {
        "discovered_interpreter_python": "/usr/bin/python"
    }, 
    "changed": true, 
    "checksum": "037df21352f59ace8da103fc7fab50459bc53f40", 
    "dest": "/tmp/script.sh", 
    "gid": 1000, 
    "group": "www", 
    "md5sum": "63900c21a6c7023dd4562669a57a1074", 
    "mode": "0644", 
    "owner": "root", 
    "size": 28, 
    "src": "/root/.ansible/tmp/ansible-tmp-1576584095.49-45916330747754/source", 
    "state": "file", 
    "uid": 0
}
  • mode : The permissions of the destination file or directory.(目标文件或目录的权限.)
#复制本地的script.sh到172.16.1.31上/tmp目录下,权限改为777
ansible 172.16.1.31 -m copy -a "src=/root/script.sh dest=/tmp/ mode=777"

#运行结果
[root@m01 ~]# ansible 172.16.1.31 -m copy -a "src=/root/script.sh dest=/tmp/ mode=777"
172.16.1.31 | CHANGED => {
    "ansible_facts": {
        "discovered_interpreter_python": "/usr/bin/python"
    }, 
    "changed": true, 
    "checksum": "037df21352f59ace8da103fc7fab50459bc53f40", 
    "dest": "/tmp/script.sh", 
    "gid": 0, 
    "group": "root", 
    "md5sum": "63900c21a6c7023dd4562669a57a1074", 
    "mode": "0777", 
    "owner": "root", 
    "size": 28, 
    "src": "/root/.ansible/tmp/ansible-tmp-1576584293.98-246668509676852/source", 
    "state": "file", 
    "uid": 0
}
  • backup : Create a backup file including the timestamp information so you can get the original file back if you somehow clobbered it incorrectly.(创建一个包含时间戳信息的备份文件,以便在不正确地删除原始文件时可以将其取回.)
#复制本地的script.sh到172.16.1.31上/tmp目录下,如果文件内容不同就会备份文件
ansible 172.16.1.31 -m copy -a "src=/root/script.sh dest=/tmp/ backup=yes"

#运行结果
[root@m01 ~]# ansible 172.16.1.31 -m copy -a "src=/root/script.sh dest=/tmp/ backup=yes"
172.16.1.31 | CHANGED => {
    "ansible_facts": {
        "discovered_interpreter_python": "/usr/bin/python"
    }, 
    "backup_file": "/tmp/script.sh.4016.2019-12-17@20:10:37~", 
    "changed": true, 
    "checksum": "037df21352f59ace8da103fc7fab50459bc53f40", 
    "dest": "/tmp/script.sh", 
    "gid": 0, 
    "group": "root", 
    "md5sum": "63900c21a6c7023dd4562669a57a1074", 
    "mode": "0644", 
    "owner": "root", 
    "size": 28, 
    "src": "/root/.ansible/tmp/ansible-tmp-1576584636.73-149758337982195/source", 
    "state": "file", 
    "uid": 0
}
  • content : When used instead of src, sets the contents of a file directly to the specified value.Works only when dest is a file. Creates the file if it does not exist.(当使用而不是src时,将文件的内容直接设置为指定值.仅当dest是文件时才有效.如果文件不存在,则创建文件.)
#将一段文件写入到172.16.1.31上/tmp/1997sty中,如果文件不存在就创建
ansible 172.16.1.31 -m copy -a "content='1997sty' dest=/tmp/1997sty"

#运行结果
[root@m01 ~]# ansible 172.16.1.31 -m copy -a "content='1997sty' dest=/tmp/1997sty"
172.16.1.31 | CHANGED => {
    "ansible_facts": {
        "discovered_interpreter_python": "/usr/bin/python"
    }, 
    "changed": true, 
    "checksum": "4f3e07cdd98a1fb64bbe1e012882d48581f132f9", 
    "dest": "/tmp/1997sty", 
    "gid": 0, 
    "group": "root", 
    "md5sum": "07e7cf3713ad84eb6f4da297d55ceb2a", 
    "mode": "0644", 
    "owner": "root", 
    "size": 7, 
    "src": "/root/.ansible/tmp/ansible-tmp-1576585516.17-227321292842338/source", 
    "state": "file", 
    "uid": 0
}
  • remote_src : Influence whether src needs to be transferred or already is present remotely.If no, it will search for src at originating/master machine.If yes it will go to the remote/target machine for the src.(影响src是需要传输还是已经远程存在.如果否,它将在原始/主计算机上搜索src.如果是,它将转到src的远程/目标计算机.)
ansible 172.16.1.31 -m copy -a "src=1997sty dest=/tmp/"
ansible 172.16.1.31 -m copy -a "src=1997sty dest=/tmp/ remote_src=yes"

remote_src.png

file模块

Manage files and file properties(管理文件和文件属性)

file模块官方文档

#将172.16.1.31上/tmp/1997sty文件,属主修改为www,属组修改为www,权限修改为666
ansible 172.16.1.31 -m file -a "dest=/tmp/1997sty owner=www group=www mode=666"

#运行结果
[root@m01 ~]# ansible 172.16.1.31 -m file -a "dest=/tmp/1997sty owner=www group=www mode=666"
172.16.1.31 | CHANGED => {
    "ansible_facts": {
        "discovered_interpreter_python": "/usr/bin/python"
    }, 
    "changed": true, 
    "gid": 1000, 
    "group": "www", 
    "mode": "0666", 
    "owner": "www", 
    "path": "/tmp/1997sty", 
    "size": 7, 
    "state": "file", 
    "uid": 1000
}

扩展应用

  • state : If file, without any other options this works mostly as a 'stat' and will return the current state of path. Even with other options (i.e mode), the file will be modified but will NOT be created if it does not exist;(如果file,没有任何其他选项,这主要作为'stat'工作,并将返回路径的当前状态.即使有其他选项(即模式),文件也会被修改,但如果它不存在,就不会被创建;)
  1. If absent, directories will be recursively deleted, and files or symlinks will be unlinked. (如果是absent,目录将被递归删除,文件或符号链接将被取消链接.)In the case of a directory, if diff is declared, you will see the files and folders deleted listed under path_contents. (在目录的情况下,如果声明了diff,您将看到在路径目录下列出的文件和文件夹被删除.)Note that absent will not cause file to fail if the path does not exist as the state did not change.(注意,如果状态不改变,如果路径不存在,则缺席不会导致文件失败.)
  2. If directory, all intermediate subdirectories will be created if they do not exist.(如果是directory,如果它们不存在,将创建所有中间子目录.)
  3. If hard, the hard link will be created or changed.(如果是hard,将创建或更改硬链接.)
  4. If link, the symbolic link will be created or changed.(如果的link,将创建或更改软链接.)
  5. If touch (new in 1.4), an empty file will be created if the path does not exist, while an existing file or directory will receive updated file access and modification times (similar to the way touch works from the command line).(如果是touch(new in 1.4),如果路径不存在,将创建一个空文件,而现有的文件或目录将接收更新的文件访问和修改时间(类似于触摸从命令行工作的方式).)
#删除文件
ansible 172.16.1.31 -m file -a "dest=/tmp/1997sty state=absent"
#删除目录
ansible 172.16.1.31 -m file -a "dest=/tmp/1/2/3  state=absent"
#创建一级目录
ansible 172.16.1.31 -m file -a "dest=/tmp/1 state=directory"
#创建多级目录
ansible 172.16.1.31 -m file -a "dest=/tmp/1/2/3 state=directory"
#创建硬链接
ansible 172.16.1.31 -m file -a "src=/tmp/1997sty dest=/tmp/1997sty_hard state=hard"
#创建软连接
ansible 172.16.1.31 -m file -a "src=/tmp/1997sty dest=/tmp/1997sty_link state=link"
#创建文件
ansible 172.16.1.31 -m file -a "dest=/tmp/1997sty state=touch"
  • 运行结果
#创建一级目录
[root@m01 ~]# ansible 172.16.1.31 -m file -a "dest=/tmp/1 state=directory"
172.16.1.31 | CHANGED => {
    "ansible_facts": {
        "discovered_interpreter_python": "/usr/bin/python"
    }, 
    "changed": true, 
    "gid": 0, 
    "group": "root", 
    "mode": "0755", 
    "owner": "root", 
    "path": "/tmp/1", 
    "size": 6, 
    "state": "directory", 
    "uid": 0
}
#创建多级目录
[root@m01 ~]# ansible 172.16.1.31 -m file -a "dest=/tmp/1/2/3 state=directory"
172.16.1.31 | CHANGED => {
    "ansible_facts": {
        "discovered_interpreter_python": "/usr/bin/python"
    }, 
    "changed": true, 
    "gid": 0, 
    "group": "root", 
    "mode": "0755", 
    "owner": "root", 
    "path": "/tmp/1/2/3", 
    "size": 6, 
    "state": "directory", 
    "uid": 0
}
#创建文件
[root@m01 ~]# ansible 172.16.1.31 -m file -a "dest=/tmp/1997sty state=touch"
172.16.1.31 | CHANGED => {
    "ansible_facts": {
        "discovered_interpreter_python": "/usr/bin/python"
    }, 
    "changed": true, 
    "dest": "/tmp/1997sty", 
    "gid": 1000, 
    "group": "www", 
    "mode": "0666", 
    "owner": "www", 
    "size": 7, 
    "state": "file", 
    "uid": 1000
}
#创建硬链接
[root@m01 ~]# ansible 172.16.1.31 -m file -a "src=/tmp/1997sty dest=/tmp/1997sty_hard state=hard"
ansible 172.16.1.31 -m file -a "src=/tmp/1997sty dest=/tmp/1997sty_link state=link"172.16.1.31 | CHANGED => {
    "ansible_facts": {
        "discovered_interpreter_python": "/usr/bin/python"
    }, 
    "changed": true, 
    "dest": "/tmp/1997sty_hard", 
    "gid": 1000, 
    "group": "www", 
    "mode": "0666", 
    "owner": "www", 
    "size": 7, 
    "src": "/tmp/1997sty", 
    "state": "hard", 
    "uid": 1000
}
#创建软连接
[root@m01 ~]# ansible 172.16.1.31 -m file -a "src=/tmp/1997sty dest=/tmp/1997sty_link state=link"
172.16.1.31 | CHANGED => {
    "ansible_facts": {
        "discovered_interpreter_python": "/usr/bin/python"
    }, 
    "changed": true, 
    "dest": "/tmp/1997sty_link", 
    "gid": 0, 
    "group": "root", 
    "mode": "0777", 
    "owner": "root", 
    "size": 12, 
    "src": "/tmp/1997sty", 
    "state": "link", 
    "uid": 0
}
#删除文件
[root@m01 ~]# ansible 172.16.1.31 -m file -a "dest=/tmp/1997sty state=absent"
172.16.1.31 | CHANGED => {
    "ansible_facts": {
        "discovered_interpreter_python": "/usr/bin/python"
    }, 
    "changed": true, 
    "path": "/tmp/1997sty", 
    "state": "absent"
}
#删除目录
[root@m01 ~]# ansible 172.16.1.31 -m file -a "dest=/tmp/1/2/3  state=absent"
172.16.1.31 | CHANGED => {
    "ansible_facts": {
        "discovered_interpreter_python": "/usr/bin/python"
    }, 
    "changed": true, 
    "path": "/tmp/1/2/3", 
    "state": "absent"
}
  • recurse : Recursively set the specified file attributes on directory contents.(递归地对目录内容设置指定的文件属性.)This applies only when state is set to directory.(仅当状态设置为'目录'时才适用.)
#将172.16.1.31上/tmp/1目录下,所有文件和目录的权限递归修改为777
ansible 172.16.1.31 -m file -a "dest=/tmp/1 mode=777 recurse=yes"

#运行结果
[root@m01 ~]# ansible 172.16.1.31 -m file -a "dest=/tmp/1 mode=777 recurse=yes"
172.16.1.31 | CHANGED => {
    "ansible_facts": {
        "discovered_interpreter_python": "/usr/bin/python"
    }, 
    "changed": true, 
    "gid": 0, 
    "group": "root", 
    "mode": "0777", 
    "owner": "root", 
    "path": "/tmp/1", 
    "size": 15, 
    "state": "directory", 
    "uid": 0
}