部署密钥认证
免密码登录、双机互信
一些服务在使用前要求做密钥认证,管理轻松。手动写批量管理脚本。
==注:密钥认证是单向==
密钥对
公钥:public key 一般以.pub结尾
私钥:private key
角色 | 主机名 | IP |
---|---|---|
管理机 | m01 | 192.168.10.50 |
被管理机 | nfs01 | 192.168.10.51 |
被管理机 | web01 | 192.168.10.52 |
被管理机 | backup | 192.168.10.53 |
常规密钥
无密钥前检测
#ping
......
#22端口 sshd服务开启或可以访问
[root@m01 ~]# nmap -p 22 nfs01 web01 buckup
Starting Nmap 6.40 ( http://nmap.org ) at 2024-03-10 21:03 EDT
Nmap scan report for nfs01 (192.168.10.51)
Host is up (0.00013s latency).
PORT STATE SERVICE
22/tcp open ssh
MAC Address: 00:0C:29:53:DD:74 (VMware)
Nmap scan report for web01 (192.168.10.52)
Host is up (0.00025s latency).
PORT STATE SERVICE
22/tcp open ssh
MAC Address: 00:0C:29:29:8F:D8 (VMware)
Nmap scan report for buckup (192.168.10.53)
Host is up (0.00022s latency).
PORT STATE SERVICE
22/tcp open ssh
MAC Address: 00:0C:29:3A:62:EB (VMware)
Nmap done: 3 IP addresses (3 hosts up) scanned in 0.42 seconds
创建密钥
[root@m01 ~]# ssh-keygen -t rsa
Your identification has been saved in /root/.ssh/id_rsa.
Your public key has been saved in /root/.ssh/id_rsa.pub.
公钥和私钥
[root@m01 ~]# cd /root/.ssh/
[root@m01 .ssh]# ls
id_rsa id_rsa.pub known_hosts #都是加密的
分发公钥
[root@m01 ~]# ssh-copy-id -i /root/.ssh/id_rsa.pub root@buckup
测试
ssh root@192.168.10.51
公钥分发的位置
[root@nfs01 ~]# cd /root/.ssh/
[root@nfs01 .ssh]# ls #位置不变 密钥文件名改变
authorized_keys
自动创建与分发密钥
集群数量庞大,无法每个单独配置
阻碍:
1.创建密钥对
2.分发公钥的时候:yes/no(yes会保存到 .ssh/know_hosts)
3.分发公钥的时候:输入密码
sshpass作用
sshpass适用于ssh相关的命令提供密码:ssh,scp,ssh-copy-id
expect,用户实现非交互式判断,认证操作 yes/no
#在无密钥认证的时候 使用ssh不可加参数也必须交互式输密码
[root@m01 ~]# sshpass -proot ssh nfs01
-p指定密码 ssh是指定命令
注意:sshpass,ssh-copy-id第一次连接,如果提示yes/no,则sshpass失效!
创建密钥参数
[root@m01 ~]# ssh-keygen -f ~/.ssh/id_rsa -P ''
-f 参数用于指定私钥位置
-P 参数是密码短语 设置为空
#创建密钥时 就不需要回车
分发密钥
[root@m01 ~]# sshpass -proot ssh-copy-id -i ~/.ssh/id_rsa.pub buckup
#分发公钥时就不需输入密码
第一次建立连接yes/no
#非建立连接过的主机在ssh,ssh-copy时会提示yes/no
#建立连接后的主机信息会记录在/root/.ssh/know_hosts中
#在建立连接时 -oStrictHostKeyChecking=no 临时不检查主机信息(know_hosts)
[root@m01 ~]# ssh nfs01
The authenticity of host 'nfs01 (192.168.10.51)' can't be established.
ECDSA key fingerprint is SHA256:p6P+DDIogoJ7Q4OMmGs18IftWDwEWR4TEhiJ5SptmZU.
ECDSA key fingerprint is MD5:6a:c1:a5:66:a0:f6:38:11:ac:72:a7:ca:8a:fe:87:18.
Are you sure you want to continue connecting (yes/no)?
[root@m01 ~]# ssh-copy-id -oStrictHostKeyChecking=no nfs01
解决建立连接时yes/no提示
[root@m01 ~]# sshpass -proot ssh-copy-id -oStrictHostKeyChecking=no nfs01
#解决yes/no以及密码提示
脚本执行
[root@m01 ~]# cat sshkey.sh
#!/bin/bash
#auther: To9cn
#version: v1
#desc: 自动创建密钥对 自动分发公钥
passwd=root
ips="192.168.10.51 192.168.10.52 192.168.10.53"
#环境判断 是否联网、是否可以使用yum...
yum install -y sshpass
#创建密钥对
if [ -f ~/.ssh/id_rsa ]
then
echo "密钥对存在!"
sleep 1
else
echo "密钥对不存在; 开始创建密钥对..."
ssh-keygen -t rsa -f ~/.ssh/id_rsa -P '' &>/dev/null
sleep 1
echo "密钥对创建成功!"
fi
#分发公钥
for ip in $ips
do
sshpass -p${passwd} ssh-copy-id -oStrictHostKeyChecking=no $ip
echo "$ip 成功分发密钥!"
sleep 1
done
检查脚本
测试无密钥的连通性
[root@m01 ~]# cat test_ssh.sh
#!/bin/bash
#auther: To9cn
#desc: 批量执行命令
for ip in 192.168.10.51 192.168.10.52 192.168.10.53
do
ssh $ip hostname
done
[root@m01 ~]# ./test_ssh.sh
nfs01
web01
buckup
Ansible
自动化运维:批量管理、批量分发、批量执行与维护...
导图:https://www.processon.com/view/link/61addd266376896056c1b1b2
任务:
- 熟练脚本部署密钥认证
- Ansible批量管理结构
- Ansible主机清单(添加、管理集群)
- Ansible常用模块
- Ansible-批量管理-批量部署-批量分发
Ansible管理架构
Inventory :主机清单---被管理主机的IP列表,分类。
ad-hoc模式:==命令行==批量管理(使用模块),临时任务。
playbook:剧本模式---把操作写出脚本,可重复运行这个脚本
Ansible模块概述:
- ansible中的模块就类似于Linux中的命令,我们Linux命令管理系统,我们通过ansible模块实现批量管理.
- ansible中模块一般相当于Linux中的一些命令.yum模块,file模块,user模块.
- ansible中的模块拥有不同的选项,这些选项一般都是一些单词.有自己格式和要求
- Ansible模块 modules Ansible中通过各种模块实现批量管理.
- 一般来说这些模块对应着Linux里面的基本操作或服务管理。找出Linux场景操作对应的模块即可.
Ansible安装
epel源
yum -y install epel-release
yum -y install vconfig -y
yum install -y ansible
[root@m01 ~]# ansible --version
ansible 2.9.27
优化配置
修改配置文件关闭Host_key_checking(yes/no)
修改配置文件开启日志功能
[root@m01 ~]# vim /etc/ansible/ansible.cfg
71行:关闭主机检测
112行:开启日志功能
[root@m01 ~]# egrep -vn '^$|#' /etc/ansible/ansible.cfg
11:[defaults]
72:host_key_checking = False
112:log_path = /var/log/ansible.log
328:[inventory]
341:[privilege_escalation]
347:[paramiko_connection]
371:[ssh_connection]
432:[persistent_connection]
446:[accelerate]
461:[selinux]
470:[colors]
486:[diff]
Ans-Inventory主机清单
主机清单格式
[分类或组的名字] #服务器集群用途
IP或主机名或域名 #主机名要解析(etc/hosts)
ansible管理的主机节点的列表---默认读取/etc/ansible/hosts,一般会把清单放在指定位置。
## db-[99:101]-node.example.com
[nfs]
192.168.10.51
[web]
192.168.10.52
[buckup]
192.168.10.53
没有公钥的主机清单配置(不推荐)
[nfs]
192.168.10.51 ansible_user=root ansible_password=123 ansible_port=22
测试
[root@m01 ~]# ansible all -m ping
#-m指定模块
#all可以替换为nfs,web等分组内容,也可写IP单必须在主机组
192.168.10.53 | SUCCESS => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/bin/python"
},
"changed": false,
"ping": "pong"
}
#获取被管理节点 系统信息
[root@m01 ~]# ansible all -a "cat /etc/os-release"
192.168.10.51 | CHANGED | rc=0 >>
NAME="CentOS Linux"
VERSION="7 (Core)"
ID="centos"
ID_LIKE="rhel fedora"
VERSION_ID="7"
PRETTY_NAME="CentOS Linux 7 (Core)"
ANSI_COLOR="0;31"
CPE_NAME="cpe:/o:centos:centos:7"
HOME_URL="https://www.centos.org/"
BUG_REPORT_URL="https://bugs.centos.org/"
子组
期望对backup,nfs两组,再创建新分组data:[data:children]
#创建新分组,包含已有的分组backup,nfs
[data:children]
nfs
backup
[root@m01 ~]# ansible data -m ping
192.168.10.51 | SUCCESS => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/bin/python"
},
"changed": false,
"ping": "pong"
}
Ansible模块
模块的本质是替换Linux命令。模块有不同选项(单词),有自己的格式
查看ansible全部模块
ansible-doc -l #全部模块
ansible-doc -s file #搜索模块、找模块参数
模块分类 | 模块 |
---|---|
命令和脚本模块 | command模块 默认模块 执行简单命令,不支持特殊符号 |
shell模块 执行命令 支持特殊符号 | |
script模块 分发脚本并执行 | |
文件 | file 创建目录,文件,软连接 |
copy 远程分发文件,修改权限,所有者,备份 | |
服务 | systemd服务管理 |
service 服务管理(了解) | |
软件包 | yum源 yum_repository |
yum命令 | |
get_url下载软件 | |
系统管理 | mount模块 挂载 |
cron模块 定时任务 | |
用户管理 | group模块 管理用户组 |
user模块 管理用户 | |
其他 | 压缩解压(unarchive),rsync模块(synchronize),数据库模块(mysql_db,mysql_user)... |
调试模块 | ping检测ansible与其它节点连通性 |
debug模块 检查、显示 变量 | |
命令和脚本
1.command模块
是ans默认模块,适用于简单命令,不支持特殊符号
[root@m01 ~]# ansible all -m command -a "hostname"
#-m 指定模块,-a模块的选项(命令);command也是默认模块 可以不写
# ansible all -a "hostname"
192.168.10.53 | CHANGED | rc=0 >>
buckup
192.168.10.52 | CHANGED | rc=0 >>
web01
192.168.10.51 | CHANGED | rc=0 >>
nfs01
2.shell模块
与command模块相似,但支持特殊符号(==避免因特殊符号和引号导致的问题==)
ansible all -m shell -a 'rm -rf /tmp/*' #可用双引号
批量获取IP
[root@m01 ~]# ip a s ens33 | awk -F'[/ ]+' 'NR==3{print $3}'
192.168.10.50
[root@m01 ~]# ansible all -m shell -a "ip a s ens33 | awk -F'[/ ]+' 'NR==3{print \$3}'"
#“”转义特殊符号,\转义‘’号中的特殊符号
192.168.10.52 | CHANGED | rc=0 >>
192.168.10.52
192.168.10.51 | CHANGED | rc=0 >>
192.168.10.51
192.168.10.53 | CHANGED | rc=0 >>
192.168.10.53
shell模块不推荐执行较为复杂的命令,如果需要,可放在脚本中执行
3.script模块
1.分发脚本(传输脚本),在被管理端执行脚本
2.运行脚本
注:被控制节点执行完脚本后才有反馈
[root@m01 script]# cat xuntest.sh
#!/bin/bash
#auther: To9cn
#desc: 系统巡检脚本
hostname
hostname -I
ip a s ens33 | awk -F'[/ ]+' 'NR==3{print $3}'
uptime
whoami
date +%F
sleep 3
#模块执行
[root@m01 script]# ansible all -m script -a '/root/script/xuntest.sh'
#被管理端ps -ef | grep ansible 可查看临时脚本文件路径
[root@nfs01 ~]# ps -ef | grep ansible
root 11774 11749 0 21:58 pts/0 00:00:00 /bin/sh -c /root/.ansible/tmp/ansible-tmp-1710208685.15-15173-53973950998774/xuntest.sh && sleep 0
#执行玩脚本以后文件自动删除
4.debug模块
执行Ansible在命令行只会显示OK,Changed等,debug模块可自定义==控制台输出内容==
[root@m01 playbook]# ansible all -m debug -a "msg='hello word'"
#剧本模式
debug:
msg: "Test Debug"
-v参数
[root@m01 test]# ansible -i inventory web --list-hosts -v #显示cfg的配置文件
Using /etc/ansible/ansible.cfg as config file
hosts (1):
192.168.10.52
文件相关模块
1.file模块
管理文件、目录、软连接
file模块把touch、mkdir、rm、ln等命令结合在一起
file模块 | 模块说明 |
---|---|
==path== | 目录、文件路径 必写 |
src | 源文件一般用link(创建软连接) 用于指定源文件 |
==state== | 状态(模式) state=directory 创建目录 state=file(默认) 更新文件,若文件不存在不创建 state=link 创建软连接 state=touch 创建文件 |
==state== | state=absent 删除 (如果是目录递归删除目录) |
mode | mode=755 创建并修改权限 |
owner | onwer=root |
group | group=root |
被控制节点批量创建删除文件、目录
[root@m01 ~]# ansible all -m file -a "path=/opt/test.sh state=touch"
#删除
[root@m01 ~]# ansible all -m file -a "path=/opt/test.sh state=absent"
[root@m01 ~]# ansible all -m file -a "path=/root/test/abc/ state=directory"
#支持创建多级目录
#软连接
ansible all -m file -a "path=/opt/hosts src=/etc/hosts state=link" #path是创建后叫什么放哪 src是源文件
#检测
[root@m01 ~]# ansible all -a 'ls -l /opt/hosts'
192.168.10.53 | CHANGED | rc=0 >>
lrwxrwxrwx. 1 root root 10 Mar 11 23:00 /opt/hosts -> /etc/hosts
192.168.10.52 | CHANGED | rc=0 >>
lrwxrwxrwx. 1 root root 10 Mar 11 23:00 /opt/hosts -> /etc/hosts
192.168.10.51 | CHANGED | rc=0 >>
lrwxrwxrwx. 1 root root 10 Mar 11 23:00 /opt/hosts -> /etc/hosts
#owner修改所有者;推荐在创建时指定属主、权限...
[root@m01 ~]# ansible all -m file -a "path=/testmdr/ owner=root group=root mode=777 state=directory"
#属主和组必须存在才可成功
#控制节点检测
[root@m01 ~]# ansible all -a 'ls -ld /testmdr'
2.copy模块
批量分发:scp,管理节点发送文件到所有被管理端
注:copy传输是单向的
copy模块 | |
---|---|
==src== | source 源文件,管理端的文件(不推荐传目录) |
==dest== | destnation 目标;被管理端的目录文件 |
backup | backup=yes 在覆盖前进行备份(文件存在且不一样会备份) |
mode | 修改权限 |
owner | 修改为指定所有者 |
group | 修改为指定用户组 |
扩展:fetch拉取
3.lineinfile
修改文件内容:类似sed -i 'sg' , sed 'cai'
path 指定文件、create 如果文件不存在是否创建(true/false)
regexp 正则 只换正则匹配的内容(匹配多行只修改最后一行)
4.replace
替换多行模块
服务管理-systemd
systemd模块相当于Linux systemd命令:
开启,关闭,重启服务
开机自启服务
systemd模块 | |
---|---|
==name== | 指定服务名称 |
==enabled== | yes开机自启 |
==state== | 表示服务开关重启 state=started 开启 state=stopped 关闭 state=reloaded 重读配置文件 state=restarted 重启 |
daemon-reload | yes是否从新加载对应的服务管理配置文件 自定义配置文件 |
#开启crond服务(集群)并设置开机自启
[root@m01 ~]# ansible all -m systemd -a "name=crond enabled=yes state=started"
#开启,关闭防火墙
[root@m01 ~]# ansible all -m systemd -a "name=firewalld enabled=yes state=started"
[root@m01 ~]# ansible all -m systemd -a "name=firewalld enabled=no state=stopped"
扩展:systemd适用于大部分Linux系统;service模块适用于旧的系统
软件管理
yum模块
get_url模块,wget命令
yum_repository模块,yum配置模块,可通过copy模块实现。
1.yum模块
yum模块不只是yum命令,包含==yum,apt==命令
yum模块 | |
---|---|
name | 指定软件包名字;可以指定==多个==,用 “ , ”分割。 |
state | installed 安装(present(默认)) removed 删除(也可写为absent) lastest 安装或更新 |
update_cache | 设置为no加速,表示不更新yum缓存,建议开启 |
#安装常用软件htop,tree,lrzsz
[root@m01 ~]# ansible all -m yum -a "name=htop,tree,lrzsz update_cache=yes state=present"
2.get_url模块
相当于wget命令,所有主机有网络才可
推荐在管理节点下载好,使用copy仅分发即可
get_url下载功能 | |
---|---|
url | 指定下载路径,地址 |
dest | 下载到本地哪个目录 |
validate_certs | 默认yes,no跳过https(SSL报错) |
#zabbix-agent地址为:#https://mirrors.aliyun.com/zabbix/zabbix/6.0/rhel/7/x86_64/zabbix-agent-6.0.13-release1.el7.x86_64.rpm
下载zabbix到/app/tools下
#创建目录
[root@m01 ~]# ansible all -m file -a "path=/app/tools state=directory"
#控制节点下载zabbix
[root@m01 ~]# ansible all -m get_url -a "url='https://mirrors.aliyun.com/zabbix/zabbix/6.0/rhel/7/x86_64/zabbix-agent-6.0.13-release1.el7.x86_64.rpm' dest=/app/tools"
#yum安装
[root@m01 ~]# ansible all -m yum -a "name=/app/tools/zabbix-agent-6.0.13-release1.el7.x86_64.rpm state=installed update_cache=no"
==有时wget识别不了https,需要加上 --no-check-certificate 参数==
wget --no-check-certificate XXXXXX
3.yum_repository模块
用处不是很多
推荐:未来在单独目录下书写好yum配置文件,copy分发过去即可。
yum源模块 yum_repository | |
---|---|
name | yum源中的名字 [Centos] |
description | yum源中的注释说明 对应的 是name的内容 |
baseurl | yum源中 baseurl 下载地址 |
enabled | 是否启动这个源 yes/no |
gpgcheck | 是否启动gpgcheck功能 no(校验官方,许可等) |
file | 指定yum源文件 自动添加.repo 默认与模块名字一致 |
与普通yum文件区别
[name] | name=centos 默认为源文件的文件名 |
---|---|
name=centos | description="" 描述 |
enabled=1 | enabled=yes |
gpgcheck=0 | gpgcheck=no |
用户管理
user用户管理:useradd
group用户组管理:groupadd
1.user模块
user模块 | |
---|---|
name | 用户名 |
uid | 指定uid |
group | 指定用户组,用于事先创建好了用户组 通过选项指定 |
shell | 指定命令解释器 |
create_home | 是否创建家目录(yes/no) |
state | present 添加 absent 删除 |
password | 更新密码 |
#创建www-ans用户uid 2000
[root@m01 ~]# ansible all -m user -a "name=www-ans uid=2000 shell=/sbin/nologin create_home=no state=present"
[root@m01 ~]# ansible all -a "grep www-ans /etc/passwd"
#带密码
ansible all -m user -a "name=wang password={{ '1' | password_hash('sha512','wang')}} state=present"
#'wang'是随机加的字符
#sha512加密格式输出加密后的结果
[root@m01 ~]# ansible all -i localhost, -m debug -a "msg={{ '1' | password_hash('sha512','wang') }}"
localhost | SUCCESS => {
"msg": "$6$wang$8N45KDaHJsVGx6VQSjHS8helqldy7geS/zTb739WyuoPNxdW49B55l5SoCxg8rx5hv/O791edTg5k5C3QV/5a0"
}
#使用加密后的msg作为密码
ansible all -m user -a "name=liu1 password='$6$wang$8N45KDaHJsVGx6VQSjHS8helqldy7geS/zTb739WyuoPNxdW49B55l5SoCxg8rx5hv/O791edTg5k5C3QV/5a0' state=present"
#等价于密码1
#shell模块更新密码
[root@m01 ~]# ansible all -m shell -a "echo 1 | passwd --stdin liu"
192.168.10.53 | CHANGED | rc=0 >>
Changing password for user liu.
passwd: all authentication tokens updated successfully.
关于{{}}解释
{{ '1' | password_hash('sha512','wang')}}
1表示密码,经过管道,传递给password_hash()插件,sha512加密算法,wang是随机字符用于生成加密后的密码。
2.group模块
group | |
---|---|
name | 指定用户组名字 |
gid | 指定组id |
state | present 添加 absent 删除 |
mount模块
实现mount命令进行挂载,且可修改/etc/fstab实现永久挂载。
mount | |
---|---|
fstype | 指定文件系统;xfs,ext4,iso9660,nfs |
src | 源地址(nfs地址 eg 192.168.10.50/data) |
path | 挂载点(把源挂载到哪里) |
state | 见下表 |
mount的state参数可用值 | |
---|---|
==absent== | 卸载并修改fstab |
unmounted | 卸载不修改/etc/fstab |
present | 仅修改/etc/fstab 不挂载 |
==mounted== | 挂载并修改/etc/fstab |
remounted | 从新挂载 |
定时任务cron
用于管理系统的定时任务,替代了crontab -e功能
cron模块 | 说明 |
---|---|
name | 定时任务名字(必加),对应下面==注释==内容 |
minute | 分钟 minute="/2" |
hour | 小时 |
day | 日期 |
month | 月份 |
week | 周几 |
job | 指定命令或脚本(定向到空) job="/sbin/ntpdate ntp1.aliyum.com &>/dev/null" |
state | present 添加定时任务(默认) absent 删除 |
#添加定时同步时间任务
*/2 * * * * /sbin/ntpdate ntp1.aliyum.com &>/dev/null
ansible all -m cron -a 'name="10.sync time wang" minute="*/10" job="/sbin/ntpdate ntp1.aliyum.com &>/dev/null" state=present'
#被控制节点查看任务
[root@nfs01 ~]# crontab -l
#Ansible: 10.sync time wang
*/10 * * * * /sbin/ntpdate ntp1.aliyum.com &>/dev/null
#删除任务 name + state
ansible all -m cron -a 'name="10.sync time wang" state=absent'
清理已有的定时任务
#使用sed替换
[root@m01 ~]# ansible all -a "sed -i '/ntpdate/d' /var/spool/cron/root"
#但注释还在
[root@nfs01 ~]# crontab -l -u root
#Ansible: 10.sync time wang
集群批量管理-Ansible-剧本-变量
剧本:可以书写部署服务脚本rsync、nfs、sersync
变量:类似脚本,在剧本使用
剧本
playbook 文件;用于长久保存并实现批量管理,维护,部署的文件
脚本中存放命令和变量,剧本中存放==模块==
剧本yaml格式;yaml格式的文件:空格,冒号
剧本和hoc区别
ans剧本 | ans ad-hoc | |
---|---|---|
共同点 | 批量管理,使用模块 | 批量管理,使用模块 |
区别 | 重复调用 | 不方便重复调用 |
应用场景 | 部署服务,多个步骤任务 | 测试模块,临时性任务 |
[root@m01 playbook]# cat 01.show.yml
---
- hosts: all
tasks:
- name: 01 起床
shell: echo 01 >> /tmp/everyday.log
- name: 02 刷牙
shell: echo 02 >> /tmp/everyday.log
- name: 03 吃早餐
shell: echo 03 >> /tmp/everyday.log
==剧本hosts指定多个集群 :====- hosts: nfs:web:buckup==
192.168.10.51 : ok=4 changed=3 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
192.168.10.52 : ok=4 changed=3 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
192.168.10.53 : ok=4 changed=3 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
#剧本执行命令
ansible-playbook 01_test.yml
#检测剧本语法
ansible-playbook 01_test.yml --syntax-check
#奶牛优化
[root@m01 playbook]# ansible-playbook 01.show.yml
#修改etc/ansible/ansible.cfg 随机图案
cow_selection = random #打开注释
#剧本目录下最好有/ansible/hosts文件
ansible-playbook -i hosts 02_file.yml
#-i 指定主机清单
注:==同级内容对齐、不同层级隔两个空格、不可用tab键==
剧本案例
1.创建并分发文件
1.创建目录 /server/files/
2.把 /etc/hosts 文件发送到 /server/files/
#创建目录server/files/
ansible all -m file a "path='/server/files/' state=directory"
#分发
ansible all -m copy a "src=/etc/hosts dest=/server/files/"
剧本模式
[root@m01 playbook]# cat 02.file.yml
---
- hosts: all
tasks:
- name: 01 Creat file
file: path=/server/files/ state=directory
- name: 02 Copy file
copy: src=/etc/hosts dest=/server/files/
==冒号格式(专业格式);==
[root@m01 playbook]# cat 02.file.yml
---
- hosts: all
tasks:
- name: 01 Creat file
file:
path: /server/files/
state: directory
- name: 02 Copy file
copy:
src: /etc/hosts
dest: /server/files/
2.安装软件
分发安装包、安装软件、启动服务
zabbix-agent软件包(下载)
安装软件包
配置(略)
开机自启
==步骤--->模块--->剧本== ==测试:分步测试==
#下载安装包
wget https://mirrors.aliyun.com/zabbix/zabbix/6.0/rhel/7/x86_64/zabbix-agent-6.0.13-release1.el7.x86_64.rpm
#安装软件
yum install -y zabbix-agent-6.0.13-release1.el7.x86_64.rpm
#启动
systemctl
模块
#下载: get_url(url)
#安装:yum(installed)
#启动:system
剧本
[root@m01 playbook]# cat 03_install_zabbix.yml
---
- hosts: all
tasks:
- name: 01 ---创建下载目录
file:
path: /root/zabbix/
state: directory
- name: 03 ---下载安装包
get_url:
url: https://mirrors.aliyun.com/zabbix/zabbix/6.0/rhel/7/x86_64/zabbix-agent-6.0.13-release1.el7.x86_64.rpm
dest: /root/zabbix/
validate_certs: no
- name: 04 ---安装软件
yum:
name: /root/zabbix/zabbix-agent-6.0.13-release1.el7.x86_64.rpm
state: present
- name: 05 ---设置自启
systemd:
name: zabbix-agent
enabled: yes
state: started
#检测
[root@m01 playbook]# ansible all -m shell -a "ps -ef | grep zabbix"
192.168.10.51 | CHANGED | rc=0 >>
zabbix 14944 1 0 14:05 ? 00:00:00 zabbix_agentd
zabbix 14945 14944 0 14:05 ? 00:00:06 zabbix_agentd: collector [idle 1 sec]
3.nfs服务
day40-9
nfs服务端:在backup部署nfs服务,共享/backup-nfs目录,all_squash,nfsnobody
nfs客户端:web挂载 /ans-upload目录挂载nfs服务端共享的/backup-nfs(永久挂载)
服务端流程:
1.部署nfs-utils
2.修改配置文件
3.创建共享目录,改所有者
4.启动服务rpcbind,nfs
客户端流程:
1.安装nfs-utils
2.挂载与永久挂载
剧本模式
#nfs Client
---
- hosts: buckup
tasks:
- name: 01 Deploy nfs-utils,rpcbind
yum:
name: nfs-utils,rpcbind
state: present
- name: 02 Present system file
lineinfile:
path: /etc/exports
line: "/buckup-nfs 192.168.10.0/24(rw,all_squash)"
create: true
- name: 03-1 Create Together file & Present User
user:
name: nfsnobody
create_home: yes
state: present
- name: 03-2 Create Together file & Present User
file:
path: /buckup-nfs
owner: nfsnobody
group: nfsnobody
state: directory
- name: 04-1 Start Service(rpcbind,nfs)
systemd:
name: rpcbind
enabled: yes
state: started
- name: 04-2 Start Service(rpcbind,nfs)
systemd:
name: nfs
enabled: yes
state: started
#nfs Server
- hosts: web
tasks:
- name: 01 Deploy nfs-utils
yum:
name: nfs-utils
state: present
- name: 02 Mount nfs
mount:
src: 192.168.10.53:/buckup-nfs
path: /ans-upload
fstype: nfs
state: mounted
Ansible变量
可以定义变量的地方 | 说明 |
---|---|
在剧本文件中定义 | 比较常用.仅仅限于当前的play使用 |
register变量(注册变量) | ip=hostname-I 实现脚本中反引号的功能,可以获取命令结果 |
变量文件,根据主机清单分组进行定义变量 | 如果多个剧本,使用相同的变量,大型的剧本roles |
inventory主机清单中定义变量 | 未来可以用于批量修改主机使用,其他很少用了 |
facts变量 | 一般用于获取主机基本信息:ip,主机名,系统(centos/ubuntu) 如果不需要可以关闭,用于加速剧本的执行 |
1.在playbook定义变量
仅在当前play生效,存放路径,用户名,ip...
[root@m01 playbook]# cat 05_var_test.yml
#var test
---
- hosts: all
vars:
dir: /to9cn/wang/oldboy/a/b/c/
tasks:
- name: Create directory
file:
path: "{{ dir }}"
state: directory
- name: debug tab
debug:
msg: "The vars: {{ dir }}:::" #不管多少空格只取变量值
#检测
[root@m01 playbook]# ansible all -i hosts -a "tree /to9cn"
192.168.10.53 | CHANGED | rc=0 >>
/to9cn
└── wang
└── oldboy
└── a
└── b
└── c
变量引号问题
#变量只要是选项的开头 就必须加引号"" ''
dir: /to9cn/wang/oldboy/a/b/c/
path: "{{ dir }}" #选项开头加引号
state: directory
path: /root/script/{{dir}} #非选项开头不加引号
2.变量文件(共用)
a. vars_files(变量文件)
可在任意目录下创建此变量文件,可使用相对和绝对路径
缺点:每个需要变量文件的剧本都==必须在开始调用变量文件==
[root@m01 vars_group]# cat 01_var_test.yml
---
- hosts: all
vars_files: ./vars.yml
# 若不是在同级目录,可直接使用相对目录
tasks:
- name: 01 Print vars
debug:
msg: "vars: {{ user }} {{ src }} {{ dest }}"
b.group_files(主机组文件)
主机组清单变量文件
在剧本文件的同级目录下创建group_vars目录,此目录中创建以主机组命名的目录;
最后在主机组目录下书写变量文件(vars.yml);
==playbook的同级目录下:group_vars/all(web nfs backup)/vars.yml==
智能==自动识别,剧本不需引用==且可针对主机组指定变量
#结构
[root@m01 vars_group]# ls
01_var_test.yml group_vars vars.yml
[root@m01 vars_group]# tree
.
├── 01_var_test.yml
├── group_vars
│ └── all
│ └── vars.yml
[root@m01 vars_group]# cat group_vars/all/vars.yml
user: wang(group)
src: https://grpup_vars
dest: /root/group_vars/vas/
剧本删除变量文件引用
[root@m01 vars_group]# cat 01_var_test.yml
---
- hosts: all
tasks:
- name: 01 Print vars
debug:
msg: "vars: {{ user }} {{ src }} {{ dest }}"
ok: [192.168.10.52] => {
"msg": "vars: wang(group) https://grpup_vars /root/group_vars/vas/"
}
ok: [192.168.10.51] => {
"msg": "vars: wang(group) https://grpup_vars /root/group_vars/vas/"
}
ok: [192.168.10.53] => {
"msg": "vars: wang(group) https://grpup_vars /root/group_vars/vas/"
}
3.register变量注册变量
实现脚本中的 `` 反引号功能 : ip='hostname -I' 期望得到ip
通过shell等系统命令结果保存到Register变量中
==stdout==全名是standard putput (标准输出)
[root@m01 playbook]# cat 06_register.yml
---
- hosts: all
tasks:
- name: 01 Get Server Time
shell: date +%F
register: result #接收命令获取结果给变量
- name: 02 Out result
debug:
msg: |
"register all: {{result}}" #
"register.stdout: {{result.stdout}}"
ok: [192.168.10.52] => {
"msg": "register.stdout: 2024-03-14"
}
"msg": "\"register all: {'stderr_lines': [],
u'changed': True,
u'end': u'2024-03-14 23:17:54.964215',
'failed': False,
u'stdout': u'2024-03-14', #标准输出
u'cmd': u'date +%F',
u'rc': 0, u'start':
u'2024-03-14 23:17:54.960870',
u'stderr': u'',
u'delta': u'0:00:00.003345',
'stdout_lines': [u'2024-03-14']}\"
4.facts变量
==ans内置变量==
ans内置变量,ans运行剧本的时候会有一个默认的TASK [Gathering Facts]。运行剧本的时候ans会收集每个主机的基本信息,这些信息形成的变量叫做facts变量.
==facts变量setup模块获取==---- ansible web -m setup
变量归属与读取
"ansible_swapfree_mb": 2047, #前面只有8个空格的变量可直接使用
#八个空格
"ansible_swaptotal_mb": 2047,
"ansible_system": "Linux",
大于8个空格:
每四个空格为一个归属,找到上级用 “ . ”读取到下级内容
"ansible_effective_user_id": 0,
"ansible_ens33": {
#八个空格
"active": true,
"device": "ens33",
"features": {
"ipv4": { #上级为ansible_ens33
"address": "192.168.10.52", #上级为ipv4
"broadcast": "192.168.10.255",
"netmask": "255.255.255.0",
"network": "192.168.10.0"
读取IP:==ansible_ens33.ipv4.address==
剧本
---
- hosts: all
tasks:
- name: 显示系统的基本信息
debug:
msg: |
你的系统是{f ansible_distribution}}
你系统的版本是{{ansible_distribution_version}}
你主机名为{{ansible_hostname}}
ok: [192.168.10.52] => {
"msg": "你的系统是CentOS\n你系统的版本是7.5\n你主机名为web01\n"
}
常见的facts变量
ansible_hostname #主机名
ansible_memtotal_mb #内存大小(总计)单位mb
ansible_processor_vcpus #cpu数量
ansible_default_ipv4.address #默认的网卡ip eth0
ansible_distribution #系统发行版本名字 Centos Ubuntu Debian...
ansible_distribution_version #系统的版本
ansible_date_time.date #时间
在剧本中如果不需要用到facts内置变量,可以==关闭此任务提高自动化效率==。
在tasks上注明:
- hosts: web
gather_facts: no
tasks:
- name:
file: ...
集群批量管理-流程控制-Roles
Ansible流程控制
==handler==
when
==loop==/with_items
1.handler触发器
修复服务的配置文件后---重启服务
配置文件无变化,不重启服务,仅配置变化才重启
应用场景:分发配置文件的时候---重启服务(或者做其他)
格式: notify: name1 , handlers: -name1 -name2
注意:handlers必须放在剧本最后,否则之后的剧本都认做handlers
[root@m01 playbook]# cat 08.handler.yml
---
- hosts: nfs
gather_facts: no
tasks:
- name: Hand files
copy:
src: exports
dest: /etc/exports
backup: yes
- name: Restart Service #无论文件如何变化 重启服务都会执行
systemd:
name: nfs
state: reloaded
使用handler与notify
[root@m01 playbook]# cat 08.handler.yml
---
- hosts: nfs
gather_facts: no
tasks:
- name: Hand files
copy:
src: /etc/exports
dest: /etc/exports
backup: yes
notify: #如果检测到此任务Changed 匹配handler中的name并执行
- Restart Service
- #可添加多个
handlers: #如果对应的任务状态不是Changed 不会执行handler
- name: Restart Service
systemd:
name: nfs
state: reloaded
2.when判断
用于给ans运行的task(模块)设置条件,满足或不满足条件在运行对应的模块.
应用建议:when进行判断,一般与变量一起使用.
when条件一般与facts变量或reqister变量较多.
# 以系统类型为条件判断 分系统安装个需软件
[root@m01 playbook]# cat 09_when.yml
- hosts: all
tasks:
- name: CentOS系统安装sl,cowsay,tree
yum:
name: sl,cowsay,tree
state: present
when: ansible_distribution == "CentOS"
- name: Ubuntu系统安装cmatrix,lolcat
apt:
name: cmatrix,lolcat
state: present
when: ansible_distribution == "Ubuntu"
# 若没条件判断,所有节点都会安装两任务的全部软件
when常见表达
== !=
is / is not match
eg: is not match("web|backup") #支持正则
条件1 and 条件2
条件1 or 条件2
eg:
when: ansible_distribution == "Ubuntu" and/or ansible_hostname is match("web|backup")
3.循环with_items 与 loop
场景:批量创建文件、添加用户、启动和重启服务
"{{item}}"+with_items 与 "{{item}}"+loop用法一致
重启多个服务(循环单个参数)
[root@m01 playbook]# cat 10_loop.yml
---
- hosts: buckup
gather_facts: no
tasks:
- name: restart Service(rpcbind,nfs)
systemd:
name: "{{item}}" #item没有s
state: restarted
with_items:
#loop: 效果和with_items:一样 loop没有s
- rpcbind
- nfs
- sshd
- crond
为集群添加用户(循环多个参数: name uid passwd...)
[root@m01 playbook]# cat 11_loop_more.yml
---
- hosts: nfs
gather_facts: no
tasks:
- name: Add User
user:
name: "{{item.name}}"
uid: "{{item.uid}}"
state: present
loop:
- {name: 'oldboy',uid: 2020} #整数不用加引号
- {name: 'wangtao',uid: 2021}
- {name: 'chaoqun',uid: 2022}
# {} 参数前需要 " - "
Ubuntu和Centos的细微差别
#CentOS的 /bin/sh 指向bash
[root@m01 playbook]# ll /bin/sh
lrwxrwxrwx. 1 root root 4 Mar 8 06:32 /bin/sh -> bash
#Ubuntu区别
# ll /bin/sh
/bin/sh -> dash* #脚本语法部分不一样
针对不同的系统优化添加playbook的解释器
user:
name: "{{item.name}}"
uid: "{{item.uid}}"
shell: /bin/bash # Ubuntu系统将会更改 解释器
state: present
Ansible剧本调试
:one:剧本单步执行
:two:tag标签
:three:忽略错误
1.单步执行
- -C --check 模拟运行,不做出改变(变量可能报错,因为没真正运行脚本)
- --syntax-check 只检查语法,不运行
- --step 单步运行:y执行这个task,n忽略这个task,c从当前开始自动运行
2.tag标签(step改进)
- tag标签类似于超市物品的分类,只不过tag标签是给ansible中的task进行分类.加上标记;也就是单独对name moudle分类
- 运行剧本的时候运行指定的tag标签或排除某些tag.
==想单独运行部分板块或者不想运行部分板块==
tags:==内容中不要有空格==
[root@m01 playbook]# cat 12_tag.yml
---
- hosts: buckup
gather_facts: no
tasks:
- name: 01 Deploy nfs-utils,rpcbind
yum:
name: nfs-utils,rpcbind
state: present
tags: 1.install #针对独立name 进行标签
- name: 02 Present system file
lineinfile:
path: /etc/exports
line: "/buckup-nfs 192.168.10.0/24(rw,all_squash)"
create: true
tags: 2.conf
- name: 03-1 Create Together file & Present User
user:
name: nfsnobody
create_home: yes
state: present
tags: 3.file
- name: 03-2 Create Together file & Present User
file:
path: /buckup-nfs
owner: nfsnobody
group: nfsnobody
state: directory
tags: 4.user
- name: 04 Start Service(rpcbind,nfs)
systemd:
name: "{{item}}"
enabled: yes
state: started
loop:
- rpcbind
- nfs
tags: 5.service
- -t 、--tags 运行的标签,如果多个标签则通过","分割
- --skip-tags 排除指定的tags,如果多个标签则通过","分割
- --list-tags 列出剧本的全部标签
# 列出标签
[root@m01 playbook]# ansible-playbook --list-tags 12_tag.yml
playbook: 12_tag.yml
play #1 (buckup): buckup TAGS: []
TASK TAGS: [1.install, 2.conf, 3.file, 4.user, 5.service]
# 运行tags板块1
[root@m01 playbook]# ansible-playbook -t 1.install 12_tag.yml
# 运行板块1和2
[root@m01 playbook]# ansible-playbook -t 1.install,2.conf 12_tag.yml #板块之间无空格
#--skip-tags 除开选择的tags标签 剩余的标签全部执行
[root@m01 playbook]# ansible-playbook --skip-tags 2.conf,3.file,4.user,5.service 12_tag.yml
#只执行 1.install
3.忽略错误
- anisble在执行出错的时候终结剧本,不再执行后续程序
- 因重复导致的错误提示(并非真错误,例如目录,用户已经存在) systemd服务名错误也能忽略
- 通过 ignore_errors忽略错误,继续剧本
ignore_errors: true
true/false
yes/no
场景:才执行创建文件、目录、用户等操作时可加此参数
- hosts: nfs
tasks:
- name: 01 Creat file
file:
path: /server/files/
state: directory
ignore_errors: true #和tags一样与模块、name对齐
Jinja2模板
1.基本使用
在分发文件时,文件中==需要使用变量==(facts,Clents_info,groups_vars)
copy传输文件 文件纹丝不动传递
==template会替换掉文件中的变量(.j2) 无需手动修改==
- 文件必须以 .j2 结尾
- 必须使用template模块(传输时替换j2文件中的变量)
# 分发主机信息文件
[root@m01 templates]# cat 01_Jinja2_test.j2
######################
welcome to oldboy elastic linux system
操作需谨慎,删根弹指间.
主机名: {{ ansible_hostname}}
ip地址: {{ansible_default_ipv4.address}}
内存大小: {{ ansible_memtotal_mb}}
CPU数量: {{ansible_processor_vcpus}}
核心总数: {{ansible_processor_cores}}
发行版本: {{ansible_distribution}}
# 剧本
[root@m01 templates]# cat 02_handj2.yml
---
- hosts: nfs
tasks:
- name: Create (copy templates) file
file:
path: /root/jinja/
state: directory
- name: template Hand J2 file
template:
src: /root/script/playbook/templates/01_Jinja2_test.j2
dest: /root/jinja/template
backup: yes
- name: copy Hand J2 file
copy:
src: /root/script/playbook/templates/01_Jinja2_test.j2
dest: /root/jinja/copy
backup: yes
#对比两模块 变量是否变化
# copy
[root@m01 templates]# ansible nfs -m shell -a "cat /root/jinja/copy"
主机名: {{ ansible_hostname}}
ip地址: {{ansible_default_ipv4.address}} #无法识别变量
# template
主机名: nfs01
ip地址: 192.168.10.51
2.判断使用
判断和循环可存在在 .j2文件中
# 条件判断
{% if ansible_hostname == "web01" %}
state Mater
{% if ansible_hostname == "backup" %}
state Node
{% endif %}
3.循环
配置文件server.conf
10.0.0.5
10.0.0.6
10.0.0.7
10.0.0.8
10.0.0.9
10.0.0.10
{% for ip in [5,6,7,8,9,10] %} #适合不连续的
10.0.0.{{ip}}
{% endfor %}
{% for ip in range(5,11)%} #适合大范围连续的
10.0.0.{{ip}}
{% endfor %}
集群批量管理-Ans-完结篇
include文件包含
- 1个ansible剧本内容过多,==涉及到多个play(-host:web)==,可读性变弱,不方便调试.
- 于是人们想出把单个大的剧本拆分为多个,小的剧本.
- 多个小的剧本可以通过include功能合并使用.
缺点: 同级目录下存在多个yml文件、变量文件vars以及j2文件,板块较为混乱 不适合大型剧本
拆分后的文件只包含tasks后面的部分:==不包含tasks的行==
[root@m01 include]# cat 01_nfs_server.yml
- name: 01 Deploy nfs-utils,rpcbind
yum:
[root@m01 include]# cat 02_nfs_client.yml
- name: 01 Deploy nfs-utils,rpcbind
yum:
[root@m01 include]# cat 03_nfs_include.yml
---
- hosts: buckup
tasks:
- include_tasks: 01_nfs_server.yml
- hosts: web
tasks:
- include_tasks: 02_nfs_client.yml
#handlers
roles
概述
include将大型剧本模块化,但handlers、变量文件、发送配置文件(.j2)等比较混乱
roles规则:这个规范是一套剧本目录结构的要求与标准,让我们书写剧本的时候,把剧本的内容和需要的文件,按照目录要求,分门别类存储。roles的本质就是规定了1套目录结构,用于书写剧本的.
roles前提:熟练剧本模块,掌握服务流程;尽量==多使用变量==让剧本灵活性变高。
[root@m01 include]# ls
01_nfs_server.yml 02_nfs_client.yml 03_nfs_include.yml # 可能还会设计多个变量、配置文件
roles框架
如果有自定义变量 ,在同级目录下有: group_vars/all/main.yml
nfs案例(S+C)
Vault加密
重要配置文件、参数文件涉密,需要通过加密保证安全
- ansible-vault encrypt 文件 :加密文件,直接读取是编码
- ans-hoc或ansible-playbook --ask-vault-pass 即可使用中解密
- ansible-vault decrypt 文件: 彻底解密(修改文件内容必须彻底解密)
#加密文件
[root@m01 vault]# ansible-vault
ansible-vault ansible-vault-2 ansible-vault-2.7
[root@m01 vault]# ansible-vault encrypt hosts
New Vault password:
Confirm New Vault password:
Encryption successful
[root@m01 vault]# cat hosts
$ANSIBLE_VAULT;1.1;AES256
6638363062643933656664643233356......
#不解密情况下直接使用加密文件:无法识别
#添加解密参数后:
[root@m01 vault]# ansible --ask-vault-pass -i hosts nfs -m shell -a "ps -ef"
Vault password:
192.168.10.51 | CHANGED | rc=0 >>
#将加密文件彻底解密
[root@m01 vault]# ansible-vault decrypt hosts
Vault password:
Decryption successful
#解密后才可对文件进行修改,也可直接识别和读取
Galaxy
别人的Roles:第三方、官方、用户的roles
ansible-galaxy collection install
#galaxy.ansible.com/search?deprecated=false&keywords=nginx&order_by=-relevance&page=1
#官网roles
# 默认下载到家目录
ansible-galaxy collection install nginxinc.nginx_core
下载失败可选择下载 ==tarbao==
优化
常见优化
- ssh连接速度优化,关闭UseDNS,GSSAPIAuthcation....
- 不要让ansible运行交互式的命令,非要用使用命令的非交互模式.
- 需要使用ans,yum安装软件,可以自建本地yum仓库,然后ans安装.(自建yum源,自己制作的rpm包)
#ansible并发默认五台机器
-f FORKS, --forks FORKS
specify number of parallel processes to use
(default=5) #根据CPU的核心数提高需求
- 给ansible配置缓存,队列。缓存(facts)
- 给主机进行分组操作(web,nfs,backup)
- 关闭gather_facts,如果不用facts变量可以关闭,剧本中:gather_facts:false配置文件:gathering = explicit
- 关闭host,key,check一般使用密码认证的时候需要关闭,如果不关闭 ansible配置文件host_key_checking = False ==第一次ssh时的yes/no==
==安全==
生产环境下一般不是ansible节点root远程集群root,默认会关闭root的远程权限,==ansible使用的时sudo提权的用户==
- ==配置sudo提权== ans ALL=(ALL) NOPASSWD: ALL 密码是1,ss端口22
- 配合 vpn,jms一起使用
- 用户--->vpn--->jms--->ansible
- 用户密码、涉密文件、配置(bash,ansible-vault)
==ansible---sudo==
客户端
# sudoers文件提权
[root@nfs01 ~]# tail -1 /etc/sudoers
ans_sudo ALL=(ALL) NOPASSWD: ALL
# 创建此用户 密码设置为1
[root@nfs01 ~]# useradd ans_sudo
useradd: user 'ans_sudo' already exists
[root@nfs01 ~]# passwd ans_sudo
Changing password for user ans_sudo.
New password:
BAD PASSWORD: The password is a palindrome
Retype new password:
passwd: all authentication tokens updated successfully.
[ans_sudo@nfs01 root]$ sudo -l
User ans_sudo may run the following commands on nfs01:
(ALL) NOPASSWD: ALL
管理端
1.修改/etc/ansible/ansible.cfg文件:添加被管理端上的sudo用户和使用的用户(不指定默认是当前root用户/root)
2.开启sudo功能和命令 指定切换用户
3.被管理端root禁止远程登录,密钥认证需要发给sudu用户;
[root@m01 ~]# ssh-copy-id ans_sudo@192.168.10.51
ans_sudo@192.168.10.51's password:
and check to make sure that only the key(s) you wanted were added.
4.如果不使用sudo用户,需要关闭sudo以及sudo指定用户:不一定全部机器有sudo配置以及指定的用户;
5.禁用root远程登录
禁用root远程前,需要注册好普通用户,配置sudo
vim /etc/ssh/sshd_config
systemctl restart sshd
评论