ansible是一个同时管理多个远程主机的软件,必须是任意可以通过ssh登录的机器,隐藏ansible可以管理的机器如
ansible特点
ansible的编排引擎可以完成各种出色的任务任务,ansible在流程控制,资源部署方便很强大,并且ansible无须安装客户端软件,管理简洁,使用yaml配置文件语法,功能强大,便于维护。
ansible是基于python语言开发,主要由python的两个ssh处理模块,paramikl以及pyyaml模块
准备好3台Linux虚拟机,配置在同一个局域网内,然后设置好静态IP
master 192.168.29.152 管理机
node1 192.168.29.137 被管理机
node2 192.168.29.134 被管理机
1、选择yum自动化安装
yum install epel-release -y
yum install ansible libselinux-python -y
2、安装情况
[root@master ~]# rpm -ql ansible|grep -E '^/etc|^/usr/bin'
/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
3、查看版本
[root@master ~]# ansible --version
ansible 2.9.27
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, Mar 12 2021, 14:55:44) [GCC 4.8.5 20150623 (Red Hat 4.8.5-44.0.3)]
安装ansible模块
yum install -y epel-release libseliunx-python -y
配置好ansible的配置文件,添加被管理机的ip,或者主机名
1.备份现有的配置文件
cp /etc/ansible/hosts{,.ori} ##将hosts文件拷贝出一个hosts.ori的文件
2.配置host文件,添加被管理的主机IP
[root@master ansible]# tail -3 hosts
[test]
node1 #可以是ip地址,可以是主机名
node2
ansible是直接利用linux本地的ssh服务,以及一些远程的ssh操作,一般情况下客户的ssh服务默认都是开启的,无须额外管理
1.在管理机上执行如下命令 -m是指功能模块(command是命令)
ansible 主机列表 -m command -a ‘hostname’ -k -u root #输出所有列表主机的主机名
2.以上命令第一次运行时可能会报错,此时需要手动连接一下被管理主机
[root@master ansible]# ansible test -m command -a 'hostname' -k -u root
SSH password:
node1 | CHANGED | rc=0 >>
node1
node2 | CHANGED | rc=0 >>
node2
命令 | 说明 |
---|---|
-m | 要执行的模块,默认为command |
-a | 指定模块的参数 |
-u | ssh连接的用户名,默认用root,ansible.cfg中可以配置 |
-b,–become | 变成那个用户身份,不提示密码 |
-k | 提示输入ssh登录密码,当使用密码验证的时候用 |
-s | sudo运行 |
-U | sudo到哪个用户,默认为root |
-K | 提示输入sudo密码,当不是NOPASSWD模式时使用 |
-C | 只是测试一下会改变什么内容,不会真正去执行 |
-c | 连接类型(default=smart) |
-f | fork多少进程并发处理,默认为5个 |
-i | 指定hosts文件路径,默认default=/etc/ansible/hosts |
-I | 指定pattern,对已匹配的主机中再过滤一次 |
-list-host | 只打印有哪些主机会执行这个命令,不会实际执行 |
-M | 要执行的模块路径,默认为/usr/share/ansible |
-o | 压缩输出,摘要输出 |
–private-key | 私钥路径 |
-T | ssh连接超时时间,默认是10秒 |
-t | 日志输出到该目录,日志文件名以主机命名 |
-v | 显示详细日志 |
每次执行ansible命令的时候,都需要输入ssh认证密码,也就是root密码,如果不同的主机密码不一致,那还有多次输入才行
可以在 /etc/ansible/hosts文件中,定义好密码即可,
参数
ansible_host 主机地址
ansible_port 端口,默认22端口
ansible_user 认证用户
ansible_ssh_pass 用户认证密码
修改如下:
[root@master ansible]# tail -5 hosts
[test]
master ansible_user=root ansible_ssh_pass=root
node1 ansible_user=root ansible_ssh_pass=root
node2 ansible_user=root ansible_ssh_pass=root
效果:
[root@master ansible]# ansible test -m command -a 'hostname'
node2 | CHANGED | rc=0 >>
node2
node1 | CHANGED | rc=0 >>
node1
master | CHANGED | rc=0 >>
master
以上的密码认证方式,存在密码泄露的风险,所以可以用hosts文件的密码参数来连接,更加安全
1.在管理机上创建ssh密钥对
ssh-keygen -f ~/.ssh/id_rsp -P “” > /dev/null 2>&1 ##创建密钥对,”-p "指忽略输入密码 并将密钥文件放在~/.ssh/目录下的id_rsp文件中,不在运行过程中输出任何内容。
内容如下:
[root@master /]# mkdir mysh
[root@master /]# cd mysh/
[root@master mysh]# touch ssh_key_send.sh
[root@master mysh]# cat ssh_key_send.sh
#!/bin/bash
rm -rf ~/.ssh/id_rsa*
ssh-keygen -f ~/.ssh/id_rsa -P "" > /dev/null 2>&1
SSH_Pass=root
touch ~/.ssh/id_rsa.pub
Key_Path=~/.ssh/id_rsa.pub
for ip in master node1 node2
do
sshpass -p$SSH_Pass ssh-copy-id -i $Key_Path "-o StrictHostKeyChecking=no" $ip
done
# 非交互式分发公钥命令需要用sshpass指定SSH密码,通过-o StrictHostKeyChecking=no 跳过SSH连接确认信息
[root@master mysh]# sh ssh_key_send.sh
/usr/bin/ssh-copy-id: INFO: Source of key(s) to be installed: "/root/.ssh/id_rsa.pub"
/usr/bin/ssh-copy-id: INFO: attempting to log in with the new key(s), to filter out any that are already installed
/usr/bin/ssh-copy-id: INFO: 1 key(s) remain to be installed -- if you are prompted now it is to install the new keys
Number of key(s) added: 1
Now try logging into the machine, with: "ssh -o ' StrictHostKeyChecking=no' 'master'"
and check to make sure that only the key(s) you wanted were added.
/usr/bin/ssh-copy-id: INFO: Source of key(s) to be installed: "/root/.ssh/id_rsa.pub"
/usr/bin/ssh-copy-id: INFO: attempting to log in with the new key(s), to filter out any that are already installed
/usr/bin/ssh-copy-id: INFO: 1 key(s) remain to be installed -- if you are prompted now it is to install the new keys
Number of key(s) added: 1
Now try logging into the machine, with: "ssh -o ' StrictHostKeyChecking=no' 'node1'"
and check to make sure that only the key(s) you wanted were added.
/usr/bin/ssh-copy-id: INFO: Source of key(s) to be installed: "/root/.ssh/id_rsa.pub"
/usr/bin/ssh-copy-id: INFO: attempting to log in with the new key(s), to filter out any that are already installed
/usr/bin/ssh-copy-id: INFO: 1 key(s) remain to be installed -- if you are prompted now it is to install the new keys
Number of key(s) added: 1
Now try logging into the machine, with: "ssh -o ' StrictHostKeyChecking=no' 'node2'"
and check to make sure that only the key(s) you wanted were added.
输入:ssh -o ’ StrictHostKeyChecking=no’ ‘node1’ 即可直接连接到node1机器上去
[root@master mysh]# ssh -o ' StrictHostKeyChecking=no' 'node1'
Last login: Mon Apr 11 11:25:11 2022 from master
[root@node1 ~]#
ansible的hosts文件里面也不用配置用户名和密码了
[root@master ansible]# tail -7 hosts
[test]
#master ansible_user=root ansible_ssh_pass=root
#node1 ansible_user=root ansible_ssh_pass=root
#node2 ansible_user=root ansible_ssh_pass=root
master
node1
node2
[root@master ansible]# ansible test -m command -a "uname -a"
node2 | CHANGED | rc=0 >>
Linux node2 3.10.0-1062.el7.x86_64 #1 SMP Wed Aug 7 18:08:02 UTC 2019 x86_64 x86_64 x86_64 GNU/Linux
node1 | CHANGED | rc=0 >>
Linux node1 3.10.0-1062.el7.x86_64 #1 SMP Wed Aug 7 18:08:02 UTC 2019 x86_64 x86_64 x86_64 GNU/Linux
master | CHANGED | rc=0 >>
Linux master 4.14.35-2047.506.8.el7uek.x86_64 #2 SMP Tue Aug 3 20:05:09 PDT 2021 x86_64 x86_64 x86_64 GNU/Linux
在生产环境中,ansible的连接方式,二选一,最好使用ssh公钥免密登录。
ansible实现批量化主机管理模式,主要有两种
查看支持的模块
ansible-doc -f
作用:在远程节点上执行一个命令
ansible-doc -s command 查看该模块支持的参数
命令 | 说明 |
---|---|
chdir | 在执行命令之前,先通过cd进入参数指定的目录 |
creates | 在创建一个文件之前,判断该文件是否存在,如果存在了则跳过前面的东西,如果不存在则执行前面的动作 |
free_form | 该参数可以输入任何的系统命令,实现远程执行和管理 |
removes | 定义一个文件是否存在,如果存在了则执行前面的动作,如果不存在则跳到动作 |
command模板是ansible的默认基本模块,也可以省略不写,但是要注意如下的坑
获取所有被管理机器的负载信息
[root@master ~]# ansible test -m command -a "uptime"
node2 | CHANGED | rc=0 >>
14:23:39 up 4:19, 2 users, load average: 0.11, 0.17, 0.20
node1 | CHANGED | rc=0 >>
14:23:40 up 4:23, 2 users, load average: 0.25, 0.22, 0.26
master | CHANGED | rc=0 >>
14:23:40 up 4:20, 3 users, load average: 2.30, 1.34, 1.01
让客户机,先切换到/tmp目录下,然后输出当前的目录位置。
[root@master ~]# ansible test -m command -a "pwd chdir=/tmp"
node1 | CHANGED | rc=0 >>
/tmp
node2 | CHANGED | rc=0 >>
/tmp
master | CHANGED | rc=0 >>
/tmp
练习creates参数
在创建一个文件之前,判断该文件或者文件夹是否存在,如果存在了则跳过前面的东西,如果不存在则执行前面的动作
判断node1主机的是否存在tmp这样的根目录,如果存在,则不执行前面的pwd,如果不存在则执行前面的pwd
[root@master ~]# ansible node1 -m command -a "pwd creates=/tmp"
node1 | SUCCESS | rc=0 >>
skipped, since /tmp exists
参数removes实践,存在则执行,不存在则跳过
[root@master ~]# ansible test -m command -a "ls /opt removes=/tmp"
node1 | CHANGED | rc=0 >>
cni
jdk1.8.0_281
jdk-8u281-linux-x64.tar.gz
mqm
nginx
node2 | CHANGED | rc=0 >>
cni
containerd
jdk1.8.0_281
jdk-8u281-linux-x64.tar.gz
mqm
nginx
src
ssh
master | CHANGED | rc=0 >>
apache-tomcat-9.0.46
apache-tomcat-9.0.46.tar.gz
cni
containerd
warn参数 是否提供告警信息
[root@master ~]# ansible test -m command -a "chmod 000 /etc/hosts"
[WARNING]: Consider using the file module with mode rather than running 'chmod'. If you need to use command because file is insufficient you can add 'warn: false' to this command task or set
'command_warnings=False' in ansible.cfg to get rid of this message.
node2 | CHANGED | rc=0 >>
node1 | CHANGED | rc=0 >>
master | CHANGED | rc=0 >>
[root@master ~]# ansible test -m command -a "chmod 000 /etc/hosts warn=False"
node1 | CHANGED | rc=0 >>
node2 | CHANGED | rc=0 >>
master | CHANGED | rc=0 >>
作用:在远程机器上执行命令(复杂的命令)
shell模块支持的参数和模块
参数 | 解释 |
---|---|
chdir | 在执行命令之前,先通过cd进入参数指定的目录 |
creates | 在创建一个文件之前,判断该文件是否存在,如果存在了则跳过前面的东西,如果不存在则执行前面的动作 |
free_form | 该参数可以输入任何的系统命令,实现远程执行和管理 |
removes | 定义一个文件是否存在,如果存在了则执行前面的动作,如果不存在则跳到动作 |
warn | 是否输出报警 |
shell模块案例
[root@master ~]# ansible test -m shell -a "ps -ef|grep ssh|grep -v grep"
node2 | CHANGED | rc=0 >>
root 1045 1 0 10:04 ? 00:00:00 /usr/sbin/sshd -D
root 52836 1045 0 14:42 ? 00:00:01 sshd: root@pts/0
master | CHANGED | rc=0 >>
root 1388 1 0 10:04 ? 00:00:00 /usr/sbin/sshd -D
root 63961 1388 0 14:07 ? 00:00:00 sshd: root@pts/1
node1 | CHANGED | rc=0 >>
root 1046 1 0 10:00 ? 00:00:00 /usr/sbin/sshd -D
root 79980 1046 5 15:14 ? 00:00:00 sshd: root@pts/0
批量执行脚本,必须要求脚本在客户端机器上要存在,这是shell模块的特点,是因为还有一个专门执行脚本的script模块
1.创建文件夹
2.创建sh脚本文件,还有写入脚本内容
3.赋予脚本可执行权限
4.执行脚本
5.忽略warning信息
[root@master tmp]# ansible test -m shell -a "mkdir -p /tmp/myscriptes/;echo 'hostname' > /tmp/myscriptes/hostname.sh;chmod +x /tmp/myscriptes/hostname.sh;sh /tmp/myscriptes/hostname.sh warn=False"
node1 | CHANGED | rc=0 >>
node1
node2 | CHANGED | rc=0 >>
node2
master | CHANGED | rc=0 >>
master
[root@master tmp]# ll
总用量 8
-rw-r--r-- 1 root root 13 4月 11 15:17 hahah.txt
drwxr-xr-x 2 root root 25 4月 11 15:28 myscriptes
功能:把管理机上的脚本远程传输到被管理的机上去执行
script模块参数
参数 | 解释 |
---|---|
chdir | 在执行命令之前,先通过cd进入参数指定的目录 |
creates | 在创建一个文件之前,判断该文件是否存在,如果存在了则跳过前面的东西,如果不存在则执行前面的动作 |
free_form | 该参数可以输入任何的系统命令,实现远程执行和管理 |
removes | 定义一个文件是否存在,如果存在了则执行前面的动作,如果不存在则跳到动作 |
warn | 是否输出报警 |
应用案例
1.在管理节点上创建一个脚本
[root@master myscriptes]# echo -e “pwd\nhostname”> ./local_hostname.sh
[root@master myscriptes]# cat local_hostname.sh
pwd
hostname
2.赋权
[root@master myscriptes]# chmod +x local_hostname.sh
远程执行脚本,且在被管理机上不需要存在该脚本
[root@master myscriptes]# ansible test -m script -a "local_hostname.sh"
node1 | CHANGED => {
"changed": true,
"rc": 0,
"stderr": "Shared connection to node1 closed.\r\n",
"stderr_lines": [
"Shared connection to node1 closed."
],
"stdout": "/root\r\nnode1\r\n",
"stdout_lines": [
"/root",
"node1"
]
}
node2 | CHANGED => {
"changed": true,
"rc": 0,
"stderr": "Shared connection to node2 closed.\r\n",
"stderr_lines": [
"Shared connection to node2 closed."
],
"stdout": "/root\r\nnode2\r\n",
"stdout_lines": [
"/root",
"node2"
]
}
master | CHANGED => {
"changed": true,
"rc": 0,
"stderr": "Shared connection to master closed.\r\n",
"stderr_lines": [
"Shared connection to master closed."
],
"stdout": "/root\r\nmaster\r\n",
"stdout_lines": [
"/root",
"master"
]
}