#!/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/4108d2f3b3c047be85a8/?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/11cce6158b9e4f59ba2c/?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/414c2646352945b282c0/?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 初始化 # ----------------------- # ----------------------- # 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 /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) grep -qE "[[:space:]]/mnt/nvme[[:space:]]" /etc/fstab || \ echo "UUID=${NVME_UUID} /mnt/nvme ext4 defaults,nofail 0 2" >> /etc/fstab grep -qE "^/mnt/nvme/rancher[[:space:]]+/var/lib/rancher[[:space:]]+none[[:space:]]+bind" /etc/fstab || \ echo "/mnt/nvme/rancher /var/lib/rancher none bind 0 0" >> /etc/fstab grep -qE "^/mnt/nvme/longhorn[[:space:]]+/var/lib/longhorn[[:space:]]+none[[:space:]]+bind" /etc/fstab || \ echo "/mnt/nvme/longhorn /var/lib/longhorn none bind 0 0" >> /etc/fstab # 显示挂载状态 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 "安装时间同步相关组件..." apt update apt install -y chrony linuxptp fi # =================================================== # chrony 配置:由客户选择是否启用 # =================================================== if [[ "${ENABLE_CHRONY}" == "true" ]]; then echo "=== 启用 chrony 时间同步 ===" 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}" >> /etc/chrony/chrony.conf done cat >> /etc/chrony/chrony.conf << EOF driftfile /var/lib/chrony/chrony.drift makestep 1.0 3 rtcsync logdir /var/log/chrony EOF systemctl enable chrony systemctl restart chrony chronyc sources || true chronyc tracking || true echo "chrony 已启用" else echo "=== 未启用 chrony ===" systemctl disable chrony 2>/dev/null || true systemctl stop chrony 2>/dev/null || true fi # =================================================== # gPTP 配置:由客户选择是否启用 # =================================================== if [[ "${ENABLE_GPTP}" == "true" ]]; then echo "=== 启用 gPTP 时间同步 ===" : "${GPTP_IFACE:?请在 bushu.conf 中配置 GPTP_IFACE}" echo "gPTP 使用物理网卡: ${GPTP_IFACE}" mkdir -p /usr/local/bin mkdir -p /etc/linuxptp # ----------------------- # 创建 gPTP 配置文件 # ----------------------- cat > /etc/linuxptp/gptp.cfg << EOF # 由 bushu.sh 自动生成 # gPTP / IEEE 802.1AS 配置 [global] gmCapable 1 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 # ----------------------- # 创建 gPTP 执行脚本 # ----------------------- cat > /usr/local/bin/start-gptp.sh << 'EOF' #!/bin/bash set -euo pipefail GPTP_IFACE="${1:?Usage: start-gptp.sh }" echo "gPTP interface: ${GPTP_IFACE}" # 等待网卡出现 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}" # 启动 ptp4l,使用 gPTP 配置 exec /usr/sbin/ptp4l \ -i "${GPTP_IFACE}" \ -f /etc/linuxptp/gptp.cfg \ -m EOF chmod +x /usr/local/bin/start-gptp.sh # ----------------------- # 创建 gPTP systemd 服务 # ----------------------- cat > /etc/systemd/system/gptp.service << EOF [Unit] Description=gPTP IEEE 802.1AS Service Documentation=man:ptp4l 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 systemctl daemon-reload systemctl enable gptp.service systemctl restart gptp.service echo "gPTP 服务已启用" systemctl status gptp.service --no-pager || true else echo "=== 未启用 gPTP ===" systemctl disable gptp.service 2>/dev/null || true systemctl stop gptp.service 2>/dev/null || true 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 配置完成"