本文为X86/amd64架构部署文档
本文使用脚本的方式安装kubernetes集群。脚本中涵盖Kubernete官方安装步骤的所有内容。

安装前必读

本文分别提供两个脚本,请仔细阅读以下内容

  • 第一个是安装Master节点脚本在整个集群搭建过程中只在第一台机器上执行,用以构建集群并安装集群组件,其余master节点请使用第二个加入节点脚本加入进集群。
  • 第二个是加入集群脚本执行时请根据提示选择加入的是master节点还是work节点,master为管理节点,一般为3个,worker为工作节点,一般在工管分离架构时选择。
  • 在脚本执行过程中如有错误,或意外中断,脚本可重复执行
  • 脚本在下载软件包时如超时或其他错误,请等待重试,直至完成下载.
  • 特殊配置,允许在Master上运行pod,如果你只有3个节点,请在机器都加入集群以后执行以下3条命令
    kubectl get node|grep -v NAME|awk '{print $1}'  |  xargs -I {} kubectl taint node {} node-role.kubernetes.io/master-
    kubectl get node|grep -v NAME|awk '{print $1}'  |  xargs -I {} kubectl taint node {} node-role.kubernetes.io/control-plane-
    kubectl get node|grep -v NAME|awk '{print $1}'  |  xargs -I {} kubectl patch node {} -p '{"spec":{"unschedulable":false}}'

    请注意: 在执行脚本时除一开始的人机交互外脚本还会输出需要人为决策性的命令! 并有完整的提示! 请仔细阅读!
    如系统为ubuntu时执行脚本不能使用 sh 需要使用 bash 来执行改脚本! 例如: bash xxx.sh

安装Master节点脚本

请根据情况修改脚本中以下变量内容

  • 服务器网卡名称
    export INTERFACE=enp4s0
  • 服务器IP
    export IP=172.16.10.79
  • 集群负载IP,必须与服务器同网段
    export VIP=172.16.10.5
  • 集群内部通讯SVC IP段
    export SERVICE_CIDR="10.254.0.0/16"
  • 实例IP段
    export POD_NETWORK_CIDR="172.30.0.0/16"

将以下脚本保存在Master机器上

    
#!/bin/bash

set -e

# 检查是否以 root 用户执行
if [ "$(id -u)" -ne 0 ]; then
    echo -e "\033[0;31m请使用 root 用户运行此脚本。\033[0m"
    exit 1
fi

# 设置环境变量
export INTERFACE=enp4s0
export IP=172.16.10.79
export VIP=172.16.10.5
export SERVICE_CIDR="10.254.0.0/16"
export POD_NETWORK_CIDR="172.30.0.0/16"
export KUBERNETES_VERSION="1.25.14"
export HOSTNAME="node01"
export PORT=6443

echo "当前设置的网卡名称为:$INTERFACE"
echo "当前设置的K8s集群负载均衡地址为:$VIP"
echo "当前设置的主机名为:$HOSTNAME"
echo "当前设置的主机IP为:$IP"
echo "当前设置的K8s集群API端口为:$PORT"
echo "当前设置的Service CIDR为:$SERVICE_CIDR"
echo "当前设置的Pod Network CIDR为:$POD_NETWORK_CIDR"
echo "当前设置的Kubernetes版本为:$KUBERNETES_VERSION"
echo "${RED}如系统为ubuntu请使用bash执行该脚本.${NC}"
read -p "请确认以上变量内容是否已修改正确 (yes/no): " confirm
if [ "$confirm" != "yes" ]; then
    echo "请修改脚本中的变量内容后再运行脚本。"
    exit 1
fi

export K8S_WORK_DIR=/install/k8s/kubernetes
export CALICO_WORK_DIR=/install/k8s/calico
export IMAGE_REPOSITORY=registry.aliyuncs.com/google_containers
export CONTROLLER_PLAN_ENDPOINT="$VIP:$PORT"

# 设置 PATH 环境变量
export PATH=$PATH:/usr/local/bin:/usr/local/sbin
if ! grep -q "/usr/local/bin" /etc/profile; then
    echo 'export PATH=$PATH:/usr/local/bin' >> /etc/profile
    echo -e "${GREEN}已将 /usr/local/bin 添加到 PATH 并写入 /etc/profile${NC}"
fi
if ! grep -q "/usr/local/sbin" /etc/profile; then
    echo 'export PATH=$PATH:/usr/local/sbin' >> /etc/profile
    echo -e "${GREEN}已将 /usr/local/sbin 添加到 PATH 并写入 /etc/profile${NC}"
fi

# 颜色定义
GREEN='\033[0;32m'
RED='\033[0;31m'
NC='\033[0m' # No Color

echo -e "${GREEN}开始安装配置...${NC}"

# 设置主机名并更新 /etc/hosts
hostnamectl set-hostname $HOSTNAME

# 检查 /etc/hosts 文件中是否存在主机名与 IP 地址的 hosts
if ! grep -q "$HOSTNAME" /etc/hosts; then
    ip_address=$(hostname -I | awk '{print $1}')
    echo "$ip_address $HOSTNAME" | tee -a /etc/hosts
    echo "$VIP core.harbor.domain" | tee -a /etc/hosts
    echo -e "${GREEN}/etc/hosts 文件中已添加主机名与 IP 地址${NC}"
else
    echo -e "${GREEN}/etc/hosts 文件中已存在主机名与 IP 地址${NC}"
fi

# 使 PATH 变量生效
source /etc/profile

configure_centos() {
    # 修改 CentOS 仓库源为阿里云镜像源
    if ! grep -q "mirrors.aliyun.com" /etc/yum.repos.d/CentOS-Base.repo; then
        if grep -q "release 7" /etc/centos-release; then
            sed -i.bak -e 's|^mirrorlist=|#mirrorlist=|g' -e 's|^#baseurl=http://mirror.centos.org|baseurl=https://mirrors.aliyun.com|g' /etc/yum.repos.d/CentOS-Base.repo
            echo -e "${GREEN}已修改 CentOS 7 仓库源为阿里云镜像源${NC}"
        elif grep -q "release 8" /etc/centos-release; then
            if ! grep -q "vault.centos.org" /etc/yum.repos.d/CentOS-Base.repo; then
                sed -i -e "s|mirrorlist=|#mirrorlist=|g" /etc/yum.repos.d/CentOS-*
                sed -i -e "s|#baseurl=http://mirror.centos.org|baseurl=http://vault.centos.org|g" /etc/yum.repos.d/CentOS-*
                echo -e "${GREEN}已修改 CentOS 8.x 仓库源${NC}"
            else
                echo -e "${GREEN}CentOS 8.x 仓库源已设置${NC}"
            fi
        else
            echo -e "${GREEN}系统不是 CentOS 7 或 8,无需修改仓库源${NC}"
        fi
    else
        echo -e "${GREEN}CentOS 仓库源已是阿里云镜像源${NC}"
    fi

    # 安装依赖包
    echo -e "${GREEN}安装依赖包中···${NC}"
    yum install -y epel-release >/dev/null
    DEPENDENCIES="conntrack ipvsadm ipset jq sysstat curl iptables wget lrzsz nc tar ntpdate nfs-utils vim netcat gcc make gperf yum-plugin-versionlock"
    for package in $DEPENDENCIES; do
        if ! rpm -q $package &>/dev/null; then
            if yum install -y $package >/dev/null; then
                echo -e "${GREEN}$package 已成功安装${NC}"
            else
                echo -e "${RED}$package 安装失败,请检查网络连接或软件源配置。${NC}"
                exit 1
            fi
        else
            echo -e "${GREEN}$package 已经安装${NC}"
        fi
    done
}

