从零搭建一个单节点 K8S 可观测实验室(二):安装单节点 Kubernetes
上一篇我们已经在 VirtualBox 里安装好了 Ubuntu 24.04 Server,并通过 SSH 连接到了这台虚拟机。
这一篇开始进入核心部分:在 Ubuntu 24.04 上安装一个单节点 Kubernetes 集群。
这套环境仍然是个人实验室定位,不追求生产级高可用,也不追求复杂架构。目标是先把一个可以反复实验的 Kubernetes 单节点环境跑起来,为后续 Prometheus、Grafana、Loki、Tempo、OpenTelemetry、CI/CD 等内容打基础。
一、这一篇要完成什么?
这一篇主要完成几件事:
Ubuntu 24.04 Server
-> 安装 Docker Engine
-> 配置 Linux 内核网络参数
-> 安装 kubeadm / kubelet / kubectl
-> 安装 cri-dockerd
-> 使用 kubeadm 初始化单节点 Kubernetes
-> 安装 Flannel Pod 网络
-> 让单节点同时承担控制平面和工作负载
最终目标是执行下面命令时,能看到节点状态为 Ready:
kubectl get nodes
并且所有 Kubernetes 系统 Pod 都正常运行:
kubectl get pods -A
二、为什么这里选择 Docker + cri-dockerd?
现在更常见、更标准的 Kubernetes 安装方式,是直接使用 containerd 作为容器运行时。
不过这次实验室里,我还是选择了 Docker Engine + cri-dockerd 这条路线,主要有几个原因。
第一,Docker 对很多人来说更熟悉。后续无论是构建镜像、查看镜像,还是做一些本地实验,Docker 命令都比较直观。
第二,这个系列是个人实验室,不是生产环境。这里的重点是把 Kubernetes、可观测、CI/CD 等内容串起来,而不是一开始就在运行时选择上追求最简洁或最标准。
第三,Kubernetes 从 1.24 开始已经移除了内置 dockershim,所以 kubelet 不能再直接把 Docker Engine 当成 CRI 运行时使用。如果仍然想用 Docker Engine,就需要额外安装 cri-dockerd,由它在 kubelet 和 Docker Engine 之间做一层适配。
也就是说,这里的关系大致是:
kubelet
-> CRI
-> cri-dockerd
-> Docker Engine
-> containerd / runc
如果你不想走 Docker 这条路线,也可以直接使用 containerd。那样会少一个 cri-dockerd 组件,但 Docker 命令使用体验会不一样。
本文先按我实际走过的 Docker + cri-dockerd 方案记录。
三、安装 Docker Engine
1. 添加 Docker 官方 apt 仓库
先更新 apt 索引,并安装基础工具:
sudo apt update
sudo apt install -y ca-certificates curl
创建 apt keyring 目录:
sudo install -m 0755 -d /etc/apt/keyrings
下载 Docker 官方 GPG key:
sudo curl -fsSL https://download.docker.com/linux/ubuntu/gpg -o /etc/apt/keyrings/docker.asc
设置 key 文件权限:
sudo chmod a+r /etc/apt/keyrings/docker.asc
添加 Docker apt 源:
sudo tee /etc/apt/sources.list.d/docker.sources <<EOF
Types: deb
URIs: https://download.docker.com/linux/ubuntu
Suites: $(. /etc/os-release && echo "${UBUNTU_CODENAME:-$VERSION_CODENAME}")
Components: stable
Architectures: $(dpkg --print-architecture)
Signed-By: /etc/apt/keyrings/docker.asc
EOF
再次更新 apt 索引:
sudo apt update

