在 VPS 上跑轻量 K8s:k3s 单节点集群入门

想在 VPS 上学 K8s 又怕太重?k3s 把 K8s 砍到几十 MB。从单机安装、部署第一个应用、用 Ingress 暴露服务,到 2GB 内存怎么算、HA 何时上 etcd、为什么必须避开 OpenVZ/LXC 假虚拟化。

想学 Kubernetes,却被「至少三台机器、etcd 集群、一周才能搭起来」的传言劝退?其实在预算 VPS 上完全可以用 k3s 先跑起来。它把完整的、CNCF 认证的 Kubernetes 压成一个不到 70MB 的二进制,单机一条命令装好,几分钟就能部署第一个应用。而且结论先说在前面:如果你只是想学 K8s、又不想每个月为一个正经集群烧钱,k3s 几乎是当前最省钱的方案——在一台 2GB 内存的低价 KVM VPS 上,关掉默认的 Traefik、用内置 SQLite 当数据库,就够你跑起一个像模像样的实验集群。本文带你在一台最普通的 VPS 上走完「安装 → 部署 nginx → 用 Ingress 暴露到公网」全流程,并补齐低配机器的内存账、HA 取舍,以及买 VPS 时最容易踩的虚拟化雷区。

延伸阅读

更多相关攻略推荐:2026 游戏服 VPS 怎么选:高主频 CPU、内存与 DDoS 2026 高主频 CPU VPS:单核性能、建站与游戏服的隐藏指标用几台便宜 VPS 组 k3s / Docker Swarm 容器集【VPS 进阶玩法精选 011】VPS 上 MySQL / Post【VPS 硬件选型指南 (存储 篇) 01】NVMe / SATA

一、为什么选 k3s 而不是原版 Kubernetes

k3s 是 Rancher(现 SUSE)出品、CNCF 沙盒项目的轻量 Kubernetes 发行版。它「轻」在三个地方。第一,把所有核心组件(API Server、controller-manager、scheduler、kubelet、容器运行时)塞进一个二进制文件,许多组件跑在同一个进程里,省掉了每个组件单独跑一份的开销,二进制本身小于 70MB。第二,它移除了上游 Kubernetes 里那些用不上的「内置存储驱动」和「云厂商适配层」,这些在 VPS 上基本用不到,需要时可以走 CSI / CCM 外接。第三,单节点默认用 SQLite 存集群状态,而不是沉重的 etcd——等你要做高可用时再切到外部数据库或嵌入式 etcd 也不迟。

关键是它「轻」但不「阉割」:你的 kubectl 命令、Helm chart、YAML 清单和原版 K8s 完全一样,学的是真 Kubernetes,不是某个玩具。而且 k3s 同时支持 x86_64 和 ARM64/ARMv7,小到树莓派、大到云服务器都能跑,特别适合拿来做学习环境和边缘部署。装好之后它还顺手把 Traefik 入口、CoreDNS、Flannel、local-path 存储、metrics-server 全打包好,并自带一个叫 ServiceLB(Klipper)的简易负载均衡器——开箱就能把 Service 暴露出去。

把两者摆在一起看更直观:原版 kubeadm 装的 K8s 安装步骤繁琐、二进制加起来 300MB 以上、空载内存约 1.5GB、默认用 etcd 且要自己装入口控制器和负载均衡;k3s 一条命令装完、二进制不到 70MB、空载约 512MB、默认用 SQLite,还把上面那些组件全打包好。换句话说,k3s 把「基础设施 plumbing」替你接好了,你只需关心怎么部署应用。

那 k3s 适合谁?最典型的三类是:想认真学 K8s 又不想先搞三台机器的人、需要在两三台机器上跑服务并要滚动发布和自愈的站长、以及做边缘或 ARM 部署的开发者。如果你的世界只有一个容器、一台机器、图省事,那 Docker Compose 依然是更简单的解;但只要你跨过这个门槛,k3s 几乎是所有轻量 K8s 场景里的首选。延伸阅读:虚拟化:KVM、LXC 与 Docker 区别

二、一条命令装好单节点集群

准备一台装了 Ubuntu 22.04/24.04 或 Debian 12 的 VPS,至少 1 vCPU、1GB 内存(学习够用,跑真实业务建议 2 vCPU、4GB,详见第六节)。先确认它是全 KVM 虚拟化——OpenVZ/LXC 这类容器级虚拟化会让 kubelet 起不来,这一步在第八节细讲。开好 6443、80、443 端口,并且务必关掉 swap:Kubernetes/kubelet 硬性要求关闭 swap,只要系统开着 swap,kubelet 就可能拒绝启动或行为异常。在 VPS 上最稳妥的做法是 sudo swapoff -a 并注释掉 /etc/fstab 里的 swap 行。

