2026年4月29日最新国内部署Kubernetes(K8S)完整教程

一、环境准备:

三台Ubuntu 26.04 虚拟机,使用Containerd方式部署

Containerd版本:V2.2.2

Kubernetes版本:V1.36.0

k8s-master 12C4G 192.168.25.148

k8s-node1  12C2G 192.168.25.138

k8s-node2  12C2G 192.168.25.142

二、准备DNS解析(所有主机)

cat >> /etc/hosts <<EOF
192.168.25.148 k8s-master
192.168.25.138 k8s-node1
192.168.25.142 k8s-node2
EOF

三、修改YUM源(可选,所有主机)

Ubuntu 默认连接国外仓库,可能速度不太好,可以尝试换成国内的仓库加快速度,如果要做,建议在所有机器上都做一下

换源脚本

#!/bin/bash
# 通用换源脚本:CentOS 固定阿里源,Debian/Ubuntu 自动测速选择最快国内源
# 不依赖 bc、lsb_release 等额外包,仅需 curl 或 wget

set -e

RED='\033[31m'
GREEN='\033[32m'
YELLOW='\033[33m'
NC='\033[0m'

info() { echo -e "${GREEN}[INFO]${NC} $1"; }
warn() { echo -e "${YELLOW}[WARN]${NC} $1"; }
error() { echo -e "${RED}[ERROR]${NC} $1"; exit 1; }

# 检查 root
if [[ $EUID -ne 0 ]]; then
    error "请使用 root 用户或 sudo 执行此脚本"
fi

# 1. 外网连通性检测(仅测试 baidu.com)
info "正在检测外网连通性..."
if curl -s --connect-timeout 5 http://www.baidu.com > /dev/null; then
    info "外网连通性正常"
elif wget -q --timeout=5 --spider http://www.baidu.com; then
    info "外网连通性正常"
else
    warn "无法访问 baidu.com,外网连接失败"
    echo -e "\n=== 网卡信息 ==="
    if command -v ip &> /dev/null; then
        ip addr show
    elif command -v ifconfig &> /dev/null; then
        ifconfig -a
    else
        echo "未找到 ip 或 ifconfig 命令,无法显示网卡信息"
    fi
    error "脚本已退出,请检查网络配置"
fi

# 2. 检查下载工具
info "检查下载工具..."
if command -v wget &> /dev/null; then
    DOWNLOADER="wget"
    info "使用 wget 下载"
elif command -v curl &> /dev/null; then
    DOWNLOADER="curl"
    info "使用 curl 下载"
else
    error "未找到 wget 或 curl,请安装其中之一后重试"
fi

# 3. 识别操作系统及版本(完全基于 /etc/os-release,不依赖 lsb_release)
get_os() {
    if [ ! -f /etc/os-release ]; then
        error "无法找到 /etc/os-release,不支持该系统"
    fi
    . /etc/os-release
    case "$ID" in
        centos|rhel)
            OS="centos"
            VERSION=$(echo "$VERSION_ID" | cut -d. -f1)
            ;;
        ubuntu)
            OS="ubuntu"
            VERSION=$(echo "$VERSION_ID" | cut -d. -f1)
            # 优先使用 UBUNTU_CODENAME,其次 VERSION_CODENAME
            CODENAME="${UBUNTU_CODENAME:-$VERSION_CODENAME}"
            if [ -z "$CODENAME" ]; then
                error "无法获取 Ubuntu 版本代号"
            fi
            ;;
        debian)
            OS="debian"
            VERSION=$(echo "$VERSION_ID" | cut -d. -f1)
            CODENAME="$VERSION_CODENAME"
            # 处理 sid / testing
            if [ -z "$CODENAME" ] && [ -f /etc/debian_version ]; then
                if grep -qi "sid" /etc/debian_version; then
                    CODENAME="sid"
                elif grep -qi "testing" /etc/debian_version; then
                    CODENAME="testing"
                fi
            fi
            ;;
        *)
            error "不支持的系统: $ID"
            ;;
    esac
}

get_os
info "检测到系统: $OS ${VERSION:-$CODENAME}"
if [ "$OS" = "ubuntu" ] || [ "$OS" = "debian" ]; then
    info "发行版代号: $CODENAME"
fi

