踩了两天坑之后我终于把这套流程捋顺了而且还特意把所有数据目录都挪到了/opt下面——因为系统盘就剩 20G不挪地方早晚要崩。我把整个过程记了下来既给自己留个底也给遇到同样问题的朋友省点时间。这篇文章不是流水账里面夹了不少我的真实感受比如“呵呵这我没想到”的那种瞬间你懂的。强烈建议搭配AI食用当然也别把AI太当一回事~1|1环境与思路项目我的实际配置主机名k8s-masterIP192.168.1.10改成你自己的系统Debian 11数据目录/opt所有容器、kubelet 数据都放这Kubernetesv1.31容器运行时containerd网络插件Flannel重点IP 和主机名后面会反复用到千万别写错了。我第一遍就是 hosts 文件里多打了一个空格结果 kubeadm init 直接报错退出了排查了半小时只能说“没办法自己手贱”。1|2一、把主机名和 hosts 收拾干净这是第一步也是最容易翻车的一步。很多人上来就装软件结果后面 service 启动不了还不知道为什么。sudo hostnamectl set-hostname k8s-master然后编辑/etc/hostssudo nano /etc/hosts内容改成这样注意 IP 换成你自己的127.0.0.1 localhost 127.0.1.1 k8s-master 192.168.1.10 k8s-master验证一下解析hostname hostname -i必须返回你的真实 IP否则 kubelet 会找不到北。1|3二、系统初始化顺手装些常用工具这步没啥好说的纯体力活sudo apt update sudo apt upgrade -y sudo apt install -y curl vim wget net-tools gnupg lsb-release早知道后面要频繁curl我第一个就该装它。1|4三、iptables 切换成 legacy 模式——Debian 11 绕不过的坎Deiban 11 默认用的是 nftables而 K8s 的一些组件尤其是 kube-proxy跟 legacy 模式更搭。不切换的话后面网络会有各种莫名其妙的问题。我一开始没当回事结果 Pod 之间死活不通查了半天日志才发现是这里。sudo apt install -y iptables arptables ebtables sudo update-alternatives --set iptables /usr/sbin/iptables-legacy sudo update-alternatives --set ip6tables /usr/sbin/ip6tables-legacy sudo update-alternatives --set arptables /usr/sbin/arptables-legacy sudo update-alternatives --set ebtables /usr/sbin/ebtables-legacy检查一下iptables --version看到(legacy)字样就对了。呵呵这步不做后面有你哭的时候。1|5四、关掉 Swap不然 kubelet 会抗议Kubernetes 很固执它认为 swap 会影响性能所以只要检测到 swap 开着kubelet 就直接罢工。sudo swapoff -a sudo sed -i / swap / s/^\(.*\)$/#\1/g /etc/fstab用free -m看一眼Swap 那行全是 0 就对了。1|6五、加载内核模块两个模块必须提前加载overlay和br_netfilter一个是给容器文件系统用的一个是给网络桥接用的。cat EOF | sudo tee /etc/modules-load.d/k8s.conf overlay br_netfilter EOF sudo modprobe overlay sudo modprobe br_netfilter1|7六、调整 sysctl 参数这几个参数允许 iptables 正确看到桥接流量并且开启内核转发。cat EOF | sudo tee /etc/sysctl.d/k8s.conf net.bridge.bridge-nf-call-iptables 1 net.bridge.bridge-nf-call-ip6tables 1 net.ipv4.ip_forward 1 EOF sudo sysctl --system1|8七、对个时分布式系统对时间很敏感差太多的话证书验证都会失败。装个 chrony 省心sudo apt install -y chrony sudo systemctl enable chrony sudo systemctl start chrony timedatectl看到System clock synchronized: yes就放心了。1|9八、创建 /opt 下的数据目录这是为了把数据从系统盘挪出来毕竟根分区空间金贵。sudo mkdir -p /opt/containerd sudo mkdir -p /opt/kubelet sudo mkdir -p /opt/etcd sudo mkdir -p /opt/cni sudo mkdir -p /opt/log其实 etcd 在单机下默认放/var/lib/etcd但我们可以后面通过配置改掉或者直接软链接这个按需来。我这里先建着后面 kubeadm init 的时候会用到/opt/etcd。1|10九、安装 containerd用 Docker 官方源用 Docker 的官方 containerd 包版本比较新兼容性也好。curl -fsSL https://download.docker.com/linux/debian/gpg | sudo gpg --dearmor -o /usr/share/keyrings/docker.gpg echo \ deb [arch$(dpkg --print-architecture) signed-by/usr/share/keyrings/docker.gpg] \ https://download.docker.com/linux/debian \ $(lsb_release -cs) stable | sudo tee /etc/apt/sources.list.d/docker.list sudo apt update sudo apt install -y containerd.io然后生成默认配置并修改两个地方数据根目录和SystemdCgroup。sudo mkdir -p /etc/containerd containerd config default | sudo tee /etc/containerd/config.toml编辑配置文件sudo nano /etc/containerd/config.toml找到root字段改成/opt/containerd找到SystemdCgroup改成trueroot /opt/containerd state /run/containerd [plugins.io.containerd.grpc.v1.cri.containerd.runtimes.runc.options] SystemdCgroup true重启并设置开机自启sudo systemctl restart containerd sudo systemctl enable containerd1|11十、安装 Kubernetes 组件添加官方源然后装 kubelet、kubeadm、kubectl并锁定版本防止被意外升级。sudo mkdir -p /etc/apt/keyrings curl -fsSL https://pkgs.k8s.io/core:/stable:/v1.31/deb/Release.key | sudo gpg --dearmor -o /etc/apt/keyrings/kubernetes-apt-keyring.gpg echo deb [signed-by/etc/apt/keyrings/kubernetes-apt-keyring.gpg] https://pkgs.k8s.io/core:/stable:/v1.31/deb/ / | sudo tee /etc/apt/sources.list.d/kubernetes.list sudo apt update sudo apt install -y kubelet kubeadm kubectl sudo apt-mark hold kubelet kubeadm kubectl1|12十一、把 kubelet 的数据目录也改到 /opt默认 kubelet 会把数据存在/var/lib/kubelet这跟我们的规划不符。通过 systemd 的 drop-in 文件来覆盖启动参数。sudo mkdir -p /etc/systemd/system/kubelet.service.d创建配置文件cat EOF | sudo tee /etc/systemd/system/kubelet.service.d/10-kubelet.conf [Service] EnvironmentKUBELET_EXTRA_ARGS--root-dir/opt/kubelet EOF重载并重启 kubeletsudo systemctl daemon-reload sudo systemctl restart kubelet这一步在 init 之前做最合适因为 init 的时候 kubelet 会开始写数据如果不提前改目录就会写到/var/lib下面去后面再挪就麻烦了。早知道我第一遍就该这么干。1|13十二、kubeadm init——最紧张的一步终于要初始化集群了。先装几个必要的网络工具包kubeadm 依赖它们sudo apt update sudo apt install -y conntrack ebtables ethtool socat iproute2然后执行 init。注意把--apiserver-advertise-address换成你自己的 IP--pod-network-cidr使用10.244.0.0/16是为了和 Flannel 默认网段匹配。sudo kubeadm init \ --apiserver-advertise-address192.168.1.10 \ --pod-network-cidr10.244.0.0/16 \ --cri-socketunix:///run/containerd/containerd.sock如果一切顺利最后会输出一段kubeadm join ...的命令一定保存下来虽然我们是单节点用不上 join但万一以后想加节点呢如果失败了怎么办我就失败过一次因为之前残留了一些配置。这时候需要彻底清理sudo kubeadm reset -f sudo rm -rf /var/lib/etcd sudo rm -rf /etc/kubernetes/manifests/*然后再重新 init。这个过程就像重启电脑没什么大不了就是多等几分钟。1|14十三、配置 kubectl 让普通用户也能用mkdir -p $HOME/.kube sudo cp /etc/kubernetes/admin.conf $HOME/.kube/config sudo chown $(id -u):$(id -g) $HOME/.kube/config测试一下kubectl get nodes这时候节点状态应该是NotReady因为网络插件还没装。别慌这是正常的。1|15十四、安装 Flannel 网络插件kubectl apply -f https://github.com/flannel-io/flannel/releases/latest/download/kube-flannel.yml等个一两分钟再kubectl get nodes状态就变成Ready了。我第一次看到这个结果的时候长舒一口气——总算没白折腾。1|16十五、允许 Master 节点调度 Pod单机必做默认情况下Master 节点是打了污点taint的不允许普通 Pod 运行。我们既然是单机就得去掉它kubectl taint nodes --all node-role.kubernetes.io/control-plane-验证一下污点没了kubectl describe node | grep -i taint1|17十六、跑个 Nginx 测试一下kubectl create deployment nginx --imagenginx kubectl expose deployment nginx --port80 --typeNodePort kubectl get svc nginx记下那个 30000 的端口浏览器访问http://你的服务器IP:端口看到 Nginx 欢迎页就说明集群完全可用了。测试完可以把这俩资源删掉免得占用端口kubectl delete deployment nginx kubectl delete service nginx1|18十七、最终的数据目录结构检查一下我们的劳动成果ls /opt/containerd ls /opt/kubelet应该能看到 containerd 的元数据、kubelet 的 pod 目录都乖乖躺在这里。没白费功夫。1|19十八、完整的安装顺序——很多人失败就是因为跳步如果你是按我的步骤从头做下来的顺序应该是这样的修改 hostname hostsapt update upgradeiptables 切换 legacy关闭 swap加载内核模块设置 sysctl时间同步安装 containerd 并配置安装 kubeadm/kubelet/kubectl修改 kubelet 数据目录kubeadm init配置 kubectl安装 Flannel去除 Master 污点测试部署Kubernetes 安装失败90% 都是顺序错了或者是某一步没生效就急着往下走。没办法这玩意就是环环相扣少一个螺丝都不行。1|20进阶想让这套环境更好用聊聊 Kite 和其他组件你可能会问接下来我该装什么我见过不少新手搭完集群就迷茫了。其实 Kubernetes 本身只提供基础能力后面要加的东西都是“选装包”。下面我结合自己的使用习惯和你提到的Kite说说怎么选。这些组件到底要不要装组件是否必须我的建议Helm非必须但强烈推荐K8s 的应用商店后面装 Kite 也会用到先装上吧。Ingress Nginx非必须如果你想用域名访问集群里的服务比如 Kite 控制台就需要单机 IP 访问可以暂时不装。Kubernetes Dashboard非必须Kite 完全可以替代它界面好看功能还多没必要装两个。Metrics Server非必须想让 Kite 或kubectl top看到 CPU/内存曲线就必须装否则图表是空的。Prometheus Grafana非必须Kite 已经内置了基础监控图表除非你需要长期存储和高级告警否则先放一放。StorageClass非必须跑无状态应用用不到等你想玩数据库了再说。单机测试用hostPath就行。Kite 能覆盖哪些根据官方介绍Kite 自带资源管理界面替代 Dashboard实时 CPU/内存/网络图表需要 Metrics Server 提供数据Web 终端直接进容器操作日志查看、YAML 编辑多集群切换所以我个人觉得对于单机实验环境装个 Kite 就够你玩的了。我推荐的后续安装顺序1. 安装 Helmcurl -fsSL -o get_helm.sh https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-3 chmod 700 get_helm.sh ./get_helm.sh2. 安装 Metrics Serverkubectl apply -f https://github.com/kubernetes-sigs/metrics-server/releases/latest/download/components.yaml注意在某些自签证书的环境下Metrics Server 可能需要添加--kubelet-insecure-tls参数才能正常工作。如果装完 Kite 看不到监控数据记得去检查一下 Metrics Server 的日志。3. 用 Helm 部署 Kitehelm repo add kite https://kite-org.github.io/kite/ helm repo update helm install kite kite/kite -n kube-system4. 访问 Kite默认 Kite 的 Service 是 ClusterIP 类型只能集群内部访问。最简单暴力的方式是用kubectl port-forwardnohup kubectl port-forward -n kube-system svc/kite 8080:8080 然后浏览器打开http://你的服务器IP:8080就行。云服务器访问不了怎么办如果你用的是云服务器port-forward默认只监听 127.0.0.1外网是打不开的。这时候有两个办法办法一改用 NodePortkubectl patch svc kite -n kube-system -p {spec:{type:NodePort}} kubectl get svc -n kube-system kite会看到一个类似8080:31234的端口映射去云控制台的安全组里开放那个31234端口然后公网访问http://公网IP:31234即可。