# 关 swap(kubelet 的硬性要求)
sudo swapoff -a
sudo sed -i '/ swap / s/^/#/' /etc/fstab

# 学习向推荐装法:禁用 Traefik、锁版本
curl -sfL https://get.k3s.io | INSTALL_K3S_VERSION=v1.32.3+k3s1 INSTALL_K3S_EXEC="--disable traefik" sh -
# 等约 30 秒,查看节点是否 Ready
sudo k3s kubectl get node

这条命令会下载对应架构的二进制、注册成 systemd 服务并立刻启动,API Server 默认在 6443 端口。如果你保留默认组件,它还会把 CoreDNS、Flannel 网络、local-path 存储、metrics-server 一并带起来(上面这行用 --disable traefik 关掉了入口控制器以省内存,需要时用 Nginx Ingress 接管即可,见第五节)。想锁定版本(推荐用于可复现的环境),加一个环境变量即可,上面的例子已经带上。看到节点状态是 Ready,集群就活了。k3s 自带 kubectl 包装命令,所以没有单独装 kubectl 也能直接用。

装完之后,k3s 是作为 systemd 服务常驻的,常用几条运维命令值得记一下:sudo systemctl status k3s 看运行状态,sudo journalctl -u k3s -f 看实时日志,sudo systemctl enable k3s 确保重启后自动拉起(默认已启用)。如果以后要升级,重新跑一次安装脚本并指定新版本号即可,过程会下载新二进制、重启服务,期间应用会有短暂不可用。想彻底卸载也有现成的 /usr/local/bin/k3s-uninstall.sh。顺带一句:k3s 性能很依赖磁盘,官方建议尽量用 SSD;在树莓派这类用 SD 卡的设备上 etcd 写放大容易把卡写坏,所以低配单机用 SQLite 反而更稳。

三、拿到 kubeconfig,用本地 kubectl 管集群

k3s 把 kubeconfig 写到了服务器的 /etc/rancher/k3s/k3s.yaml。在 VPS 本机上,最省事的方式就是继续用 sudo k3s kubectl。如果你想在笔记本上用自己的 kubectl 操作,把这个文件拷到本地,并把里面的 server: https://127.0.0.1:6443 改成你 VPS 的公网 IP 或域名:

sudo cat /etc/rancher/k3s/k3s.yaml
# 本地执行,放到默认位置
mkdir -p ~/.kube
scp root@你的IP:/etc/rancher/k3s/k3s.yaml ~/.kube/config
# 记得把 127.0.0.1 改成公网 IP,并 chmod 600 ~/.kube/config
kubectl get nodes

如果连不上,先确认 6443 端口放行了:sudo ufw allow 6443/tcp。公网暴露 API 端口有风险,正式环境请把这条规则限制成你自己的 IP。

四、部署第一个应用:nginx + Service

写一份清单,起两个 nginx 副本,再用一个 Service 在集群内部暴露 80 端口。保存为 nginx.yaml

apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-demo
spec:
  replicas: 2
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
        - name: nginx
          image: nginx:alpine
          ports:
            - containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
  name: nginx-service
spec:
  selector:
    app: nginx
  ports:
    - port: 80
      targetPort: 80

应用并观察滚动状态:

kubectl apply -f nginx.yaml
kubectl rollout status deployment/nginx-demo
kubectl get pods -o wide

此时 Pod 已经在跑了,但 Service 的 IP 只在集群内可达,外面还访问不到——下一步用 Ingress 把它推到公网。过来人建议:首次部署先确认集群内部通断,跑一句 kubectl get pods -A 看 coredns、local-path-provisioner、metrics-server 都已经是 Running,再做 Ingress 暴露,比一口气堆一堆 YAML 然后对着报错发呆省时间得多。

顺带解释几个刚出现的关键词。replicas: 2 表示让 nginx 同时跑两份副本,挂掉一个另一个立刻顶上,这也是 K8s「自愈」的来源;Service 则给这两份副本一个稳定的内部访问入口,并做简单的负载均衡。想临时扩容到 4 份,跑一句 kubectl scale deployment nginx-demo --replicas=4 就行;想换镜像做滚动更新,kubectl set image deployment/nginx-demo nginx=nginx:1.27 会一个一个替换旧 Pod,做到零停机。这些在 Docker Compose 里要么没有、要么要自己写脚本,而 k3s 原生就给你。