2. 安装 Docker 相关组件
安装 Docker Engine、Docker CLI、containerd 以及常用插件:
sudo apt install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
安装完成后,可以查看 Docker 服务状态:
systemctl status docker
也可以执行:
sudo docker version
如果能正常显示 Docker Client 和 Server 信息,说明 Docker 已经安装成功。
四、配置 Docker
1. 配置 cgroup driver 和日志大小
Kubernetes 里推荐让容器运行时和 kubelet 使用一致的 cgroup driver。这里把 Docker 的 cgroup driver 设置为 systemd。
创建 Docker 配置目录:
sudo mkdir -p /etc/docker
写入 Docker daemon 配置:
sudo tee /etc/docker/daemon.json <<EOF
{
"exec-opts": ["native.cgroupdriver=systemd"],
"log-driver": "json-file",
"log-opts": {
"max-size": "100m"
}
}
EOF
这里顺手限制了 Docker 容器日志文件大小,避免后面实验过程中日志无限增长。
2. 可选:给 Docker 配置 HTTP 代理
如果你的网络环境需要代理访问 Docker Hub 或其他镜像源,可以给 Docker 服务配置代理。
创建 systemd drop-in 目录:
sudo mkdir -p /etc/systemd/system/docker.service.d
配置 HTTP 代理:
sudo vi /etc/systemd/system/docker.service.d/http-proxy.conf
写入:
[Service]
Environment="HTTP_PROXY=http://proxy_ip_address:proxy_port"
Environment="NO_PROXY=127.0.0.1,localhost,10.96.0.0/12,10.244.0.0/16,192.168.56.0/24,192.168.31.0/24"
配置 HTTPS 代理:
sudo vi /etc/systemd/system/docker.service.d/https-proxy.conf
写入:
[Service]
Environment="HTTPS_PROXY=http://proxy_ip_address:proxy_port"
Environment="NO_PROXY=127.0.0.1,localhost,10.96.0.0/12,10.244.0.0/16,192.168.56.0/24,192.168.31.0/24"
其中:
10.96.0.0/12
是后面 Kubernetes 默认 Service 网段。
10.244.0.0/16
是本文后面 Flannel 使用的 Pod 网段。
192.168.56.0/24
是 VirtualBox Host-Only 网络常见网段。
192.168.31.0/24
是我这里局域网网段示例。你的环境如果不是这个网段,可以按实际情况修改。
代理地址也要按自己的情况替换,例如:
http://192.168.31.49:7890
如果你不需要代理,可以跳过这一小节。
3. 重启 Docker 服务
配置完成后,重新加载 systemd 配置:
sudo systemctl daemon-reload
设置 Docker 开机自启:
sudo systemctl enable docker
重启 Docker:
sudo systemctl restart docker
查看 Docker 状态:
systemctl status docker
如果状态是 active (running),说明 Docker 服务正常。

五、打开 Kubernetes 需要的内核网络参数
Kubernetes 网络需要 Linux 内核支持转发和桥接流量处理。这里按 kubeadm 常见要求配置 overlay、br_netfilter 和 sysctl 参数。
1. 加载内核模块
写入模块配置:
sudo tee /etc/modules-load.d/k8s.conf <<EOF
overlay
br_netfilter
EOF
立即加载模块:
sudo modprobe overlay
sudo modprobe br_netfilter
检查模块是否加载:
lsmod | grep -E 'overlay|br_netfilter'
2. 配置 sysctl 参数
写入 Kubernetes 所需网络参数:
sudo tee /etc/sysctl.d/k8s.conf <<EOF
net.bridge.bridge-nf-call-iptables = 1
net.bridge.bridge-nf-call-ip6tables = 1
net.ipv4.ip_forward = 1
EOF
立即生效:
sudo sysctl --system
可以检查 IP 转发是否打开:
sysctl net.ipv4.ip_forward
正常应该看到:
net.ipv4.ip_forward = 1
这一步很重要。否则后面 Pod 网络、Service 转发等可能出现各种奇怪问题。
六、安装 kubeadm、kubelet、kubectl
接下来安装 Kubernetes 三个核心工具:
kubeadm:用于初始化和管理 Kubernetes 集群
kubelet:运行在每个节点上的核心 Agent
kubectl:命令行客户端,用于操作 Kubernetes 集群
本文使用 Kubernetes v1.36 版本仓库。
1. 安装基础依赖
sudo apt-get update
sudo apt-get install -y apt-transport-https ca-certificates curl gnupg
如果系统提示 apt-transport-https 是 dummy package,也没关系,继续即可。
2. 添加 Kubernetes v1.36 apt key
确保 keyring 目录存在:
sudo mkdir -p -m 755 /etc/apt/keyrings
下载 Kubernetes 仓库签名 key:
curl -fsSL https://pkgs.k8s.io/core:/stable:/v1.36/deb/Release.key | sudo gpg --dearmor -o /etc/apt/keyrings/kubernetes-apt-keyring.gpg
设置权限:
sudo chmod 644 /etc/apt/keyrings/kubernetes-apt-keyring.gpg
3. 添加 Kubernetes v1.36 apt 仓库
echo 'deb [signed-by=/etc/apt/keyrings/kubernetes-apt-keyring.gpg] https://pkgs.k8s.io/core:/stable:/v1.36/deb/ /' | sudo tee /etc/apt/sources.list.d/kubernetes.list
设置权限:
sudo chmod 644 /etc/apt/sources.list.d/kubernetes.list
更新 apt 索引:
sudo apt-get update
4. 查看可安装版本
安装之前,可以先看看 apt 仓库里有哪些版本:
apt-cache policy kubeadm
apt-cache policy kubelet
apt-cache policy kubectl
这里可以确认将要安装的具体 patch 版本。
比如我这里后面使用的是:
Kubernetes 1.36.2
你的环境中可能会显示不同 patch 版本。只要是同一个小版本分支,一般问题不大。
5. 安装 kubeadm、kubelet、kubectl
sudo apt-get install -y kubelet kubeadm kubectl
安装完成后,锁定版本,避免后续 apt upgrade 时自动升级导致集群组件版本变化:
sudo apt-mark hold kubelet kubeadm kubectl

