使用python脚本一个简单的搭建ansible集群
1.环境说明:
角色 | 主机名 | ip地址 |
---|---|---|
控制主机 | server | 192.168.174.150 |
受控主机/被管节点 | client1 | 192.168.174.151 |
受控主机/被管节点 | client2 | 192.168.174.152 |
2.安装python和pip包
yum install -y epel-release
yum install -y python python-pip
3.pip安装依赖库
pip install pexpect # 此库用相当于linux中的expect命令
4.完整脚本:
# coding=UTF-8
import sys,os,pexpect,subprocessmaster_addresses=["192.168.174.150"] # 主节点们的IP地址
master_domains=["server"] # 域名们
client_addresses=["192.168.174.151","192.168.174.152"] # 从节点们的IP地址
client_domains=["client1","client2"] # 域名们host_username="root" # ssh连接的用户,控制端的用户为root
host_passwd="110119" # ssh连接的用户密码
chrony_allows_addresses="192.168.174.0"ansible_hostGroup_all="clients_all"
ansible_hostGroup_master="clients_master"
ansible_hostGroup_client="clients_client"# 1.本地创建ssh公钥
if os.path.exists("/root/.ssh/id_rsa.pub") == True:print("\033[32m"+"ssh公钥已创建"+"\033[0m") # 输出绿色字体
else:print("\033[32m"+"ssh公钥未创建,开始创建"+"\033[0m")child = pexpect.spawn('ssh-keygen -t rsa -b 1024')child.expect('Enter file in which to save the key')child.sendline('')child.expect('Enter passphrase')child.sendline('')child.expect('Enter same passphrase again')child.sendline('')child.expect(pexpect.EOF) # 用于等待子进程的结束print(child.before.decode()) # 等待命令执行完毕并打印输出信息print("\033[32m" + "ssh公钥已创建" + "\033[0m")print("\n")# 向被控主机添加公钥的方法
def add_ssh_public_key_client(address,username,password):print("\033[32m"+"{}正在被添加公钥".format(address)+"\033[0m")# BatchMode=yes:表示使SSH在连接过程中不会提示输入密码,而直接尝试免密连接,-o ConnectTimeout=5:表示限制连接超时时间为5秒public_key_flag=os.system("ssh {}@{} -o BatchMode=yes 'exit' &> /dev/null".format(username,address))if public_key_flag== 0:print("\033[32m" + "{}已经可以ssh连接".format(address) + "\033[0m")returnchild = pexpect.spawn('ssh-copy-id -i /root/.ssh/id_rsa.pub {}@{}'.format(username,address))try:child.expect('Are you sure you want to continue connecting')except pexpect.exceptions.TIMEOUT: # 如果try块中的咨询超时5秒没有出现就会出现异常pexpect.TIMEOUTprint("\033[32m"+"{}已经不是首次ssh连接了".format(address)+"\033[0m")else: # 是否回答咨询yeschild.sendline('yes')finally:child.expect('password')child.sendline(password)child.expect(pexpect.EOF) # 用于等待子进程的结束print(child.before.decode()) # 等待命令执行完毕并打印输出信息
# 测试ssh连接的方法
def test_ssh_connection(all_flag,address,username):print("\033[32m" + "{}测试是否可以ssh连接".format(address) + "\033[0m")flag=os.system('ssh {}@{} -o ConnectTimeout=5 "exit"'.format(username,address))if flag==0:print("\033[32m" + "Success: {}可以ssh免密连接".format(address) + "\033[0m")else:print("\033[1;31m" + "Failed: {}ssh免密连接失败".format(address) + "\033[0m") # 输出红色字体all_flag=1return all_flag# 本地的密钥开始加入被控制主机
for i in range(0, len(master_addresses)):add_ssh_public_key_client(master_addresses[i],host_username,host_passwd)print("\n")
for i in range(0, len(client_addresses)):add_ssh_public_key_client(client_addresses[i],host_username,host_passwd)print("\n")
# 测试ssh连接
for i in range(0, len(master_addresses)):final_flag=test_ssh_connection(0,master_addresses[i],host_username)
for i in range(0, len(client_addresses)):final_flag = test_ssh_connection(0, client_addresses[i], host_username)
if final_flag ==1:sys.exit("ssh测试失败,请检查!")
else:print("\033[32m" + "Success: 全部可以ssh免密连接" + "\033[0m")
print("\n")# 配置防火墙和selinux的方法
def set_firwalld_selinux(address,username):print("\033[32m" + "{}正在配置防火墙和selinux".format(address + "\033[0m"))fir_flag=os.system('ssh {}@{} "systemctl stop firewalld;systemctl disable firewalld"'.format(username,address))if fir_flag!=0:print("\033[1;31m" + "Failed: 防火墙修改失败" + "\033[0m")sys.exit("请检查!")sel_flag=os.system("ssh {}@{} 'sed -i 's/SELINUX=.*/SELINUX=disabled/' /etc/selinux/config'".format(username,address))if sel_flag!=0:print("\033[1;31m" + "Failed: selinux修改失败" + "\033[0m")sys.exit("请检查!")
# 配置防火墙和selinux
for i in range(0, len(master_addresses)):set_firwalld_selinux(master_addresses[i],host_username)
for i in range(0, len(client_addresses)):set_firwalld_selinux(client_addresses[i],host_username)
print("\n")# 配置域名映射
print("\033[32m" + "本地开始配置域名映射" + "\033[0m")
with open("/etc/hosts","w") as f: # w重写,a添加,只读f.write("127.0.0.1 localhost localhost.localdomain localhost4 localhost4.localdomain4\n")f.write("::1 localhost localhost.localdomain localhost6 localhost6.localdomain6\n")for i in range(0, len(master_addresses)):f.write("{} {}\n".format(master_addresses[i],master_domains[i]))for i in range(0, len(client_addresses)):f.write("{} {}\n".format(client_addresses[i],client_domains[i]))
# 复制本地的/etc/hosts覆盖掉远程主机的/etc/hosts文件
for i in range(0, len(master_addresses)):os.system("scp /etc/hosts {}@{}:/etc/hosts".format(host_username,master_addresses[i]))
for i in range(0, len(client_addresses)):os.system("scp /etc/hosts {}@{}:/etc/hosts".format(host_username,client_addresses[i]))# 使用域名首次ssh连接
# 首次域名ssh连接的方法
def first_domain_name_con(domain,username,password):print("\033[32m"+"{}首次ssh连接".format(domain)+"\033[0m")# BatchMode=yes:表示使SSH在连接过程中不会提示输入密码,而直接尝试免密连接,-o ConnectTimeout=5:表示限制连接超时时间为5秒os.system("ssh -o BatchMode=yes -o ConnectTimeout=5 {}@{} 'exit' &> /dev/null".format(username, domain))first_domain_flag = os.system("ssh -o BatchMode=yes -o ConnectTimeout=5 {}@{} 'exit'".format(username, domain))if first_domain_flag == 0:print("\033[32m" + "{}已经可以ssh连接".format(domain) + "\033[0m")returnchild = pexpect.spawn('ssh {}@{} "exit"'.format(username,domain))try:connecting_tuple = child.expect('Are you sure you want to continue connecting')except pexpect.exceptions.TIMEOUT:print("\033[32m"+"{}已经不是首次ssh连接了".format(domain)+"\033[0m")else:child.sendline('yes')child.expect(pexpect.EOF) # 用于等待子进程的结束print(child.before.decode()) # 等待命令执行完毕并打印输出信息for i in range(0, len(master_domains)):first_domain_name_con(master_domains[i],host_username,host_passwd)
for i in range(0, len(client_domains)):first_domain_name_con(client_domains[i], host_username, host_passwd)print("\n")# 配置chrony服务器
print("\033[32m" + "开始配置chrony" + "\033[0m")
# 配置chrony主服务器的方法
def chrony_master_service(username,address):print("\033[32m" + "{}配置主chrony".format(address) + "\033[0m")# 安装chronychrony_flag = os.system("ssh {}@{} 'yum install -y chrony'".format(username,address))if chrony_flag != 0:print("\033[1;31m" + "Failed: {}chrony安装失败".format(address) + "\033[0m")sys.exit("请检查!")# 开启同步地址范围chrony_master_allows_addresses = "sed -i 's/#allow 192.168.0.0\/16/allow {}\/24/' /etc/chrony.conf".format(chrony_allows_addresses)os.system('ssh {}@{} "{}"'.format(username, address, chrony_master_allows_addresses))# 开启stratum层数chrony_master_allows_stratum = "sed -i 's/#local stratum 10/local stratum 10/' /etc/chrony.conf"os.system('ssh {}@{} "{}"'.format(username, address, chrony_master_allows_stratum))# 重启服务chrony_service = "systemctl restart chronyd && systemctl enable chronyd &> /dev/null"os.system('ssh {}@{} "{}"'.format(username, address, chrony_service))os.system('ssh {}@{} "sleep 5"'.format(username, address))# 开启时间同步os.system('ssh {}@{} "timedatectl set-ntp true"'.format(username, address))
#配置chrony同步节点的方法
def chrony_master_client(username,address):print("\033[32m" + "{}配置同步chrony".format(address) + "\033[0m")# 安装chronychrony_flag = os.system("ssh {}@{} 'yum install -y chrony'".format(username,address))if chrony_flag != 0:print("\033[1;31m" + "Failed: {}chrony安装失败".format(address) + "\033[0m")sys.exit("请检查!")# 删除默认的server地址sed_chrony_delete = "sed -i '{}' /etc/chrony.conf".format('/^server/d')os.system('ssh {}@{} "{}"'.format(username,address,sed_chrony_delete))# 添加自定义的server地址for j in range(0, len(master_addresses)):sed_chrony_add = "sed -i '{}' /etc/chrony.conf".format("2a\server {} iburst".format(master_addresses[j]))os.system('ssh {}@{} "{}"'.format(username, address, sed_chrony_add))# 重启服务chrony_service = "systemctl restart chronyd && systemctl enable chronyd &> /dev/null"os.system('ssh {}@{} "{}"'.format(username,address,chrony_service))# 开启时间同步os.system('ssh {}@{} "timedatectl set-ntp true"'.format(username, address))os.system('ssh {}@{} "sleep 5"'.format(username, address))chrony_time = "chronyc sources -v | sed -n '{}'".format("/^\^\*/p")chrony_output = subprocess.check_output('ssh {}@{} "{}"'.format(username,address,chrony_time) ,shell=True)# 输出结果print(chrony_output)if chrony_output == "" or chrony_output is None:print("\033[1;31m" + "Failed: {}时间同步失败".format(address) + "\033[0m")sys.exit("请检查!")for i in range(0, len(master_addresses)):chrony_master_service(host_username,master_addresses[i])
for i in range(0, len(client_addresses)):chrony_master_client(host_username,client_addresses[i])
print("\n")# 安装ansbile
print("\033[32m" + "本地安装ansible软件" + "\033[0m")
os.system("yum install -y epel-release && yum install -y ansible")
try:ansible_output = subprocess.check_output("ansible --version", shell=True)
except subprocess.CalledProcessError:print("\033[1;31m" + "Failed: 本地安装ansible失败" + "\033[0m")sys.exit("请检查!")
finally:print("\033[32m" + "安装的ansible软件版本如下: " + "\033[0m")print(ansible_output)# /etc/ansible/hosts文件中添加主机租
print("\033[32m" + "修改配置文件/etc/ansible/hosts" + "\033[0m")
with open('/etc/ansible/hosts','a') as f:# ansible主机组clients_allf.write("["+ansible_hostGroup_all+"]"+"\n")for i in range(0, len(master_domains)):f.write(master_domains[i] + "\n")for i in range(0, len(client_domains)):f.write(client_domains[i] + "\n")# ansible主机组clients_masterf.write("[" + ansible_hostGroup_master + "]" + "\n")for i in range(0, len(master_domains)):f.write(master_domains[i] + "\n")# ansible主机组clients_clientf.write("[" + ansible_hostGroup_client + "]" + "\n")for i in range(0, len(client_domains)):f.write(client_domains[i] + "\n")# 测试
print("\033[32m" + "测试ansible命令" + "\033[0m")
try:ansible_hoc_output = subprocess.check_output("ansible {} -a uptime".format(ansible_hostGroup_all), shell=True)
except subprocess.CalledProcessError:print("\033[1;31m" + "Failed: 测试失败无法使用ansible命令" + "\033[0m")sys.exit("请检查!")
finally:print("\033[32m" + "测试结果如下" + "\033[0m")print("\033[1;33;40m"+ansible_hoc_output+"\033[0m")
相关文章:
使用python脚本一个简单的搭建ansible集群
1.环境说明: 角色主机名ip地址控制主机server192.168.174.150受控主机/被管节点client1192.168.174.151受控主机/被管节点client2192.168.174.152 2.安装python和pip包 yum install -y epel-release yum install -y python python-pip 3.pip安装依赖库 pip in…...

