本文为arm64架构部署文档适用于鲲鹏处理器,麒麟v10-sp3操作系统

本文使用脚本的方式安装kubernetes集群。脚本中涵盖Kubernete官方安装步骤的所有内容。

安装前必读

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

  • 第一个是安装Master节点脚本在整个集群搭建过程中只在第一台机器上执行,用以构建集群并安装集群组件,其余master节点请使用第二个加入节点脚本加入进集群。
  • 第二个是加入集群脚本执行时请根据提示选择加入的是master节点还是work节点,master为管理节点,一般为3个,worker为工作节点,一般在工管分离架构时选择。
  • 在脚本执行过程中如有错误,或意外中断,脚本可重复执行
  • 脚本在下载软件包时如超时或其他错误,请等待重试,直至完成下载.
  • 特殊配置,允许在Master上运行pod,如果你只有3个master节点,请在机器都加入集群以后执行以下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}}'

    请注意: 在执行脚本时除一开始的人机交互外脚本还会输出需要人为决策性的命令! 并有完整的提示! 请仔细阅读!

安装Master节点脚本

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

  • 服务器网卡名称
    export INTERFACE=eth0
  • 服务器IP
    export IP=192.168.0.251
  • 集群负载IP,必须与服务器同网段
    export VIP=192.168.0.200
  • 集群内部通讯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=eth0
export IP=192.168.0.251
export VIP=192.168.0.200
export SERVICE_CIDR="10.254.0.0/16"
export POD_NETWORK_CIDR="172.30.0.0/16"
export PORT=6443
export KUBERNETES_VERSION="1.25.14"

echo "当前设置的网卡名称为:$INTERFACE"
echo "当前设置的K8s集群负载均衡地址为:$VIP"
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 HOSTNAME="node01"
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'
YELLOW='\033[1;33m'
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_Kylin() {
    # 安装依赖包
    DEPENDENCIES="conntrack ipvsadm ipset jq sysstat curl iptables wget lrzsz nc tar ntpdate nfs-utils vim 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
}


# 检查 /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
}


# 停止并禁用防火墙和 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() {
    # 定义需要配置的 sysctl 参数及其值
    declare -A sysctl_params=(
        ["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
    )

    # 检查并更新 /etc/sysctl.conf
    for param in "${!sysctl_params[@]}"; do
        value="${sysctl_params[$param]}"
        if grep -qE "^${param}=" /etc/sysctl.conf; then
            # 如果参数存在但值不一样,更新它
            if ! grep -qE "^${param}=${value}" /etc/sysctl.conf; then
                sed -i "s/^${param}=.*/${param}=${value}/" /etc/sysctl.conf
                echo -e "${GREEN}${param} 已更新为 ${value}${NC}"
            else
                echo -e "${GREEN}${param} 已存在并且值正确${NC}"
            fi
        else
            # 如果参数不存在,添加它
            echo "${param}=${value}" >> /etc/sysctl.conf
            echo -e "${GREEN}${param} 已添加到 /etc/sysctl.conf${NC}"
        fi
    done

    # 应用 sysctl 配置
    sysctl -p /etc/sysctl.conf >/tmp/sysctl.log &
    echo -e "${GREEN}sysctl 配置已应用${NC}"

    # 加载内核模块
    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}"
}

install_libseccomp() {
    local LIBSECCOMP_VERSION="2.5.2"

    # 检查已安装的 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
}


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

    # 检测 /tmp 目录下是否有该文件
    if [ -f "$file" ]; then
        echo -e "${GREEN}检测到 /tmp 目录下已存在 cri-containerd-cni-1.7.20-linux-arm64.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
cat </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


configure_ulimit
disable_services
disable_swap_selinux
    echo "=========================================================="
    echo -e "${GREEN} 开始安装基础环境 ${NC}"
    echo "=========================================================="
configure_Kylin
    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=eth0
  • 集群负载IP
    export VIP=192.168.0.200

请注意: 如果你的机器是使用虚拟机模版克隆的也就是说不是刚装好操作系统的机器,为避免某些错误,请手动修改机器的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=eth0
export VIP=192.168.0.200
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


# 设置 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'
YELLOW='\033[1;33m'
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

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


configure_Kylin() {
    # 安装依赖包
    DEPENDENCIES="conntrack ipvsadm ipset jq sysstat curl iptables wget lrzsz nc tar ntpdate nfs-utils vim 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
}


# 检查 /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
}


# 停止并禁用防火墙和 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() {
    # 定义需要配置的 sysctl 参数及其值
    declare -A sysctl_params=(
        ["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
    )

    # 检查并更新 /etc/sysctl.conf
    for param in "${!sysctl_params[@]}"; do
        value="${sysctl_params[$param]}"
        if grep -qE "^${param}=" /etc/sysctl.conf; then
            # 如果参数存在但值不一样,更新它
            if ! grep -qE "^${param}=${value}" /etc/sysctl.conf; then
                sed -i "s/^${param}=.*/${param}=${value}/" /etc/sysctl.conf
                echo -e "${GREEN}${param} 已更新为 ${value}${NC}"
            else
                echo -e "${GREEN}${param} 已存在并且值正确${NC}"
            fi
        else
            # 如果参数不存在,添加它
            echo "${param}=${value}" >> /etc/sysctl.conf
            echo -e "${GREEN}${param} 已添加到 /etc/sysctl.conf${NC}"
        fi
    done

    # 应用 sysctl 配置
    sysctl -p /etc/sysctl.conf >/tmp/sysctl.log &
    echo -e "${GREEN}sysctl 配置已应用${NC}"

    # 加载内核模块
    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}"
}

install_libseccomp() {
    local LIBSECCOMP_VERSION="2.5.2"

    # 检查已安装的 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
}


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

    # 检测 /tmp 目录下是否有该文件
    if [ -f "$file" ]; then
        echo -e "${GREEN}检测到 /tmp 目录下已存在 cri-containerd-cni-1.7.20-linux-arm64.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
cat </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
}





ulimit -SHn 1048576


configure_ulimit
disable_services
disable_swap_selinux
    echo "=========================================================="
    echo -e "${GREEN} 开始安装基础环境 ${NC}"
    echo "=========================================================="
configure_Kylin
    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

if [ "$node_type" == "master" ]; then
    echo "=========================================================="
    echo -e "${GREEN} 开始生成 kube-vip 配置文件 ${NC}"
    echo "=========================================================="
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 和主机名的条目:${NC}"
grep -E '^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+' /etc/hosts

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