查看版本:
kubeadm version
kubectl version --client
kubelet --version
七、关闭 swap
Kubernetes 默认要求关闭 swap。否则 kubelet 可能无法正常工作,或者需要额外配置才能允许 swap。
先立即关闭 swap:
sudo swapoff -a
查看是否已经关闭:
free -h
如果 Swap 显示为 0,说明当前已经关闭。
1. 修改 fstab,避免重启后 swap 再次启用
先备份 /etc/fstab:
sudo cp /etc/fstab $HOME/fstab.backup.$(date +%F)
编辑 /etc/fstab:
sudo vi /etc/fstab
找到类似下面这一行:
/swap.img none swap sw 0 0
把它注释掉:
#/swap.img none swap sw 0 0
保存退出。
2. 可选:删除 swap 文件
如果确认后续不再使用 swap,可以删除 swap 文件:
sudo rm -f /swap.img
再次检查:
free -h
八、启用 kubelet 服务
可以先设置 kubelet 开机自启:
sudo systemctl enable --now kubelet
这时 kubelet 可能还不是正常运行状态,这很正常。
因为集群还没有通过 kubeadm 初始化,kubelet 暂时还没有完整配置。后面 kubeadm init 完成后,它才会真正进入正常状态。
九、安装 cri-dockerd
前面已经安装了 Docker Engine,但 Kubernetes v1.36 的 kubelet 不能直接通过内置 dockershim 使用 Docker Engine。
所以这里需要安装 cri-dockerd。
1. 下载 cri-dockerd deb 包
到 cri-dockerd 的 GitHub Releases 页面选择适合自己系统和架构的 deb 包。
我这里使用的是 amd64 架构,示例命令如下:
wget https://github.com/Mirantis/cri-dockerd/releases/download/v0.4.4/cri-dockerd_0.4.4.3-0.debian-bookworm_amd64.deb
注意:这里的版本号和包名以实际 Releases 页面为准。你操作时如果已经有更新版本,可以选择对应的新版本。
2. 安装 cri-dockerd
sudo dpkg -i cri-dockerd_*.deb
如果安装过程中提示缺少依赖,可以执行:
sudo apt -f install
然后再确认安装状态。
3. 启动 cri-docker 服务
重新加载 systemd:
sudo systemctl daemon-reload
设置开机自启:
sudo systemctl enable cri-docker
重启服务:
sudo systemctl restart cri-docker
查看服务状态:
systemctl status cri-docker
如果看到 active (running),说明 cri-dockerd 已经正常运行。