# 配置Ubuntu
configure_ubuntu() {
    echo -e "${GREEN}正在配置 Ubuntu...${NC}"

    #强制免交互自动重启服务
    export DEBIAN_FRONTEND=noninteractive
    export UCF_FORCE_CONFFOLD=YES

    # 修改APT源为阿里云源
    if ! grep -q "mirrors.aliyun.com" /etc/apt/sources.list; then
        cp /etc/apt/sources.list /etc/apt/sources.list.bak
        cat > /etc/apt/sources.list << EOF
deb http://mirrors.aliyun.com/ubuntu/ $(lsb_release -sc) main restricted universe multiverse
deb http://mirrors.aliyun.com/ubuntu/ $(lsb_release -sc)-security main restricted universe multiverse
deb http://mirrors.aliyun.com/ubuntu/ $(lsb_release -sc)-updates main restricted universe multiverse
deb http://mirrors.aliyun.com/ubuntu/ $(lsb_release -sc)-proposed main restricted universe multiverse
deb http://mirrors.aliyun.com/ubuntu/ $(lsb_release -sc)-backports main restricted universe multiverse
EOF
        echo -e "${GREEN}APT源已修改为阿里云源${NC}"
    else
        echo -e "${GREEN}APT源已是阿里云源${NC}"
    fi

    # 更新系统
    apt-get update

    # 安装依赖包
    echo -e "${GREEN}安装依赖包中···${NC}"
    apt-get install -y apt-utils >/dev/null
    DEPENDENCIES="conntrack ipvsadm ipset jq sysstat curl iptables wget lrzsz tar ntpdate nfs-common vim build-essential"
    for package in $DEPENDENCIES; do
        if ! dpkg -l | grep -q "^ii  $package "; then
            if apt-get install -y $package >/dev/null; then
                echo -e "${GREEN}$package 已成功安装${NC}"
            else
                echo -e "${RED}$package 安装失败,请检查网络连接或软件源配置。${NC}"
                exit 1
            fi
        else
            echo -e "${GREEN}$package 已经安装${NC}"
        fi
    done

    # 逐个检查每个依赖包是否已安装成功
    for package in $DEPENDENCIES; do
        if ! dpkg -l | grep -q "^ii  $package "; then
            echo -e "${RED}$package 安装失败,请手动检查并安装。${NC}"
            exit 1
        else
            echo -e "${GREEN}$package 已成功安装并可用${NC}"
        fi
    done
}

# 检查 /etc/profile 中是否有 ulimit 设置,如果没有就添加进去
configure_ulimit() {
    if ! grep -q "ulimit -SHn 1048576" /etc/profile; then
        echo "ulimit -SHn 1048576" >> /etc/profile
        echo -e "${GREEN}已将 ulimit -SHn 1048576 添加到 /etc/profile${NC}"
    else
        echo -e "${GREEN}/etc/profile 中已存在 ulimit -SHn 1048576${NC}"
    fi

    # 使 ulimit 设置生效
    source /etc/profile
}

# 调整时区
adjust_timezone() {
    if [ "$(timedatectl show --property=Timezone --value)" != "Asia/Shanghai" ];then
        timedatectl set-timezone Asia/Shanghai
        echo -e "${GREEN}时区已设置为 Asia/Shanghai${NC}"
    else
        echo -e "${GREEN}时区已是 Asia/Shanghai${NC}"
    fi

    # 将当前的 UTC 时间写入硬件时钟
    if [ "$(timedatectl show --property=LocalRTC --value)" != "0" ];then
        timedatectl set-local-rtc 0
        echo -e "${GREEN}已将 UTC 时间写入硬件时钟${NC}"
    else
        echo -e "${GREEN}硬件时钟已是 UTC 时间${NC}"
    fi

    # 重启时间的服务和任务调度服务
    #systemctl restart rsyslog
    #systemctl restart crond
    #echo -e "${GREEN}时间服务和任务调度服务已重启${NC}"

    # 同步时间
    /usr/sbin/ntpdate pool.ntp.org
    if [ $? -eq 0 ]; then
        echo -e "${GREEN}时间已同步${NC}"
    else
        echo -e "${RED}时间同步失败,请检查网络连接或时间服务器配置。${NC}"
    fi
}

# 安装 libseccomp 的函数
install_libseccomp() {
    local LIBSECCOMP_VERSION="2.5.2"

    # 检查系统版本
    if { [ -f /etc/centos-release ] && grep -q -E "7\.([0-8]|9[^\.])|8\.[0-9]+" /etc/centos-release; } || { [ -f /etc/os-release ] && grep -q "22\.[0-9]\|24\.[0-9]" /etc/os-release; }; then
        echo -e "${GREEN}系统版本高于 Ubuntu 22 或 CentOS 7.9,不需要安装 libseccomp${NC}"
        return
    fi

    # 检查已安装的 libseccomp 版本
    if [ -f "/usr/local/lib/pkgconfig/libseccomp.pc" ]; then
        local INSTALLED_VERSION=$(grep "Version:" /usr/local/lib/pkgconfig/libseccomp.pc | awk '{print $2}')

        if [ "$INSTALLED_VERSION" = "$LIBSECCOMP_VERSION" ]; then
            echo -e "${GREEN}libseccomp $LIBSECCOMP_VERSION 已经安装${NC}"
            return
        else
            echo -e "${YELLOW}已安装 libseccomp 版本为 $INSTALLED_VERSION, 需要升级到 $LIBSECCOMP_VERSION${NC}"
        fi
    else
        echo -e "${YELLOW}未检测到已安装的 libseccomp,准备安装 $LIBSECCOMP_VERSION${NC}"
    fi

    cd /tmp
    if [ ! -f libseccomp-${LIBSECCOMP_VERSION}.tar.gz ]; then
        attempts=0
        success=false
        url="https://cloud-help.mandao.com/uploads/cloud/install/runtime/libseccomp-${LIBSECCOMP_VERSION}.tar.gz"

        while [ $attempts -lt 6 ]; do
            wget $url -O libseccomp-${LIBSECCOMP_VERSION}.tar.gz && success=true && break
            attempts=$((attempts + 1))
            echo -e "${GREEN}下载失败,重试第 $attempts 次...${NC}"
            sleep 5
        done

        if ! $success; then
            echo -e "${RED}下载 libseccomp 失败,请检查网络连接或下载地址。${NC}"
            exit 1
        fi
    else
        echo -e "${GREEN}libseccomp-${LIBSECCOMP_VERSION}.tar.gz 已存在,跳过下载。${NC}"
    fi

    tar -xzf libseccomp-${LIBSECCOMP_VERSION}.tar.gz
    cd libseccomp-${LIBSECCOMP_VERSION}

    echo -e "${GREEN}正在配置,请等待!${NC}"
    # 配置并隐藏输出,失败时提示查看日志
    ./configure > /tmp/libseccomp_configure.log 2>&1 || {
        echo -e "${RED}配置失败,请查看 /tmp/libseccomp_configure.log 了解详情。${NC}"
        exit 1
    }

    echo -e "${GREEN}正在编译,请等待!${NC}"
    # 编译并隐藏输出,失败时提示查看日志
    make -j2 > /tmp/libseccomp_make.log 2>&1 || {
        echo -e "${RED}编译失败,请查看 /tmp/libseccomp_make.log 了解详情。${NC}"
        exit 1
    }

    # 安装并隐藏输出,失败时提示查看日志
    make install > /tmp/libseccomp_install.log 2>&1 || {
        echo -e "${RED}安装失败,请查看 /tmp/libseccomp_install.log 了解详情。${NC}"
        exit 1
    }

    ldconfig
    echo -e "${GREEN}libseccomp $LIBSECCOMP_VERSION 已成功安装${NC}"

    # 检查并更新 ldconfig 缓存
    echo "/usr/local/lib" > /etc/ld.so.conf.d/local-lib.conf
    ldconfig
}


# 停止并禁用防火墙和 dnsmasq
disable_services() {
    # 停止并禁用防火墙
    if systemctl is-active --quiet firewalld; then
        systemctl stop firewalld
        echo -e "${GREEN}防火墙已停止${NC}"
    fi

    if systemctl is-enabled --quiet firewalld; then
        systemctl disable firewalld
        echo -e "${GREEN}防火墙已禁用${NC}"
    fi

    iptables -F && iptables -X && iptables -F -t nat && iptables -X -t nat
    iptables -P FORWARD ACCEPT
    echo -e "${GREEN}iptables 规则已清除${NC}"

    # 停止并禁用 dnsmasq
    if systemctl is-active --quiet dnsmasq; then
        systemctl stop dnsmasq
        echo -e "${GREEN}dnsmasq 已停止${NC}"
    fi

    if systemctl is-enabled --quiet dnsmasq; then
        systemctl disable dnsmasq
        echo -e "${GREEN}dnsmasq 已禁用${NC}"
    fi
}

