在 Ubuntu 系统中,默认通过 Netplan 工具管理网络接口。通常我们只需要手动写好 /etc/netplan/ 目录下的 YAML 文件,一劳永逸地让系统在每次启动时应用相同配置。
然而,有些场景下可能需要一个脚本能:
-
自动检测当前服务器是否已经是一个可用的静态 IP;如果网络畅通,就无需改动;
-
如果网络不可用,则尝试对服务器所有网卡进行DHCP 获取 IP,并检测能否访问外网(例如 Ping 目标 IP 或域名);
-
一旦找到能连通外网的网卡,就固定(静态)它当前的 IP/Gateway/DNS;
-
如果所有网卡都无法获取可用网络,退出并提示失败。
类似逻辑多用于初次部署或自动化安装场景。
有以下风险需了解:
-
如果只有单块网卡且依赖 SSH 远程,IP 变更后 SSH 会话极有可能断开;
-
脚本会移除所有原先的 Netplan 文件后再写新的配置,过程里没有“netplan try”的回滚;
-
如果脚本未能找出可用网卡并成功配置,系统最终会没有 Netplan 配置文件,需要人工从备份里恢复。
二、脚本逻辑概述
最终版本脚本(详见后文)包含以下步骤:
1、STEP A:判断是否已有可用静态网络
如果系统内没有任何网卡显示为“dynamic”,一般表示所有网卡要么是静态,要么未配置 IP。
脚本尝试 ping -c 3 baidu.com(或其他可达地址);若能联通,则说明已有可用的静态 IP 配置,脚本直接退出,不做改动。
如果 Ping 不通,则继续执行后续步骤。
2、STEP 0:备份并清空 Netplan 文件
将 /etc/netplan/.yaml 文件备份到 /var/backups/netplan-时间戳;
然后 rm -f /etc/netplan/.yaml,保证后续生成的配置不与旧文件冲突。
3、STEP 1 ~ STEP 2:枚举所有网卡,检测/强制设置 DHCP
脚本列出除 lo 以外的所有网卡(ip link show),依次检查:
若成功,可马上把它转成静态配置;若失败(未分配到 IP,或无法通外网),就删掉临时文件,继续下一个网卡。
如果网卡已经是 “dynamic”(DHCP 模式),那么直接获取其当前 IP / 网关 / DNS,然后转为静态;
否则,脚本临时写入一个只含 dhcp4: yes 的 netplan 文件,netplan apply 后等待几秒,看能否成功分配 IP 并Ping 通目标。
4、STEP 3:将获取到的 IP 配置写回静态
用 ip -4 addr show dev NIC 拿到 IP(带 CIDR),ip route 拿到网关,/etc/resolv.conf 里拿到 DNS;
写进 /etc/netplan/99-auto-network.yaml,其中将 gateway4 替换为用 routes: 设置默认路由,并将 dhcp4 改为 no;
nameservers 部分默认会追加 8.8.8.8 和 114.114.114.114,如果只想用这两个,可把脚本里追加的逻辑改为覆盖;
netplan apply 使之生效,然后做一次 Ping 测试,观察连通性。
5、若所有网卡都尝试完仍失败
脚本会退出,并不会留下任何新的 netplan 文件;此时需要从前面备份的目录手动复制恢复。
三、常见注意事项
1、SSH 连接风险
如果脚本在改动当前使用的网卡 IP 段,SSH 会立刻断开,需要物理/带外或多网卡支持才能继续操作。
2、netplan apply 无回滚
脚本使用 netplan apply 而非 netplan try,一旦出现配置不通,将无法自动回退。
所以要么有冗余的访问方式,要么在测试环境充分验证。
3、DNS 逻辑
脚本默认将 DHCP 下发的 DNS 与 8.8.8.8、114.114.114.114 一起写入静态配置;
如果你只想保留那两个公共 DNS,请把相关代码改成直接覆盖。
4、DNS 或外网
脚本主要通过 ping baidu.com 判断外网连通。如果你所在网络访问百度不通,请改成 ping 114.114.114.114 或其他更适合的目标。
5、一次性或开机自启
大多数情况下,这种自动脚本用于一次性的网络初始化,不必在每次开机都重复执行;
如果确实要开机时自动跑,可做一个 systemd service 或放进 cron @reboot(但要注意网络依赖顺序)。
四、脚本示例
下文为最终整合的脚本示例:auto_dhcp_then_static.sh。
其中包含:
前置检查
:如果没有网卡处于 DHCP(dynamic),且 ping 测试外网成功,说明已有可用静态网络,脚本立即退出。
否则,清空 netplan 文件并循环尝试各网卡:
若网卡已是 DHCP,则转为静态;否则临时改为 DHCP,看能否上网;一旦成功,就“锁定”成静态 IP 并停止脚本。如果所有网卡都失败,则提示错误并退出。
请将其以 UTF-8 编码保存为 auto_dhcp_then_static.sh
并给予可执行权限:
#!/usr/bin/env bash
# -*- coding: utf-8 -*-
#
# auto_dhcp_then_static.sh
#
# 功能:
# 1) 如果当前已有可用静态网络(无dynamic网卡,且能ping外网),则直接退出
# 2) 否则备份并删除 /etc/netplan/*.yaml
# 3) 枚举所有网卡(excl. lo),若网卡是dynamic则直接转静态,否则强制DHCP测试
# 4) 找到能ping通外网的网卡后,将其固定IP
# 5) 若所有网卡都失败,退出不做最终保存
#
# 注意:
# - netplan apply 无回滚,可能导致SSH断开
# - 默认会追加 8.8.8.8、114.114.114.114 到 DNS
# - ping目标默认为 baidu.com,请根据需要修改set -e # 一旦出错立即退出CONFIG_FILE="/etc/netplan/99-auto-network.yaml"
PING_TARGET="baidu.com" # 或换成 114.114.114.114###############################################################################
# STEP A:判断是否已有可用静态网络
###############################################################################
echo ">>> 检查是否已有可用的静态IP和网络连通..."HAS_DYNAMIC=false
ALL_NICS=$(ip -o link show | awk -F': ' '{print $2}' | grep -v '^lo$')
for nic in $ALL_NICS; doif ip -4 addr show dev "$nic" | grep -q "dynamic"; thenHAS_DYNAMIC=truebreakfi
done# 无dynamic网卡 -> 可能全是静态或没IP -> 测试能否ping通
if [ "$HAS_DYNAMIC" = false ]; thenecho "系统内未检测到dynamic网卡,可能已有静态IP或无IP。测试ping: $PING_TARGET"if ping -c 3 "$PING_TARGET" &> /dev/null; thenecho ">>> 当前网络已可达,视为静态网络可用,无需修改。退出。"exit 0elseecho ">>> 无法ping通,继续脚本流程..."fi
elseecho ">>> 存在dynamic网卡,可能需要转换,继续执行..."
fi###############################################################################
# STEP 0:备份并删除旧的 netplan 配置
###############################################################################
timestamp=$(date +%Y%m%d-%H%M%S)
backup_path="/var/backups/netplan-${timestamp}"echo ">>> 备份 /etc/netplan 到: $backup_path"
mkdir -p "$backup_path"
cp -r /etc/netplan/* "$backup_path"/ 2>/dev/null || true
echo ">>> 备份完成。"echo ">>> 删除现有 /etc/netplan/*.yaml"
rm -f /etc/netplan/*.yaml
echo ">>> 已删除旧的 netplan 文件。"
echo###############################################################################
# 列出非 lo 的网卡
###############################################################################
NICS=$(ip -o link show | awk -F': ' '{print $2}' | grep -v '^lo$')
if [[ -z "$NICS" ]]; thenecho "没有可用网卡(除lo外)!退出。"exit 0
fi###############################################################################
# 函数:尝试给网卡启用 DHCP 并测试连通
###############################################################################
try_dhcp_and_test() {local nic="$1"echo ">>> 对网卡 $nic 写入临时 DHCP 配置..."cat <<EOF > "$CONFIG_FILE"
network:version: 2renderer: networkdethernets:$nic:dhcp4: yes
EOFchmod 600 "$CONFIG_FILE"echo ">>> netplan apply (DHCP) on $nic..."netplan applyecho ">>> 等待5秒,让DHCP有机会拿到IP..."sleep 5local ip_cidrip_cidr=$(ip -4 addr show dev "$nic" | grep -oP '(?<=inet\s)\S+')if [[ -z "$ip_cidr" ]]; thenecho ">>> DHCP模式下,$nic 未获取到IP。"return 1fiecho ">>> 测试ping: $PING_TARGET"if ping -c 3 "$PING_TARGET" &> /dev/null; thenecho ">>> 网卡 $nic 已可连通 $PING_TARGET。"return 0elseecho ">>> 虽拿到IP,但无法ping通 $PING_TARGET。"return 2fi
}###############################################################################
# 函数:将当前 DHCP 下发的IP/Gateway/DNS 转为静态
###############################################################################
make_static_config() {local nic="$1"echo ">>> 读取 $nic 的IP/Gateway/DNS,准备写入静态配置..."local ip_cidrip_cidr=$(ip -4 addr show dev "$nic" | grep -oP '(?<=inet\s)\S+')local gatewaygateway=$(ip route | grep -E "^default .* $nic" | awk '{print $3}')local dns_listdns_list=$(grep -E '^nameserver' /etc/resolv.conf | awk '{print $2}' | xargs echo)dns_list="$dns_list 8.8.8.8 114.114.114.114"# 拼成 YAML 列表local dns_yaml="["local first=1for dns in $dns_list; doif [[ $first -eq 1 ]]; thendns_yaml="$dns_yaml$dns"first=0elsedns_yaml="$dns_yaml, $dns"fidonedns_yaml="$dns_yaml]"echo ">>> 生成最终静态配置 $CONFIG_FILE"cat <<EOF > "$CONFIG_FILE"
network:version: 2renderer: networkdethernets:$nic:addresses:- $ip_cidr
EOFif [[ -n "$gateway" ]]; thencat <<EOF >> "$CONFIG_FILE"routes:- to: defaultvia: $gateway
EOFficat <<EOF >> "$CONFIG_FILE"nameservers:addresses: $dns_yamldhcp4: no
EOFchmod 600 "$CONFIG_FILE"echo ">>> netplan apply (static) on $nic..."netplan applyecho ">>> 再次测试ping: $PING_TARGET"if ping -c 3 "$PING_TARGET" &> /dev/null; thenecho ">>> $nic (静态) 可成功访问 $PING_TARGET。"elseecho ">>> 警告:$nic (静态) 依然无法ping通 $PING_TARGET。"fi
}###############################################################################
# 主循环:对每个网卡检查
###############################################################################
found_working_nic=falsefor nic in $NICS; doecho "=== 检查网卡: $nic ==="# 如果网卡是 DHCP (dynamic),直接转静态if ip -4 addr show dev "$nic" | grep -q "dynamic"; thenecho ">>> 网卡 $nic 已是 DHCP 模式,直接转换为静态..."make_static_config "$nic"found_working_nic=truebreakelse# 否则尝试强制 DHCPif try_dhcp_and_test "$nic"; thenecho ">>> 成功拿到IP并连通外网,现在转为静态..."make_static_config "$nic"found_working_nic=truebreakelseecho ">>> $nic DHCP 尝试失败或无法连接外网,继续下一个网卡..."rm -f "$CONFIG_FILE"fifi
doneif [ "$found_working_nic" = false ]; thenechoecho "没有任何网卡成功配置DHCP并连通外网,退出,不做最终保存。"
fiecho
echo "===== [脚本结束] ====="
五、总结
该脚本是一个“先判断是否已有可用静态网络,若否再进行DHCP→静态”的综合示例。
主要功能与注意事项包括:
1、如果脚本检测到已有静态网络并可访问外网,则不修改任何配置;
2、备份后清空 /etc/netplan/,避免旧文件干扰;
3、逐一尝试网卡:若已是 DHCP,直接将其当前分配信息转静态;否则强制启用 DHCP,能连通就转静态,不能就尝试下一个网卡;
4、最终只固定找到的首个可用网卡。若无可用网卡,全局退出、不写任何新的 netplan 文件;
5、DNS 默认追加 8.8.8.8 与 114.114.114.114,可按需改成只使用这两个;
6、警惕 SSH 断开、无 netplan try 回滚等风险,确保有可回退或带外访问方式。
在实际生产环境,通常只需在安装或首配时运行此脚本一次,一旦拿到稳定 IP 并静态化,后续就可无需重复执行。
原创 K8sCat DevOpsAI