前言
Kubernetes(简称K8s)作为容器编排领域的事实标准,是云原生技术栈的核心组件。对于初学者而言,手动部署K8s集群往往涉及大量配置项和依赖处理,容易踩坑。本文分享一套经过优化的K8s单节点集群一键部署脚本,涵盖Containerd运行时配置、K8s组件安装、Calico网络部署等全流程,帮助大家快速搭建可用于学习和测试的单节点K8s环境。
环境说明
- 操作系统:Ubuntu(Debian系发行版均可适配)
- 架构:amd64(x86_64)
- 核心版本 :
- Kubernetes:1.33.6
- Containerd:1.7.30
- Calico网络插件:v3.29.0
- 前提条件 :
- 服务器关闭Swap(脚本已自动处理)
- 服务器有外网访问能力(或配置好内网代理)
- 服务器IP:192.168.56.111(需根据实际环境修改)
脚本核心功能
该脚本实现了从环境清理到集群初始化的全自动化,核心流程包括:
- 系统基础配置(时区、依赖包、Swap关闭)
- 旧K8s/Containerd环境清理
- Containerd运行时部署与配置
- K8s核心组件(kubeadm/kubelet/kubectl)安装
- K8s集群初始化
- Calico网络插件部署
- 临时文件清理
完整部署脚本
bash
#!/bin/bash
set -e
# 核心配置(根据实际环境修改以下参数)
PROXY_ADDR="http://192.168.56.103:8080" # 代理地址(无代理可注释相关curl --proxy参数)
HARBOR_REGISTRY="192.168.56.103" # Harbor私有仓库地址
HARBOR_FULL_ADDR="http://${HARBOR_REGISTRY}"
HARBOR_USER="admin" # Harbor用户名
HARBOR_PASS="Harbor12345" # Harbor密码
K8S_VERSION="1.33.6" # K8s版本
NODE_IP="192.168.56.111" # 节点IP(必填,需修改为自身服务器IP)
ARCH="amd64" # 架构
DOWNLOAD_DIR="/tmp/k8s-bin"
CALICO_VERSION="v3.29.0" # Calico版本
SOURCE_REGISTRY="registry.k8s.io"
TARGET_REGISTRY="${HARBOR_REGISTRY}/library"
PAUSE_VERSION="3.8"
PAUSE_TARGET_VERSION="3.10"
# 1. 系统基础配置
timedatectl set-timezone Asia/Shanghai
apt update -y
apt upgrade -y
# 安装必要依赖包
apt install -y curl wget iptables apt-transport-https ca-certificates gnupg2 software-properties-common net-tools
# 2. 清理旧环境(避免残留配置干扰)
systemctl stop kubelet containerd || true
pkill -9 containerd || true
pkill -9 kubelet || true
mount | grep /run/containerd | awk '{print $3}' | xargs -r umount -l
rm -rf /run/containerd /var/lib/containerd /etc/containerd /etc/kubernetes /var/lib/kubelet /var/lib/cni /opt/cni/bin /run/kubelet/*
rm -f /usr/bin/kubeadm /usr/bin/kubelet /usr/bin/kubectl /usr/local/bin/crictl
iptables -F && iptables -X && iptables -F -t nat && iptables -X -t nat
ip link delete cni0 || true
ip link delete cali* || true
systemctl daemon-reload
# 3. 部署Containerd运行时
swapoff -a
sed -i '/swap/s/^/#/' /etc/fstab # 永久关闭Swap
# 加载内核模块
cat <<EOF | tee /etc/modules-load.d/containerd.conf
overlay
br_netfilter
EOF
modprobe overlay
modprobe br_netfilter
# 配置内核参数
cat <<EOF | tee /etc/sysctl.d/99-kubernetes-cri.conf
net.bridge.bridge-nf-call-iptables = 1
net.ipv4.ip_forward = 1
net.bridge.bridge-nf-call-ip6tables = 1
EOF
sysctl --system
# 安装containerd、runc、CNI插件
curl -L --proxy ${PROXY_ADDR} --insecure -s https://github.com/containerd/containerd/releases/download/v1.7.30/containerd-1.7.30-linux-${ARCH}.tar.gz -o /tmp/containerd.tar.gz
tar Cxzvf /usr/local /tmp/containerd.tar.gz
curl -L --proxy ${PROXY_ADDR} --insecure -s https://github.com/opencontainers/runc/releases/download/v1.1.12/runc.${ARCH} -o /tmp/runc
install -m 755 /tmp/runc /usr/local/sbin/runc
CNI_VERSION="1.4.0"
curl -L --proxy ${PROXY_ADDR} --insecure -s https://github.com/containernetworking/plugins/releases/download/v${CNI_VERSION}/cni-plugins-linux-${ARCH}-v${CNI_VERSION}.tgz -o /tmp/cni-plugins.tgz
mkdir -p /opt/cni/bin
tar Cxzvf /opt/cni/bin /tmp/cni-plugins.tgz
# 配置containerd
mkdir -p /etc/containerd
containerd config default > /etc/containerd/config.toml
sed -i 's/SystemdCgroup \= false/SystemdCgroup \= true/' /etc/containerd/config.toml # 启用SystemdCgroup
sed -i 's/config_path = ""/config_path = "\/etc\/containerd\/certs.d"/' /etc/containerd/config.toml
sed -i 's/^\(\s*\)tls_verify = true/\1tls_verify = false/' /etc/containerd/config.toml
# 配置Harbor私有仓库认证
mkdir -p /etc/containerd/certs.d/${HARBOR_REGISTRY}
cat > /etc/containerd/certs.d/${HARBOR_REGISTRY}/hosts.toml << EOF
server = "${HARBOR_FULL_ADDR}"
[host."${HARBOR_FULL_ADDR}"]
capabilities = ["pull", "resolve", "push"]
skip_verify = true
allow_insecure = true
[host."${HARBOR_FULL_ADDR}".auth]
username = "${HARBOR_USER}"
password = "${HARBOR_PASS}"
EOF
# 启动containerd
cat <<EOF | tee /etc/systemd/system/containerd.service
[Unit]
Description=containerd container runtime
After=network.target local-fs.target
[Service]
ExecStartPre=-/sbin/modprobe overlay
ExecStart=/usr/local/bin/containerd
Type=notify
Restart=always
RestartSec=5
LimitNOFILE=infinity
[Install]
WantedBy=multi-user.target
EOF
systemctl daemon-reload
systemctl enable --now containerd
# 4. 安装crictl(容器运行时命令行工具)
CRICTL_VERSION="v1.30.0"
curl -L --proxy ${PROXY_ADDR} --insecure -s https://github.com/kubernetes-sigs/cri-tools/releases/download/${CRICTL_VERSION}/crictl-${CRICTL_VERSION}-linux-amd64.tar.gz | tar zxvf - -C /usr/local/bin
cat > /etc/crictl.yaml << EOF
runtime-endpoint: unix:///run/containerd/containerd.sock
timeout: 10
debug: false
EOF
# 配置pause镜像(K8s基础容器镜像)
crictl pull ${TARGET_REGISTRY}/pause:${PAUSE_TARGET_VERSION}
ctr -n k8s.io images tag ${TARGET_REGISTRY}/pause:${PAUSE_TARGET_VERSION} ${SOURCE_REGISTRY}/pause:${PAUSE_VERSION}
# 5. 安装K8s核心组件
mkdir -p ${DOWNLOAD_DIR} && cd ${DOWNLOAD_DIR}
for bin in kubeadm kubelet kubectl; do
curl -L --proxy ${PROXY_ADDR} --insecure -s https://dl.k8s.io/v${K8S_VERSION}/bin/linux/${ARCH}/${bin} -o ${bin}
chmod +x ${bin} && mv ${bin} /usr/bin/
done
# 配置kubelet
cat <<EOF | tee /etc/systemd/system/kubelet.service
[Unit]
Description=kubelet: The Kubernetes Node Agent
After=network-online.target
[Service]
ExecStart=/usr/bin/kubelet
Restart=always
RestartSec=10
LimitNOFILE=infinity
[Install]
WantedBy=multi-user.target
EOF
mkdir -p /etc/systemd/system/kubelet.service.d
cat <<EOF | tee /etc/systemd/system/kubelet.service.d/10-kubeadm.conf
[Service]
Environment="KUBELET_KUBECONFIG_ARGS=--bootstrap-kubeconfig=/etc/kubernetes/bootstrap-kubelet.conf --kubeconfig=/etc/kubernetes/kubelet.conf"
Environment="KUBELET_CONFIG_ARGS=--config=/var/lib/kubelet/config.yaml"
EnvironmentFile=-/var/lib/kubelet/kubeadm-flags.env
ExecStart=
ExecStart=/usr/bin/kubelet \$KUBELET_KUBECONFIG_ARGS \$KUBELET_CONFIG_ARGS \$KUBELET_KUBEADM_ARGS --container-runtime-endpoint=unix:///run/containerd/containerd.sock
EOF
cat <<EOF | tee /etc/default/kubelet
KUBELET_EXTRA_ARGS="--pod-infra-container-image=${TARGET_REGISTRY}/pause:${PAUSE_TARGET_VERSION}"
EOF
systemctl daemon-reload
systemctl enable --now kubelet
# 6. 初始化K8s集群
cat > /root/kubeadm-config.yaml << EOF
apiVersion: kubeadm.k8s.io/v1beta3
kind: ClusterConfiguration
kubernetesVersion: v1.33.6
imageRepository: ${TARGET_REGISTRY}
networking:
podSubnet: 192.168.32.0/24 # Calico网络子网,需与Calico配置一致
---
apiVersion: kubelet.config.k8s.io/v1beta1
kind: KubeletConfiguration
podSandboxImage: "${TARGET_REGISTRY}/pause:${PAUSE_TARGET_VERSION}"
---
apiVersion: kubeadm.k8s.io/v1beta3
kind: InitConfiguration
localAPIEndpoint:
advertiseAddress: ${NODE_IP}
bindPort: 6443
nodeRegistration:
criSocket: unix:///run/containerd/containerd.sock
EOF
kubeadm init --config /root/kubeadm-config.yaml --ignore-preflight-errors all --v=5
# 配置kubectl认证
mkdir -p $HOME/.kube
cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
chown $(id -u):$(id -g) $HOME/.kube/config
# 7. 部署Calico网络插件
curl -L --proxy ${PROXY_ADDR} --insecure -s https://raw.githubusercontent.com/projectcalico/calico/${CALICO_VERSION}/manifests/calico.yaml -o /tmp/calico.yaml
sed -i "s|docker.io/calico|${TARGET_REGISTRY}/calico|g" /tmp/calico.yaml # 替换镜像仓库为Harbor
kubectl apply -f /tmp/calico.yaml
# 移除控制平面污点(单节点集群允许Pod调度到控制平面)
kubectl taint nodes --all node-role.kubernetes.io/control-plane- || true
# 8. 清理临时文件
rm -rf ${DOWNLOAD_DIR} /tmp/containerd.tar.gz /tmp/runc /tmp/cni-plugins.tgz /tmp/calico.yaml /root/kubeadm-config.yaml
echo "K8s单节点集群部署完成!"
echo "验证集群状态:kubectl get nodes"
echo "验证网络插件:kubectl get pods -n kube-system -l k8s-app=calico-node"
脚本使用步骤
1. 前置修改
- 必改项:
NODE_IP修改为服务器实际IP; - 可选项:若无Harbor私有仓库,需注释/删除相关Harbor配置段落;若无代理,删除curl命令中的
--proxy ${PROXY_ADDR}参数;
2. 执行脚本
bash
# 赋予脚本执行权限
chmod +x k8s-single-node.sh
# 执行脚本(建议使用root用户)
./k8s-single-node.sh
3. 验证部署结果
bash
# 查看节点状态(Ready即为正常)
kubectl get nodes
# 查看系统组件Pod状态(所有Pod Running即为正常)
kubectl get pods -n kube-system
关键配置说明
1. Containerd配置
- 启用
SystemdCgroup:适配Systemd系统的cgroup管理,避免容器资源管理异常; - 私有仓库配置:通过
certs.d目录配置Harbor认证,解决私有仓库拉取镜像权限问题;
2. K8s初始化配置
podSubnet: 192.168.32.0/24:Calico网络子网,需与Calico插件配置一致;ignore-preflight-errors all:忽略预检查错误(适合学习环境,生产环境需谨慎);- 移除控制平面污点:单节点集群中,允许业务Pod调度到控制平面节点;
3. Calico网络插件
Calico是K8s主流的网络插件,支持网络策略、高性能网络转发,脚本中替换了镜像仓库地址为私有Harbor,解决官方镜像拉取慢的问题。
常见问题排查
- Containerd启动失败 :检查内核模块
overlay和br_netfilter是否加载成功(lsmod | grep overlay); - kubelet启动失败 :查看日志
journalctl -u kubelet -f,常见原因是Swap未关闭、镜像拉取失败; - Calico Pod未Running :检查Pod子网与
podSubnet配置是否一致,或节点网络是否互通; - 镜像拉取失败:确认Harbor仓库可访问,或替换为公有镜像仓库(如阿里云镜像);
总结
本文提供的一键部署脚本封装了K8s单节点集群的全流程,适合初学者快速上手。实际生产环境中,需根据需求调整配置(如高可用、安全认证、镜像仓库等),但该脚本可作为基础模板,帮助理解K8s部署的核心流程。建议大家在测试环境中反复调试,熟悉每个配置项的作用,逐步掌握K8s部署的底层逻辑。