Files
zhongche-bushu/bushujb.sh
2026-04-28 15:12:57 +08:00

612 lines
15 KiB
Bash
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/bin/bash
# ===================================================
# 脚本功能:
# 1. 配置 systemd-networkd 网络桥接与 VLAN
# 2. 配置 k3s agent 节点并启动服务
# 3. 可通过配置文件 bushu.conf 管理所有参数
# ===================================================
set -euo pipefail
# -----------------------
# 检查 root 权限
# -----------------------
if [[ $EUID -ne 0 ]]; then
echo "请使用 root 用户运行此脚本"
exit 1
fi
# -----------------------
# 引入配置文件
# -----------------------
CONFIG_FILE="./bushu.conf"
if [[ -f "$CONFIG_FILE" ]]; then
source "$CONFIG_FILE"
else
echo "配置文件 $CONFIG_FILE 不存在,请先创建!"
exit 1
fi
# -----------------------
# 网络配置部分
# -----------------------
echo "=== 开始 cloud 网桥配置 ==="
# 备份现有网络配置
mkdir -p /etc/systemd/network/backup
cp /etc/systemd/network/*.network /etc/systemd/network/backup/ 2>/dev/null || true
cp /etc/systemd/network/*.netdev /etc/systemd/network/backup/ 2>/dev/null || true
echo "网络配置备份已完成"
# 创建 cloud bridge
cat > /etc/systemd/network/00-cloud.netdev << EOF
[NetDev]
Name=cloud
Kind=bridge
MACAddress=$CLOUD_MAC
[Bridge]
VLANFiltering=yes
EOF
# 配置 cloud 网络
cat > /etc/systemd/network/00-cloud.network << EOF
[Match]
Name=cloud
[Network]
Address=$CLOUD_IP
Address=$CLOUD_SECOND_IP
Gateway=$CLOUD_GATEWAY
DNS=$CLOUD_DNS
ConfigureWithoutCarrier=yes
[Link]
RequiredForOnline=no-carrier
EOF
cat > /etc/systemd/network/00-$CLOUD_IFACE.network << EOF
[Match]
Name=$CLOUD_IFACE
[Network]
Bridge=cloud
DHCP=no
# VLAN=cloud-monitor
[BridgeVLAN]
VLAN=1-4094
[BridgeVLAN]
VLAN=1
PVID=1
EgressUntagged=1
EOF
echo "cloud 网桥配置已完成"
# -----------------------
echo "=== 开始 yewu 网桥配置 ==="
# 创建 yewu bridge
cat > /etc/systemd/network/00-yewu.netdev << EOF
[NetDev]
Name=yewu
Kind=bridge
MACAddress=$YEWU_MAC
[Bridge]
VLANFiltering=yes
EOF
# 配置 yewu 网络
cat > /etc/systemd/network/00-yewu.network << EOF
[Match]
Name=yewu
[Network]
Address=$YEWU_IP
Gateway=$YEWU_GATEWAY
DNS=$YEWU_DNS
ConfigureWithoutCarrier=yes
[Link]
RequiredForOnline=no-carrier
EOF
# 用户网卡接入 yewu bridge
cat > /etc/systemd/network/00-$YEWU_IFACE.network << EOF
[Match]
Name=$YEWU_IFACE
[Network]
Bridge=yewu
DHCP=no
[BridgeVLAN]
VLAN=1-4094
[BridgeVLAN]
VLAN=1
PVID=1
EgressUntagged=1
EOF
echo "yewu 网桥配置已完成"
# 使用 networkctl reload 应用配置
echo "正在重新加载网络配置..."
networkctl reload
echo "网络配置已生效"
# ===================================================
# 新增部分monitor VLAN 子接口配置
# ===================================================
echo "=== 开始配置 monitor VLAN 子接口 ==="
: "${MONITOR_VLAN_ID:?请在 bushu.conf 中配置 MONITOR_VLAN_ID}"
: "${MONITOR_PHY_IFACE:?请在 bushu.conf 中配置 MONITOR_PHY_IFACE}"
: "${MONITOR_ALIAS:=lsa}"
MONITOR_VLAN_IFACE="${MONITOR_PHY_IFACE}.${MONITOR_VLAN_ID}"
echo "monitor 物理网卡: ${MONITOR_PHY_IFACE}"
echo "monitor VLAN ID: ${MONITOR_VLAN_ID}"
echo "monitor VLAN 子接口: ${MONITOR_VLAN_IFACE}"
echo "monitor VLAN alias: ${MONITOR_ALIAS}"
modprobe 8021q || true
if ip link show "${MONITOR_VLAN_IFACE}" >/dev/null 2>&1; then
echo "VLAN 子接口 ${MONITOR_VLAN_IFACE} 已存在,跳过创建"
else
echo "正在创建 VLAN 子接口 ${MONITOR_VLAN_IFACE} ..."
ip link add link "${MONITOR_PHY_IFACE}" name "${MONITOR_VLAN_IFACE}" type vlan id "${MONITOR_VLAN_ID}"
fi
ip link set dev "${MONITOR_VLAN_IFACE}" alias "${MONITOR_ALIAS}"
ip link set dev "${MONITOR_VLAN_IFACE}" up
echo "monitor VLAN 子接口 ${MONITOR_VLAN_IFACE} 当前已生效"
# -----------------------
# 新增部分:写入 rc.local保证重启后自动创建
# -----------------------
echo "=== 写入 rc.local配置 monitor VLAN 开机自动创建 ==="
if [[ ! -f /etc/rc.local ]]; then
cat > /etc/rc.local << 'EOF'
#!/bin/bash
exit 0
EOF
chmod +x /etc/rc.local
fi
sed -i '/# BEGIN MONITOR VLAN/,/# END MONITOR VLAN/d' /etc/rc.local
sed -i "/^exit 0/i\\
# BEGIN MONITOR VLAN\\
modprobe 8021q || true\\
while ! ip link show ${MONITOR_PHY_IFACE} >/dev/null 2>&1; do\\
sleep 1\\
done\\
ip link show ${MONITOR_VLAN_IFACE} >/dev/null 2>&1 || ip link add link ${MONITOR_PHY_IFACE} name ${MONITOR_VLAN_IFACE} type vlan id ${MONITOR_VLAN_ID}\\
ip link set dev ${MONITOR_VLAN_IFACE} alias ${MONITOR_ALIAS}\\
ip link set dev ${MONITOR_VLAN_IFACE} up\\
# END MONITOR VLAN\\
" /etc/rc.local
chmod +x /etc/rc.local
systemctl enable rc-local 2>/dev/null || true
systemctl enable rc-local.service 2>/dev/null || true
echo "rc.local 已写入 monitor VLAN 配置"
# -----------------------
# k3s 配置部分
# -----------------------
echo "=== k3s 安装配置 ==="
echo "=== 下载 K3s 二进制到 /usr/bin/ ==="
curl -L -o /usr/bin/k3s "https://file.piicloud.com/f/acfd6bc97c7e42de8647/?dl=1"
chmod +x /usr/bin/k3s
ls -lh /usr/bin/k3s
echo "=== 检查/创建 K3s agent 镜像目录 ==="
if [ ! -d "/var/lib/rancher/agent/images" ]; then
mkdir -p /var/lib/rancher/agent/images
echo "目录已创建"
else
echo "目录已存在,跳过创建"
fi
# 下载镜像
[ -f "/var/lib/rancher/agent/images/base.tar" ] || \
curl -L -o /var/lib/rancher/agent/images/base.tar "https://file.piicloud.com/f/40e4c1cc37564dd8900d/?dl=1"
[ -f "/var/lib/rancher/agent/images/expend.tar" ] || \
curl -L -o /var/lib/rancher/agent/images/expend.tar "https://file.piicloud.com/f/c6cf4a7811d344ca9bf6/?dl=1"
chown root:root /var/lib/rancher/agent/images/*.tar
chmod 644 /var/lib/rancher/agent/images/*.tar
ls -lh /var/lib/rancher/agent/images/
# 创建 systemd 服务文件
cat > /etc/systemd/system/k3s.service << EOF
[Unit]
Description=Lightweight Kubernetes
Documentation=https://k3s.io
Wants=network-online.target
After=network-online.target
[Install]
WantedBy=multi-user.target
[Service]
Type=notify
EnvironmentFile=-/etc/default/%N
EnvironmentFile=-/etc/sysconfig/%N
EnvironmentFile=-/etc/systemd/system/k3s.service.env
KillMode=process
Delegate=yes
User=root
LimitNOFILE=1048576
LimitNPROC=infinity
LimitCORE=infinity
TasksMax=infinity
TimeoutStartSec=0
Restart=always
RestartSec=5s
ExecStartPre=-/sbin/modprobe br_netfilter
ExecStartPre=-/sbin/modprobe overlay
ExecStart=/usr/bin/k3s server
EOF
# 创建 override 配置
mkdir -p /etc/systemd/system/k3s.service.d
cat > /etc/systemd/system/k3s.service.d/override.conf << EOF
[Service]
ExecStart=
ExecStart=/usr/bin/k3s agent \
--server https://$MASTER_IP:6443 \
--token $K3S_TOKEN \
--node-name $NODE_NAME \
--node-ip $NODE_IP \
--node-external-ip $NODE_EXT_IP \
--kubelet-arg max-pods=120
EOF
# 创建 registries.yaml
mkdir -p /etc/rancher/k3s/
cat > /etc/rancher/k3s/registries.yaml << EOF
configs:
harbor.tdology.com:
auth:
password: Y_TSq6qDJBZC}538
username: admin
mirrors:
docker.io:
endpoint:
- http://localhost:30500
- https://harbor.tdology.com
EOF
# -----------------------
# NVMe 分区与格式化
# -----------------------
# 检查磁盘是否存在
if [[ ! -b /dev/nvme0n1 ]]; then
echo "错误:/dev/nvme0n1 不存在"
exit 1
fi
# 如果分区不存在,则创建
if [[ ! -b /dev/nvme0n1p1 ]]; then
echo "/dev/nvme0n1p1 不存在,开始创建分区..."
if lsblk -nr /dev/nvme0n1 | awk '{print $6}' | grep -q '^part$'; then
echo "检测到已有分区,但没有 nvme0n1p1请手动检查"
exit 1
fi
parted -s /dev/nvme0n1 mklabel gpt
parted -s /dev/nvme0n1 mkpart primary 0% 100%
partprobe /dev/nvme0n1
sleep 2
if [[ ! -b /dev/nvme0n1p1 ]]; then
echo "错误:分区创建失败"
exit 1
fi
echo "分区创建成功:/dev/nvme0n1p1"
else
echo "/dev/nvme0n1p1 已存在,跳过创建分区"
fi
# 如果没有文件系统,则格式化
if ! blkid /dev/nvme0n1p1 >/dev/null 2>&1; then
echo "/dev/nvme0n1p1 没有文件系统,开始格式化为 ext4..."
mkfs.ext4 -F /dev/nvme0n1p1
else
echo "/dev/nvme0n1p1 已有文件系统,跳过格式化"
fi
# -----------------------
# NVMe 挂载与绑定挂载
# -----------------------
# 确保主挂载点存在
mkdir -p /mnt/nvme
# 挂载 /mnt/nvme
if ! mountpoint -q /mnt/nvme; then
echo "挂载 /dev/nvme0n1p1 到 /mnt/nvme ..."
mount /dev/nvme0n1p1 /mnt/nvme
else
echo "/mnt/nvme 已经挂载,跳过挂载"
fi
# ✅ 确保源目录存在(关键修复点)
mkdir -p /mnt/nvme/rancher
mkdir -p /mnt/nvme/longhorn
# 确保绑定挂载目标目录存在
mkdir -p /var/lib/rancher
mkdir -p /var/lib/longhorn
# 挂载 /var/lib/rancher
if ! mountpoint -q /var/lib/rancher; then
echo "绑定挂载 /mnt/nvme/rancher 到 /var/lib/rancher ..."
mount --bind /mnt/nvme/rancher /var/lib/rancher
else
echo "/var/lib/rancher 已经挂载,跳过绑定挂载"
fi
# 挂载 /var/lib/longhorn
if ! mountpoint -q /var/lib/longhorn; then
echo "绑定挂载 /mnt/nvme/longhorn 到 /var/lib/longhorn ..."
mount --bind /mnt/nvme/longhorn /var/lib/longhorn
else
echo "/var/lib/longhorn 已经挂载,跳过绑定挂载"
fi
# -----------------------
# 更新 /etc/fstab
# -----------------------
NVME_UUID=$(blkid -s UUID -o value /dev/nvme0n1p1)
NVME_FSTYPE=$(blkid -s TYPE -o value /dev/nvme0n1p1)
if [[ -z "$NVME_UUID" || -z "$NVME_FSTYPE" ]]; then
echo "错误:无法获取 UUID 或文件系统类型,停止写入 fstab"
exit 1
fi
# 主挂载(安全)
grep -qE "[[:space:]]/mnt/nvme[[:space:]]" /etc/fstab || \
echo "UUID=${NVME_UUID} /mnt/nvme ${NVME_FSTYPE} defaults,nofail,x-systemd.device-timeout=5 0 2" >> /etc/fstab
# bind mount安全
grep -qE "[[:space:]]/var/lib/rancher[[:space:]]" /etc/fstab || \
echo "/mnt/nvme/rancher /var/lib/rancher none bind,nofail,x-systemd.requires-mounts-for=/mnt/nvme 0 0" >> /etc/fstab
grep -qE "[[:space:]]/var/lib/longhorn[[:space:]]" /etc/fstab || \
echo "/mnt/nvme/longhorn /var/lib/longhorn none bind,nofail,x-systemd.requires-mounts-for=/mnt/nvme 0 0" >> /etc/fstab
# -----------------------
# 验证
# -----------------------
echo "测试 fstab..."
mount -a
echo "显示挂载状态"
findmnt /mnt/nvme
findmnt /var/lib/rancher
findmnt /var/lib/longhorn
# -----------------------
# 时间同步
# -----------------------
echo "=== 时间同步配置 ==="
: "${ENABLE_CHRONY:=true}"
: "${ENABLE_GPTP:=false}"
if [[ "${ENABLE_CHRONY}" == "true" && "${ENABLE_GPTP}" == "true" ]]; then
echo "错误ENABLE_CHRONY 和 ENABLE_GPTP 不能同时为 true"
exit 1
fi
echo "=== 从 RTC 恢复系统时间 ==="
hwclock -s 2>/dev/null || hwclock --hctosys 2>/dev/null || true
date
if [[ "${ENABLE_CHRONY}" == "true" || "${ENABLE_GPTP}" == "true" ]]; then
echo "安装时间同步相关组件..."
apt update
apt install -y chrony linuxptp
fi
if [[ "${ENABLE_CHRONY}" == "true" ]]; then
echo "=== 启用 chrony 时间同步 ==="
systemctl disable --now gptp.service 2>/dev/null || true
systemctl disable --now phc2sys.service 2>/dev/null || true
pkill ptp4l 2>/dev/null || true
pkill phc2sys 2>/dev/null || true
cp /etc/chrony/chrony.conf /etc/chrony/chrony.conf.bak 2>/dev/null || true
cat > /etc/chrony/chrony.conf << EOF
# 由 bushu.sh 自动生成
EOF
for server in "${CHRONY_SERVERS[@]}"; do
echo "server ${server} iburst" >> /etc/chrony/chrony.conf
done
cat >> /etc/chrony/chrony.conf << EOF
driftfile /var/lib/chrony/chrony.drift
makestep 1.0 -1
rtcsync
logdir /var/log/chrony
EOF
systemctl enable --now chrony
chronyc -a makestep || true
sleep 3
chronyc sources -v || true
chronyc tracking || true
elif [[ "${ENABLE_GPTP}" == "true" ]]; then
echo "=== 启用 gPTP 时间同步 ==="
systemctl disable --now chrony 2>/dev/null || true
: "${GPTP_IFACE:?请在 bushu.conf 中配置 GPTP_IFACE}"
mkdir -p /usr/local/bin
mkdir -p /etc/linuxptp
cat > /etc/linuxptp/gptp.cfg << EOF
# 由 bushu.sh 自动生成
# gPTP / IEEE 802.1AS 配置
[global]
gmCapable 0
priority1 248
priority2 248
logAnnounceInterval 0
logSyncInterval -3
syncReceiptTimeout 3
neighborPropDelayThresh 800
min_neighbor_prop_delay -20000000
assume_two_step 1
path_trace_enabled 1
follow_up_info 1
transportSpecific 0x1
ptp_dst_mac 01:80:C2:00:00:0E
network_transport L2
delay_mechanism P2P
time_stamping hardware
EOF
cat > /usr/local/bin/start-gptp.sh << 'EOF'
#!/bin/bash
set -euo pipefail
GPTP_IFACE="${1:?Usage: start-gptp.sh <interface>}"
while ! ip link show "${GPTP_IFACE}" >/dev/null 2>&1; do
echo "等待网卡 ${GPTP_IFACE} 出现..."
sleep 1
done
ip link set dev "${GPTP_IFACE}" up
if ethtool -T "${GPTP_IFACE}" 2>/dev/null | grep -q "hardware-transmit"; then
TS_MODE="hardware"
else
echo "警告:${GPTP_IFACE} 不支持硬件时间戳,切换为 software timestamp"
TS_MODE="software"
sed -i 's/^time_stamping.*/time_stamping software/' /etc/linuxptp/gptp.cfg
fi
echo "gPTP timestamp mode: ${TS_MODE}"
exec /usr/sbin/ptp4l \
-i "${GPTP_IFACE}" \
-f /etc/linuxptp/gptp.cfg \
-m
EOF
chmod +x /usr/local/bin/start-gptp.sh
cat > /etc/systemd/system/gptp.service << EOF
[Unit]
Description=gPTP IEEE 802.1AS Service
After=network-online.target
Wants=network-online.target
[Service]
Type=simple
ExecStart=/usr/local/bin/start-gptp.sh ${GPTP_IFACE}
Restart=always
RestartSec=5
User=root
[Install]
WantedBy=multi-user.target
EOF
cat > /etc/systemd/system/phc2sys.service << EOF
[Unit]
Description=Synchronize system clock from gPTP PHC
After=gptp.service
Requires=gptp.service
[Service]
Type=simple
ExecStartPre=/bin/sleep 10
ExecStart=/usr/sbin/phc2sys -s ${GPTP_IFACE} -c CLOCK_REALTIME -O 0 -m
Restart=always
RestartSec=5
User=root
[Install]
WantedBy=multi-user.target
EOF
systemctl daemon-reload
systemctl enable --now gptp.service
systemctl enable --now phc2sys.service
else
echo "=== 未启用时间同步 ==="
systemctl disable --now chrony 2>/dev/null || true
systemctl disable --now gptp.service 2>/dev/null || true
systemctl disable --now phc2sys.service 2>/dev/null || true
fi
echo "=== 检查系统时间 ==="
date
timedatectl || true
YEAR=$(date +%Y)
if (( YEAR < 2024 )); then
echo "错误:系统时间异常,当前时间:$(date)"
echo "拒绝继续执行,避免 apt/curl/k3s TLS 失败"
exit 1
fi
# -----------------------
# 域名解析
# -----------------------
echo "=== 配置 /etc/hosts ==="
for entry in "${HOSTS_ENTRIES[@]}"; do
grep -qF "$entry" /etc/hosts || echo "$entry" >> /etc/hosts
done
# -----------------------
# 启动 k3s 服务
# -----------------------
systemctl daemon-reload
systemctl enable k3s
systemctl start k3s
echo "k3s 配置完成"