1. Ansible 基础和常用模块

1 Ansible 安装和入门

1.1 Ansible安装

  • 官方EPEL源提供Ansible
# CentOS7安装
[12:02:55 root@ansible ~]#yum -y install ansible
[12:03:01 root@ansible ~]#ansible --version
ansible 2.9.16
  config file = /etc/ansible/ansible.cfg
  configured module search path = [u'/root/.ansible/plugins/modules', u'/usr/share/ansible/plugins/modules']
  ansible python module location = /usr/lib/python2.7/site-packages/ansible
  executable location = /usr/bin/ansible
  python version = 2.7.5 (default, Apr  2 2020, 13:16:51) [GCC 4.8.5 20150623 (Red Hat 4.8.5-39)]

1.2 Ansible 配置文件

1.2.1 配置文件

  • /etc/ansible/ansible.cfg # 主配置文件, 用来配置Ansible功能
  • /etc/ansible/hosts # 定义主机清单文件
  • /etc/ansible/roles # 定义角色目录

1.2.2 Ansible 主配置文件

  • /etc/ansible/ansible.cfg: 大部分内容都无需修改
[defaults]

# some basic default values...

#inventory      = /etc/ansible/hosts # 定义主机清单
#library        = /usr/share/my_modules/ # 库文件
#module_utils   = /usr/share/my_module_utils/ 
#remote_tmp     = ~/.ansible/tmp # 用来存放Python临时文件的目录, ansible推送时产生的临时文件会存放在被管理节点的这个目录里
#local_tmp      = ~/.ansible/tmp # Python临时文件在ansible主机的存放目录
# 这两个临时目录会在ansible执行时, 自动创建
#plugin_filters_cfg = /etc/ansible/plugin_filters.yml
#forks          = 5 # ansbile并发处理的数量, 默认为5, 也就是每次处理5个主机
#poll_interval  = 15
#sudo_user      = root # 默认的sudo用户, 该账户需要在被管理节点存在, 并且该账户要对目标主机有相应的管理权限. 如果不用root, 而是用其他账户, 比如admin, 那么admin需要在被管理节点存在, 并且在被管理节点具有sudo权限(admin all all all), 给予admin在被管理节点的全部sudo权限. 这样主控端利用admin连接到被管理节点后, 可以sudo切换成root用户执行命令
# 一般情况, 直接就用root管理即可, 提高管理效率. 本身ansible利用的就是ssh协议, 效率本身就有问题. 如果连接百台服务器, 再切换sudo, 那么效率就更低了, 而且还要提前创建账号, 配置sudo权限
#ask_sudo_pass = True # 当ansible使用上面的sudo账号连接到被管理节点时, 是否需要被管理节点的该sudo账户的密码
#ask_pass      = True # ssh远程连接时是否需要远端用户的密码
#transport      = smart 
#remote_port    = 22 # 被管理节点ssh端口号
#module_lang    = C
#module_set_locale = False
#host_key_checking = False # 第一次连接某个主机时, 是否需要手动输入yes, 才下载对端主机公钥. False表示无需手动输入yes, 需要取消注释才会生效
# 还可以修改ansible管理端主机的/etc/ssh/ssh_config文件(#StrictHostKeyChecking ask --> StrictHostKeyChecking no )
# 还可以在执行时使用`ssh IP -o StrictHostKeyChecking=no`
#log_path=/var/log/ansible.log # ansible日志, 建议开启
#module_name= command # ansible执行命令时, 默认使用的模块, 改成shell比较好

1.2.3 主机清单

格式:

域名
IP
[名称]
IP
域名
...
[名称]
IP1
IP2
...
[websrvs]
www[1:100].example.com
[dbsrvs]
db-[a:f].example.com
[appsrvs]
10.0.0.[1:100]  # 表示10.0.0.1, 10.0.0.2, 10.0.0.3 ... 10.0.0.100

本文案例:

# ansible主机: 10.0.0.237

# 被管理节点

CentOS-8
10.0.0.85 
10.0.0.86
CentOS-7
10.0.0.187
[websrvs]
10.0.0.85 
10.0.0.86

[appsrvs]
10.0.0.187
10.0.0.85

[dbsrvs]
10.0.0.187
10.0.0.86

1.3 Ansible 工具

[18:06:08 root@ansible ~]#ansible
ansible               ansible-config        ansible-console-2     ansible-doc-2         ansible-galaxy-2      ansible-playbook      ansible-pull          ansible-vault         
ansible-2             ansible-connection    ansible-console-2.7   ansible-doc-2.7       ansible-galaxy-2.7    ansible-playbook-2    ansible-pull-2        ansible-vault-2       
ansible-2.7           ansible-console       ansible-doc           ansible-galaxy        ansible-inventory     ansible-playbook-2.7  ansible-pull-2.7      ansible-vault-2.7 
  • /usr/bin/ansible # 主程序, 临时命令执行工具
  • /usr/bin/ansible-doc # 查看配置文档, 模块功能查看工具
  • /usr/bin/ansible-playbook # 定制自动化任务, 编排剧本工具, 相当于脚本
  • /usr/bin/ansible-pull # 远程执行命令的工具
  • /usr/bin/ansible-vault # 文件加密工具
  • /usr/bin/ansible-console # 基于Console界面与用于交互的执行工具
  • /usr/bin/ansible-galaxy # 下载/上传优秀代码或Roles模块的官网平台