五、用 Ingress 把服务暴露到公网

k3s 默认就带 Traefik 作为入口控制器(如果你在第二节用 --disable traefik 关掉了,这里就改用 Nginx Ingress,下面会讲)。再写一份 Ingress,把你的域名路由到上面的 Service(把 app.example.com 换成你真实解析到 VPS 的域名):

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: nginx-demo
spec:
  rules:
    - host: app.example.com
      http:
        paths:
          - path: /
            pathType: Prefix
            backend:
              service:
                name: nginx-service
                port:
                  number: 80

把域名的 A 记录指向 VPS 公网 IP,Traefik 会自动在 80/443 上接管流量,一分钟内就能用浏览器打开 app.example.com。想要 HTTPS,可以再装 cert-manager 并给 Ingress 加一个 Let's Encrypt 注解,证书会自动签发续期。至此,你已经拥有了一个「真·Kubernetes」:声明式部署、滚动更新、服务发现一应俱全。

证书这块多说一句,k3s 自带的是 Traefik,cert-manager 需要单独用 helm 装一下,然后给 Ingress 加注解就能自动申请。典型的注解长这样:cert-manager.io/cluster-issuer: letsencrypt-prod 配合 kubernetes.io/tls-acme: "true",再在 spec 里声明 tls 字段,Traefik 就会走 HTTP-01 校验签发 Let's Encrypt 证书并自动续期。如果你的域名还没备案或暂时不想折腾证书,先用 http 访问验证流程也完全没问题,等环境稳了再加 TLS 不迟。

如果你在装的时候关掉了 Traefik,备选路线是改用 Nginx Ingress:通过 k3s 自带的 HelmChart 清单声明式部署 ingress-nginx,Service 类型设为 LoadBalancer,外部 IP 由 k3s 内置的 ServiceLB 分配,同样把域名 A 记录指向 VPS 公网 IP 即可。两条路线都能工作,区别只在入口控制器本身吃多少内存(见第六节)。

六、资源占用与低配 VPS 内存账

这是大家最关心的:便宜 VPS 跑得动吗?k3s 空载大约占 300–500MB 内存,最低 512MB 能装起来,但那是「只跑控制面、几乎没应用」的极限值。原版 kubeadm 装的 K8s 空载就要 1.5GB 左右,差距明显。需要强调的是,官方文档列的最低 512MB、建议 1GB,只是「能装起来、能跑 hello-world」的下限,不是「能跑真实微服务」的下限;社区反复验证的经验值是:一旦你部署真实业务(哪怕只是几个带数据库的 Web 服务),内存低于 2GB 就会频繁触发 OOM 杀进程。所以把 2GB 当作实用地板最稳妥。

在 2GB 这么紧的预算下,每一兆内存都要算计,三件事能把控制平面压到最低:关 swap(硬性要求,第二节已讲)、禁用 Traefik(它默认要吃 100–200MB,学习或改用 Nginx 时加 --disable traefik 关掉)、单节点用 SQLite 就够(SQLite 通过 Kine 这个垫片把 etcd 的 API 调用翻译成 SQL、落在一个本地文件,零维护,除非你要做多节点 HA 否则没必要上 etcd)。把这三件事做对,一个 2GB 单节点空闲时系统组件大约占 500MB,剩下 1GB 多可以放心交给业务 Pod。

低配机型还有几个省资源的小技巧:把不需要的组件按需禁用;镜像尽量选 alpine 这类小体积标签;磁盘尽量用 SSD(性能与稳定性都更好)。实际建议:只学 k3s 本身、跑两三个轻量服务,1GB 内存的单节点能凑合;但要跑真实网站加数据库,至少 2 vCPU、4GB 内存才舒服,留足应用余量。如果你的需求其实只是一个博客加数据库,Docker Compose 可能更轻更省心;但只要你想要多节点调度、滚动发布、Helm 生态,或者就是想认真学 K8s,k3s 在 4 美元/月的入门 VPS 上就能给你完整体验。开放端口方面,单机只需保证 6443(API)、80/443(入口)可达,多节点才需要补 8472/UDP(Flannel)与 etcd 的 2379/2380。