4. 确认 CRI socket
后面 kubeadm 需要使用这个 socket:
unix:///var/run/cri-dockerd.sock
可以查看 socket 文件是否存在:
ls -l /var/run/cri-dockerd.sock
十、提前拉取 Kubernetes 镜像
在初始化集群之前,可以先让 kubeadm 拉取所需镜像。
因为我们使用 Docker + cri-dockerd,所以这里显式指定 CRI socket:
sudo kubeadm config images pull --cri-socket=unix:///var/run/cri-dockerd.sock
如果你的网络需要代理,这一步可能会比较慢,甚至失败。
这时可以检查:
systemctl show --property=Environment docker
确认 Docker 服务代理是否配置成功。
十一、生成 kubeadm 初始化配置
接下来生成 kubeadm 默认配置:
kubeadm config print init-defaults > kubeadm.conf
编辑配置文件:
vi kubeadm.conf
这里主要调整几个地方。
1. 配置 criSocket
找到 nodeRegistration 部分,确保 criSocket 指向 cri-dockerd:
nodeRegistration:
criSocket: unix:///var/run/cri-dockerd.sock
name: vbox-ubuntu24-server
name 建议和你上一章安装 Ubuntu 时配置的主机名保持一致。
可以用下面命令查看当前主机名:
hostname
2. 配置 Kubernetes 版本
找到:
kubernetesVersion:
改成当前实际安装的 Kubernetes 版本,例如:
kubernetesVersion: 1.36.2
版本号可以通过下面命令确认:
kubeadm version
如果你的环境显示的是其他 patch 版本,就按自己的实际版本填写。
3. 配置 Pod 网段
后面我们会使用 Flannel。Flannel 默认常用 Pod 网段是:
10.244.0.0/16
所以需要在 networking 部分加上或修改为:
networking:
dnsDomain: cluster.local
serviceSubnet: 10.96.0.0/12
podSubnet: 10.244.0.0/16
这里:
serviceSubnet: 10.96.0.0/12
是 Kubernetes Service 网段。
podSubnet: 10.244.0.0/16
是 Pod 网络网段,后面 Flannel 会用到。
4. 配置 advertiseAddress
配置文件里会有类似:
localAPIEndpoint:
advertiseAddress: 1.2.3.4
bindPort: 6443
这里可以改成当前节点的管理 IP。
如果你希望使用 VirtualBox Host-Only 网络作为管理地址,可以填第一篇里查到的 Host-Only IP,例如:
localAPIEndpoint:
advertiseAddress: 192.168.56.103
bindPort: 6443
我实操过程中也尝试过使用:
advertiseAddress: 0.0.0.0
单节点实验环境可以跑起来,但从表达和后续理解上,写成一个明确的节点 IP 会更直观。
所以更建议使用你自己的 Host-Only IP。
5. 配置文件示例
最终关键配置大致类似下面这样:
localAPIEndpoint:
advertiseAddress: 192.168.56.103
bindPort: 6443
nodeRegistration:
criSocket: unix:///var/run/cri-dockerd.sock
name: vbox-ubuntu24-server
kubernetesVersion: 1.36.2
networking:
dnsDomain: cluster.local
serviceSubnet: 10.96.0.0/12
podSubnet: 10.244.0.0/16
注意:不要只复制这一小段覆盖整个文件。建议在 kubeadm config print init-defaults 生成的完整文件里修改对应字段。
十二、使用 kubeadm 初始化集群
确认配置文件无误后,执行:
sudo kubeadm init --config kubeadm.conf
如果之前初始化失败过,可以先执行:
sudo kubeadm reset
然后再重新初始化。
初始化成功后,会看到类似输出:
Your Kubernetes control-plane has initialized successfully!
并且 kubeadm 会提示你执行下面几行命令:
mkdir -p $HOME/.kube
sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
sudo chown $(id -u):$(id -g) $HOME/.kube/config
后面还会提示你安装 Pod 网络插件,并给出 worker node 加入集群用的 kubeadm join 命令。