# 关闭 SELinux 和 Swap
disable_swap_selinux() {
    # 关闭 Swap
    if swapon --summary | grep -q 'partition\|file'; then
        swapoff -a
        echo -e "${GREEN}Swap 已关闭${NC}"
    fi

    if grep -q 'swap' /etc/fstab; then
        sed -i '/swap/d' /etc/fstab
        echo -e "${GREEN}/etc/fstab 中的 Swap 条目已删除${NC}"
    fi

    # 关闭 SELinux(如果安装了工具)
    if command -v getenforce &> /dev/null; then
        if [ "$(getenforce)" != "Disabled" ];then
            setenforce 0
            echo -e "${GREEN}SELinux 已设置为 Permissive${NC}"
        fi
    else
        echo -e "${YELLOW}getenforce 命令未找到,跳过 SELinux 设置步骤。${NC}"
    fi

    if command -v setenforce &> /dev/null; then
        if grep -q 'SELINUX=enforcing' /etc/selinux/config;then
            sed -i 's#SELINUX=enforcing#SELINUX=disabled#g' /etc/selinux/config
            echo -e "${GREEN}SELinux 配置文件已修改为 Disabled${NC}"
        fi
    else
        echo -e "${YELLOW}setenforce 命令未找到,跳过 SELinux 设置步骤。${NC}"
    fi
}


# 配置 Kubernetes 优化参数和加载内核模块
configure_kubernetes() {
    # 配置 Kubernetes 优化参数
    if [ ! -f /etc/sysctl.d/kubernetes.conf ]; then
        cat > /tmp/kubernetes.conf << EOF
net.bridge.bridge-nf-call-iptables=1
net.bridge.bridge-nf-call-ip6tables=1
net.ipv4.ip_forward=1
vm.swappiness=0
vm.overcommit_memory=1
vm.panic_on_oom=0
fs.inotify.max_user_watches=89100
EOF

        cp /tmp/kubernetes.conf /etc/sysctl.d/kubernetes.conf
        sysctl -p /etc/sysctl.d/kubernetes.conf &
        rm -rf /tmp/kubernetes.conf
        echo -e "${GREEN}Kubernetes 优化参数已配置${NC}"
    else
        echo -e "${GREEN}Kubernetes 优化参数已存在${NC}"
    fi

    # 加载内核模块
    for module in br_netfilter ip_vs; do
        if ! lsmod | grep -q "$module"; then
            modprobe $module
            echo -e "${GREEN}内核模块 $module 已加载${NC}"
        else
            echo -e "${GREEN}内核模块 $module 已存在${NC}"
        fi
    done
}

# 设置文件句柄
configure_file_handles() {
    updateSysCtl() {
        key=$1
        value=$2
        filePath=/etc/sysctl.conf
        if grep -q $key $filePath; then
            sed -i "/$key/d" $filePath
        fi
        echo "$key = $value" | tee -a $filePath
        echo -e "${GREEN}已设置 $key = $value${NC}"
    }

    updateSysCtl "fs.file-max" "1000000"
    updateSysCtl "net.ipv4.ip_conntrack_max" "1000000"
    updateSysCtl "net.ipv4.netfilter.ip_conntrack_max" "1000000"

    sysctl -p &
    echo -e "${GREEN}文件句柄已设置${NC}"
}