利用ansible实现管理的主要方式

  • Ad-Hoc: 利用ansible命令, 临时执行任务
  • Ansible-playbook: 主要用于长期规划好的, 大型项目的场景, 需要前期规划好

1.3.1 ansible-doc

  • 查看可用模块
ansible-doc -l 
  • 查看某个模块的使用方法
ansible-doc -s MODULES_NAME, 简要描述
ansible-doc MODULES_NAME, 详细使用方法
ping模块只是检测某个主机是否可以被ansible管理, 并不是执行icmp协议的ping命令
[12:15:56 root@ansible ~]#ansible-doc -s ping
- name: Try to connect to host, verify a usable python and return `pong' on success
  ping:
      data:                  # Data to return for the `ping' return value. If this parameter is set to `crash', the module will cause an exception.

1.3.2 利用sshpass配置基于key的ssh认证

ansible通过ssh协议,实现对远程主机的配置管理、应用部署、任务执行等功能
建议:使用此工具前,先配置ansible主控端能基于密钥认证的方式连接各个被管理节点
如果是基于key验证, 那么第一次连接被管理节点时, 还需要手动输入是否将对端公钥下载到本地
如果是基于密码验证, 一旦被管理节点的密码不同, 那么就没法做到统一管理

范例: 修改ansible配置文件, 取消首次ssh下载公钥的确认

[21:21:47 root@ansible ~]#vim /etc/ansible/ansible.cfg
# uncomment this to disable SSH key host checking
host_key_checking = False        
[21:40:13 root@ansible ~]#vim /etc/ansible/hosts 

[websrvs]
10.0.0.85
10.0.0.86

[appsrvs]
10.0.0.187
10.0.0.85

[dbsrvs]
10.0.0.187
10.0.0.86   
[21:38:39 root@ansible ~]#ansible all -m ping
10.0.0.85 | UNREACHABLE! => {
    "changed": false, 
    "msg": "Failed to connect to the host via ssh: Warning: Permanently added '10.0.0.85' (ECDSA) to the list of known hosts.\r\nPermission denied (publickey,gssapi-keyex,gssapi-with-mic,password).", 
    "unreachable": true
}
10.0.0.187 | UNREACHABLE! => {
    "changed": false, 
    "msg": "Failed to connect to the host via ssh: Warning: Permanently added '10.0.0.187' (ECDSA) to the list of known hosts.\r\nPermission denied (publickey,gssapi-keyex,gssapi-with-mic,password).", 
    "unreachable": true
}
10.0.0.86 | UNREACHABLE! => {
    "changed": false, 
    "msg": "Failed to connect to the host via ssh: Warning: Permanently added '10.0.0.86' (ECDSA) to the list of known hosts.\r\nPermission denied (publickey,gssapi-keyex,gssapi-with-mic,password).", 
    "unreachable": true
}
[21:38:42 root@ansible ~]#cat .ssh/known_hosts 
10.0.0.187 ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBHbDLtLE1uBBbjdaPQA0OB/doEFXlwmzi4eQ8YwKIfHKQm/XcLk3U8kEOW1A5eIWrMnhjmoD7JU/J/4eMkcr7cc=
10.0.0.85 ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBFF9+KPILpkSQfzg5/11sFpohPFd8XPretJMBzSCD/I/7rNs6Q85IJQzWquZy9KHyCBkyJJjz6lWHVJal5DCCjY=
10.0.0.86 ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBFF9+KPILpkSQfzg5/11sFpohPFd8XPretJMBzSCD/I/7rNs6Q85IJQzWquZy9KHyCBkyJJjz6lWHVJal5DCCjY=

范例: ansible默认是基于key验证, 如果想使用密码验证, 那么就在ansible命令里加上-k选项

[21:42:42 root@ansible ~]#ansible all -m ping -k
SSH Password:

不过基于密码验证时, 每次执行ansible命令, 只能输一个密码. 如果多台主机的密码不同, 那么只有密码匹配的那些主机才会执行命令, 不匹配的主机还要重新再执行

一旦ansible和某台主机的密码校验成功, 那么ansible会对该主机和密码进行缓存(重启后丢失), 下次再使用ansible去连接该被管理节点时, 虽然仍然提示要输密码, 但是可以直接敲回车, 不用真的输入密码

所以, 实际工作中, 不会基于密码进行验证.

范例: 基于sshpass的key验证

  • 方法1:
[root@centos8 ~]#cat hosts.list
10.0.0.18
10.0.0.28
[root@centos8 ~]#vim push_ssh_key.sh
#!/bin/bash

rpm -q sshpass &> /dev/null || yum -y install sshpass  
[ -f /root/.ssh/id_rsa ] || ssh-keygen -f /root/.ssh/id_rsa  -P ''
export SSHPASS=000000
while read IP;do
   sshpass -e ssh-copy-id  -o StrictHostKeyChecking=no $IP
done < hosts.list
  • 方法2:
#!/bin/bash