由于我们这里是单节点实验室,暂时不需要关心 worker node 的 join 命令。
十三、配置 kubectl
按 kubeadm 提示,初始化当前用户的 kubeconfig:
mkdir -p $HOME/.kube
复制 admin 配置:
sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
修改文件属主:
sudo chown $(id -u):$(id -g) $HOME/.kube/config
这时可以试一下:
kubectl get nodes
此时节点可能还是:
NotReady
这是正常的,因为 Pod 网络插件还没有安装。
十四、安装 Flannel Pod 网络
Kubernetes 初始化完成后,还需要安装 CNI 网络插件。这里选择 Flannel,原因是简单、轻量、适合单节点实验环境。
1. 下载 Flannel 配置文件
wget https://github.com/flannel-io/flannel/releases/latest/download/kube-flannel.yml
如果前面 kubeadm 配置里的 Pod 网段使用的是:
10.244.0.0/16
通常可以直接使用这个 Flannel 配置文件。
2. 部署 Flannel
kubectl apply -f kube-flannel.yml
部署后,可以查看所有 namespace 下的 Pod:
kubectl get pods -A
刚开始可能会看到一些 Pod 处于 Pending、ContainerCreating 或 Init 状态。等一会儿再看即可。
可以用下面命令持续观察:
watch kubectl get pods -A
十五、让控制平面节点也能运行普通 Pod
默认情况下,kubeadm 初始化出来的控制平面节点会带有 taint,普通业务 Pod 不会被调度到这个节点上。
但我们这是单节点实验室,只有一个节点。如果不去掉 taint,后面很多 Pod 会一直 Pending。
执行:
kubectl taint nodes --all node-role.kubernetes.io/control-plane-
如果提示 taint not found,也不用紧张,说明当前节点上可能已经没有这个 taint,或者版本行为有所变化。
查看节点信息:
kubectl describe node vbox-ubuntu24-server | grep -i taint -A2
如果看到:
Taints: <none>
说明普通 Pod 可以调度到这个节点。
十六、检查集群状态
1. 查看 Pod 状态
kubectl get pods -A
正常情况下,会看到类似这些组件:
kube-system coredns-xxx
kube-system etcd-vbox-ubuntu24-server
kube-system kube-apiserver-vbox-ubuntu24-server
kube-system kube-controller-manager-vbox-ubuntu24-server
kube-system kube-proxy-xxx
kube-system kube-scheduler-vbox-ubuntu24-server
kube-flannel kube-flannel-ds-xxx
等待它们都变成 Running。
2. 查看节点状态
kubectl get nodes
最终希望看到类似:
NAME STATUS ROLES AGE VERSION
vbox-ubuntu24-server Ready control-plane 10m v1.36.2
看到 Ready,说明这个单节点 Kubernetes 集群已经跑起来了。

十七、做一个最小验证
为了确认集群能正常调度 Pod,可以创建一个 nginx 测试 Pod。
kubectl create deployment nginx --image=nginx
查看 Pod:
kubectl get pods
等到 Pod 变成 Running。
再暴露一个 NodePort 服务:
kubectl expose deployment nginx --port=80 --type=NodePort
查看服务:
kubectl get svc
会看到类似:
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP ...
nginx NodePort 10.96.x.x <none> 80:30xxx/TCP ...
其中 30xxx 就是 NodePort 端口。
可以在 Ubuntu 虚拟机里访问:
curl http://127.0.0.1:30xxx
也可以在 Windows 宿主机上,通过 Host-Only IP 访问:
http://192.168.56.103:30xxx
如果能看到 nginx 欢迎页,说明 Pod 调度、Service 暴露和基础网络都已经正常。
测试完成后,可以删除 nginx:
kubectl delete svc nginx
kubectl delete deployment nginx
十八、这一篇完成了什么?
到这里,单节点 Kubernetes 环境已经安装完成。
这一篇我们完成了:
-
安装 Docker Engine
-
配置 Docker cgroup driver 和日志限制
-
可选配置 Docker HTTP/HTTPS 代理
-
打开 Kubernetes 所需内核模块和 sysctl 参数
-
安装 kubeadm、kubelet、kubectl
-
关闭 swap
-
安装 cri-dockerd
-
使用 kubeadm 初始化 Kubernetes 控制平面
-
安装 Flannel Pod 网络
-
去掉控制平面节点 taint,让单节点可以运行普通工作负载
-
验证节点和系统 Pod 状态
-
用 nginx 做了最小可用性验证
现在,这台 Ubuntu 24.04 虚拟机已经从一台普通 Linux Server,变成了一个可以继续扩展的单节点 Kubernetes 实验环境。
下一篇开始,就可以在这个 Kubernetes 集群上安装 Prometheus + Grafana,开始观察集群指标。
参考资料
- Kubernetes 官方文档:Installing kubeadm
- Kubernetes 官方文档:Container Runtimes
- Docker 官方文档:Install Docker Engine on Ubuntu
本文基于个人实验环境整理,具体版本和命令可能会随官方文档更新而变化。实际操作时建议结合以上官方资料确认最新安装方式。
更多推荐



所有评论(0)