# ------------------------------------------------------------
# CentOS 部分(固定阿里源)
# ------------------------------------------------------------
if [ "$OS" = "centos" ]; then
    case "$VERSION" in
        6) REPO_URL="https://mirrors.aliyun.com/repo/Centos-vault-6.10.repo" ;;
        7) REPO_URL="https://mirrors.aliyun.com/repo/Centos-7.repo" ;;
        8) REPO_URL="https://mirrors.aliyun.com/repo/Centos-vault-8.5.2111.repo" ;;
        *) error "CentOS $VERSION 不受支持(仅支持 6/7/8)" ;;
    esac

    BACKUP_DIR="/etc/yum.repos.d/backup_$(date +%Y%m%d_%H%M%S)"
    info "备份原有 repo 文件到 $BACKUP_DIR"
    mkdir -p "$BACKUP_DIR"
    cp -a /etc/yum.repos.d/*.repo "$BACKUP_DIR/" 2>/dev/null || true
    rm -rf /etc/yum.repos.d/*.repo
    TARGET="/etc/yum.repos.d/CentOS-Base.repo"
    info "下载阿里云镜像源..."
    if [ "$DOWNLOADER" = "wget" ]; then
        wget -O "$TARGET" "$REPO_URL" || error "下载失败"
    else
        curl -o "$TARGET" "$REPO_URL" || error "下载失败"
    fi

    # 修复非阿里云 ECS 用户可能出现的域名解析问题
    info "清理无效域名(mirrors.cloud.aliyuncs.com / mirrors.aliyuncs.com)..."
    sed -i -e '/mirrors.cloud.aliyuncs.com/d' -e '/mirrors.aliyuncs.com/d' "$TARGET"

    info "生成 yum 缓存..."
    yum clean all || error "换源失败:yum clean all 失败"
    yum makecache || error "换源失败:yum makecache 失败"
    info "CentOS 换源完成!"
    exit 0
fi

# ------------------------------------------------------------
# Debian / Ubuntu 部分:多镜像源延迟测速(纯 Shell,无 bc)
# ------------------------------------------------------------
declare -A MIRRORS
MIRRORS=(
    ["阿里源"]="http://mirrors.aliyun.com"
    ["腾讯源"]="http://mirrors.cloud.tencent.com"
    ["华为源"]="https://mirrors.huaweicloud.com"
    ["清华源"]="https://mirrors.tuna.tsinghua.edu.cn"
)

# 根据发行版确定路径和组件
if [ "$OS" = "debian" ]; then
    REPO_PATH="debian"
    COMPONENTS="main contrib non-free non-free-firmware"
    # Debian 特殊处理:如果代号是 sid 或 testing,使用对应的 Release 文件
    if [ "$CODENAME" = "sid" ] || [ "$CODENAME" = "testing" ]; then
        TEST_CODENAME="$CODENAME"
    else
        TEST_CODENAME="$CODENAME"
    fi
elif [ "$OS" = "ubuntu" ]; then
    REPO_PATH="ubuntu"
    COMPONENTS="main restricted universe multiverse"
    TEST_CODENAME="$CODENAME"
else
    error "不支持的系统"
fi

# 测速函数:返回连接时间(毫秒整数),失败返回 999999
test_speed() {
    local base_url=$1
    local test_url="${base_url}/${REPO_PATH}/dists/${TEST_CODENAME}/Release"
    local timeout=3
    if command -v curl &> /dev/null; then
        # curl 输出 time_total 单位为秒(浮点),转换为毫秒整数
        local time_sec=$(curl -o /dev/null -s -w '%{time_total}' --connect-timeout $timeout --max-time $timeout "$test_url" 2>/dev/null)
        if [[ -n "$time_sec" && "$time_sec" != "0" && "$time_sec" != "0.000" ]]; then
            # 去掉小数点,取整毫秒:例如 0.123 -> 123
            local ms=$(echo "$time_sec" | awk '{printf "%.0f", $1 * 1000}')
            echo "${ms:-999999}"
        else
            echo "999999"
        fi
    elif command -v wget &> /dev/null; then
        # wget 使用 --spider 和 --server-response,记录耗时(需要 date 计算差值)
        local start=$(date +%s%3N)
        if wget --spider --timeout=$timeout --tries=1 "$test_url" 2>/dev/null; then
            local end=$(date +%s%3N)
            local elapsed=$((end - start))
            echo "${elapsed:-999999}"
        else
            echo "999999"
        fi
    else
        echo "999999"
    fi
}

info "正在检测各镜像源延迟(请稍候)..."
BEST_MIRROR=""
BEST_TIME=999999
for name in "${!MIRRORS[@]}"; do
    url=${MIRRORS[$name]}
    printf "测试 %-8s (%s) ... " "$name" "$url"
    time_ms=$(test_speed "$url")
    echo "${time_ms}ms"
    if [ "$time_ms" -lt "$BEST_TIME" ]; then
        BEST_TIME=$time_ms
        BEST_MIRROR="$name"
        BEST_URL="$url"
    fi
done

if [ -z "$BEST_MIRROR" ]; then
    error "所有镜像源均不可达,请检查网络或手动配置源"
fi
info "最优镜像源: $BEST_MIRROR ($BEST_URL), 延迟 ${BEST_TIME}ms"

# 备份现有源配置
BACKUP_DIR="/etc/apt/backup_$(date +%Y%m%d_%H%M%S)"
info "备份现有 APT 源配置到 $BACKUP_DIR"
mkdir -p "$BACKUP_DIR"
[ -f /etc/apt/sources.list ] && cp -a /etc/apt/sources.list "$BACKUP_DIR/"
# 备份并移除所有 sources.list.d 下的 .list 和 .sources 文件,避免冲突
if ls /etc/apt/sources.list.d/*.{list,sources} &>/dev/null 2>&1; then
    mkdir -p "$BACKUP_DIR/sources.list.d"
    cp -a /etc/apt/sources.list.d/*.{list,sources} "$BACKUP_DIR/sources.list.d/" 2>/dev/null || true
    rm -f /etc/apt/sources.list.d/*.{list,sources}
    warn "已清空 /etc/apt/sources.list.d/ 下的所有源文件,改用传统 sources.list"
fi

# 生成新的 sources.list
info "生成新的源列表..."
cat > /etc/apt/sources.list <<EOF
deb ${BEST_URL}/${REPO_PATH} ${TEST_CODENAME} ${COMPONENTS}
deb ${BEST_URL}/${REPO_PATH} ${TEST_CODENAME}-updates ${COMPONENTS}
deb ${BEST_URL}/${REPO_PATH} ${TEST_CODENAME}-backports ${COMPONENTS}
EOF

# Ubuntu 额外添加安全源
if [ "$OS" = "ubuntu" ]; then
    cat >> /etc/apt/sources.list <<EOF
deb ${BEST_URL}/${REPO_PATH} ${TEST_CODENAME}-security ${COMPONENTS}
EOF
fi

# 清空 APT 缓存
info "清空 APT 软件包索引..."
apt clean || error "换源失败:apt clean 失败"

# 更新 APT 缓存
info "更新 APT 软件包索引..."
apt update || error "换源失败:apt update 失败"

info "换源完成!当前使用镜像源: $BEST_MIRROR ($BEST_URL)"

在线版

curl -sSL https://www.sunzishaokao.com/Linux换源脚本.sh | bash

四、Containerd 部署(所有主机)

安装Containerd

wget https://gh-proxy.com/github.com/containerd/nerdctl/releases/download/v2.2.2/nerdctl-full-2.2.2-linux-amd64.tar.gz
tar Cxzvvf /usr/local nerdctl-full-2.2.2-linux-amd64.tar.gz

生成配置文件

mkdir -p /etc/containerd/certs.d/
containerd config default > /etc/containerd/config.toml

配置镜像源

# 方案1(快速、但付费,最低10元50GB流量)
# 先去https://1ms.run/?aff=1726注册账户并购买资源包,然后使用下方命令一键配置付费镜像源
sudo bash -c "$(curl -sSL https://n3.ink/helper)"

# 方案2
#沙盒镜像改为国内
sed -i '/^\s*\[plugins.'"'"'io.containerd.cri.v1.images'"'"'.pinned_images\]/{n;s|^\(\s*\)sandbox = .*$|\1sandbox = '"'"'registry.cn-hangzhou.aliyuncs.com/google_containers/pause:3.10'"'"'|}' /etc/containerd/config.toml

#添加加速器地址
sed -i '/^\s*\[plugins.'"'"'io.containerd.cri.v1.images'"'"'.registry\]/{n;s|^\(\s*\)config_path = .*$|\1config_path = '"'"'/etc/containerd/certs.d'"'"'|}' /etc/containerd/config.toml

#添加docker.io加速
mkdir /etc/containerd/certs.d/docker.io/ -p
cat > /etc/containerd/certs.d/docker.io/hosts.toml <<-'EOF'
server = "https://registry-1.docker.io"
[host."https://docker.1ms.run"]
  capabilities = ["pull", "resolve", "push"]
EOF

#添加registry.k8s.io加速
mkdir /etc/containerd/certs.d/registry.k8s.io/ -p
cat > /etc/containerd/certs.d/registry.k8s.io/hosts.toml <<-'EOF'
server = "https://registry.k8s.io"

[host."https://registry.aliyuncs.com/google_containers"]
  capabilities = ["pull", "resolve"]

EOF

启动Containerd服务

systemctl daemon-reload
systemctl enable --now containerd
systemctl enable --now buildkit

添加nerdctl命令自动补齐功能(可选)

nerdctl completion bash > /etc/bash_completion.d/nerdctl
source /etc/bash_completion.d/nerdctl

五、Kubernetes 组件安装(所有主机)

关闭虚拟内存

swapoff -a
sed -i 's/.*swap.*/#&/' /etc/fstab

