ansible批量管理
ansible批量管理
-
使用ansible之前必须配置好密钥认证或者在hosts文件中指定目标主机的用户名和密码
-
一键分发密钥脚本
#!/bin/bash
#author:supershy
#desc:
# 1.创建密钥对(判断是否存在密钥)
# 2.分发公钥(指定存放ip的文件)
# 3.检查
#1.vars
key=/root/.ssh/id_rsa
passwd=666666
ips=`cat /server/ips.txt`
#2.一键创建密钥对
if [ ! -f $key ];then
ssh-keygen -f $key -P '' &>/dev/null
if [ $? -eq 0 ];then
echo "密钥对创建成功"
else
echo "密钥对创建失败"
exit
fi
fi
#3.一键分发公钥
for ip in $ips
do
sshpass -p$passwd ssh-copy-id -o StrictHostKeyChecking=no $ip &>/dev/null
if [ $? -ne 0 ];then
echo "$ip公钥分发失败"
fi
done
#4.一键检查
for ip in $ips
do
ssh -p22 root@$ip hostname -I
done
- hosts文件指定用户名密码
[web]
192.168.1.10 ansible_user=myuser ansible_password=mypassword
192.168.1.11 ansible_user=myuser ansible_password=mypassword
[db]
192.168.1.20 ansible_user=myuser ansible_password=mypassword
expect免密登录脚本
- shell脚本 expect的常见用法
命 令 | 说 明 |
---|---|
spawn | 启动新的交互进程, 后面跟命令或者指定程序 |
expect | 从进程中接收信息, 如果匹配成功, 就执行expect后的动作 |
send | 向进程发送字符串 |
send exp_send | 用于发送指定的字符串信息 |
exp_continue | 在expect中多次匹配就需要用到 |
send_user | 用来打印输出 相当于shell中的echo |
interact | 允许用户交互 |
exit | 退出expect脚本 |
eof | expect执行结束, 退出 |
set | 定义变量 |
puts | 输出变量 |
set timeout | 设置超时时间 |
# 配置批量免密钥登录脚本
cat > password_free_login.sh <<'EOF'
#!/bin/bash
# 创建密钥对
ssh-keygen -t rsa -P "" -f /root/.ssh/id_rsa -q
# 声明你服务器密码,建议所有节点的密码均一致,否则该脚本需要再次进行优化
export mypasswd=666666
# 定义主机列表
k8s_host_list=(k8s-master01 k8s-master02 k8s-master03)
# 配置免密登录,利用expect工具免交互输入
for i in ${k8s_host_list[@]};do
expect -c "
spawn ssh-copy-id -i /root/.ssh/id_rsa.pub root@$i
expect {
\"*yes/no*\" {send \"yes\r\"; exp_continue}
\"*password*\" {send \"$mypasswd\r\"; exp_continue}
}"
done
EOF
sh password_free_login.sh
ansible配置文件
egrep -v '^$|#' /etc/ansible/ansible.cfg
[defaults]
host_key_checking = False #类似于 ssh -o StrictHostKeyChecking=no
log_path = /var/log/ansible.log #ansible的日志文件
[inventory]
[privilege_escalation]
[paramiko_connection]
[ssh_connection]
[persistent_connection]
[accelerate]
[selinux]
[colors]
[diff]
hosts被管理主机清单文件
/etc/ansible/hosts
#格式1
[web]
172.16.1.7
172.16.1.8
[backup]
172.16.1.41
[nfs]
172.16.1.31
#格式2,执行相同的操作时可以用这种方式,直接调用data等同于调用data的所有孩子
[data:children]
web
backup
nfs
#格式2的用法
ansible data -m commant -a 'hostname'
#格式3
[web]
192.168.1.10 ansible_user=myuser ansible_password=mypassword
192.168.1.11 ansible_user=myuser ansible_password=mypassword
[db]
192.168.1.20 ansible_user=myuser ansible_password=mypassword
ansible必会模块
- 查看模块用法:ansible-doc -s copy
模块分类 | 模块 |
---|---|
命令和脚本模块 | command |
shell shell和command区别:shell支持正则,通配符匹配 | |
script | |
文件 | file 创建文件,目录,软链接 |
copy 远程分发文件,修改权限,所有者,备份 | |
fetch 全程拉取文件 | |
template 和copy模块用法一样,区别:copy模块不会检测到传送文件中的变量,template会把文件中的变量解析出来 | |
lineinfile 修改文件 | |
replace 使用正则找到文件内容并替换 | |
服务 | systemd 服务管理 |
软件包 | yum/apt |
get_url 下载浏览器软件相当于wget | |
用户管理 | user 管理用户 |
ground 管理用户组 | |
其他系统管理 | mount 挂载 |
cron 编写定时任务 | |
用于调试的模块 | ping 检查ansible与其他节点的连通性 |
debug 用户检查/显示 变量 msg: | |
其他 | 管理docker,k8s,zabbix,grafana…… |
rsync(synchronize),mysql(mysql_db,mysql_user)…… | |
打包压缩 | archive 打包压缩 |
unarchive 解压缩 |
命令和脚本模块选项参数
ansible | 说明 |
---|---|
-i 指定主机清单文件 | 默认主机清单文件/etc/ansible/hosts,修改了位置需要-i指定位置 |
-m 指定模块 | |
-a 指定模块中的选项 |
file文件文件模块
file模块参数 | 说明 | 用法 |
---|---|---|
path | 路径(目录,文件),必须要写 | |
src | 指定源文件,一般用于创建软链接 | |
state | 状态,指定要做什么(创建,删除,操作文件/操作目录) state=directory 创建目录 state=file(默认) 更新文件,如果文件不存在也不创建 state=link 创建软链接 state=touch 创建文件 |
ansible all -m file -a ‘path=/tmp/oldboy.txt state=touch’ ansible all -m file -a 'src=/tmp/oldboy.txt path=/tmp/oldboy.txt.link state=link' |
state | state=absent 删除(!!!如果是目录,递归删除目录,包括根!!!) | |
mode | mode=755 修改权限 | |
owner | owner=root 修改所属者 | |
group | group=root 修改所属组 |
copy批量分发模块
copy模块参数 | 说明 | 用法 |
---|---|---|
src | 源文件,管理端某个文件 | |
dest | 目标,被管理端某个目录/文件 | |
backup | backup=yes 文件内容有变化,则会在覆盖前进行备份 | ansible all -m copy -a ‘src=/etc/hosts dest=/tmp/hosts.txt backup=yes’ |
mode | 修改权限 | |
owner | 修改所有者 | |
group | 修改所属组 |
- 扩展:copy是推送,批量推送,fetch是拉取,批量拉取
template模块
-
#用法和copy模块一样,template会把文件中的变量解析出来,固定在templates目录下以.j2结尾的文件./templates/motd.j2 cat templates/motd.j2 "主机名:{{ansible_hostname}}" "内存大小(总计) 单位mb:{{ansible_memtotal_mb}}" "cpu数量:{{ansible_processor_vcpus}}" "默认的网卡ip eth0:{{ansible_default_ipv4.address}}" "系统发行版本名字:{{ansible_distribution}}" "系统的版本:{{ansible_distribution_version}}" "系统时间:{{ansible_date_time.date}}" #template模块剧本 - hosts: all tasks: - name: 01 分发文件 template: src: templates/motd.j2 dest: /etc/motd backup: yes
lineinfile修改文件的多种策略:
- sed修改替换功能
- cat批量写入功能
- echo写入功能
- 管理机准备号配置文件copy分发
- lineinfile模块
lineinfile模块参数 | 说明 | 用法 |
---|---|---|
path | 指定文件 | |
regexp | 指定正则,通过正则过滤出你要修改的行 | |
line | 这一行修改后的内容,向文件里写内容,如果添加的内容在文件中存在则不会添加 | ansible all -m lineinfile -a ‘ path=/etc/ssh/sshd_config regexp=“^#Port” line=“Port 22” ’ |
replace替换模块
- name: 03.修改ssh配置文件禁止root远程连接
replace:
path: "{{sshd_cfg}}"
regexp: "^(#PermitRootLogin yes)|(PermitRootLogin yes)"
replace: "PermitRootLogin no"
systemd服务管理
systemd模块参数 | 说明 | 用法 |
---|---|---|
name | 指定服务名字 | |
enabled | enabled=yes开机自启(yes/no) | |
state | 指定服务开,关,重启… state=started 开启 state=stopped 关 state=restarted 重启 state=reloaded 重读配置文件(个别服务支持) |
ansible all -m systemd -a ‘name=crond enabled=yes state=started’ |
daemon-reload | daemon-reload=yes 是否重新加载对应的服务管理配置文件 |
yum/get_url软件管理
yum/apt模块参数 | 说明 | 用法 |
---|---|---|
name | 指定软件包名字 | |
state | present 安装(也可以写为 installed) absent 删除(也可以写为:removed) lastest 安装或更新 |
|
update_cache | 可以设置为update_cache=no加速,表示不更新本地缓存,实际应用中建议开启 |
get_url模块参数 | 说明 | 用法 |
---|---|---|
url | 指定下载地址 | |
dest | 下载到哪个目录 | 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” desc=/tmp/’ #下载rpm包到本地,后续通过yum安装 ansible all -m yum -a ‘name=/tmp/zabbix* state=present’ |
user用户管理
user模块参数 | 说明 | 用法 |
---|---|---|
name | 指定用户名 | |
uid | 指定uid号 | |
group | 指定用户组 | |
shell | 指定命令解释器 | |
create_home | 是否创建家目录(yes/no) | |
state | present 添加 absent 删除 |
|
password | 加密的密码 | #方法1,可以更新密码,密码为666666,密码经过管道传递给password_hash()插件,sha512加密算法,abcdefg是随机字符用于生成随机加密后的密码 ansible all -m user -a ‘ name=oldboy password={{“666666” |password_hash(“sha512”,”abcdefg”)}} state=present ’ #方法2 ansible all -m shell -a ‘ echo “1” |passwd - -stdin oldboy ’ |
group组模块 | 说明 | 用法 |
---|---|---|
name | 指定用户组名 | |
gid | 指定组gid号 | |
state | present 增加 absent 删除 |
cron定时任务管理
- 用ansible定时任务cron模块写的定时任务只能通过ansible修改
cron模块参数 | 说明 | 用法 |
---|---|---|
name | 定时任务里的注释(一定要加上),对应下面注释内容 | |
minute | minute=“*/3”,minute=“00” | |
hour | hour=“00” | |
day | ||
month | ||
week | ||
job | 指定命令或脚本(定向到空) | ansible all -m cron -a ‘ name=“同步时间” minute=“”*/3” job=/sbin/ntpdate ntp1.aliyun.com &>/dev/null ’ |
state | present 添加定时任务 absent 删除 |
mount挂载服务管理
mount模块参数 | 说明 | 用法 |
---|---|---|
fstype | 指定文件系统nfs,xfs,ext4,相当于mount -t | |
src | 源地址(nfs服务端共享地址,src=172.16.1.31:/data) | |
path | 挂载点,这里不是dest(哪个目录挂载到源地址目录) | |
state | absent 卸载并修改fstab unmounted 卸载但不修改fstab present 仅修改fstab,但不挂载 mounted 挂载并修改fstab remounted 重新挂载 |
|
debug调试模块
#剧本里应用,msg里写什么就输出什么也可以在里面调用变量
debug:
msg: "gaojiaxing"
archive打包压缩模块
archive参数 | 说明 |
---|---|
path | 要打包压缩的目录名称 |
dest | 生成压缩包的名字 |
format | 指定打包格式 |
unarchive解压缩模块
unarchive参数 | 说明 |
---|---|
src | 要解压的文件名 |
dest | 解压到哪个目录 |
mysql模块
- ansible在调用mysql模块时需要插件:MySQL-python
剧本与变量
剧本调试
调试方法 | 说明 | 用法 |
---|---|---|
-C | - -check模拟运行,不做出改变,一些变量可能会报错,因为剧本没有真正运行 | 命令行中使用 |
- -syntax-check | 只做语法检查,不运行 | 命令行中使用 |
- -start-at-task | 从指定任务开始执行 | ansible-playbook -i hosts - -start-at-task test.yml |
高级:- -step | 单步运行,y执行这个task,n忽略这个task,c自动全部运行 | 命令行中使用 |
tags: | -t 指定运行标签,多个标签用‘ ,’分割 - -skip-tags 排除指定标签,多个标签用‘,’分割 | ansible-playbook -i hosts test.yml -t 01_nfs_server_yum,03_nfs_server_conf 在剧本中添加标签,在命令行中指定标签 |
ignore_errors: | ignore_errors: yes/no 忽略错误 | 在剧本中添加 |
- -list-tags | 查看剧本中所有标签 |
剧本中符号说明
-
特殊符号 说明 | 在剧本表示下面内容是多行 {{ }} 调用变量方式 在剧本循环中使用,用来写变量
ansible定义变量方式
-
常见变量和定义方式 应用场景 在剧本中定义vars: 仅在一个play中使用 变量文件存放group_vars/目录下l 自动读取 group_vars/all/vars.yml文件,适用于大多数场景,也可以根据主机清单不同服务设置变量 group_vars/web/vars.yml group_vars/nfs/vars.yml facts(ansible运行收集信息变量) register注册变量
ansible内置facts变量
-
ansible内置变量,在运行剧本时会有一个默认的task(Gathering Facts),这个在背后收集每个主机信息(eg:ip信息,主机名,磁盘,各种主机的信息)这些基本信息称为facts变量
-
facts默认执行剧本时自动执行,如果不使用facts可以在剧本中关闭 gather_facts: no
-
- hosts: all gather_facts: no tasks: -name:
-
#获取方式facts变量所有内容 ansible backup -i hosts -m setup #facts常用的变量 "主机名:{{ansible_hostname}}" "内存大小(总计) 单位mb:{{ansible_memtotal_mb}}" "cpu数量:{{ansible_processor_vcpus}}" "默认的网卡ip eth0:{{ansible_default_ipv4.address}}" "系统发行版本名字:{{ansible_distribution}}" "系统的版本:{{ansible_distribution_version}}" "系统时间:{{ansible_date_time.date}}"
-
#剧本中使用facts变量 - hosts: backup tasks: - name: 01 调试 debug: msg: | "主机名:{{ ansible_hostname }}" "系统发行版本名:{{ ansible_distribution }}" - name: 02 保存到文件 lineinfile: path: /tmp/info.txt create: yes line: | "主机名:{{ ansible_hostname }}" "系统发行版本名:{{ ansible_distribution }}"
register变量输出剧本中模块信息(用于输出脚本执行时输出的值的模块)
- 结合debug调试,输出模块执行的结果
#register获取到的变量结果会输出很多内容,结果是以字典形式输出,可以用调用字典key的方式只显示出来命令的结果,reg.stdout
- hosts: all
gather_facts: no
tasks:
- name: test register
shell: date +%F
register: reg
- name: result
debug:
msg: |
"{{ reg }}" #输出很多内容
"{{ reg.stdout }}" #只调用出来命令的结果
- shell + register
- name: Execute a shell script and capture the output
ansible.builtin.shell: /path/to/script.sh
register: script_output
- name: Display the script output
ansible.builtin.debug:
var: script_output.stdout
- command + register
- name: Execute a command and capture the output
ansible.builtin.command: ls -l /var/log
register: log_files
- name: Display the command output
ansible.builtin.debug:
var: log_files.stdout_lines
- script + register
- name: Execute a local script and capture the output
ansible.builtin.script: /path/to/local_script.sh
register: script_output
- name: Display the script output
ansible.builtin.debug:
var: script_output.stdout
with_items / loop循环
- hosts: all
gather_facts: no
tasks:
- name: 01 批量创建用户
user:
name: "{{ item.name }}"
uid: "{{ item.uid }}"
state: present
with_items:
- {name: oldboy,uid: 2020}
- {name: jiaxing,uid: 2021}
handlers触发器+notify
- 需求:配置nfs服务,修改好配置文件后分发给nfs服务端机器,然后重启服务,如果nfs配置文件没有被修改则不需要重启服务
- 实现方案:handlers+notify
#服务端配置
- hosts: nfs
gather_facts: no
tasks:
- name: 01 安装nfs服务
yum:
name: nfs-utils
state: installed
- name: 02 启动nfs服务
systemd:
name: "{{ item }}"
enabled: yes
state: started
with_items:
- rpcbind
- nfs
- name: 03 创建data共享目录
file:
path: "{{nfs_ser_dir}}"
owner: nfsnobody
group: nfsnobody
state: directory
- name: 04 分发exports
template:
src: templates/exports.j2
dest: /etc/exports
backup: yes
notify: 05 更改配置时重启nfs
handlers:
- name: 05 更改配置时重启nfs
systemd:
name: nfs
state: reloaded
when判断
when中的符号 | 说明 |
---|---|
is match(“正则”) | match表示以什么开头,可以使用正则 |
is not match(“ ”) | 取反 |
is regex(“ ”) | 表示包括什么字符 |
== , != , > , >= , < , <= |
- hosts: all
tasks:
- name: CentOS安装sl,cowsay
yum:
name: sl,cowsay
state: present
when: ansible_distribution == "CentOS"
- name: Ubuntu安装cmatrix
yum:
name: cmatrix
state: present
when: ansible_distribution is match("Ubuntu")
jinja2文件中的判断
- 使用template模块分发带有变量的.j2文件
cat templates/keepalived.conf.j2
{% if ansible_hostname == "web01" %}
state 主节点
{% elif ansible_hostname == "backup" %}
state 备节点
{% endif %}
jinja2文件中的循环
####jinja2循环参数调用变量时不需要加{{ }}
cat templates/keepalived.conf.j2
{% for ip in range(3,10) %}
10.0.0.{{ip}}
{% endfor %}
{% for ip in [3,4,5,6] %}
10.0.0.{{ip}}
{% endfor %}
剧本进阶roles
roles基本格式(运行指定top.yml文件)
include_tasks文件包含
-
和python中模块调用方式一样,可以把一个服务中的每个功能单独写到一个文件中,然后在tasks/main.yml中调用这个模块就行
-
调用方法(模块必须和main.yml在同一层目录下tasks/ )
-
include_tasks: install.yml include_tasks: config.yml
-
vault文件加密
#加密指定文件,ansible-vault
#加密hosts
ansible-vault encrypt hosts
#使用加密后的hosts
ansible或ansible-playbook --ask-vault-pass -i hosts test.yml
--ask-vault-pass 交互模式手动输入密码
--vault-password-file 指定密码文件
#解密文件
ansible-vault decrypt hosts
ansible优化
1)ansible安全优化—sudo
-
a)整体流程
- 被管理端禁用root远程登录
######ansible安全优化--sudo###### #被管理端 #1.添加普通用户ans设置密码 #2.配置sudo权限 #3.修改ssh配置文件禁止root远程连接 #4.重载sshd - hosts: all vars: username: "ans" passwd: "666666" sudo_cfg: /etc/sudoers sshd_cfg: /etc/ssh/sshd_config tasks: - name: 01.添加普通用户ans设置密码 user: name: "{{username}}" shell: /bin/bash password: '{{passwd |password_hash("sha512","jiaxing")}}' state: present tags: - useradd ans - name: 02.配置sudo权限 lineinfile: path: "{{sudo_cfg}}" line: "{{username}} ALL=(ALL) NOPASSWD: ALL" backup: yes tags: - update sudo config - name: 03.修改ssh配置文件禁止root远程连接 replace: path: "{{sshd_cfg}}" regexp: "^(#PermitRootLogin yes)|(PermitRootLogin yes)" replace: "PermitRootLogin no"
- ansible使用普通用户ans远程登录(具备sudo权限,不需要密码)
#管理端
#1.向被管理端分发密钥 执行脚本
#2.修改ansible管理端配置文件使用sudo登录
#3.调试测试 ansible all -i hosts -m ping
#ansible本地配置需要改的内容/etc/ansible/ansible.cfg
forks=5 #ansible最大并行操作几台机器,根据情况怎加数量
sudo_user=ans #远端具有sudo权限的用户ans
remote_port=22 #远程连接的端口
host_key_checking=False #运行ansible时是否检查key
remote_user=ans #远端使用的用户ans
log_path=/var/log/ansible.log #ansible日志文件
become=True #开启sudo功能
become_method=sudo #远端连接ans使用sudo命令
become_user=root #普通用户切换为root
其他优化
- 性能
- ssh连接速度优化,关闭UseDNS,GSSAPIAuthcation ....
- 不要让ansible运行交互式的命令,非要用使用命令的非交互模式.
- 需要使用ans,yum安装软件,可以自建本地yum仓库,然后ans安装.(自建yum源,自己制作的rpm包)
- 调整ansible并发数量( -f 调整并发数量 默认是5 ansible.cfg ,forks=5,实际调整根据负载情况.)
- 给ansible配置缓存(redis),队列.缓存facts.
- 给主机进行分组操作与管理.
- 关闭gather_facts,如果不用facts变量可以关闭, 剧本中: gather_facts: false 配置文件:
gathering = explicit
- 关闭host,key,check 一般使用密码认证的时候需要关闭,如果不关闭
ansible配置文件 host_key_checking = False
- 安全⭐
- ⭐ 配置sudo用户 ans ALL=(ALL) NOPASSWD: ALL 密码是1,ssh端口是 22
- 配合vpn,jms一起使用
- 用户 ---->vpn---->jms(跳板机)---->ansible
- 用户的密码,进行加密( hash, ansible-vault)
踩坑日记
_________________________
< TASK [解压etcd软件包到etcd集群] >
-------------------------
\ ^__^
\ (oo)\_______
(__)\ )\/\
||----w |
|| ||
fatal: [10.0.0.242]: FAILED! => {"ansible_facts": {"discovered_interpreter_python": "/usr/bin/python"}, "changed": false, "msg": "Failed to find handler for \"/root/.ansible/tmp/ansible-tmp-1727671502.32-11899-50716666834698/source\". Make sure the required command to extract the file is installed. Command \"/usr/bin/unzip\" could not handle archive. Command \"/usr/bin/gtar\" could not handle archive."}
fatal: [10.0.0.241]: FAILED! => {"ansible_facts": {"discovered_interpreter_python": "/usr/bin/python"}, "changed": false, "msg": "Failed to find handler for \"/root/.ansible/tmp/ansible-tmp-1727671502.33-11898-259959298978359/source\". Make sure the required command to extract the file is installed. Command \"/usr/bin/unzip\" could not handle archive. Command \"/usr/bin/gtar\" could not handle archive."}
fatal: [10.0.0.243]: FAILED! => {"ansible_facts": {"discovered_interpreter_python": "/usr/bin/python"}, "changed": false, "msg": "Failed to find handler for \"/root/.ansible/tmp/ansible-tmp-1727671502.34-11900-22085878717261/source\". Make sure the required command to extract the file is installed. Command \"/usr/bin/unzip\" could not handle archive. Command \"/usr/bin/gtar\" could not handle archive."}
原因:压缩包损坏导致
解决:手动检查压缩包是否损坏,重新拉取软件包
[root@m01 /server/ansible/roles/ansible-kubernetes]# tar tf /download/etcd-v3.5.10-linux-amd64.tar.gz
etcd-v3.5.10-linux-amd64/
etcd-v3.5.10-linux-amd64/README.md
etcd-v3.5.10-linux-amd64/READMEv2-etcdctl.md
etcd-v3.5.10-linux-amd64/etcdutl
gzip: stdin: unexpected end of file
tar: Unexpected EOF in archive
tar: Error is not recoverable: exiting now
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 记一次.NET内存居高不下排查解决与启示
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
· DeepSeek 开源周回顾「GitHub 热点速览」