装好之后怎么知道机器撑不撑得住?k3s 自带 metrics-server,直接 kubectl top nodeskubectl top pods 就能看到每个节点和每个 Pod 的实时 CPU、内存占用,是发现「某个容器偷偷吃满整台 VPS」最快的办法。还有 kubectl get events --sort-by=.lastTimestamp 能列出最近的调度和运行事件,Pod 卡在 Pending 或 CrashLoopBackOff 时,先 kubectl describe pod 看原因,多半是资源不够或镜像拉不下来。至于选哪家 VPS:内存和 CPU 核心数比单核频率更重要,RackNerdContabo 这类给大内存低价的商家很适合练手(RackNerd 常年有年付十几美元档的 KVM VPS,2GB 档刚好踩在实用地板上),Vultr 胜在节点多、全线 KVM,但它最低档 VX1 只有 1GB 内存对控制平面偏小,建议选 2GB 及以上档位;按你手感挑一台 2 vCPU、4GB 起步的即可。

七、多节点与高可用:何时需要 etcd / 外部数据库

SQLite 有个铁律:它不能用于多服务器(多 Server)集群。也就是说,只要你想「多个控制节点」,SQLite 就不够用了。这时候你有两个选择,对应两种不同的成本结构。

第一种是嵌入式 etcd 高可用。适合你手里有 3 台及以上 VPS、希望控制平面本身也冗余的场景。etcd 要求奇数个 Server 节点(最少 3 个)以维持仲裁,它们之间需要互相打通 2379、2380 端口。这种方案的「成本」是实打实的:3 个节点,每台都要能跑 Server,所以整体内存和月费大约是单节点的 3 倍量级,并不便宜。

第二种是外部数据库高可用。k3s 支持把数据放到外部的 MySQL、MariaDB、PostgreSQL 或独立的 etcd 集群上,此时只需要 2 个及以上 Server 节点连同一个公共数据库即可。对于已经养着数据库团队的公司,这是更顺手的选择。但要注意 Kine 要求数据库支持预编译语句,像 PgBouncer 这类连接池、以及 Galera 这种多主 MySQL 集群是不兼容的。

那么成本会不会「翻倍」?要分情况:如果你只是想从单节点升级到「一主一从」的双节点学习集群,SQLite 压根不支持多 Server,你被迫上外部数据库或 etcd,确实要多花一台机器的钱;但如果你本来就打算用外部数据库(很多 VPS 厂商的托管数据库很便宜),那 Server 节点本身 2 台也就比 1 台多一份钱,谈不上翻几倍。对纯学习用途,我的建议很明确:单节点 SQLite 起步,别一上来就追求 HA,等你真的理解多节点调度和 Pod 跨主机网络了,再考虑加节点。

要加 Worker 节点也很简单:先在 Server 上读 /var/lib/rancher/k3s/server/node-token 拿到令牌,然后在 Worker 上带 K3S_URL(指向 Server 的 6443 端口)和 K3S_TOKEN 再跑同一脚本即可。多台机器 hostname 不能重复,重复了用 --with-node-id--node-name 区分。

八、虚拟化雷区:必须全 KVM,避开 OpenVZ/LXC

这是低价 VPS 上玩 k3s 最容易踩、也最隐蔽的坑。Kubernetes 的 kubelet 启动时需要访问一系列内核设备与参数,比如 /dev/kmsg(内核消息缓冲,kubelet 用它监听 OOM 事件)、可读写的 /proc/sys(写内核参数)、kube-proxy 要用的 IP_VS 内核模块、CNI 要用的 /dev/net/tun 等等。这些在「完整虚拟化」环境里天然存在,但在 OpenVZ、LXC 这类「容器级虚拟化」里默认缺失或只读。

后果很直接:在 OpenVZ/LXC 的 VPS 上装 k3s,kubelet 几乎必定起不来,报错多半是 open /dev/kmsg: no such file or directory,或者各种 permission denied、read-only file system。有人为了救活它,去手动 bind mount /dev/kmsg、把 LXC 改成特权容器、关掉 AppArmor、把 /proc 挂成可写——折腾一圈能跑,但稳定性和安全性都打了折扣,完全不值得。

所以结论很硬:选 VPS 必须选全 KVM 虚拟化(每个实例有独立内核),避开默认 OpenVZ/LXC 的厂商。某些低价厂商的入门档默认就是 OpenVZ/LXC,社区里「k3s 装不上」的帖子十有八九根因在此;他们的 KVM 档存在,但 SKU 标注含糊,新手容易买错。相对而言,RackNerdVultrHetznerDigitalOcean、Linode 这些整机线都是 KVM,闭眼买不会错。判断方法也简单:下单前看商品页是否写明 KVM,或者开机后执行 hostnamectl 看虚拟化类型,显示 KVM 就放心。更多背景见 虚拟化:KVM、LXC 与 Docker 区别

延伸阅读:用 Docker Compose 在 VPS 搭全家桶虚拟化:KVM、LXC 与 Docker 区别VPS 安全基础