允许 iptables 检查桥接流量

cat <<EOF | sudo tee /etc/modules-load.d/k8s.conf
br_netfilter
EOF
modprobe br_netfilter
cat <<EOF | sudo tee /etc/sysctl.d/k8s.conf
net.bridge.bridge-nf-call-ip6tables = 1
net.bridge.bridge-nf-call-iptables = 1
net.ipv4.ip_forward = 1
EOF
sudo sysctl --system

安装 kubeadm

# 安装依赖
apt-get update && apt-get install -y apt-transport-https curl
# 创建密钥存储目录
mkdir -p /etc/apt/keyrings
# 下载并安装阿里云 Kubernetes GPG 密钥
curl -fsSL https://mirrors.aliyun.com/kubernetes-new/core/stable/v1.36/deb/Release.key | gpg --dearmor -o /etc/apt/keyrings/kubernetes.gpg
# 配置 Kubernetes 阿里云 APT 软件源
echo "deb [signed-by=/etc/apt/keyrings/kubernetes.gpg] https://mirrors.aliyun.com/kubernetes-new/core/stable/v1.36/deb/ /" | tee /etc/apt/sources.list.d/kubernetes.list
# 更新软件源索引并安装k8s组件
apt-get update && apt-get install -y kubelet kubeadm kubectl
# 固定版本
apt-mark hold kubelet kubeadm kubectl