IPLIST="
10.0.0.85
10.0.0.86
10.0.0.187                                                                                                                                                                          
"
rpm -q sshpass &> /dev/null || yum -y install sshpass
[ -f /root/.ssh/id_rsa ] || ssh-keygen -f /root/.ssh/id_rsa -P ''
export SSHPASS=000000  # 被管理节点, root账户的登录密码要一致
for IP in $IPLIST;do
        sshpass -e ssh-copy-id -o StrictHostkeyChecking=no $IP   # -o StrictHostkeyChecking=no 不再提示是否下载公钥, 直接把对方主机的公钥下载到本地~/.ssh/known_hosts                                                                                                                                                                                                                                   
done
[12:21:54 root@ansible ~]#ansible all -m ping
10.0.0.187 | SUCCESS => {
    "ansible_facts": {
        "discovered_interpreter_python": "/usr/bin/python"
    }, 
    "changed": false, 
    "ping": "pong"
}
10.0.0.86 | SUCCESS => {
    "ansible_facts": {
        "discovered_interpreter_python": "/usr/libexec/platform-python"
    }, 
    "changed": false, 
    "ping": "pong"
}
10.0.0.85 | SUCCESS => {
    "ansible_facts": {
        "discovered_interpreter_python": "/usr/libexec/platform-python"
    }, 
    "changed": false, 
    "ping": "pong"
}

1.3.3 列出主机清单

[12:22:00 root@ansible ~]#ansible websrvs --list-hosts
  hosts (2):
    10.0.0.85
    10.0.0.86
[12:24:09 root@ansible ~]#ansible all --list-hosts
  hosts (3):
    10.0.0.187
    10.0.0.85
    10.0.0.86

1.3.4 Ansible用于匹配被控制的主机的列表

  • 格式要求
不支持的格式:
ansible 10.0.0.8[5:6] -m ping 
ansible "10.0.0.8[5:6]" -m ping
[12:24:14 root@ansible ~]#ansible 10.0.0.8[5:6] -m ping
[WARNING]: Could not match supplied host pattern, ignoring: 10.0.0.8
[WARNING]: No hosts matched, nothing to do
  • 一一列举
ansible "10.0.0.236 10.0.0.237" -m ping
  • 通配符
ansible '*' -m ping
ansible 192.168.1.* -m ping
ansible "srvs" -m ping 
  • 或关系: :

在websrvs组或在appsrvs组里的主机

[12:25:29 root@ansible ~]#ansible websrvs:appsrvs --list-hosts
  hosts (3):
    10.0.0.85
    10.0.0.86
    10.0.0.187
  • 逻辑与: :&

在websrvs组并且也在dbsrvs组里的主机

[12:29:30 root@ansible ~]#ansible 'websrvs:&appsrvs' --list-hosts
  hosts (1):
    10.0.0.85
  • 逻辑非: :!

在websrvs组, 但不在dbsrvs组中的主机

注意: 此处必须用单引号

[12:29:37 root@ansible ~]#ansible 'websrvs:!dbsrvs' --list-hosts
  hosts (1):
    10.0.0.85
  • 综合逻辑
ansible 'websrvs:dbsegs:&appsrvs:!ftpsrvs' -m ping
  • 正则表达式
ansible "~(web|db).*\.linux\.com" -m ping  # ~符号是格式要求, 必须加

eg: 在k8s环境中, 如果ansible本机也被加入到了host清单里, 那么当k8s配置完主机, 需要批量重启远程主机时, 需要把本机先刨除在ansible命令执行清单外. 避免如果本机先重启了那么这条ansible命令也就不会执行后续重启其他主机的操作了

ansible 'kube*:etcd:!10.0.0.101' -a reboot; reboot

ansible命令执行过程

  1. 加载自己的配置文件, 默认/etc/ansible/ansible.cfg
  2. 加载自己对应的模块文件, 如: command
  3. 通过ansible, 为要在远程主机运行的模块或命令, 生成对应的临时py文件, 这些临时文件会先存储在ansible主控端的~/.ansible/tmp目录下, 然后会被传输至远程服务器的对应执行用户的家目录, $HOME/.ansible/tmp/ansible-tmp-数字/XXX.py
  4. 给远程主机的临时文件添加执行权限
  5. 执行并返回结果
  6. 删除本地和远程主机上的临时py文件, 退出

ansible执行状态
绿色: 执行成功并且不需要做改变的操作
黄色: 执行成功并且对目标主机做了变更, 或者仅表示信息查看成功, 没有做修改
红色: 执行失败
颜色可以在配置文件自定义

2 Ansible 常用模块

2.1 command 模块

  • ansible的默认模块, 执行命令时不指定-m,那么就是使用command模块
  • command模块只支持基本的Linux命令
  • 不支持特殊符号,如($VARNAME < > | ; & ...), 使用特殊符号需要用shell模块
  • 命令需要写在单引号或者双引号里,ansible all -m command -a 'cat /etc/issue'
  • -a表示模块的参数, 适用于ansible所有模块
