批量配置IP
#!/bin/bash
# ============================================================
# Linux 批量虚拟机网络初始化脚本
#
# 功能:
#
# 1. 安装 sshpass
# 2. 创建 SSH Key
# 3. 批量分发 SSH Key
# 4. 重新生成 machine-id
# 5. 检查 ens32 网卡
# 6. 重建 ens32 NetworkManager 连接
# 7. 配置静态 IPv4
# 8. 配置内网 IPv6
# 9. 自动检测新 IPv4 是否可以 SSH
# 10. 输出最终配置结果
#
# ============================================================
#
# 使用:
#
# chmod +x network_init.sh
# ./network_init.sh
#
# ============================================================
# ============================================================
# 基础配置
# ============================================================
# 网络接口名称
NET_IF="ens160"
# IPv4 网段
IP_PREFIX="192.168.1"
# 新 IPv4 起始地址
START_IP=21
# IPv4 子网掩码
IP_MASK=24
# IPv4 网关
GATEWAY="192.168.1.1"
# IPv4 DNS
DNS="223.5.5.5"
# ============================================================
# IPv6 配置
# ============================================================
# IPv6 前缀
IPV6_PREFIX="fc00::"
# IPv6 前缀长度
IPV6_MASK=8
# 是否配置 IPv6 网关
#
# 0 = 只配置 IPv6 地址
# 1 = 配置 IPv6 地址 + 网关 + DNS
#
CONFIG_IPV6_GATEWAY=0
# IPv6 网关
IPV6_GATEWAY="fc00::1"
# IPv6 DNS
IPV6_DNS="2400:3200::1"
# ============================================================
# SSH 配置
# ============================================================
SSH_USER="root"
SSH_TIMEOUT=5
SSH_KEY="/root/.ssh/id_rsa"
# ============================================================
# 颜色
# ============================================================
GREEN="\033[32m"
YELLOW="\033[33m"
RED="\033[31m"
BLUE="\033[36m"
RESET="\033[0m"
# ============================================================
# 日志目录
# ============================================================
LOG_DIR="/tmp/network-init"
mkdir -p "$LOG_DIR"
# ============================================================
# 输出函数
# ============================================================
info()
{
echo -e "${BLUE}[INFO]${RESET} $1"
}
success()
{
echo -e "${GREEN}[ OK ]${RESET} $1"
}
warning()
{
echo -e "${YELLOW}[WARN]${RESET} $1"
}
error()
{
echo -e "${RED}[ERROR]${RESET} $1"
}
# ============================================================
# 检查 root
# ============================================================
if [ "$EUID" -ne 0 ]; then
error "请使用 root 用户运行脚本。"
exit 1
fi
# ============================================================
# 开始
# ============================================================
clear
echo
echo "============================================================"
echo " Linux 批量虚拟机网络初始化工具"
echo "============================================================"
echo
# ============================================================
# 输入服务器 IP
# ============================================================
read -rp "请输入服务器旧 IP(空格分隔): " IP_LIST
if [ -z "$IP_LIST" ]; then
error "没有输入服务器 IP。"
exit 1
fi
# ============================================================
# 输入 SSH 密码
# ============================================================
echo
read -rsp "请输入 root SSH 密码: " SSHPASS
echo
if [ -z "$SSHPASS" ]; then
error "SSH 密码不能为空。"
exit 1
fi
export SSHPASS
# ============================================================
# 统计服务器数量
# ============================================================
COUNT=0
for HOST in $IP_LIST
do
COUNT=$((COUNT + 1))
done
# ============================================================
# 显示配置计划
# ============================================================
echo
echo "============================================================"
echo "配置计划"
echo "============================================================"
echo
echo "网卡 : $NET_IF"
echo "IPv4 网段 : $IP_PREFIX"
echo "IPv4 起始地址 : $START_IP"
echo "IPv4 网关 : $GATEWAY"
echo "IPv4 DNS : $DNS"
echo "IPv6 前缀 : $IPV6_PREFIX"
echo "IPv6 前缀长度 : /$IPV6_MASK"
echo "服务器数量 : $COUNT"
echo
INDEX=0
for HOST in $IP_LIST
do
NEW_IP=$((START_IP + INDEX))
echo "$HOST -> ${IP_PREFIX}.${NEW_IP} -> ${IPV6_PREFIX}${NEW_IP}"
INDEX=$((INDEX + 1))
done
# ============================================================
# 确认
# ============================================================
echo
warning "即将修改远程服务器网络配置。"
echo
read -rp "确认继续执行?[y/N]: " CONFIRM
if [[ ! "$CONFIRM" =~ ^[Yy]$ ]]; then
warning "用户取消操作。"
exit 0
fi
# ============================================================
# 1. 安装 sshpass
# ============================================================
echo
echo "============================================================"
echo "1. 检查 sshpass"
echo "============================================================"
if command -v sshpass >/dev/null 2>&1; then
success "sshpass 已安装"
else
info "正在安装 sshpass..."
yum install -y sshpass
if [ $? -ne 0 ]; then
error "sshpass 安装失败。"
exit 1
fi
success "sshpass 安装成功"
fi
# ============================================================
# 2. 创建 SSH Key
# ============================================================
echo
echo "============================================================"
echo "2. 创建 SSH Key"
echo "============================================================"
mkdir -p /root/.ssh
chmod 700 /root/.ssh
if [ -f "$SSH_KEY" ]; then
warning "$SSH_KEY 已存在,不重新生成。"
else
ssh-keygen -t rsa -b 4096 -f "$SSH_KEY" -N ""
if [ $? -ne 0 ]; then
error "SSH Key 创建失败。"
exit 1
fi
success "SSH Key 创建成功"
fi
# ============================================================
# 3. 测试 SSH
# ============================================================
echo
echo "============================================================"
echo "3. 测试服务器 SSH"
echo "============================================================"
SUCCESS_HOSTS=""
FAILED_HOSTS=""
for HOST in $IP_LIST
do
echo
info "测试 $HOST ..."
timeout "$SSH_TIMEOUT" sshpass -e ssh \
-o StrictHostKeyChecking=no \
-o UserKnownHostsFile=/dev/null \
-o ConnectTimeout="$SSH_TIMEOUT" \
"$SSH_USER@$HOST" \
"echo SSH_OK" >/dev/null 2>&1
if [ $? -eq 0 ]; then
success "$HOST SSH 正常"
SUCCESS_HOSTS="$SUCCESS_HOSTS $HOST"
else
error "$HOST SSH 连接失败"
FAILED_HOSTS="$FAILED_HOSTS $HOST"
fi
done
# ============================================================
# SSH 失败检查
# ============================================================
if [ -n "$FAILED_HOSTS" ]; then
echo
warning "以下服务器 SSH 连接失败:"
for HOST in $FAILED_HOSTS
do
echo " $HOST"
done
echo
read -rp "是否跳过这些服务器继续?[Y/n]: " SKIP_FAILED
if [[ "$SKIP_FAILED" =~ ^[Nn]$ ]]; then
error "脚本终止。"
exit 1
fi
fi
# ============================================================
# 4. SSH Key 分发
# ============================================================
echo
echo "============================================================"
echo "4. 分发 SSH Key"
echo "============================================================"
for HOST in $SUCCESS_HOSTS
do
echo
info "$HOST -> ssh-copy-id"
timeout 15 sshpass -e ssh-copy-id \
-o StrictHostKeyChecking=no \
-o UserKnownHostsFile=/dev/null \
-o ConnectTimeout="$SSH_TIMEOUT" \
"$SSH_USER@$HOST" >/dev/null 2>&1
if [ $? -eq 0 ]; then
success "$HOST SSH Key 分发成功"
else
warning "$HOST SSH Key 分发失败"
fi
done
# ============================================================
# 5. 重新生成 machine-id
# ============================================================
echo
echo "============================================================"
echo "5. 重新生成 Machine-ID"
echo "============================================================"
for HOST in $SUCCESS_HOSTS
do
info "$HOST -> machine-id"
timeout 10 ssh \
-o BatchMode=yes \
-o StrictHostKeyChecking=no \
-o UserKnownHostsFile=/dev/null \
-o ConnectTimeout="$SSH_TIMEOUT" \
"$SSH_USER@$HOST" \
"rm -f /etc/machine-id;
systemd-machine-id-setup"
if [ $? -eq 0 ]; then
success "$HOST machine-id 已重新生成"
else
warning "$HOST machine-id 修改失败"
fi
done
# ============================================================
# 6. 检查 ens32
# ============================================================
echo
echo "============================================================"
echo "6. 检查远程 ens32 网卡"
echo "============================================================"
for HOST in $SUCCESS_HOSTS
do
info "$HOST -> 检查 $NET_IF"
RESULT=$(timeout 10 ssh \
-o BatchMode=yes \
-o StrictHostKeyChecking=no \
-o UserKnownHostsFile=/dev/null \
-o ConnectTimeout="$SSH_TIMEOUT" \
"$SSH_USER@$HOST" \
"ip link show '$NET_IF' >/dev/null 2>&1;
echo \$?" 2>/dev/null)
if [ "$RESULT" = "0" ]; then
success "$HOST 存在 $NET_IF"
else
error "$HOST 不存在 $NET_IF"
fi
done
# ============================================================
# 7. 重建 ens32
#
# 注意:
#
# 不在这里强制 nmcli con up。
#
# 因为 SSH 正在通过当前网络连接。
#
# 先创建新的连接。
# 后面修改 IPv4 时再统一切换。
# ============================================================
echo
echo "============================================================"
echo "7. 重建 NetworkManager ens32"
echo "============================================================"
for HOST in $SUCCESS_HOSTS
do
info "$HOST -> 重建 $NET_IF"
timeout 15 ssh \
-o BatchMode=yes \
-o StrictHostKeyChecking=no \
-o UserKnownHostsFile=/dev/null \
-o ConnectTimeout="$SSH_TIMEOUT" \
"$SSH_USER@$HOST" "
nmcli con delete '$NET_IF' >/dev/null 2>&1 || true
nmcli con add \
type ethernet \
ifname '$NET_IF' \
con-name '$NET_IF'
"
if [ $? -eq 0 ]; then
success "$HOST ens32 创建成功"
else
error "$HOST ens32 创建失败"
fi
done
# ============================================================
# 8. 配置 IPv4
#
# 这里是整个脚本最重要的部分。
#
# 不直接:
#
# ssh host "nmcli con up ens32"
#
# 而是:
#
# 1. 远程后台启动
# 2. sleep 2
# 3. 修改 IPv4
# 4. nmcli con up
# 5. SSH 立即退出
# 6. 等待网络恢复
# 7. 使用新 IP 检查
#
# 防止脚本卡住。
# ============================================================
echo
echo "============================================================"
echo "8. 配置静态 IPv4"
echo "============================================================"
INDEX=0
for HOST in $SUCCESS_HOSTS
do
NEW_IP="${IP_PREFIX}.$((START_IP + INDEX))"
echo
echo "------------------------------------------------------------"
info "$HOST"
echo " 新 IPv4 : ${NEW_IP}/${IP_MASK}"
echo " Gateway : ${GATEWAY}"
echo " DNS : ${DNS}"
echo "------------------------------------------------------------"
# --------------------------------------------------------
# 新 IP 是否就是当前 IP
# --------------------------------------------------------
if [ "$HOST" = "$NEW_IP" ]; then
warning "$HOST 和新 IP 相同,跳过网络切换。"
INDEX=$((INDEX + 1))
continue
fi
# --------------------------------------------------------
# 远程后台修改网络
# --------------------------------------------------------
timeout 10 ssh \
-o BatchMode=yes \
-o StrictHostKeyChecking=no \
-o UserKnownHostsFile=/dev/null \
-o ConnectTimeout="$SSH_TIMEOUT" \
"$SSH_USER@$HOST" "
nohup bash -c '
sleep 2
echo \"===== Network Change Start =====\" >> /tmp/network-init.log
nmcli con mod '$NET_IF' \
ipv4.addresses '${NEW_IP}/${IP_MASK}' \
ipv4.gateway '$GATEWAY' \
ipv4.method manual \
ipv4.dns '$DNS'
echo \"nmcli con mod result=\$?\" >> /tmp/network-init.log
nmcli con up '$NET_IF'
echo \"nmcli con up result=\$?\" >> /tmp/network-init.log
echo \"===== Network Change End =====\" >> /tmp/network-init.log
' >/tmp/network-init-run.log 2>&1 &
echo NETWORK_CHANGE_STARTED
" >/dev/null 2>&1
SSH_RESULT=$?
if [ "$SSH_RESULT" -ne 0 ]; then
error "$HOST 网络修改任务启动失败"
INDEX=$((INDEX + 1))
continue
fi
success "$HOST 网络修改任务已启动"
# --------------------------------------------------------
# 等待网络切换
# --------------------------------------------------------
echo " 等待网络切换..."
sleep 5
# --------------------------------------------------------
# 使用新 IP 检查
# --------------------------------------------------------
CHECK_OK=0
for RETRY in 1 2 3 4 5 6 7 8
do
echo -n " 检查 ${NEW_IP} SSH ($RETRY/8)... "
timeout 5 ssh \
-o BatchMode=yes \
-o StrictHostKeyChecking=no \
-o UserKnownHostsFile=/dev/null \
-o ConnectTimeout=3 \
"$SSH_USER@$NEW_IP" \
"echo OK" >/dev/null 2>&1
if [ $? -eq 0 ]; then
echo -e "${GREEN}成功${RESET}"
CHECK_OK=1
break
else
echo -e "${YELLOW}等待${RESET}"
fi
sleep 2
done
if [ "$CHECK_OK" -eq 1 ]; then
success "$HOST -> $NEW_IP IPv4 配置成功"
else
error "$HOST -> $NEW_IP IPv4 检查失败"
warning "请检查:"
echo " IP 是否冲突"
echo " Gateway 是否正确"
echo " ens32 是否存在"
echo " NetworkManager 是否正常"
echo " /tmp/network-init.log"
# ----------------------------------------------------
# 记录失败
# ----------------------------------------------------
echo "$HOST -> $NEW_IP" >> "$LOG_DIR/ipv4_failed.log"
fi
INDEX=$((INDEX + 1))
done
# ============================================================
# 9. 配置 IPv6
#
# IPv6 使用:
#
# fc00::21/8
# fc00::22/8
# fc00::23/8
#
# 默认:
#
# 只配置 IPv6 地址
# 不配置 IPv6 Gateway
# 不配置 IPv6 DNS
#
# ============================================================
echo
echo "============================================================"
echo "9. 配置内网 IPv6"
echo "============================================================"
INDEX=0
for HOST in $SUCCESS_HOSTS
do
NEW_IP="${IP_PREFIX}.$((START_IP + INDEX))"
NEW_IPV6="${IPV6_PREFIX}$((START_IP + INDEX))"
echo
info "$HOST"
echo " IPv4 : $NEW_IP"
echo " IPv6 : ${NEW_IPV6}/${IPV6_MASK}"
# --------------------------------------------------------
# 使用新 IPv4 连接
# --------------------------------------------------------
timeout 5 ssh \
-o BatchMode=yes \
-o StrictHostKeyChecking=no \
-o UserKnownHostsFile=/dev/null \
-o ConnectTimeout=3 \
"$SSH_USER@$NEW_IP" \
"echo IPv4_OK" >/dev/null 2>&1
if [ $? -ne 0 ]; then
error "$HOST -> $NEW_IP SSH 不可用,跳过 IPv6"
INDEX=$((INDEX + 1))
continue
fi
# --------------------------------------------------------
# 配置 IPv6
# --------------------------------------------------------
if [ "$CONFIG_IPV6_GATEWAY" -eq 1 ]; then
timeout 10 ssh \
-o BatchMode=yes \
-o StrictHostKeyChecking=no \
-o UserKnownHostsFile=/dev/null \
-o ConnectTimeout="$SSH_TIMEOUT" \
"$SSH_USER@$NEW_IP" "
nmcli con mod '$NET_IF' \
ipv6.addresses '${NEW_IPV6}/${IPV6_MASK}' \
ipv6.gateway '$IPV6_GATEWAY' \
ipv6.method manual \
ipv6.dns '$IPV6_DNS'
nmcli con up '$NET_IF'
"
else
timeout 10 ssh \
-o BatchMode=yes \
-o StrictHostKeyChecking=no \
-o UserKnownHostsFile=/dev/null \
-o ConnectTimeout="$SSH_TIMEOUT" \
"$SSH_USER@$NEW_IP" "
nmcli con mod '$NET_IF' \
ipv6.addresses '${NEW_IPV6}/${IPV6_MASK}'
nmcli con up '$NET_IF'
"
fi
if [ $? -eq 0 ]; then
success "$HOST IPv6 配置成功"
else
warning "$HOST IPv6 配置可能失败"
fi
INDEX=$((INDEX + 1))
done
# ============================================================
# 10. 最终检查
# ============================================================
echo
echo "============================================================"
echo "10. 最终网络配置检查"
echo "============================================================"
INDEX=0
for HOST in $SUCCESS_HOSTS
do
NEW_IP="${IP_PREFIX}.$((START_IP + INDEX))"
NEW_IPV6="${IPV6_PREFIX}$((START_IP + INDEX))"
echo
echo "============================================================"
echo "服务器"
echo "旧 IP : $HOST"
echo "新 IP : $NEW_IP"
echo "IPv6 : ${NEW_IPV6}/${IPV6_MASK}"
echo "============================================================"
timeout 10 ssh \
-o BatchMode=yes \
-o StrictHostKeyChecking=no \
-o UserKnownHostsFile=/dev/null \
-o ConnectTimeout="$SSH_TIMEOUT" \
"$SSH_USER@$NEW_IP" "
echo
echo '--- Machine ID ---'
cat /etc/machine-id
echo
echo '--- Connection ---'
nmcli con show '$NET_IF'
echo
echo '--- IPv4 ---'
nmcli -g ipv4.addresses,ipv4.gateway,ipv4.dns \
con show '$NET_IF'
echo
echo '--- IPv6 ---'
nmcli -g ipv6.addresses,ipv6.gateway,ipv6.method \
con show '$NET_IF'
echo
echo '--- Device ---'
nmcli device show '$NET_IF' |
grep -E 'GENERAL.STATE|GENERAL.CONNECTION|IP4.ADDRESS|IP4.GATEWAY|IP6.ADDRESS'
"
if [ $? -ne 0 ]; then
warning "$NEW_IP 最终检查失败"
fi
INDEX=$((INDEX + 1))
done
# ============================================================
# 11. 输出 IP 对应关系
# ============================================================
echo
echo "============================================================"
echo "最终 IP 对应关系"
echo "============================================================"
printf "%-20s %-20s %-25s %-10s\n" \
"旧 IP" \
"新 IPv4" \
"新 IPv6" \
"状态"
echo "--------------------------------------------------------------------------"
INDEX=0
for HOST in $SUCCESS_HOSTS
do
NEW_IP="${IP_PREFIX}.$((START_IP + INDEX))"
NEW_IPV6="${IPV6_PREFIX}$((START_IP + INDEX))"
if timeout 5 ssh \
-o BatchMode=yes \
-o StrictHostKeyChecking=no \
-o UserKnownHostsFile=/dev/null \
-o ConnectTimeout=3 \
"$SSH_USER@$NEW_IP" \
"echo OK" >/dev/null 2>&1
then
STATUS="OK"
else
STATUS="FAILED"
fi
printf "%-20s %-20s %-25s %-10s\n" \
"$HOST" \
"$NEW_IP" \
"${NEW_IPV6}/${IPV6_MASK}" \
"$STATUS"
INDEX=$((INDEX + 1))
done
# ============================================================
# 12. 失败日志
# ============================================================
echo
if [ -f "$LOG_DIR/ipv4_failed.log" ]; then
echo "============================================================"
echo "IPv4 配置失败列表"
echo "============================================================"
cat "$LOG_DIR/ipv4_failed.log"
echo
echo "详细日志:"
echo "$LOG_DIR/"
else
success "所有 IPv4 配置检查正常。"
fi
# ============================================================
# 完成
# ============================================================
echo
echo "============================================================"
echo -e "${GREEN}批量网络初始化完成${RESET}"
echo "============================================================"
echo
echo "SSH 登录示例:"
echo
INDEX=0
for HOST in $SUCCESS_HOSTS
do
NEW_IP="${IP_PREFIX}.$((START_IP + INDEX))"
echo "ssh root@$NEW_IP"
INDEX=$((INDEX + 1))
done
echo
echo "日志目录:$LOG_DIR"
echo
评论 (0)