# 安装容器运行时 Containerd
install_containerd() {
    export PATH=$PATH:/usr/local/bin
    if [ ! -f /usr/local/bin/containerd ]; then
    #local url="https://github.com/containerd/containerd/releases/download/v1.7.7/cri-containerd-cni-1.7.7-linux-amd64.tar.gz"
    local url="https://cloud-help.mandao.com/uploads/cloud/install/runtime/cri-containerd-cni-1.7.20-linux-amd64.tar.gz"
    local file="/tmp/cri-containerd-cni-1.7.20-linux-amd64.tar.gz"
    local attempts=0
    local success=false

    # 检测 /tmp 目录下是否有该文件
    if [ -f "$file" ]; then
        echo -e "${GREEN}检测到 /tmp 目录下已存在 cri-containerd-cni-1.7.20-linux-amd64.tar.gz 文件,尝试解压...${NC}"
        tar -zxvf "$file" -C / || {
            echo -e "${RED}解压失败,删除文件并重新下载...${NC}"
            rm -f "$file"
        }
    fi

    # 如果文件不存在或解压失败后被删除,则重新下载
    if [ ! -f "$file" ]; then
        while [ $attempts -lt 6 ]; do
            wget "$url" -O "$file" && success=true && break
            attempts=$((attempts + 1))
            echo -e "${GREEN}下载失败,重试第 $attempts 次...${NC}"
            sleep 5
        done

        if ! $success; then
            echo -e "${RED}下载 containerd 失败,请检查网络连接或下载地址。${NC}"
            exit 1
        fi

        tar -zxvf "$file" -C / || {
            echo -e "${RED}解压失败,请手动检查问题。${NC}"
            exit 1
        }
    else
        echo -e "${GREEN}文件已存在且解压成功。${NC}"
    fi

        source /etc/profile
        echo -e "${GREEN}Containerd 已安装${NC}"
    else
        echo -e "${GREEN}Containerd 已存在${NC}"
    fi

    # 配置 Containerd 服务
    if [ ! -f /usr/local/lib/systemd/system/containerd.service ]; then
        mkdir -p /usr/local/lib/systemd/system/
        cp /etc/systemd/system/containerd.service /usr/local/lib/systemd/system/containerd.service
        systemctl daemon-reload
        systemctl enable --now containerd
        sleep 2
        echo -e "${GREEN}Containerd 服务已启动${NC}"
    else
        echo -e "${GREEN}Containerd 服务已存在${NC}"
    fi

    # 生成 Containerd 配置
    if [ ! -f /etc/containerd/config.toml ]; then
        mkdir -p /etc/containerd
        containerd config default | tee /etc/containerd/config.toml
        sed -i 's/SystemdCgroup = false/SystemdCgroup = true/' /etc/containerd/config.toml
        sed -i 's/registry.k8s.io\/pause:3.8/registry.aliyuncs.com\/google_containers\/pause:3.8/' /etc/containerd/config.toml
        systemctl restart containerd
        echo -e "${GREEN}Containerd 配置已生成并应用${NC}"
    else
        echo -e "${GREEN}Containerd 配置已存在${NC}"
    fi


    # 检查默认 CNI 配置文件是否存在
    DEFAULT_CNI_CONFIG="/etc/cni/net.d/10-containerd-net.conflist"

    if [ -f "$DEFAULT_CNI_CONFIG" ]; then
        echo -e "${GREEN}检测到默认 CNI 配置文件 $DEFAULT_CNI_CONFIG,开始清理。${NC}"

        # 清理默认 CNI 配置文件
        rm -rf /etc/cni/net.d/*
        echo -e "${GREEN}默认 CNI 配置文件已清理。${NC}"

        # 重启 containerd 服务
        systemctl restart containerd
        echo -e "${GREEN}containerd 服务已重启。${NC}"
    else
        echo -e "${GREEN}未检测到默认 CNI 配置文件,无需清理。${NC}"
    fi

}

# 安装 Kubernetes 工具的函数
install_kubernetes_tools() {
    if ! kubectl version --client &>/dev/null; then
        if [ -f /etc/centos-release ]; then
            cat << EOF > /etc/yum.repos.d/kubernetes.repo
[kubernetes]
name=Kubernetes
baseurl=https://mirrors.aliyun.com/kubernetes/yum/repos/kubernetes-el7-x86_64/
enabled=1
gpgcheck=1
repo_gpgcheck=0
gpgkey=https://mirrors.aliyun.com/kubernetes/yum/doc/yum-key.gpg https://mirrors.aliyun.com/kubernetes/yum/doc/rpm-package-key.gpg
EOF
            yum install -y kubelet-$KUBERNETES_VERSION kubeadm-$KUBERNETES_VERSION kubectl-$KUBERNETES_VERSION --disableexcludes=kubernetes
            systemctl enable kubelet && systemctl start kubelet
            yum versionlock kubelet-$KUBERNETES_VERSION-0 kubeadm-$KUBERNETES_VERSION-0 kubectl-$KUBERNETES_VERSION-0
            echo -e "${GREEN}kubelet-$KUBERNETES_VERSION、kubeadm-$KUBERNETES_VERSION 和 kubectl-$KUBERNETES_VERSION 已安装并锁定版本${NC}"
        elif [ -f /etc/lsb-release ]; then
            curl -s https://mirrors.aliyun.com/kubernetes/apt/doc/apt-key.gpg | apt-key add -
            cat << EOF >/etc/apt/sources.list.d/kubernetes.list
deb https://mirrors.aliyun.com/kubernetes/apt/ kubernetes-xenial main
EOF
            apt-get update
            apt-get install -y kubelet=$KUBERNETES_VERSION-00 kubeadm=$KUBERNETES_VERSION-00 kubectl=$KUBERNETES_VERSION-00
            systemctl enable kubelet && systemctl start kubelet
            apt-mark hold kubeadm kubelet kubectl
            echo -e "${GREEN}kubelet-$KUBERNETES_VERSION、kubeadm-$KUBERNETES_VERSION 和 kubectl-$KUBERNETES_VERSION 已安装并锁定版本${NC}"
        fi
    else
        echo -e "${GREEN}kubelet-$KUBERNETES_VERSION、kubeadm-$KUBERNETES_VERSION 和 kubectl-$KUBERNETES_VERSION 已安装并锁定版本${NC}"
    fi
}

# 安装负载均衡器 kube-vip 的函数
install_kube_vip() {
    #export KVVERSION=$(curl -sL https://api.github.com/repos/kube-vip/kube-vip/releases | jq -r ".[0].name")
    if [ -z "$KVVERSION" ]; then
        export KVVERSION="v0.8.0" # 使用一个已知存在的版本
    fi

    #while ! ctr images ls | grep -q "ghcr.io/kube-vip/kube-vip:$KVVERSION"; do
    while ! ctr images ls | grep -q "dockerhub.mandao.com/kube-vip/kube-vip:$KVVERSION"; do
        #ctr image pull ghcr.io/kube-vip/kube-vip:$KVVERSION
        ctr image pull dockerhub.mandao.com/kube-vip/kube-vip:$KVVERSION
        if [ $? -eq 0 ]; then
            echo -e "${GREEN}kube-vip 镜像已下载${NC}"
        else
            echo -e "${RED}kube-vip 镜像下载失败,正在重试...${NC}"
            sleep 5
        fi
    done
    echo -e "${GREEN}kube-vip 镜像已存在${NC}"

    export kube_vip_file="/etc/kubernetes/manifests/kube-vip.yaml"

    # 检查是否已存在有效的 kube-vip 配置文件
    if [ -f $kube_vip_file ] && grep -q "$INTERFACE" $kube_vip_file && grep -q "$VIP" $kube_vip_file; then
        echo -e "${GREEN}kube-vip 配置文件已存在且有效,跳过生成。${NC}"
    else
        # 如果文件不存在或内容无效,则删除并生成新的配置文件
        echo "生成新的 kube-vip 配置文件..."
        rm -f /etc/kubernetes/manifests/kube-vip.yaml
        #ctr run --rm --net-host ghcr.io/kube-vip/kube-vip:$KVVERSION vip /kube-vip manifest pod \
        ctr run --rm --net-host dockerhub.mandao.com/kube-vip/kube-vip:$KVVERSION vip /kube-vip manifest pod \
            --interface $INTERFACE \
            --vip $VIP \
            --controlplane \
            --arp \
            --leaderElection | tee $kube_vip_file >/dev/null &

        # 等待配置文件生成
        echo -e "${GREEN}等待3秒${NC}"
        sleep 3

        if [ ! -f $kube_vip_file ] || ! (grep -q "$INTERFACE" $kube_vip_file && grep -q "$VIP" $kube_vip_file); then
            echo -e "${RED}kube-vip 文件生成出错,请检查。${NC}"
            echo -e "${RED}若文件生成出错请尝试修改 KVVERSION 变量,降低 kube-vip 版本。${NC}"
            exit 1
        fi

        grep -q "image: ghcr.io/kube-vip/kube-vip:$KVVERSION" /etc/kubernetes/manifests/kube-vip.yaml
        if [ $? -eq 0 ]; then
            echo -e "${GREEN}正在将镜像地址替换为 dockerhub.mandao.com/kube-vip/kube-vip:$KVVERSION ${NC}"
            sed -i "s|image: ghcr.io/kube-vip/kube-vip:$KVVERSION|image: dockerhub.mandao.com/kube-vip/kube-vip:$KVVERSION|" /etc/kubernetes/manifests/kube-vip.yaml
            echo -e "${GREEN}替换完成。${NC}"
        else
            echo -e "${GREEN}未找到原始镜像地址 ghcr.io/kube-vip/kube-vip:$KVVERSION,无需替换。${NC}"
        fi

    fi
}


# 初始化 Kubernetes 集群
initialize_kubernetes_cluster() {
# 初始化 Kubernetes 集群
if [ -f /etc/kubernetes/admin.conf ]; then
    echo -e "${RED}检测到 /etc/kubernetes/admin.conf 文件,Kubernetes 集群已初始化。跳过初始化步骤。${NC}"
else
    kubeadm init \
        --control-plane-endpoint "$CONTROLLER_PLAN_ENDPOINT" \
        --upload-certs \
        --kubernetes-version $KUBERNETES_VERSION \
        --image-repository $IMAGE_REPOSITORY \
        --pod-network-cidr $POD_NETWORK_CIDR \
        --service-cidr=$SERVICE_CIDR 2>&1 | tee -a /tmp/kubernetes_install_token.txt
fi

# 配置 kubeconfig
if [ ! -f $HOME/.kube/config ]; then
    rm -rf $HOME/.kube
    mkdir -p $HOME/.kube
    ln -s /etc/kubernetes/admin.conf $HOME/.kube/config
    sudo chown $(id -u):$(id -g) $HOME/.kube/config
    echo -e "${GREEN}kubeconfig 已配置${NC}"
else
    echo -e "${GREEN}kubeconfig 已存在${NC}"
fi

export KUBECONFIG=/etc/kubernetes/admin.conf

# 检查 kubelet 服务状态并输出
if systemctl is-active --quiet kubelet; then
    echo -e "${GREEN}kubelet 服务正在运行${NC}"
else
    echo -e "${RED}kubelet 服务未运行${NC}"
fi

if systemctl is-enabled --quiet kubelet; then
    echo -e "${GREEN}kubelet 服务已启用开机启动${NC}"
else
    echo -e "${RED}kubelet 服务未启用开机启动${NC}"
fi

# 查看组件状态
echo -e "${GREEN}等待5秒查看组件状态...${NC}"
sleep 5
kubectl get pod -n kube-system
}


install_calico() {
# 安装网络组件
# 初始化环境变量
echo -e "\e[1;32m POD_NETWORK_CIDR=$POD_NETWORK_CIDR \e[0m"

# 下载calico模版
mkdir -p $CALICO_WORK_DIR

if [ ! -f $CALICO_WORK_DIR/tigera-operator.yaml ]; then
    attempts=0
    success=false
    url="https://cloud-help.mandao.com/uploads/cloud/install/calico/v3.26.3/tigera-operator.yaml"

    while [ $attempts -lt 6 ]; do
        wget $url -O tigera-operator.yaml && success=true && break
        attempts=$((attempts + 1))
        echo -e "${GREEN}下载失败,重试第 $attempts 次...${NC}"
        sleep 5
    done

    if ! $success; then
        echo -e "${RED}下载 tigera-operator.yaml 失败,请检查网络连接或下载地址。${NC}"
        exit 1
    fi

    mv tigera-operator.yaml $CALICO_WORK_DIR/tigera-operator.yaml
    echo -e "${GREEN}tigera-operator.yaml 已下载并移动到 $CALICO_WORK_DIR${NC}"
else
    echo -e "${GREEN}tigera-operator.yaml 已存在${NC}"
fi

if [ ! -f $CALICO_WORK_DIR/custom-resources.yaml ]; then
    attempts=0
    success=false
    url="https://cloud-help.mandao.com/uploads/cloud/install/calico/v3.26.3/custom-resources.yaml"

    while [ $attempts -lt 6 ]; do
        wget -O custom-resources.yaml $url && success=true && break
        attempts=$((attempts + 1))
        echo -e "${GREEN}下载失败,重试第 $attempts 次...${NC}"
        sleep 5
    done

    if ! $success; then
        echo -e "${RED}下载 custom-resources.yaml 失败,请检查网络连接或下载地址。${NC}"
        exit 1
    fi

    mv custom-resources.yaml $CALICO_WORK_DIR/custom-resources.yaml
    echo -e "${GREEN}custom-resources.yaml 已下载并移动到 $CALICO_WORK_DIR${NC}"
else
    echo -e "${GREEN}custom-resources.yaml 已存在${NC}"
fi

# 修改配置
if ! grep -q "blockSize: 24" $CALICO_WORK_DIR/custom-resources.yaml; then
    sed -i s/"blockSize: 26"/"blockSize: 24"/g $CALICO_WORK_DIR/custom-resources.yaml
    echo -e "${GREEN}blockSize 已修改为 24${NC}"
else
    echo -e "${GREEN}blockSize 已经是 24${NC}"
fi

if ! grep -q "$POD_NETWORK_CIDR" $CALICO_WORK_DIR/custom-resources.yaml; then
    sed -i "s#cidr: 192.168.0.0/16#cidr: $POD_NETWORK_CIDR#g" $CALICO_WORK_DIR/custom-resources.yaml
    echo -e "${GREEN}cidr 已修改为 $POD_NETWORK_CIDR${NC}"
else
    echo -e "${GREEN}cidr 已经是 $POD_NETWORK_CIDR${NC}"
fi

if ! grep -q "  registry: dockerhub.mandao.com" $CALICO_WORK_DIR/custom-resources.yaml; then
    sed -i 's/  # Configures Calico networking./&\n  registry: dockerhub.mandao.com/' $CALICO_WORK_DIR/custom-resources.yaml
    echo -e "${GREEN}registry 已添加为 dockerhub.mandao.com${NC}"
else
    echo -e "${GREEN}registry 已经存在${NC}"
fi

echo -e "${GREEN}睡眠5秒${NC}"
sleep 5

# 创建
kubectl create -f $CALICO_WORK_DIR/tigera-operator.yaml

echo -e "${GREEN}睡眠10秒${NC}"
sleep 10

kubectl create -f $CALICO_WORK_DIR/custom-resources.yaml

echo -e "${GREEN}睡眠30秒${NC}"
sleep 30

# 验证
kubectl get pod -n calico-system


# 查看集群状态
kubectl get node
echo -e "${GREEN}STATUS都变为Ready则网络组件安装正常${NC}"
echo -e "${GREEN}网络组件不正常时可暂时跳过,先加入两个机器进入集群后再来修复网络组件,一般该组件需要去下载calico镜像${NC}"

# 特殊配置:允许给 Master 节点分配实例(仅用于测试环境)
echo -e "${RED}特殊配置:允许给 Master 节点分配实例(仅用于测试环境)
kubectl get node|grep -v NAME|awk '{print \$1}'  |  xargs -I {} kubectl taint node {} node-role.kubernetes.io/master-
kubectl get node|grep -v NAME|awk '{print \$1}'  |  xargs -I {} kubectl taint node {} node-role.kubernetes.io/control-plane-
kubectl get node|grep -v NAME|awk '{print \$1}'  |  xargs -I {} kubectl patch node {} -p '{\"spec\":{\"unschedulable\":false}}'
${NC}"


}

ulimit -SHn 1048576


    echo "=========================================================="
    echo -e "${GREEN} 开始安装基础环境 ${NC}"
    echo "=========================================================="
# 检查系统类型并调用相应的函数
if [ -f /etc/centos-release ]; then
    configure_centos
elif [ -f /etc/lsb-release ]; then
    configure_ubuntu
else
    echo -e "${RED}不支持的操作系统。${NC}"
    exit 1
fi
configure_ulimit
adjust_timezone
disable_services
disable_swap_selinux
    echo "=========================================================="
    echo -e "${GREEN} 配置系统参数 ${NC}"
    echo "=========================================================="
configure_kubernetes
configure_file_handles
    echo "=========================================================="
    echo -e "${GREEN} 开始安装 runc 依赖包 ${NC}"
    echo "=========================================================="
    sleep 2
install_libseccomp
    echo "=========================================================="
    echo -e "${GREEN} 开始安装 Containerd 容器运行时 ${NC}"
    echo "=========================================================="
install_containerd
    echo "=========================================================="
    echo -e "${GREEN} 开始安装 Kubernetes 软件包 ${NC}"
    echo "=========================================================="
install_kubernetes_tools
    echo "=========================================================="
    echo -e "${GREEN} 开始生成 kube-vip 配置文件 ${NC}"
    echo "=========================================================="
install_kube_vip
    echo "=========================================================="
    echo -e "${GREEN} 开始初始化 Kubernetes 集群 ${NC}"
    echo "=========================================================="
initialize_kubernetes_cluster
    echo "=========================================================="
    echo -e "${GREEN} 开始安装 Calico ${NC}"
    echo "=========================================================="
install_calico

    

加入集群脚本

请根据情况修改脚本中以下变量内容

  • 服务器网卡名称
    export INTERFACE=ens192
  • 集群负载IP
    export VIP=172.16.10.5

请注意: 如果你的机器是使用虚拟机模版克隆的也就是说不是刚装好操作系统的机器,为避免某些错误,请手动修改机器的hostname

将以下脚本保存在需要加入集群的机器上

    
#!/bin/bash

# 其它节点加入集群脚本
# 在需要加入的节点上运行

set -e

# 检查是否以 root 用户执行
if [ "$(id -u)" -ne 0 ]; then
    echo -e "\033[0;31m请使用 root 用户运行此脚本。\033[0m"
    exit 1
fi

# 设置环境变量
export INTERFACE=ens192
export VIP=172.16.10.5
export KUBERNETES_VERSION="1.25.14"

echo "当前设置的网卡名称为:$INTERFACE"
echo "当前设置的K8s集群负载均衡地址为:$VIP"
echo "当前设置的Kubernetes版本为:$KUBERNETES_VERSION"
read -p "请确认以上变量内容是否已修改正确 (yes/no): " confirm
if [ "$confirm" != "yes" ]; then
    echo "请修改脚本中的变量内容后再运行脚本。"
    exit 1
fi

# 颜色定义
GREEN='\033[0;32m'
RED='\033[0;31m'
NC='\033[0m' # No Color

echo -e "${GREEN}开始安装配置...${NC}"

# 选择节点类型
echo -e "${RED}不加master就选worker master为主节点,worker为工作节点!${NC}"

read -p "请选择节点类型 (master/worker): " node_type
if [ "$node_type" != "master" ] && [ "$node_type" != "worker" ]; then
    echo -e "${RED}无效的节点类型。请选择 'master' 或 'worker'。${NC}"
    exit 1
fi

# 检查主机名是否为 localhost
hostname=$(hostname)
if [[ "$hostname" == *"localhost"* ]]; then
    echo -e "${RED}为区分节点机器,请修改主机名,建议主机名中包含明显的IP标识${NC}"
    exit 1
fi

# 检查 /etc/hosts 文件中是否存在主机名与 IP 地址的 hosts
if ! grep -q "$hostname" /etc/hosts; then
    ip_address=$(hostname -I | awk '{print $1}')
    echo "$ip_address $hostname" | tee -a /etc/hosts
    echo "$VIP core.harbor.domain" | tee -a /etc/hosts
    echo -e "${GREEN}/etc/hosts 文件中已添加主机名与 IP 地址${NC}"
else
    echo -e "${GREEN}/etc/hosts 文件中已存在主机名与 IP 地址${NC}"
fi

# 配置CentOS
configure_centos() {
    # 修改 CentOS 仓库源为阿里云镜像源
    if grep -q "release 7" /etc/centos-release; then
        sed -i.bak -e 's|^mirrorlist=|#mirrorlist=|g' -e 's|^#baseurl=http://mirror.centos.org|baseurl=https://mirrors.aliyun.com|g' /etc/yum.repos.d/CentOS-Base.repo
        echo -e "${GREEN}已修改 CentOS 7 仓库源为阿里云镜像源${NC}"
    elif grep -q "release 8" /etc/centos-release; then
        if ! grep -q "vault.centos.org" /etc/yum.repos.d/CentOS-Base.repo; then
            sed -i -e "s|mirrorlist=|#mirrorlist=|g" /etc/yum.repos.d/CentOS-*
            sed -i -e "s|#baseurl=http://mirror.centos.org|baseurl=http://vault.centos.org|g" /etc/yum.repos.d/CentOS-*
            echo -e "${GREEN}已修改 CentOS 8.x 仓库源${NC}"
        else
            echo -e "${GREEN}CentOS 8.x 仓库源已设置${NC}"
        fi
    else
        echo -e "${GREEN}系统不是 CentOS 7 或 8,无需修改仓库源${NC}"
    fi

    # 安装依赖包
    echo -e "${GREEN}安装依赖包中···${NC}"
    yum install -y epel-release >/dev/null
    DEPENDENCIES="conntrack ipvsadm ipset jq sysstat curl iptables wget lrzsz nc tar ntpdate nfs-utils vim netcat gcc make gperf yum-plugin-versionlock"
    for package in $DEPENDENCIES; do
        if ! rpm -q $package &>/dev/null; then
            if yum install -y $package >/dev/null; then
                echo -e "${GREEN}$package 已成功安装${NC}"
            else
                echo -e "${RED}$package 安装失败,请检查网络连接或软件源配置。${NC}"
                exit 1
            fi
        else
            echo -e "${GREEN}$package 已经安装${NC}"
        fi
    done
}

# 配置Ubuntu
configure_ubuntu() {
    echo -e "${GREEN}正在配置 Ubuntu...${NC}"

    #强制免交互自动重启服务
    export DEBIAN_FRONTEND=noninteractive
    export UCF_FORCE_CONFFOLD=YES

    # 修改APT源为阿里云源
    if ! grep -q "mirrors.aliyun.com" /etc/apt/sources.list; then
        cp /etc/apt/sources.list /etc/apt/sources.list.bak
        cat > /etc/apt/sources.list << EOF
deb http://mirrors.aliyun.com/ubuntu/ $(lsb_release -sc) main restricted universe multiverse
deb http://mirrors.aliyun.com/ubuntu/ $(lsb_release -sc)-security main restricted universe multiverse
deb http://mirrors.aliyun.com/ubuntu/ $(lsb_release -sc)-updates main restricted universe multiverse
deb http://mirrors.aliyun.com/ubuntu/ $(lsb_release -sc)-proposed main restricted universe multiverse
deb http://mirrors.aliyun.com/ubuntu/ $(lsb_release -sc)-backports main restricted universe multiverse
EOF
        echo -e "${GREEN}APT源已修改为阿里云源${NC}"
    else
        echo -e "${GREEN}APT源已是阿里云源${NC}"
    fi

    # 更新系统
    apt-get update

    # 安装依赖包
    echo -e "${GREEN}安装依赖包中···${NC}"
    apt-get install -y apt-utils >/dev/null
    DEPENDENCIES="conntrack ipvsadm ipset jq sysstat curl iptables wget lrzsz tar ntpdate nfs-common vim build-essential"
    for package in $DEPENDENCIES; do
        if ! dpkg -l | grep -q "^ii  $package "; then
            if apt-get install -y $package >/dev/null; then
                echo -e "${GREEN}$package 已成功安装${NC}"
            else
                echo -e "${RED}$package 安装失败,请检查网络连接或软件源配置。${NC}"
                exit 1
            fi
        else
            echo -e "${GREEN}$package 已经安装${NC}"
        fi
    done

    # 逐个检查每个依赖包是否已安装成功
    for package in $DEPENDENCIES; do
        if ! dpkg -l | grep -q "^ii  $package "; then
            echo -e "${RED}$package 安装失败,请手动检查并安装。${NC}"
            exit 1
        else
            echo -e "${GREEN}$package 已成功安装并可用${NC}"
        fi
    done
}

# 检查 /etc/profile 中是否有 ulimit 设置,如果没有就添加进去
configure_ulimit() {
    if ! grep -q "ulimit -SHn 1048576" /etc/profile; then
        echo "ulimit -SHn 1048576" >> /etc/profile
        echo -e "${GREEN}已将 ulimit -SHn 1048576 添加到 /etc/profile${NC}"
    else
        echo -e "${GREEN}/etc/profile 中已存在 ulimit -SHn 1048576${NC}"
    fi

    # 使 ulimit 设置生效
    source /etc/profile
}

# 调整时区
adjust_timezone() {
    if [ "$(timedatectl show --property=Timezone --value)" != "Asia/Shanghai" ]; then
        timedatectl set-timezone Asia/Shanghai
        echo -e "${GREEN}时区已设置为 Asia/Shanghai${NC}"
    else
        echo -e "${GREEN}时区已是 Asia/Shanghai${NC}"
    fi

    # 将当前的 UTC 时间写入硬件时钟
    if [ "$(timedatectl show --property=LocalRTC --value)" != "0" ]; then
        timedatectl set-local-rtc 0
        echo -e "${GREEN}已将 UTC 时间写入硬件时钟${NC}"
    else
        echo -e "${GREEN}硬件时钟已是 UTC 时间${NC}"
    fi

    # 重启时间的服务和任务调度服务
    #systemctl restart rsyslog
    #systemctl restart crond
    #echo -e "${GREEN}时间服务和任务调度服务已重启${NC}"

    # 同步时间
    /usr/sbin/ntpdate pool.ntp.org
    if [ $? -eq 0 ]; then
        echo -e "${GREEN}时间已同步${NC}"
    else
        echo -e "${RED}时间同步失败,请检查网络连接或时间服务器配置。${NC}"
    fi
}

# 安装 libseccomp 的函数
install_libseccomp() {
    local LIBSECCOMP_VERSION="2.5.2"

    # 检查系统版本
    if { [ -f /etc/centos-release ] && grep -q -E "7\.([0-8]|9[^\.])|8\.[0-9]+" /etc/centos-release; } || { [ -f /etc/os-release ] && grep -q "22\.[0-9]\|24\.[0-9]" /etc/os-release; }; then
        echo -e "${GREEN}系统版本高于 Ubuntu 22 或 CentOS 7.9,不需要安装 libseccomp${NC}"
        return
    fi

    # 检查已安装的 libseccomp 版本
    if [ -f "/usr/local/lib/pkgconfig/libseccomp.pc" ]; then
        local INSTALLED_VERSION=$(grep "Version:" /usr/local/lib/pkgconfig/libseccomp.pc | awk '{print $2}')

        if [ "$INSTALLED_VERSION" = "$LIBSECCOMP_VERSION" ]; then
            echo -e "${GREEN}libseccomp $LIBSECCOMP_VERSION 已经安装${NC}"
            return
        else
            echo -e "${YELLOW}已安装 libseccomp 版本为 $INSTALLED_VERSION, 需要升级到 $LIBSECCOMP_VERSION${NC}"
        fi
    else
        echo -e "${YELLOW}未检测到已安装的 libseccomp,准备安装 $LIBSECCOMP_VERSION${NC}"
    fi

    cd /tmp
    if [ ! -f libseccomp-${LIBSECCOMP_VERSION}.tar.gz ]; then
        attempts=0
        success=false
        url="https://cloud-help.mandao.com/uploads/cloud/install/runtime/libseccomp-${LIBSECCOMP_VERSION}.tar.gz"

        while [ $attempts -lt 6 ]; do
            wget $url -O libseccomp-${LIBSECCOMP_VERSION}.tar.gz && success=true && break
            attempts=$((attempts + 1))
            echo -e "${GREEN}下载失败,重试第 $attempts 次...${NC}"
            sleep 5
        done

        if ! $success; then
            echo -e "${RED}下载 libseccomp 失败,请检查网络连接或下载地址。${NC}"
            exit 1
        fi
    else
        echo -e "${GREEN}libseccomp-${LIBSECCOMP_VERSION}.tar.gz 已存在,跳过下载。${NC}"
    fi

    tar -xzf libseccomp-${LIBSECCOMP_VERSION}.tar.gz
    cd libseccomp-${LIBSECCOMP_VERSION}

    echo -e "${GREEN}正在配置,请等待!${NC}"
    # 配置并隐藏输出,失败时提示查看日志
    ./configure > /tmp/libseccomp_configure.log 2>&1 || {
        echo -e "${RED}配置失败,请查看 /tmp/libseccomp_configure.log 了解详情。${NC}"
        exit 1
    }

    echo -e "${GREEN}正在编译,请等待!${NC}"
    # 编译并隐藏输出,失败时提示查看日志
    make -j2 > /tmp/libseccomp_make.log 2>&1 || {
        echo -e "${RED}编译失败,请查看 /tmp/libseccomp_make.log 了解详情。${NC}"
        exit 1
    }

    # 安装并隐藏输出,失败时提示查看日志
    make install > /tmp/libseccomp_install.log 2>&1 || {
        echo -e "${RED}安装失败,请查看 /tmp/libseccomp_install.log 了解详情。${NC}"
        exit 1
    }

    ldconfig
    echo -e "${GREEN}libseccomp $LIBSECCOMP_VERSION 已成功安装${NC}"

    # 检查并更新 ldconfig 缓存
    echo "/usr/local/lib" > /etc/ld.so.conf.d/local-lib.conf
    ldconfig
}

# 停止并禁用防火墙和 dnsmasq
disable_services() {
    # 停止并禁用防火墙
    if systemctl is-active --quiet firewalld; then
        systemctl stop firewalld
        echo -e "${GREEN}防火墙已停止${NC}"
    fi

    if systemctl is-enabled --quiet firewalld; then
        systemctl disable firewalld
        echo -e "${GREEN}防火墙已禁用${NC}"
    fi

    iptables -F && iptables -X && iptables -F -t nat && iptables -X -t nat
    iptables -P FORWARD ACCEPT
    echo -e "${GREEN}iptables 规则已清除${NC}"

    # 停止并禁用 dnsmasq
    if systemctl is-active --quiet dnsmasq; then
        systemctl stop dnsmasq
        echo -e "${GREEN}dnsmasq 已停止${NC}"
    fi

    if systemctl is-enabled --quiet dnsmasq; then
        systemctl disable dnsmasq
        echo -e "${GREEN}dnsmasq 已禁用${NC}"
    fi
}

# 关闭 SELinux 和 Swap
disable_swap_selinux() {
    # 关闭 Swap
    if swapon --summary | grep -q 'partition\|file'; then
        swapoff -a
        echo -e "${GREEN}Swap 已关闭${NC}"
    fi

    if grep -q 'swap' /etc/fstab; then
        sed -i '/swap/d' /etc/fstab
        echo -e "${GREEN}/etc/fstab 中的 Swap 条目已删除${NC}"
    fi

    # 关闭 SELinux(如果安装了工具)
    if command -v getenforce &> /dev/null; then
        if [ "$(getenforce)" != "Disabled" ];then
            setenforce 0
            echo -e "${GREEN}SELinux 已设置为 Permissive${NC}"
        fi
    else
        echo -e "${YELLOW}getenforce 命令未找到,跳过 SELinux 设置步骤。${NC}"
    fi

    if command -v setenforce &> /dev/null; then
        if grep -q 'SELINUX=enforcing' /etc/selinux/config;then
            sed -i 's#SELINUX=enforcing#SELINUX=disabled#g' /etc/selinux/config
            echo -e "${GREEN}SELinux 配置文件已修改为 Disabled${NC}"
        fi
    else
        echo -e "${YELLOW}setenforce 命令未找到,跳过 SELinux 设置步骤。${NC}"
    fi
}

# 配置 Kubernetes 优化参数和加载内核模块
configure_kubernetes() {
    # 配置 Kubernetes 优化参数
    if [ ! -f /etc/sysctl.d/kubernetes.conf ]; then
        cat > /tmp/kubernetes.conf << EOF
net.bridge.bridge-nf-call-iptables=1
net.bridge.bridge-nf-call-ip6tables=1
net.ipv4.ip_forward=1
vm.swappiness=0
vm.overcommit_memory=1
vm.panic_on_oom=0
fs.inotify.max_user_watches=89100
EOF

        cp /tmp/kubernetes.conf /etc/sysctl.d/kubernetes.conf
        sysctl -p /etc/sysctl.d/kubernetes.conf &
        rm -rf /tmp/kubernetes.conf
        echo -e "${GREEN}Kubernetes 优化参数已配置${NC}"
    else
        echo -e "${GREEN}Kubernetes 优化参数已存在${NC}"
    fi

    # 加载内核模块
    for module in br_netfilter ip_vs; do
        if ! lsmod | grep -q "$module"; then
            modprobe $module
            echo -e "${GREEN}内核模块 $module 已加载${NC}"
        else
            echo -e "${GREEN}内核模块 $module 已存在${NC}"
        fi
    done
}

# 设置文件句柄
configure_file_handles() {
    updateSysCtl() {
        key=$1
        value=$2
        filePath=/etc/sysctl.conf
        if grep -q $key $filePath; then
            sed -i "/$key/d" $filePath
        fi
        echo "$key = $value" | tee -a $filePath
        echo -e "${GREEN}已设置 $key = $value${NC}"
    }

    updateSysCtl "fs.file-max" "1000000"
    updateSysCtl "net.ipv4.ip_conntrack_max" "1000000"
    updateSysCtl "net.ipv4.netfilter.ip_conntrack_max" "1000000"

    sysctl -p &
    echo -e "${GREEN}文件句柄已设置${NC}"
}

# 安装容器运行时 Containerd
install_containerd() {
    export PATH=$PATH:/usr/local/bin
    if [ ! -f /usr/local/bin/containerd ]; then
    #local url="https://github.com/containerd/containerd/releases/download/v1.7.7/cri-containerd-cni-1.7.7-linux-amd64.tar.gz"
    local url="https://cloud-help.mandao.com/uploads/cloud/install/runtime/cri-containerd-cni-1.7.20-linux-amd64.tar.gz"
    local file="/tmp/cri-containerd-cni-1.7.20-linux-amd64.tar.gz"
    local attempts=0
    local success=false

    # 检测 /tmp 目录下是否有该文件
    if [ -f "$file" ]; then
        echo -e "${GREEN}检测到 /tmp 目录下已存在 cri-containerd-cni-1.7.20-linux-amd64.tar.gz 文件,尝试解压...${NC}"
        tar -zxvf "$file" -C / || {
            echo -e "${RED}解压失败,删除文件并重新下载...${NC}"
            rm -f "$file"
        }
    fi

    # 如果文件不存在或解压失败后被删除,则重新下载
    if [ ! -f "$file" ]; then
        while [ $attempts -lt 6 ]; do
            wget "$url" -O "$file" && success=true && break
            attempts=$((attempts + 1))
            echo -e "${GREEN}下载失败,重试第 $attempts 次...${NC}"
            sleep 5
        done

        if ! $success; then
            echo -e "${RED}下载 containerd 失败,请检查网络连接或下载地址。${NC}"
            exit 1
        fi

        tar -zxvf "$file" -C / || {
            echo -e "${RED}解压失败,请手动检查问题。${NC}"
            exit 1
        }
    else
        echo -e "${GREEN}文件已存在且解压成功。${NC}"
    fi

        source /etc/profile
        echo -e "${GREEN}Containerd 已安装${NC}"
    else
        echo -e "${GREEN}Containerd 已存在${NC}"
    fi

    # 配置 Containerd 服务
    if [ ! -f /usr/local/lib/systemd/system/containerd.service ]; then
        mkdir -p /usr/local/lib/systemd/system/
        cp /etc/systemd/system/containerd.service /usr/local/lib/systemd/system/containerd.service
        systemctl daemon-reload
        systemctl enable --now containerd
        sleep 2
        echo -e "${GREEN}Containerd 服务已启动${NC}"
    else
        echo -e "${GREEN}Containerd 服务已存在${NC}"
    fi

    # 生成 Containerd 配置
    if [ ! -f /etc/containerd/config.toml ]; then
        mkdir -p /etc/containerd
        containerd config default | tee /etc/containerd/config.toml
        sed -i 's/SystemdCgroup = false/SystemdCgroup = true/' /etc/containerd/config.toml
        sed -i 's/registry.k8s.io\/pause:3.8/registry.aliyuncs.com\/google_containers\/pause:3.8/' /etc/containerd/config.toml
        systemctl restart containerd
        echo -e "${GREEN}Containerd 配置已生成并应用${NC}"
    else
        echo -e "${GREEN}Containerd 配置已存在${NC}"
    fi


    # 检查默认 CNI 配置文件是否存在
    DEFAULT_CNI_CONFIG="/etc/cni/net.d/10-containerd-net.conflist"

    if [ -f "$DEFAULT_CNI_CONFIG" ]; then
        echo -e "${GREEN}检测到默认 CNI 配置文件 $DEFAULT_CNI_CONFIG,开始清理。${NC}"

        # 清理默认 CNI 配置文件
        rm -rf /etc/cni/net.d/*
        echo -e "${GREEN}默认 CNI 配置文件已清理。${NC}"

        # 重启 containerd 服务
        systemctl restart containerd
        echo -e "${GREEN}containerd 服务已重启。${NC}"
    else
        echo -e "${GREEN}未检测到默认 CNI 配置文件,无需清理。${NC}"
    fi

}

# 安装 Kubernetes 工具的函数
install_kubernetes_tools() {
    if ! kubectl version --client &>/dev/null; then
        if [ -f /etc/centos-release ]; then
            cat << EOF > /etc/yum.repos.d/kubernetes.repo
[kubernetes]
name=Kubernetes
baseurl=https://mirrors.aliyun.com/kubernetes/yum/repos/kubernetes-el7-x86_64/
enabled=1
gpgcheck=1
repo_gpgcheck=0
gpgkey=https://mirrors.aliyun.com/kubernetes/yum/doc/yum-key.gpg https://mirrors.aliyun.com/kubernetes/yum/doc/rpm-package-key.gpg
EOF
            yum install -y kubelet-$KUBERNETES_VERSION kubeadm-$KUBERNETES_VERSION kubectl-$KUBERNETES_VERSION --disableexcludes=kubernetes
            systemctl enable kubelet && systemctl start kubelet
            yum versionlock kubelet-$KUBERNETES_VERSION-0 kubeadm-$KUBERNETES_VERSION-0 kubectl-$KUBERNETES_VERSION-0
            echo -e "${GREEN}kubelet-$KUBERNETES_VERSION、kubeadm-$KUBERNETES_VERSION 和 kubectl-$KUBERNETES_VERSION 已安装并锁定版本${NC}"
        elif [ -f /etc/lsb-release ]; then
            curl -s https://mirrors.aliyun.com/kubernetes/apt/doc/apt-key.gpg | apt-key add -
            cat << EOF >/etc/apt/sources.list.d/kubernetes.list
deb https://mirrors.aliyun.com/kubernetes/apt/ kubernetes-xenial main
EOF
            apt-get update
            apt-get install -y kubelet=$KUBERNETES_VERSION-00 kubeadm=$KUBERNETES_VERSION-00 kubectl=$KUBERNETES_VERSION-00
            systemctl enable kubelet && systemctl start kubelet
            apt-mark hold kubeadm kubelet kubectl
            echo -e "${GREEN}kubelet-$KUBERNETES_VERSION、kubeadm-$KUBERNETES_VERSION 和 kubectl-$KUBERNETES_VERSION 已安装并锁定版本${NC}"
        fi
    else
        echo -e "${GREEN}kubelet-$KUBERNETES_VERSION、kubeadm-$KUBERNETES_VERSION 和 kubectl-$KUBERNETES_VERSION 已安装并锁定版本${NC}"
    fi
}

# 安装负载均衡器 kube-vip 的函数
install_kube_vip() {
    #export KVVERSION=$(curl -sL https://api.github.com/repos/kube-vip/kube-vip/releases | jq -r ".[0].name")
    if [ -z "$KVVERSION" ]; then
        export KVVERSION="v0.8.0" # 使用一个已知存在的版本
    fi

    #while ! ctr images ls | grep -q "ghcr.io/kube-vip/kube-vip:$KVVERSION"; do
    while ! ctr images ls | grep -q "dockerhub.mandao.com/kube-vip/kube-vip:$KVVERSION"; do
        #ctr image pull ghcr.io/kube-vip/kube-vip:$KVVERSION
        ctr image pull dockerhub.mandao.com/kube-vip/kube-vip:$KVVERSION
        if [ $? -eq 0 ]; then
            echo -e "${GREEN}kube-vip 镜像已下载${NC}"
        else
            echo -e "${RED}kube-vip 镜像下载失败,正在重试...${NC}"
            sleep 5
        fi
    done
    echo -e "${GREEN}kube-vip 镜像已存在${NC}"

    export kube_vip_file="/etc/kubernetes/manifests/kube-vip.yaml"

    # 检查是否已存在有效的 kube-vip 配置文件
    if [ -f $kube_vip_file ] && grep -q "$INTERFACE" $kube_vip_file && grep -q "$VIP" $kube_vip_file; then
        echo -e "${GREEN}kube-vip 配置文件已存在且有效,跳过生成。${NC}"
    else
        # 如果文件不存在或内容无效,则删除并生成新的配置文件
        echo "生成新的 kube-vip 配置文件..."
        rm -f /etc/kubernetes/manifests/kube-vip.yaml
        #ctr run --rm --net-host ghcr.io/kube-vip/kube-vip:$KVVERSION vip /kube-vip manifest pod \
        ctr run --rm --net-host dockerhub.mandao.com/kube-vip/kube-vip:$KVVERSION vip /kube-vip manifest pod \
            --interface $INTERFACE \
            --vip $VIP \
            --controlplane \
            --arp \
            --leaderElection | tee $kube_vip_file >/dev/null &

        # 等待配置文件生成
        echo -e "${GREEN}等待3秒${NC}"
        sleep 3

        if [ ! -f $kube_vip_file ] || ! (grep -q "$INTERFACE" $kube_vip_file && grep -q "$VIP" $kube_vip_file); then
            echo -e "${RED}kube-vip 文件生成出错,请检查。${NC}"
            echo -e "${RED}若文件生成出错请尝试修改 KVVERSION 变量,降低 kube-vip 版本。${NC}"
            exit 1
        fi

        grep -q "image: ghcr.io/kube-vip/kube-vip:$KVVERSION" /etc/kubernetes/manifests/kube-vip.yaml
        if [ $? -eq 0 ]; then
            echo -e "${GREEN}正在将镜像地址替换为 dockerhub.mandao.com/kube-vip/kube-vip:$KVVERSION ${NC}"
            sed -i "s|image: ghcr.io/kube-vip/kube-vip:$KVVERSION|image: dockerhub.mandao.com/kube-vip/kube-vip:$KVVERSION|" /etc/kubernetes/manifests/kube-vip.yaml
            echo -e "${GREEN}替换完成。${NC}"
        else
            echo -e "${GREEN}未找到原始镜像地址 ghcr.io/kube-vip/kube-vip:$KVVERSION,无需替换。${NC}"
        fi

    fi
}

# 检查系统类型并调用相应的函数
if [ -f /etc/centos-release ]; then
    configure_centos
elif [ -f /etc/lsb-release ]; then
    configure_ubuntu
else
    echo -e "${RED}不支持的操作系统。${NC}"
    exit 1
fi

configure_ulimit
adjust_timezone
install_libseccomp
disable_services
disable_swap_selinux
configure_kubernetes
configure_file_handles
install_containerd
install_kubernetes_tools

if [ "$node_type" == "master" ]; then
    install_kube_vip
fi

# 在第一台Master节点执行以下语句
echo "================================================================================"

    echo -e "${RED}请注意,以下为加入集群的方式,请仔细阅读!!!!${NC}"
    echo -e "${RED}请在已加入集群的Master节点上执行以下命令,并根据下方的说明进行操作${NC}"

    echo -e "
================================================================================
#设置环境变量
cat << EOF > kubeadm-init-config
apiVersion: kubeadm.k8s.io/v1beta3
kind: InitConfiguration
nodeRegistration:
  criSocket: /var/run/cri-dockerd.sock
EOF

#此命令生成的结果粘贴至需要加入Master节点的机器
echo \$(kubeadm token create --print-join-command) --control-plane --certificate-key \$(kubeadm init phase upload-certs --upload-certs --config kubeadm-init-config | tail -n 1)

#此命令生成的结果粘贴至需要加入worker节点的机器
kubeadm token create --print-join-command

===============================================================================
"

# 最终检查 /etc/hosts 文件内容
echo -e "${RED}请检查 /etc/hosts 文件中包含 IP 和主机名的条目,如果没有,请手动添加hostname的解析:${NC}"
grep -E '^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+' /etc/hosts

    
作者:范云龙  创建时间:2024-09-04 11:03
最后编辑:范云龙  更新时间:2025-04-29 18:46