ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

linux集群如何批量ssh,亲测可用

linux集群如何批量ssh,亲测可用 按照本文批量ssh需要所有服务器用来ssh互信的账户和密码是一样的不一样的改一下后期公钥配置好之后可以再改回来因为批量的话要向所有主机推送文件和交互还没有免密只能用密码1、首先我们要安装一个自动化的集成套件我们需要使用这个套件完成ssh批量免密时的自动操作选一台执行机就行不需要所有节点安装yum install -y expect sshpass2、准备一个shell脚本名字自定义我的叫ssh_all.sh#!/bin/sh DEST_USER$1 PASSWORD$2 HOSTS_FILE$3 if [ $# -ne 3 ]; then echo 用法 echo $0 远程用户 远程密码 主机文件 exit 1 fi SSH_DIR~/.ssh SCRIPT_PREFIX./tmp # 1. 在当前用户的主目录下准备.ssh目录 并保证权限只有自己有 mkdir $SSH_DIR chmod 700 $SSH_DIR # 2. 生成一个统一的ssh密钥 TMP_SCRIPT$SCRIPT_PREFIX.sh { echo #!/usr/bin/expect echo spawn ssh-keygen -b 1024 -t rsa echo expect *key* echo send \r if [ -f $SSH_DIR/id_rsa ]; then echo expect *overwrite* echo send y\r fi echo expect *passphrase* echo send \r echo expect *again: echo send \r echo interact } $TMP_SCRIPT chmod x $TMP_SCRIPT /usr/bin/expect $TMP_SCRIPT rm $TMP_SCRIPT # 3. 生成authorized_keys文件 cat $SSH_DIR/id_rsa.pub $SSH_DIR/authorized_keys # 4. 设置authorized_keys文件权限为600 chmod 600 $SSH_DIR/authorized_keys # 5. 将文件复制到其他主机 for ip in $(cat $HOSTS_FILE) do if [ x$ip ! x ]; then TMP_SCRIPT${SCRIPT_PREFIX}.$ip.sh # 检查known_hosts valssh-keygen -F $ip if [ x$val x ]; then echo $ip 不在 $SSH_DIR/known_hosts 中, 需要添加 valssh-keyscan $ip 2/dev/null if [ x$val x ]; then echo ssh-keyscan $ip 失败! else echo $val $SSH_DIR/known_ hosts fi fi echo 将 $SSH_DIR 复制到 $ip { echo #!/usr/bin/expect echo spawn scp -r $SSH_DIR $DEST_USER$ip:~/ echo expect *assword* echo send $PASSWORD\r echo interact } $TMP_SCRIPT chmod x $TMP_SCRIPT /usr/bin/expect $TMP_SCRIPT rm $TMP_SCRIPT echo 复制完成. fi done echo 完成3、准备集群ips文件一行一个ip如下192.168.43.186 192.168.43.187 192.168.43.1884、将shell脚本赋权chmod 777 ssh_all.sh5、运行参数1是用来ssh的用户参数2是该用户密码参数3是集群ips文件./ssh_all.sh root 123456 ./host_list如果脚本运行正常会出现如下日志注意我没有截全最后会出现几个100%的进度条之后用测试ssh效果就可以了上面这个脚本是单线程执行而且没有专注处理公钥身份唯一问题可以应用于测试集群上跑一跑如果你要正式的部署商用化集群用下面的这个脚本#!/bin/bash# 1. 处理脚本需要的参数以及所需服务检查# 免密用的用户DEST_USER# 密码PASSWORD# 节点列表文件HOSTS_FILE/opt/hosts# 默认并行度为1可通过参数调整PARALLEL_JOBS1# 公钥等文件存放的路径根据用户名动态设置root用户为/root/.ssh普通用户为/home/user/.sshSSH_DIRif[$#-lt4];thenecho 用法$0-u 远程用户 -pw 远程密码 [-ipf 主机文件默认使用 /opt/hosts] [-t 并行度]exit1fiwhile[[$#-gt0]];docase$1in-u)#用户if[[-n$2$2!-*]];then#设置文件并将参数整体向左移动2位DEST_USER$2shift2elseecho错误: -u 需要指定用户exit1fi;;-pw)# 密码if[[-n$2$2!-*]];then#设置文件并将参数整体向左移动2位PASSWORD$2shift2elseecho错误: -pw 需要指定密码exit1fi;;-ipf)#主机文件if[[-n$2$2!-*]];thenHOSTS_FILE$(realpath$2)shift2elseecho错误: -ipf 需要指定主机文件exit1fi;;-t)#并行度if[[-n$2$2!-*]];thenPARALLEL_JOBS$2shift2elseecho错误: -t 需要指定并行度exit1fi;;-*)# 其他参数属于检测到未知选项echo错误: 未知选项$1exit1;;esacdone# 根据目标用户设置SSH目录if[$DEST_USERroot];thenexportSSH_DIR/root/.sshelseexportSSH_DIR/home/$DEST_USER/.sshfi#获取 HOMEif[-z${TOOLS_HOME}];thenexportTOOLS_HOME$(cd $(dirname$0)/..;pwd) fi #确保本地日志路径存在 if [ ! -d${TOOLS_HOME}/logs/ssh_all ]; then echo -e \e[1;35;44m生成日志路径\e[0m mkdir -p${TOOLS_HOME}/logs/ssh_all fi #expect 交互式模拟套件 echo -e \e[1;35;44m开始检测当前系统必要软件\e[0m if rpm -q expect /dev/null 21; then echo expect环境存在 else echo expect环境不完整开始yum安装 yum install -y expect fi #sshpass ssh密码输入工具 if rpm -q sshpass /dev/null 21; then echo sshpass 环境存在 else echo sshpass 环境不完整开始yum安装 yum install -y sshpass fi # 2. 让所有节点生成自己的SSH密钥如果密钥不存在 generate_key_with_stats() { local ip$1local user$2local password$3echo -e \e[1;35;44m[$ip]\e[0m 通知生成密钥 # 检查密钥是否存在 # sshpass 需要yum安装 本身是一个和expect类似的交互套件用来专门托管ssh命令提供密码填充功能 # -p $password 直接提供访问密码 # ssh 托管ssh服务 # -o StrictHostKeyCheckingno -o ConnectTimeout10 跳过ssh客户端认证 设置连接超时为10秒 # $user$ip 目标机器 # test-f~/.ssh/id_rsatest-f~/.ssh/id_rsa.pub 检查两个文件是否存在 # 这个 if 判断的是 ssh 的返回test命令如果文件不存在状态码返回 非 0 if sshpass -p $password ssh -o StrictHostKeyCheckingno -o ConnectTimeout10 $user$ip \ test-f~/.ssh/id_rsatest-f~/.ssh/id_rsa.pub 2/dev/null; then echo -e \e[1;35;44m[$ip]\e[0m 密钥已存在跳过 return 0 fi # 生成密钥 if sshpass -p $password ssh -o StrictHostKeyCheckingno $user$ip \ mkdir-p~/.sshchmod700~/.ssh\ssh-keygen-trsa-b2048-N-f~/.ssh/id_rsa-C$user$ip/dev/null21; then echo -e \e[1;35;44m[$ip]\e[0m 密钥生成成功 echo return0elseecho-e\e[1;35;44m[$ip]\e[0m 密钥生成失败echoreturn1fi}# 导出方法让并行子进程跑export-fgenerate_key_with_statsechoecho-e\e[1;34;47m开始构造所有主机密钥 generate_key_with_stats all\e[0m cat$HOSTS_FILE|grep-v#|xargs-I{}-P$PARALLEL_JOBSbash-cgenerate_key_with_stats $ _{}$DEST_USER$PASSWORDecho-e\e[1;34;47m所有主机密钥构造结束 generate_key_with_stats all\e[0m echo# 3. 回收所有公钥把公钥写在all_authorized_keys文件里权限600700也可以不过不需要执行600就够了echo 构造新的临时文件 build$SSH_DIR下的 all_authorized_keys 与 all_known_hosts# 保险起见这里先清理一下rm-f$SSH_DIR/all_authorized_keys${SSH_DIR}/all_known_hoststouch$SSH_DIR/all_authorized_keystouch$SSH_DIR/all_known_hostsecho 设置权限 chmod 600 all_authorized_keys all_known_hostschmod600$SSH_DIR/all_authorized_keyschmod600$SSH_DIR/all_known_hostsforipin$(cat${HOSTS_FILE}|grep-v#);doecho-e\e[1;35;44m[$ip]\e[0m 正在回收公钥/密钥# 收集公钥sshpass-p$PASSWORDssh-oConnectTimeout3$DEST_USER$ipcat ~/.ssh/id_rsa.pub$SSH_DIR/all_authorized_keys# 收集主机密钥ssh-keyscan-H$ip$SSH_DIR/all_known_hostsdoneecho 新的临时文件构造完成 build all_authorized_keys all_known_hostsechoecho 检查本地是否存在原有密钥对文件如果存在则不再额外处理# 确保本地 authorized_keys 和 known_hosts 存在新用户首次执行时这两个文件可能不存在# [ 命令 ] 这里不是 if 该语法是一个单独的命令格式等价于 test 命令返回 0真或 1假[!-f${SSH_DIR}/authorized_keys]touch${SSH_DIR}/authorized_keyschown$DEST_USER:$DEST_USER${SSH_DIR}/authorized_keyschmod700${SSH_DIR}/authorized_keysecho 本地 authorized_keys 不存在已自动创建[!-f${SSH_DIR}/known_hosts]touch${SSH_DIR}/known_hostschown$DEST_USER:$DEST_USER${SSH_DIR}/known_hostschmod700${SSH_DIR}/known_hostsecho 本地 known_hosts 不存在已自动创建echoecho 追加本地结果文件 into authorized_keys known_hosts 原有的免密串只要在执行机上就并不会被覆盖丢失其他同步节点如有差异会丢失因此请注意免密执行的环境cat${SSH_DIR}/all_authorized_keys${SSH_DIR}/authorized_keyscat${SSH_DIR}/all_known_hosts${SSH_DIR}/known_hostsecho 追加结果文件完成 into authorized_keys known_hostsecho# 4. 并行分发所有节点当前的所有用户登录公钥和ssh客户端密钥process_host(){localip$1localuser$2localpassword$3#提示输出 开始echo-e\e[1;35;44m[$ip]\e[0m 开始执行免密# 使用expect进行SCP 把 ~/.ssh 下含有所有节点公钥以及ssh客户端私钥的文件同步所有节点的 ~/.ssh/ 路径下# set timeout 30 设置目标服务或命令响应超时时间为30秒# spawn scp -r 文件路径 $user$ip:~/ 启用一个新的子进程发送文件# expect 规定发生交互时的动作# \*assword*\ 当遇到 assword 关键字时 发送密码和回车# \yes/no\ 当遇到yes/no 关键子时 发送yes和回车# timeout 如果超时 推出返回 状态码 1# eof 不超时正常结束交互 wait关键字用来表明等待spawn子进程结束 catch表明捕获可能出现的错误 result声明保存的变量 exit [lindex \$result 3] 表示获取第四位的子线程状态码为expect的返回码expect-c set timeout 30 spawn scp$SSH_DIR/authorized_keys$SSH_DIR/known_hosts$user$ip:~/.ssh/ expect {\*assword*\{ send\$password\r\exp_continue }\yes/no\{ send\yes\r\exp_continue } timeout { exit 1 } eof { catch wait result exit [lindex \$result3] } } ${TOOLS_HOME}/logs/ssh_all/${ip}.log21if[$?-eq0];thenecho-e\e[1;35;44m[$ip]\e[0m 执行免密结束\e[1;32;44m成功\e[0mechoreturn0elseecho-e\e[1;35;44m[$ip]\e[0m 执行免密结束\e[1;37;41m失败\e[0mechoreturn1fi}# 导出函数和执行关键参数以便在子shell中使用export-fprocess_hostechoecho-e\e[1;34;47m开始并行分发SSH密钥到各节点\e[0m#xargs centos7系统内置 、 -I 设置行数据占位表达式 、-P 并行度 、 bash -c 开始把函数动态重组成一个脚本后面是参数执行是会被 “$” 展开_ 缺省函数名称部分{} 是前面的占位符号后米两个就是用户和密码cat$HOSTS_FILE|grep-v#|xargs-I{}-P$PARALLEL_JOBSbash-cprocess_host $_{}$DEST_USER$PASSWORDecho-e\e[1;34;47m完成所有节点的SSH密钥分发\e[0mecho# 5.删除临时文件echo 临时文件清理 rm -f all_authorized_keys all_known_hostsrm-f${SSH_DIR}/all_authorized_keys${SSH_DIR}/all_known_hostsecho完成免密exit0这个脚本使用起来就很直观了./ssh_all.sh-ipf./ips-uroot-pw123456-t2如果在免密中部分节点因为网络等问题失败了单独执行那些失败的就行使用这个脚本批量完成后所有的节点都有自己的公钥免密完成后检查操作用户主目录下的.ssh文件夹正常来说里面会有四个文件id_rsa.pub存放了本台节点的自己的公钥信息内容通常是ssh-rsa 公钥串内容 用户节点ssh-rsa表示公钥串的类型用户节点在这个文件中只是用来标识这个串是那个节点那个用户的而已在此只有节点自身和用户自己所以没有其他特殊含义authorized_keys这个文件里数据和id_rsa.pub中格式是一样的不过意义不同该文件中的公钥串放的是其他可连接登录到本机的其他机器的公钥相比之下最后一位的用户节点则标识当前串来自于那个节点和用户known_hosts这个文件中存放着的也是公钥但是它和authorized_keys里公钥的所属对象不一样它不是.ssh文件夹中用户的公钥而是其他服务器ssh客户端的公钥有自己的生成和验证逻辑不用人为操心。通俗的讲known_hosts文件用来验证连接到服务器后客户端和目标服务器做一次公钥检查来确定连接到服务器的客户端就是原本的客户端而不是被中间人攻击了authorized_keys解决的是那些机器可以用某个用户来登录id_rsa这个是私钥用来证明当前节点自身通常不会给别人在免密登录操作上用不到
返回列表