【价值几十万的仿抖音直播电商系统源码共享】
当下,传统的图文电商模式已经走向没落,以抖音为首的直播电商模式备受用户追捧,它具有实时直播和强互动的特点,是传统电商所不具备的优势。而且,当前正是直播电商的红利期,很多主播和品牌商都通过直播电商业…...
对于vue3项目中使用shareReward还是shareReward.value的问题
问: // 设置当前有没有分享过 默认是false const shareReward ref(false) // 是否是第一次分享 来判断是否发放抽奖次数 function haveShare() { console.log(进入haveshare) if (userInfo.uid && shareReward.value) { rewardTimes(2).then((res) &…...
利用websockify将websocket通信转换成tcp
文章目录 前言websockifywebsockify 介绍websockify 使用 探索的过程提供基础TCP服务测试可用 实现Websocket客户端开始测试websockify功能再次启动websockify单独实现一个js版本websocket客户端 什么是VNC总结 前言 目前遇到一个问题,原本的服务都是利用tcp通信的…...

【LeetCode刷题】-- 163.缺失的区间
163.缺失的区间 class Solution {public List<List<Integer>> findMissingRanges(int[] nums, int lower, int upper) {List<List<Integer>> res new ArrayList<>();for(int num : nums){if(lower < num){res.add(Arrays.asList(lower,num -…...
ClickHouse为何如此之快
针对ClickHouse为什么很快的问题,基于对ClickHouse的基础概念之上,一般会回答是因为是列式存储数据库,同时也会说是使用了向量化引擎,所以快。上面两方面的解释也都能够站得住脚,但是依然不能够解释真正核心的原因。因…...
Avalonia中如何将View事件映射到ViewModel层
前言 前面的文章里面我们有介绍在Wpf中如何在View层将事件映射到ViewModel层的文章,传送门,既然WPF和Avalonia是两套不同的前端框架,那么WPF里面实现模式肯定在这边就用不了,本篇我们将分享一下如何在Avalonia前端框架下面将事件映射到ViewModel层。本章内容还是在上一节的…...
(第42天)DataGuard 搭建之使用 Duplicate 复制
环境准备 本文讲解 Oracle 19C 环境通过 Duplicate 在线复制搭建单机 Active DataGuard 的完整步骤,以下为测试环境信息: 角色主机名IP地址数据库版本实例名DB名DB_UNIQUE名services名TNS名sys密码主lucifer10.211.55.20019CoradboradboradboradbORADB_PRIoracle备luciferdg…...
LeetCode 0070. 爬楼梯:动态规划(递推)
【LetMeFly】70.爬楼梯:动态规划(递推) 力扣题目链接:https://leetcode.cn/problems/climbing-stairs/ 假设你正在爬楼梯。需要 n 阶你才能到达楼顶。 每次你可以爬 1 或 2 个台阶。你有多少种不同的方法可以爬到楼顶呢&#x…...
XMemcached network layout exception java.nio.channels.ClosedChannelException
java.nio.channels.ClosedChannelException 表示尝试在已关闭的通道上进行 I/O 操作,通常发生在网络连接意外关闭后尝试在关闭的通道上执行读取或写入操作。 XMemcached network layout exception 可能是由于 XMemcached 客户端在尝试与 Memcached 服务器通信时发生…...

记录 | vscode pyhton c++调试launch.json配置
下面提供 vscode 中 python 和 c 调试配置的 launch.json (好用,已用好几年,建议收藏) {// 使用 IntelliSense 了解相关属性。 // 悬停以查看现有属性的描述。// 欲了解更多信息,请访问: https://go.microsoft.com/fwlink/?linkid830387&qu…...
Java入门基础:浅显易懂 死循环
文章目录 一、什么是死循环二、以fo循环示例三、如何避免死循环 一、什么是死循环 死循环就是循环语句的 循环布尔表达式 一直为true,没有终止循环的条件或者终止循环的条件根本不可能达成 二、以fo循环示例 /** 终止循环的条件根本不可能达成* 循环布尔表达式&a…...

LeetCode刷题--- 验证二叉搜索树
个人主页:元清加油_【C】,【C语言】,【数据结构与算法】-CSDN博客 http://t.csdnimg.cn/ZxuNL个人专栏:力扣递归算法题 http://t.csdnimg.cn/ZxuNL 【C】 http://t.csdnimg.cn/c9twt 前言:这个专栏主要讲述递归递归、搜索与回溯算法&#x…...
go-zero 开发入门-加法客服端示例
定义 RPC 接口文件 接口文件 add.proto 的内容如下: syntax "proto3"; package add;// 当 protoc-gen-go 版本大于 1.4.0 时需加上 go_package,否则编译报错“unable to determine Go import path for” option go_package "./add&qu…...
Python 快速入门——基础语法
python 的语法逻辑完全靠缩进,建议缩进 4 个空格。 如果是顶级代码,那么必须顶格书写,哪怕只有一个空格也会有语法错误。 下面示例中,满足 if 条件要输出两行内容,这两行内容必须都缩进,而且具有相同的缩进…...

EasyRecovery2024苹果电脑mac破解版安装包下载
EasyRecovery是一款操作安全、价格便宜、用户自主操作的非破坏性的只读应用程序,它不会往源驱上写任何东西,也不会对源驱做任何改变。它支持从各种各样的存储介质恢复删除或者丢失的文件,其支持的媒体介质包括:硬盘驱动器、光驱、…...
Git常用命令大全
1.强制推送(慎用,除非你认为其他冲突等可以丢弃 或者不是很重要) git push -- force2.创建文件等小命令 touch a // 创建一个a文件 echo 1234 >> a // 把1234这个内容放入a文件 cat a // 打开a文件 读取出a文件中的内容 mkdir test /…...
vue项目本地正常运行,打包到线上时无法访问js等资源
nginx配置错误,如: location /aaa/ {gzip on;gzip_static on;try_files $uri $uri/ /aaa/index.html;alias /home/ec2-user/data/aaa/;#这里必须以斜杆结束,否则就会报错}前端配置文件错误,如: config/index.js文件的b…...

计网Lesson10 - 网络层之IP协议分析
文章目录 网络层协议IPv4 数据报格式IPv4 数据报首部格式版本(Version)首部长度(Header Length)区分服务(Differentiated Services Field)可选字段填充总长度(Total Length)标识、标…...

LangChain 25: SQL Agent通过自然语言查询数据库sqlite
LangChain系列文章 LangChain 实现给动物取名字,LangChain 2模块化prompt template并用streamlit生成网站 实现给动物取名字LangChain 3使用Agent访问Wikipedia和llm-math计算狗的平均年龄LangChain 4用向量数据库Faiss存储,读取YouTube的视频文本搜索I…...

eNSP-Cloud(实现本地电脑与eNSP内设备之间通信)
说明: 想象一下,你正在用eNSP搭建一个虚拟的网络世界,里面有虚拟的路由器、交换机、电脑(PC)等等。这些设备都在你的电脑里面“运行”,它们之间可以互相通信,就像一个封闭的小王国。 但是&#…...
Golang 面试经典题:map 的 key 可以是什么类型?哪些不可以?
Golang 面试经典题:map 的 key 可以是什么类型?哪些不可以? 在 Golang 的面试中,map 类型的使用是一个常见的考点,其中对 key 类型的合法性 是一道常被提及的基础却很容易被忽视的问题。本文将带你深入理解 Golang 中…...

UE5 学习系列(三)创建和移动物体
这篇博客是该系列的第三篇,是在之前两篇博客的基础上展开,主要介绍如何在操作界面中创建和拖动物体,这篇博客跟随的视频链接如下: B 站视频:s03-创建和移动物体 如果你不打算开之前的博客并且对UE5 比较熟的话按照以…...

为什么需要建设工程项目管理?工程项目管理有哪些亮点功能?
在建筑行业,项目管理的重要性不言而喻。随着工程规模的扩大、技术复杂度的提升,传统的管理模式已经难以满足现代工程的需求。过去,许多企业依赖手工记录、口头沟通和分散的信息管理,导致效率低下、成本失控、风险频发。例如&#…...
工程地质软件市场:发展现状、趋势与策略建议
一、引言 在工程建设领域,准确把握地质条件是确保项目顺利推进和安全运营的关键。工程地质软件作为处理、分析、模拟和展示工程地质数据的重要工具,正发挥着日益重要的作用。它凭借强大的数据处理能力、三维建模功能、空间分析工具和可视化展示手段&…...

1.3 VSCode安装与环境配置
进入网址Visual Studio Code - Code Editing. Redefined下载.deb文件,然后打开终端,进入下载文件夹,键入命令 sudo dpkg -i code_1.100.3-1748872405_amd64.deb 在终端键入命令code即启动vscode 需要安装插件列表 1.Chinese简化 2.ros …...

SpringCloudGateway 自定义局部过滤器
场景: 将所有请求转化为同一路径请求(方便穿网配置)在请求头内标识原来路径,然后在将请求分发给不同服务 AllToOneGatewayFilterFactory import lombok.Getter; import lombok.Setter; import lombok.extern.slf4j.Slf4j; impor…...

智能分布式爬虫的数据处理流水线优化:基于深度强化学习的数据质量控制
在数字化浪潮席卷全球的今天,数据已成为企业和研究机构的核心资产。智能分布式爬虫作为高效的数据采集工具,在大规模数据获取中发挥着关键作用。然而,传统的数据处理流水线在面对复杂多变的网络环境和海量异构数据时,常出现数据质…...

Mac下Android Studio扫描根目录卡死问题记录
环境信息 操作系统: macOS 15.5 (Apple M2芯片)Android Studio版本: Meerkat Feature Drop | 2024.3.2 Patch 1 (Build #AI-243.26053.27.2432.13536105, 2025年5月22日构建) 问题现象 在项目开发过程中,提示一个依赖外部头文件的cpp源文件需要同步,点…...

力扣热题100 k个一组反转链表题解
题目: 代码: func reverseKGroup(head *ListNode, k int) *ListNode {cur : headfor i : 0; i < k; i {if cur nil {return head}cur cur.Next}newHead : reverse(head, cur)head.Next reverseKGroup(cur, k)return newHead }func reverse(start, end *ListNode) *ListN…...