添加命令自动补齐功能

kubectl completion bash > /etc/bash_completion.d/kubectl
kubeadm completion bash > /etc/bash_completion.d/kubeadm
source /etc/bash_completion.d/kubectl
source /etc/bash_completion.d/kubeadm

集成containerd

crictl config runtime-endpoint unix:///run/containerd/containerd.sock
crictl images

六、Kubernetes Master部署

集群部署

下方kubeadm.yaml中name字段必须在网络中可被解析,也可以将解析记录添加到集群中所有机器的/etc/hosts中

生成默认配置

kubeadm config print init-defaults > kubeadm.yaml

修改配置

# 1. 设置master节点IP
sed -i 's/.*advert.*/  advertiseAddress: 192.168.25.148/g' kubeadm.yaml

# 2.设置master主机名
sed -i 's/.*name.*/  name: k8s-master/g' kubeadm.yaml

# 3.修改k8s镜像源
# 如果你购买了1ms.run镜像源
sed -i 's/imageRepo.*/imageRepository: k8s.1ms.run/g' kubeadm.yaml
# 如果你没有购买1ms.run镜像源
sed -i 's@imageRepo.*@imageRepository: registry.aliyuncs.com/google_containers@g' kubeadm.yaml

如果遇到coredns拉取问题(not found),建议在imageRepository下方通过dns.imageRepository方式指定一下coredns仓库名(如图,根据情况修改镜像源)

20260429194834402-image

开始部署

modprobe br_netfilter 
kubeadm init --config kubeadm.yaml

出现下面的提示就是成功了,保存好join的命令

Your Kubernetes control-plane has initialized successfully!
...
kubeadm join 192.168.8.3:6443 --token abcdef.0123456789abcdef \
    --discovery-token-ca-cert-hash sha256:d0edd579cbefc3baee6c2253561e24261300ede214ae172bf9687404e09104bf

授权管理权限

mkdir -p $HOME/.kube
sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
sudo chown $(id -u):$(id -g) $HOME/.kube/config

部署Calico网络插件

下载配置

curl -O https://gh-proxy.com/raw.githubusercontent.com/projectcalico/calico/v3.31.4/manifests/calico.yaml

修改镜像源

# 如已购买1ms.run镜像源
sed -i 's/quay.io/quay.1ms.run/g' calico.yaml

应用部署

kubectl apply -f calico.yaml

六、Kubernetes Node部署

通过之前生成的jojn命令到node节点部署,如果时间长忘记了join参数,可以在master节点上用以下方法重新生成

kubeadm token create --print-join-command

七、重置集群(针对于部署失败)

kubeadm reset -f
rm -rf /etc/kubernetes /var/lib/etcd /var/lib/kubelet
iptables -F && iptables -t nat -F && iptables -t mangle -F && iptables -X
systemctl stop containerd
systemctl stop kubelet
crictl rm -f $(crictl ps -aq) 2>/dev/null
crictl rmi --prune 2>/dev/null
systemctl daemon-reload
systemctl restart containerd
systemctl restart kubelet
rm -rf /etc/cni/net.d
rm -rf $HOME/.kube/config

八、交流答疑

如果你也深耕或想入门云计算,不妨扫码进软栈交流群!圈内头部大佬常驻,有问题随时提问,即时答疑交流。

20260429195958326-image


广告:

© 版权声明
THE END
喜欢就支持一下吧
点赞10打赏 分享
评论 抢沙发

请登录后发表评论

    暂无评论内容