[13:55:48 root@ansible ~]#ansible-doc -s command
- name: Execute commands on targets
  command:
      argv:                  # Passes the command as a list rather than a string. Use `argv'
                               to avoid quoting values that
                               would otherwise be interpreted
                               incorrectly (for example "user
                               name"). Only the string or the
                               list form can be provided, not
                               both.  One or the other must be
                               provided.
      chdir:                 # Change into this directory before running the command.
      cmd:                   # The command to run.
      creates:               # A filename or (since 2.0) glob pattern. If it already exists,
                               this step *won't* be run.
      free_form:             # The command module takes a free form command to run. There is
                               no actual parameter named 'free
                               form'.
      removes:               # A filename or (since 2.0) glob pattern. If it already exists,
                               this step *will* be run.
      stdin:                 # Set the stdin of the command directly to the specified value.
      stdin_add_newline:     # If set to `yes', append a newline to stdin data.
      strip_empty_ends:      # Strip empty lines from the end of stdout/stderr in result.
      warn:                  # Enable or disable task warnings.

eg: 执行简单shell命令

[12:37:10 root@ansible ~]#ansible all -m command -a 'cat /etc/centos-release '
10.0.0.187 | CHANGED | rc=0 >>
CentOS Linux release 7.8.2003 (Core)
10.0.0.86 | CHANGED | rc=0 >>
CentOS Linux release 8.2.2004 (Core) 
10.0.0.85 | CHANGED | rc=0 >>
CentOS Linux release 8.2.2004 (Core) 

eg: command 模块不支持特殊符号

[12:37:27 root@ansible ~]#ansible all -m command -a 'ls /data/*'
10.0.0.187 | FAILED | rc=2 >>
ls: cannot access /data/*: No such file or directorynon-zero return code
10.0.0.85 | FAILED | rc=2 >>
ls: cannot access '/data/*': No such file or directorynon-zero return code
10.0.0.86 | FAILED | rc=2 >>
ls: cannot access '/data/*': No such file or directorynon-zero return code
[12:39:01 root@ansible ~]#ansible all -m command -a 'echo $HOSTNAME' # ansible中查看对端主机上某个变量的值时, 需要使用单引号, 不过command模块不支持, 要用shell模块
10.0.0.187 | CHANGED | rc=0 >>
$HOSTNAME
10.0.0.86 | CHANGED | rc=0 >>
$HOSTNAME
10.0.0.85 | CHANGED | rc=0 >>
$HOSTNAME
[12:39:34 root@ansible ~]#ansible all -m command -a "echo $HOSTNAME" # ansible中查看对端主机上某个变量的值时, 需要使用单引号, 双引号会显示变量在本机的值
10.0.0.187 | CHANGED | rc=0 >>
ansible
10.0.0.85 | CHANGED | rc=0 >>
ansible
10.0.0.86 | CHANGED | rc=0 >>
ansible

[14:08:01 root@ansible ~]#ansible all -a "ls /boot > /data/ls.log"
#command模块不支持重定向, 因为>也属于特殊符号

2.2 shell 模块

  • 类似command模块, 但是支持特殊符号, 通配符, $VAR, <, >,...
  • 对于变量, 需要写在单引号
  • shell模块无法支持复杂的命令, 复杂命令需要使用script模块

范例:

[12:44:54 root@ansible ~]#ansible all -m shell -a "echo $HOSTNAME"
10.0.0.187 | CHANGED | rc=0 >>
ansible
10.0.0.85 | CHANGED | rc=0 >>
ansible
10.0.0.86 | CHANGED | rc=0 >>
ansible
[12:45:10 root@ansible ~]#ansible all -m shell -a 'echo $HOSTNAME'
10.0.0.187 | CHANGED | rc=0 >>
centos-7-6.prac
10.0.0.86 | CHANGED | rc=0 >>
CentOS-8-6
10.0.0.85 | CHANGED | rc=0 >>
CentOS-8-5
[12:45:27 root@ansible ~]#ansible all -m shell -a "ls /boot > /data/ls.log"
10.0.0.187 | CHANGED | rc=0 >>

10.0.0.85 | CHANGED | rc=0 >>

10.0.0.86 | CHANGED | rc=0 >>


[12:00:07 root@CentOS-8-5 ~]#ls /data
ls.log

ansible log: /var/log/ansible.log, 需要在配置文件中取消注释才能生效

chdir: 执行命令前, 先切换到某个目录, 相当于 cd /dir; CMD

格式: chdir=/PATH 命令

[12:47:43 root@ansible ~]#ansible all -m shell -a 'chdir=/data ls'
10.0.0.187 | CHANGED | rc=0 >> 
ls.log
pkgs
prac
scripts
10.0.0.86 | CHANGED | rc=0 >>
ls.log
pkgs
prac
scripts
10.0.0.85 | CHANGED | rc=0 >>
ls.log
pkgs
prac
scripts

creates: 如果指定的文件或者目录存在, 则不会执行后续命令. 如果指定的文件或者目录不存在, 则会执行后续命令

[12:49:22 root@ansible ~]#ansible all -a 'creates=/etc ls -l /etc/issue'
10.0.0.187 | SUCCESS | rc=0 >>   # /etc目录存在, 所以不会执行ls -l /etc/issue
skipped, since /etc exists
10.0.0.86 | SUCCESS | rc=0 >>
skipped, since /etc exists
10.0.0.85 | SUCCESS | rc=0 >>
skipped, since /etc exists
[12:50:09 root@ansible ~]#ansible all -a 'creates=/etc/issue ls -l /etc/issue'
10.0.0.187 | SUCCESS | rc=0 >>
skipped, since /etc/issue exists
10.0.0.85 | SUCCESS | rc=0 >>
skipped, since /etc/issue exists
10.0.0.86 | SUCCESS | rc=0 >>
skipped, since /etc/issue exists
[19:49:20 root@CentOS-8-5 ~]#touch creates.log
[22:40:54 root@ansible ~]#ansible all -a 'creates=creates.log ls /data'
10.0.0.187 | CHANGED | rc=0 >>  # 10.0.0.187的root家目录, 没有creates.log文件, 所以会执行后续命令
pkgs
prac
scripts
test.log
10.0.0.85 | SUCCESS | rc=0 >>  # 10.0.0.85的root家目录, 有creates.log文件, 所以不会执行后续命令
skipped, since creates.log exists
10.0.0.86 | CHANGED | rc=0 >>
pkgs
prac
scripts
test.log

removes: 如果指定的文件或目录存在, 则执行后续命令

[12:52:22 root@ansible ~]#ansible all -a 'removes=/etc/issue ls -l /etc/issue'
10.0.0.187 | CHANGED | rc=0 >>
-rw-r--r--. 1 root root 23 Apr  8  2020 /etc/issue
10.0.0.85 | CHANGED | rc=0 >>
-rw-r--r--. 1 root root 23 Jun  3  2020 /etc/issue
10.0.0.86 | CHANGED | rc=0 >>
-rw-r--r--. 1 root root 23 Jun  3  2020 /etc/issue

2.3 script 模块

  • 在被管理节点执行脚本, 脚本只需要在管理节点存在即可
  • 脚本在ansible本机或者远程主机都无需执行权限
  • 脚本在管理节点的路径必须指定, 可以是绝对路径或者相对路径

eg: 执行test.sh脚本

test.sh

#!/bin/bash
echo $HOSTNAME
[12:56:15 root@ansible ~]#ansible all -m script -a '/root/test.sh' # 直接把脚本路径写到-a后的参数即可
10.0.0.187 | CHANGED => {
    "changed": true, 
    "rc": 0, 
    "stderr": "Shared connection to 10.0.0.187 closed.\r\n", 
    "stderr_lines": [
        "Shared connection to 10.0.0.187 closed."
    ], 
    "stdout": "centos-7-6.prac\r\n",   # 返回结果
    "stdout_lines": [
        "centos-7-6.prac"
    ]
}
10.0.0.85 | CHANGED => {
    "changed": true, 
    "rc": 0, 
    "stderr": "Shared connection to 10.0.0.85 closed.\r\n", 
    "stderr_lines": [
        "Shared connection to 10.0.0.85 closed."
    ], 
    "stdout": "CentOS-8-5\r\n", 
    "stdout_lines": [
        "CentOS-8-5"
    ]
}
10.0.0.86 | CHANGED => {
    "changed": true, 
    "rc": 0, 
    "stderr": "Shared connection to 10.0.0.86 closed.\r\n", 
    "stderr_lines": [
        "Shared connection to 10.0.0.86 closed."
    ], 
    "stdout": "CentOS-8-6\r\n", 
    "stdout_lines": [
        "CentOS-8-6"
    ]
}

2.4 copy 模块

  • 将本地文件拷贝到远程节点
  • 如果没有指定mode='权限', 那么拷贝过去的文件的权限是644, 目录是755权限
  • 由于ansible的幂等性, 除非文件内容做了修改, 否则无论执行了几次命令, ansible都不会再拷贝文件
      src:    如果复制的是一个目录, 那么目录如果没有加/补全, 那么复制的是整个目录, 如果加了/补全, 那么复制的是目录里的内容, 而不是目录本身              

                               # Local path to a file to copy to the remote server. This can be
                               absolute or relative. If path is
                               a directory, it is copied
                               recursively. In this case, if
                               path ends with "/", only inside
                               contents of that directory are
                               copied to destination.
                               Otherwise, if it does not end
                               with "/", the directory itself
                               with all contents is copied.
                               This behavior is similar to the
                               `rsync' command line tool.

    dest:     远程目标路径必须是绝对路径, 并且如果源是目录那么目标也必须是目录; 此外, 如果目标主机已经有了相同的文件, 默认会覆盖, 可以加 backup=yes 来先备份目标文件          
                               # (required) Remote absolute path where the file should be copied
                               to. If `src' is a directory,
                               this must be a directory too. If
                               `dest' is a non-existent path
                               and if either `dest' ends with
                               "/" or `src' is a directory,
                               `dest' is created. If `dest' is
                               a relative path, the starting
                               directory is determined by the
                               remote host. If `src' and `dest'
                               are files, the parent directory
                               of `dest' is not created and the
                               task fails if it does not
                               already exist.

eg: copy /data/scripts/test.sh to remote hosts

[15:03:06 root@ansible ~]#ansible all -m copy -a 'src=/data/scripts/test.sh dest=/data/scripts/test1.sh'
[15:03:13 root@ansible ~]#ansible all -m shell -a 'ls /data/scripts'
10.0.0.187 | CHANGED | rc=0 >>
test1.sh
10.0.0.85 | CHANGED | rc=0 >>
test1.sh
10.0.0.86 | CHANGED | rc=0 >>
test1.sh

owner: 可以指定owner参数, 但是用户必须在被管理节点事先存在, 否则文件或目录拷贝过去后owner是不会变的.

backup: 如果远程节点有相同的文件, 那么copy时可以指定'backup=yes', 这会创建一个备份文件. 当某个文件需要被经常修改时, 要加backup=yes参数, 否则新的文件copy过去后会把旧的文件覆盖了

范例:

  1. 先在被管理节点/opt目录下创建test.sh脚本
[15:18:42 root@ansible ~]#ansible all -m shell -a 'touch /opt/test.sh'
  1. 将管理节点的test.sh文件copy到被管理节点/opt下, 指定ower,mode和backup=yes
[15:20:38 root@ansible ~]#ansible all -m copy -a 'src=/root/test.sh dest=/opt mode=600 owner=daemon backup=yes'
[12:46:24 root@CentOS-8-5 ~]#ls -l /opt
total 4
-rw------- 1 daemon root 19 Jan 31 15:21 test.sh # copy过来的文件, 权限, owner都修改了
-rw-r--r-- 1 root   root  0 Jan 31 15:19 test.sh.28220.2021-01-31@15:21:45~ # 原先的文件会被打上timestamp

content: 将命令行的内容, 写入到被管理节点目标文件, 目标文件如果不存在, 会自动创建

范例:

[15:25:44 root@ansible ~]#ansible all -m copy -a 'content="line1\nline2\nline3" dest=/opt/test.txt'
[15:21:25 root@centos-7-6 ~]#ll /opt
total 8
drwxr-xr-x 5 root   root 45 Jan 31 15:05 data
-rw------- 1 daemon root 19 Jan 31 15:21 test.sh
-rw-r--r-- 1 root   root  0 Jan 31 15:19 test.sh.29262.2021-01-31@15:21:46~
-rw-r--r-- 1 root   root 17 Jan 31 15:25 test.txt
[15:25:54 root@centos-7-6 ~]#cat /opt/test.txt 
line1
line2
line3

copy 目录:

[15:28:36 root@ansible ~]#ansible all -m copy -a 'src=/tmp/ dest=/tmp'
[15:29:22 root@centos-7-6 ~]#ls /tmp
file.txt
[15:28:36 root@ansible ~]#ansible all -m copy -a 'src=/tmp dest=/tmp'
[15:29:22 root@centos-7-6 ~]#ls /tmp
file.txt  tmp

2.5 fetch 模块

  • 从被管理节点抓取文件到ansible主机的目录, 目前不支持抓取整个目录, 只能抓文件
  • fetch的源只能是文件, 目前不支持抓目录, 也就是说fetch的源是管理节点的文件, 而目标是ansible主机的一个目录, 如果是从多台主机抓文件, 那么会在ansible目标目录按照抓取主机的ip地址生成各自的文件夹, 防止抓取同名文件覆盖

范例: 从被管理节点抓取/etc/issue文件到/opt目录下

[15:41:57 root@ansible ~]#ansible all -m fetch -a 'src=/etc/issue dest=/opt'

源文件存放的上级目录也会被抓取和创建, 相当于抓的整个路径

[15:42:22 root@ansible ~]#tree /opt
/opt
├── 10.0.0.187
│   └── etc
│       └── issue
├── 10.0.0.85
│   └── etc
│       └── issue
└── 10.0.0.86
    └── etc
        └── issue

6 directories, 3 files

2.6 file 模块

  • 配置被管理节点上的文件属性和目录属性
  • 也可以用来在被管理节点创建和删除文件
  • path=/PATH/文件名来指定文件路径和名称
  • state支持: absent, directory, file, hard, link, touch
touch: 创建文件, 要求上级目录已经存在, 否则会报错
absent: 如果文件存在则删除
directory: 
file: 仅显示文件状态
  返回state=absent: 说明文件在目标节点不存在
  返回state=file: 说明文件在目标节点不存在  

范例: state=file, 只会显示文件的状态

[15:45:57 root@ansible ~]#ansible all -m file -a 'path=/etc/issue state=file'
10.0.0.187 | SUCCESS => {
    "ansible_facts": {
        "discovered_interpreter_python": "/usr/bin/python"
    }, 
    "changed": false, 
    "gid": 0, 
    "group": "root", 
    "mode": "0644", 
    "owner": "root", 
    "path": "/etc/issue", 
    "size": 23, 
    "state": "file", 
    "uid": 0
}
10.0.0.85 | SUCCESS => {
    "ansible_facts": {
        "discovered_interpreter_python": "/usr/libexec/platform-python"
    }, 
    "changed": false, 
    "gid": 0, 
    "group": "root", 
    "mode": "0644", 
    "owner": "root", 
    "path": "/etc/issue", 
    "size": 23, 
    "state": "file", 
    "uid": 0
}
10.0.0.86 | SUCCESS => {
    "ansible_facts": {
        "discovered_interpreter_python": "/usr/libexec/platform-python"
    }, 
    "changed": false, 
    "gid": 0, 
    "group": "root", 
    "mode": "0644", 
    "owner": "root", 
    "path": "/etc/issue", 
    "size": 23, 
    "state": "file", 
    "uid": 0
}

state=touch - 创建文件, 但是需要所在路径存在, 否则命令执行会失败
state=absent - 删除文件

范例: 修改被管理节点的/data/yum.conf文件属性

  1. 先将ansible节点的yum.conf文件copy到被管理节点
[15:52:15 root@ansible ~]#ansible all -m copy -a 'src=/etc/yum.conf dest=/data'
[15:52:38 root@ansible ~]#ansible all -m shell -a 'ls -l /data'
10.0.0.187 | CHANGED | rc=0 >>
total 4
-rw-r--r-- 1 root root 970 Jan 31 15:52 yum.conf
10.0.0.85 | CHANGED | rc=0 >>
total 4
-rw-r--r-- 1 root root 970 Jan 31 15:52 yum.conf
10.0.0.86 | CHANGED | rc=0 >>
total 4
-rw-r--r-- 1 root root 970 Jan 31 15:52 yum.conf
  1. 修改文件属性
[15:54:48 root@ansible ~]#ansible all -m file -a 'path=/data/yum.conf mode=600 owner=daemon'
[15:54:48 root@ansible ~]#ansible all -m shell -a 'ls -l /data'
10.0.0.187 | CHANGED | rc=0 >>
total 4
-rw------- 1 daemon root 970 Jan 31 15:52 yum.conf
10.0.0.86 | CHANGED | rc=0 >>
total 4
-rw------- 1 daemon root 970 Jan 31 15:52 yum.conf
10.0.0.85 | CHANGED | rc=0 >>
total 4
-rw------- 1 daemon root 970 Jan 31 15:52 yum.conf

如果不涉及从ansible复制文件到目标主机, 只是修改目标主机的文件或者目录, 那么只需要path即可, 后面加state=MODE

范例:

#创建空文件
ansible all -m file -a 'path=/data/test.txt state=touch' #state=touch不会递归创建目录, 因此要求路径必须已经存在
ansible all -m file -a 'path=/data/test.txt state=absent' #absent,如果文件存在则删除
ansible all -m file -a 'path=/root/test.sh owner=wang mode=755'

#创建目录
ansible all -m file -a 'path=/data/mysql state=directory owner=mysql' group=mysql' # directory会递归创建父目录
#创建软连接
ansible all -m file -a 'src=/data/testfile path|dest|name=/data/testfile-link state=link' # src是被管理节点本地的文件, 因为file就是管理远程节点的文件或目录
#创建目录
ansible all -m file -a 'path=/data/testdir state=directory'

2.7 unarchive 模块

  • 解包解压文件

实现有两种用法:

  • 1 将ansible主机上的压缩包传到远程主机后解压缩至指定目录, 设置copy=yes
  • 2 将远程主机上的某个压缩包解压缩到指定的路径下, 设置copy=no

常见参数:

copy: 默认为yes, 当copy=yes, 拷贝的文件是从ansible主机复制到远程主机上, 如果设置为copy=no, 那么会在远程主机上寻找src源文件
remote_src: 和copy功能一样且互斥, yes表示在远程主机, 不在ansible主机, no表示文件在ansible主机上
src: 源文件, 可以是ansible主机上的路径, 也可以是远程主机上的路径, 如果是远程主机上的路径则需要设置copy=no
dest: 远程主机上的目标路径
mode: 设置解压缩后的文件权限
# 注意: 将ansible主机上的压缩包, 复制到目标主机的路径必须是存在的, 不存在会报错, 要手动创建
ansible all -m unarchive -a 'src=/data/foo.tgz dest=/var/lib owner=daemon group=bin'
ansible all -m unarchive -a 'src=/tmp/foo.zip dest=/data copy=no mode=0777'
# 也可以直接把互联网上的文件, 直接下载到被管理节点, 此时copy=no, src的值为互联网的文件的路径
ansible all -m unarchive -a 'src=https://www.baidu.com/image.jpg dest=/data copy=no'

2.8 archive 模块

  • 将远程主机上的文件打包压缩到指定的路径

  • 可以配合fetch模块, 先将远程主机上的文件打包, 然后抓取到ansible管理节点

范例:

#archive
[16:04:17 root@ansible ~]#ansible all -m archive -a 'path=/var/log dest=/tmp/log.tar.bz2 format=bz2 mode=600' # archive可以指定权限
#fetch
[16:04:51 root@ansible ~]#ansible all -m fetch -a 'src=/tmp/log.tar.bz2 dest=/data/prac'
[16:05:53 root@ansible ~]#ll /data/prac
total 0
drwxr-xr-x 3 root root 17 Jan 31 16:05 10.0.0.187
drwxr-xr-x 3 root root 17 Jan 31 16:05 10.0.0.85
drwxr-xr-x 3 root root 17 Jan 31 16:05 10.0.0.86
[16:05:55 root@ansible ~]#tree /data/prac
/data/prac
├── 10.0.0.187
│   └── tmp
│       └── log.tar.bz2
├── 10.0.0.85
│   └── tmp
│       └── log.tar.bz2
├── 10.0.0.86
│   └── tmp
│       └── log.tar.bz2

2.9 hostname 模块

  • 无法批量修改主机名, 每次只能修改一个
  • 支持多版本, 会自动识别不同版本系统存放主机名的文件, 并且修改该文件, 并且立即永久生效
CentOS6: /etc/sysconfig/network
CentOS7-8: /etc/network

范例:

[16:28:56 root@ansible ~]#ansible 10.0.0.100 -m hostname -a 'name=node1.com'

2.10 cron 模块

功能: 定义远程管理主机上执行计划任务
支持时间: minute, hour, day, month, weekday
如果计划任务是执行脚本, 那么要求远程主机上有该脚本, 或者先在ansible上编写脚本, 再通过copy拷贝到远程主机

范例:

#创建任务
ansible 10.0.0.238 -m cron -a 'hour=2 minute=30 weekday=1-5 name="backup mysql" job=/root/mysql_backup.sh'
#hour=2 表示2点
#minute=30 表示2点半
#weekday=1-5 表示周一到周五
#name 给计划任务起名
#job 实际执行的脚本

执行命令后, 会在管理节点的/etc/crontab里面创建计划任务

禁用计划任务

ansible websrvs -m cron -a 'hour=2 minute=30 weekday=1-5 name="backup mysql" job=/root/mysql_backup.sh disabled=yes'

启用计划任务

ansible websrvs -m cron -a 'hour=2 minute=30 weekday=1-5 name="backup mysql" job=/root/mysql_backup.sh disabled=no'

删除计划任务

ansible websrvs -m cron -a 'name="backup mysql" state=absent'
ansible websrvs -m crom -a 'name=backup mysql state=absent'

2.11 yum和apt 模块

红帽系统用yum模块
Ubuntu用apt
需要仓库在目标节点提前配好

范例: websrvs组安装httpd

[14:39:31 root@ansible ~]#ansible websrvs -m yum -a 'name=httpd state=present' # present是安装,默认就是present安装,  absent是卸载

范例: websrvs组卸载httpd

[14:39:31 root@ansible ~]#ansible websrvs -m yum -a 'name=httpd state=absent'

范例: 同时安装多个软件

[00:30:59 root@ansible ~]#ansible all -m yum -a 'name=nginx,httpd state=present'

2.12 service 模块

  • 管理远程主机上的service 服务

管理目标主机上的服务, 设置为开机启动, 停止, 重启等

ansible all -m service -a 'name=httpd state=started enabled=yes'  # 启动httpd, 设置开启自启
ansible all -m service -a 'name=httpd state=stopped' # 关闭httpd
ansible all -m service -a 'name=httpd state=reloaded' # 重启httpd
ansible all -m shell -a "sed -i 's/^Listen 80/Listen 8080/ /etc/httpd/conf/httpd.conf'" # 批量修改配置文件

2.13 user 模块

管理用户: 批量创建, 删除同一个用户

#创建用户
ansible all -m user -a 'name=user1 comment="test user" uid=2048 home=/app/user1 group=root'
ansible all -m user -a 'name=nginx comment=nginx uid=88 group=nginx groups="root, daemon" shell=/sbin/nologin system=yes create_home=no home=/data/nginx non_unique=yes' # non_uniqu=yes: 忽略同名用户引起的冲突
#state=absent表示删除用户
#remove=yes表示删除用户家目录数据,默认remove=no
ansible all -m user -a 'name=nginx state=absent remove=yes'

2.14 group 模块

管理组: 批量创建, 删除同一个组

#创建组
ansible websrvs -m group -a 'name=nginx gid=88 system=yes'
#删除组
ansible websrvs -m group -a 'name=nginx state=absent'

2.15 lineinfile 模块

ansible在使用sed时经常会遇到需要转义的问题, 而且ansible在遇到特殊符号进行替换时存在问题, 无法正常进行替换, 其实在ansible自身还提供了两个模块, lineinfile模块和replace模块

一般在ansible中当去修改某个文件的单行进行替换的时候需要使用lineinfile

regexp参数: 使用正则表达式匹配对应的行, 进行替换文本时, 如果有多行文本都能被匹配, 则只有最后面被匹配到的那行才会被替换, 当删除文本时, 如果有多行文本都能被匹配, 这些行都会被删除, 如果想多行匹配替换, 建议用replace

ansible websrvs -m lineinfile -a "path=/etc/httpd/conf/httpd.conf regexp='^Listen' line='Listen 80'"

2.16 replace 模块

类似于sed命令, 基于正则匹配和替换, 会对匹配到的所有行进行操作

ansible all -m replace -a "path=/etc/fstab regexp='^(UUID.*)' replace='#\1'"

2.17 setup 模块

该模块用来收集主机的系统信息, 这些facts信息可以直接以变量的形式使用, 但是如果主机较多, 会影响执行速度, 可以使用gather_facts:no 来禁止ansible收集facts信息

通过这些信息, 在进行批量管理时, 可以根据每台服务器上的不同参数进行操作, 实现条件判断

范例:

ansible all -m setup #获取所有setup信息, 可以当做变量使用
ansible all -m setup -a 'filter=ansible_hostname' #获取指定的setup信息
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 214,837评论 6 496
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,551评论 3 389
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 160,417评论 0 350
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,448评论 1 288
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,524评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,554评论 1 293
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,569评论 3 414
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,316评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,766评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,077评论 2 330
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,240评论 1 343
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,912评论 5 338
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,560评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,176评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,425评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,114评论 2 366
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,114评论 2 352

推荐阅读更多精彩内容