#!/bin/bash set -euo pipefail # ========================== 全局配置 ========================== # 脚本版本 SCRIPT_VERSION="1.8" # 默认K8s版本 DEFAULT_K8S_VERSION="1.30.5" # 阿里云K8s镜像基础路径(验证有效) ALIBABA_MIRROR_BASE="https://mirrors.aliyun.com/kubernetes-new/core/stable" # 用户指定的nerdctl内网下载地址 NERDCTL_DOWNLOAD_URL="http://10.102.32.207:5588/k8s/nerdctl-1.5.0-linux-amd64.tar.gz" # 颜色定义(终端兼容) RED='\033[0;31m' GREEN='\033[0;32m' YELLOW='\033[1;33m' NC='\033[0m' # 无颜色 # 打印工具函数(统一格式) info() { echo -e "${YELLOW}[INFO]${NC} $1"; } success() { echo -e "${GREEN}[SUCCESS]${NC} $1"; } error() { echo -e "${RED}[ERROR]${NC} $1"; } step() { echo -e "\n${YELLOW}[STEP $1/$2]${NC} $3"; } # ========================== 帮助信息 ========================== usage() { cat << EOF Kubernetes Master组件 + nerdctl 完整安装脚本(适配内网nerdctl下载) 脚本版本:${SCRIPT_VERSION} 功能: 1. 安装:K8s组件(kubelet/kubeadm/kubectl)、nerdctl,配置crictl和kubectl补全 2. 卸载:K8s组件、nerdctl及相关配置(保留containerd) 前提: - 需预先安装containerd(脚本会自动检测) - 确保能访问内网nerdctl下载地址:${NERDCTL_DOWNLOAD_URL} 用法: $0 [选项] 选项: --install 执行组件安装及配置 --uninstall 执行组件卸载及配置清理(保留containerd) --version 指定K8s版本(格式x.y.z,如1.30.5,仅与--install配合) --help 显示此帮助信息 --script-version 显示脚本当前版本 示例: 1. 安装默认版本(${DEFAULT_K8S_VERSION}): sudo $0 --install 2. 安装指定版本(如1.30.5): sudo $0 --install --version 1.30.5 3. 卸载(需二次确认): sudo $0 --uninstall EOF exit 1 } # ========================== 前置检查 ========================== # 检查是否为root用户 check_root() { if [ "$(id -u)" -ne 0 ]; then error "请使用root权限运行脚本,命令格式:sudo $0 ..." exit 1 fi success "root权限检查通过" } # 检查containerd是否已安装并运行 check_containerd() { step 1 1 "检查containerd状态" # 检查是否安装 if ! command -v containerd &> /dev/null; then error "未检测到containerd,请先执行以下命令安装:" exit 1 fi # 检查版本 local containerd_ver=$(containerd --version | head -n1 | awk '{print $3}') info "已检测到containerd,版本:${containerd_ver}" # 检查运行状态 if ! systemctl is-active --quiet containerd; then info "containerd未运行,尝试启动..." if systemctl start containerd; then success "containerd启动成功" else error "containerd启动失败,请手动执行 'systemctl status containerd' 检查原因" exit 1 fi else success "containerd已处于运行状态" fi } # 校验K8s版本格式(x.y.z) validate_version() { local version=$1 if ! [[ $version =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]]; then error "无效的K8s版本格式:'${version}',正确格式为 x.y.z(如1.30.5)" exit 1 fi success "K8s版本格式校验通过:${version}" } # 提取主版本(如1.30.5 -> 1.30) get_major_version() { local version=$1 echo "$version" | cut -d '.' -f 1,2 } # ========================== 安装相关函数 ========================== # 配置kubectl命令补全 configure_kubectl_completion() { step 4 4 "配置kubectl命令补全" # 安装bash-completion依赖 info "安装bash-completion依赖..." if apt-get install -y -qq bash-completion; then success "bash-completion安装完成" else error "bash-completion安装失败" exit 1 fi # 写入补全配置到全局profile(所有用户生效) local bash_profile="/etc/profile.d/kubectl-completion.sh" if ! grep -q "source <(kubectl completion bash)" "$bash_profile" 2>/dev/null; then info "添加kubectl补全配置到 ${bash_profile}..." echo "source <(kubectl completion bash)" | tee -a "$bash_profile" > /dev/null success "kubectl补全配置写入成功(所有用户生效)" else info "kubectl补全配置已存在,跳过写入" fi # 立即生效当前会话 info "使当前会话生效kubectl补全..." source <(kubectl completion bash) success "kubectl命令补全配置完成(当前会话已生效)" } # 安装nerdctl(使用用户指定的内网下载地址) install_nerdctl() { step 3 4 "安装nerdctl并配置crictl" # 优先通过系统仓库安装(兼容性更好) if apt-cache show nerdctl &> /dev/null; then info "系统仓库存在nerdctl,通过apt安装..." if apt-get install -y -qq nerdctl; then success "nerdctl通过系统仓库安装完成" else error "nerdctl系统仓库安装失败" exit 1 fi else # 系统仓库无则使用内网地址下载二进制包 info "系统仓库无nerdctl,从内网地址下载:${NERDCTL_DOWNLOAD_URL}" # 下载二进制包到临时目录 info "开始下载nerdctl压缩包..." if curl -fsSL "$NERDCTL_DOWNLOAD_URL" -o /tmp/nerdctl.tar.gz; then success "nerdctl压缩包下载完成(保存到 /tmp/nerdctl.tar.gz)" else error "nerdctl下载失败,请检查:" echo " 1. 内网地址是否可访问:${NERDCTL_DOWNLOAD_URL}" echo " 2. 网络连通性(可执行 curl ${NERDCTL_DOWNLOAD_URL} 测试)" exit 1 fi # 解压到/usr/local/bin(系统可执行路径) info "解压nerdctl到 /usr/local/bin..." if tar -zxf /tmp/nerdctl.tar.gz -C /usr/local/bin nerdctl; then success "nerdctl解压完成" else error "nerdctl解压失败" exit 1 fi # 清理临时文件 info "清理临时压缩包..." rm -f /tmp/nerdctl.tar.gz success "临时文件清理完成" fi # 配置crictl连接containerd info "配置crictl连接containerd运行时..." if crictl config runtime-endpoint unix:///run/containerd/containerd.sock; then success "crictl配置完成(已关联containerd)" else error "crictl配置失败" exit 1 fi # 验证nerdctl安装 info "验证nerdctl版本..." local nerdctl_ver=$(nerdctl --version | awk '{print $3}') success "nerdctl安装完成,版本:${nerdctl_ver}" } # 安装Kubernetes组件(核心流程) install_k8s() { local k8s_version=$1 local major_version=$(get_major_version "$k8s_version") local deb_version="${k8s_version}-1.1" # 前置检查:containerd check_containerd info "开始执行Kubernetes组件安装,目标版本:${k8s_version}" # 1. 更新系统并安装基础依赖 step 1 4 "安装K8s基础依赖" info "更新系统包索引..." if apt-get update -qq; then success "系统包索引更新完成" else error "系统包索引更新失败,请检查网络" exit 1 fi info "安装基础依赖(apt-transport-https/ca-certificates等)..." if apt-get install -y -qq apt-transport-https ca-certificates curl lsb-release bash-completion; then success "基础依赖安装完成" else error "基础依赖安装失败" exit 1 fi # 确保密钥目录存在 info "创建apt密钥目录(/etc/apt/keyrings)..." mkdir -p /etc/apt/keyrings success "apt密钥目录准备完成" # 2. 添加阿里云K8s GPG密钥 step 2 4 "添加K8s GPG密钥与软件源" local key_url="${ALIBABA_MIRROR_BASE}/v${major_version}/deb/Release.key" info "下载K8s GPG密钥,地址:${key_url}" if curl -fsSL "$key_url" | gpg --dearmor > /etc/apt/keyrings/kubernetes-apt-keyring.gpg 2>/dev/null; then success "K8s GPG密钥添加完成(保存到 /etc/apt/keyrings/kubernetes-apt-keyring.gpg)" else error "K8s GPG密钥获取失败,URL:${key_url}" echo " 建议:手动访问URL检查是否有效,或更换网络环境" exit 1 fi # 3. 添加K8s软件源 local repo_url="${ALIBABA_MIRROR_BASE}/v${major_version}/deb/" info "配置K8s软件源,地址:${repo_url}" echo "deb [signed-by=/etc/apt/keyrings/kubernetes-apt-keyring.gpg] $repo_url /" | \ tee /etc/apt/sources.list.d/kubernetes.list > /dev/null success "K8s软件源配置完成(保存到 /etc/apt/sources.list.d/kubernetes.list)" # 4. 刷新软件源 info "刷新新配置的软件源..." if apt-get update -qq; then success "软件源刷新完成" else error "软件源刷新失败,请检查网络或源地址" exit 1 fi # 5. 安装指定版本的K8s组件 step 3 4 "安装K8s核心组件(kubelet/kubeadm/kubectl)" info "安装目标版本:${deb_version}..." #调试 历史去掉-qq if apt-get install -y --allow-downgrades\ kubelet="$deb_version" \ kubeadm="$deb_version" \ kubectl="$deb_version"; then success "K8s组件安装完成(版本:${k8s_version})" else error "K8s组件安装失败,可能原因:" echo " 1. 版本 ${deb_version} 不存在(可执行 'apt-cache madison kubeadm' 查看可用版本)" echo " 2. 软件源配置错误(检查 /etc/apt/sources.list.d/kubernetes.list)" exit 1 fi # 6. 配置kubelet(锁定版本+自启) info "锁定K8s组件版本(防止意外升级)..." apt-mark hold kubelet kubeadm kubectl > /dev/null success "K8s组件版本锁定完成" info "设置kubelet开机自启并启动..." if systemctl enable kubelet --now; then success "kubelet配置完成(已开机自启并启动)" else error "kubelet启动失败,请执行 'systemctl status kubelet' 检查原因" exit 1 fi # 验证K8s组件安装 info "验证K8s组件版本..." local kubelet_ver=$(kubelet --version | awk '{print $2}') success "K8s核心组件安装验证通过,版本:${kubelet_ver}" # 安装nerdctl(使用内网地址) install_nerdctl # 配置kubectl补全 configure_kubectl_completion # 安装完成汇总 echo -e "\n========================================" success "所有组件安装及配置全部完成!" echo -e "${YELLOW}[汇总信息]${NC}" echo " - K8s版本:${k8s_version}" echo " - nerdctl版本:$(nerdctl --version | awk '{print $3}')" echo " - 下一步:执行 'kubeadm init' 初始化集群(需根据网络配置参数)" echo -e "========================================" } # ========================== 卸载相关函数 ========================== # 卸载组件及配置(保留containerd) uninstall_k8s() { # 二次确认(防止误操作) echo -e "\n${RED}[WARNING]${NC} 即将执行卸载操作,将移除以下内容:" echo " 1. K8s组件:kubelet、kubeadm、kubectl" echo " 2. 工具:nerdctl" echo " 3. 配置:crictl配置、kubectl补全、K8s软件源及密钥" echo " 4. 数据目录:/var/lib/kubelet、/etc/kubernetes、/var/lib/etcd等" echo -e "${RED}注意:此操作不可逆,且会保留containerd!${NC}" read -p "请确认是否继续卸载?[y/N] " -n 1 -r echo if [[ ! $REPLY =~ ^[Yy]$ ]]; then info "用户取消卸载操作,脚本退出" exit 0 fi info "开始执行卸载流程,共6个步骤" # 1. 停止kubelet服务 step 1 6 "停止kubelet服务" if systemctl is-active --quiet kubelet; then info "kubelet当前处于运行状态,正在停止..." if systemctl stop kubelet; then success "kubelet停止成功" else error "kubelet停止失败,将强制继续卸载" fi else info "kubelet已处于停止状态,跳过停止步骤" fi # 2. 卸载K8s组件 step 2 6 "卸载K8s核心组件" if dpkg -l | grep -qE "kubelet|kubeadm|kubectl"; then info "检测到K8s组件,正在卸载..." if apt-get purge -y -qq kubelet kubeadm kubectl; then success "K8s组件卸载完成" else error "K8s组件卸载失败,建议手动执行 'apt-get purge -y kubelet kubeadm kubectl'" exit 1 fi else info "未检测到K8s组件,跳过卸载步骤" fi # 3. 卸载nerdctl step 3 6 "卸载nerdctl" if command -v nerdctl &> /dev/null; then info "检测到nerdctl,正在卸载..." # 根据安装方式选择卸载方法(系统仓库或二进制) if dpkg -l | grep -q nerdctl; then # 系统仓库安装:apt卸载 if apt-get purge -y -qq nerdctl; then success "nerdctl(系统仓库版)卸载完成" else error "nerdctl卸载失败" exit 1 fi else # 二进制安装:删除文件 if rm -f /usr/local/bin/nerdctl; then success "nerdctl(二进制版)删除完成" else error "nerdctl删除失败,建议手动执行 'rm -f /usr/local/bin/nerdctl'" exit 1 fi fi else info "未检测到nerdctl,跳过卸载步骤" fi # 4. 清理依赖残留 step 4 6 "清理系统依赖残留" info "执行autoremove清理无用依赖..." if apt-get autoremove -y -qq; then success "系统依赖残留清理完成" else error "依赖残留清理失败,建议手动执行 'apt-get autoremove -y'" fi # 5. 解锁版本锁定 step 5 6 "解除版本锁定" info "解除K8s组件和nerdctl的版本锁定..." apt-mark unhold kubelet kubeadm kubectl nerdctl > /dev/null 2>&1 || true success "版本锁定解除完成(无锁定则跳过)" # 6. 清理配置文件和数据目录 step 6 6 "清理配置文件与数据目录" local clean_items=( "/etc/apt/sources.list.d/kubernetes.list" # K8s软件源 "/etc/apt/keyrings/kubernetes-apt-keyring.gpg" # K8s GPG密钥 "/var/lib/kubelet" # kubelet数据目录 "/etc/kubernetes" # K8s配置目录 "/var/lib/etcd" # etcd数据目录(若存在) "/var/lib/cni" # CNI网络配置 "/etc/crictl.yaml" # crictl配置 "/etc/profile.d/kubectl-completion.sh" # kubectl补全脚本 ) for item in "${clean_items[@]}"; do if [ -e "$item" ]; then info "清理文件/目录:${item}" if rm -rf "$item"; then success "清理完成:${item}" else error "清理失败:${item}(权限不足?)" fi else info "文件/目录不存在,跳过:${item}" fi done # 刷新软件源(确保清理生效) info "刷新系统软件源,确保配置清理生效..." apt-get update -qq > /dev/null success "软件源刷新完成" # 卸载完成汇总 echo -e "\n========================================" success "卸载流程全部完成!" echo -e "${YELLOW}[残留说明]${NC}" echo " - 已保留:containerd及相关配置" echo " - 建议:若需重新安装,直接执行 '--install' 选项即可" echo -e "========================================" } # ========================== 主逻辑 ========================== main() { local install=0 local uninstall=0 local k8s_version="" # 解析命令行参数 while [[ $# -gt 0 ]]; do case "$1" in --install) install=1 shift ;; --uninstall) uninstall=1 shift ;; --version) if [[ -z "$2" ]]; then error "--version选项需指定K8s版本(如1.30.5)" usage fi k8s_version="$2" shift 2 ;; --help) usage ;; --script-version) echo "脚本版本:${SCRIPT_VERSION}" exit 0 ;; *) error "未知参数:'$1'" usage ;; esac done # 检查参数冲突 if [[ $install -eq 1 && $uninstall -eq 1 ]]; then error "不能同时指定--install和--uninstall选项" usage fi if [[ $install -eq 0 && $uninstall -eq 0 ]]; then error "必须指定--install(安装)或--uninstall(卸载)选项" usage fi # 检查root权限(安装/卸载均需) check_root # 处理安装逻辑 if [[ $install -eq 1 ]]; then # 未指定版本则使用默认 if [[ -z "$k8s_version" ]]; then k8s_version="$DEFAULT_K8S_VERSION" info "未指定K8s版本,使用默认版本:${k8s_version}" fi # 校验版本格式 validate_version "$k8s_version" # 执行安装 install_k8s "$k8s_version" fi # 处理卸载逻辑 if [[ $uninstall -eq 1 ]]; then uninstall_k8s fi } # 启动主逻辑 main "$@"