Лёгкие дистрибутивы Kubernetes спроектированы для простоты и экономии ресурсов. k0s — один из самых «компактных» вариантов: единый бинарник, встроенный containerd, разумные дефолты. На небольшом VDS это позволяет получить полноценный кластер без громоздких установщиков и сложных зависимостей — отличный вариант для pet-проектов, staging, edge и даже аккуратного продакшна.
В этой инструкции мы развернём k0s на VDS, настроим CNI, выберем практичное динамическое хранилище и поднимем ingress без внешнего балансировщика (через hostPort/hostNetwork). Параллельно разберём firewall, версии ядра, MTU, типовые ошибки и апгрейд.
Когда k0s уместен на VDS
k0s хорош, когда нужно получить «настоящий» Kubernetes, но без лишнего веса и долгой притирки компонентов. Он:
- быстро устанавливается (единый бинарник, auto-bootstrapping control plane);
- экономно расходует CPU/RAM (важно на небольших тарифах VDS);
- совместим с привычной экосистемой: Helm, CSI/CNI, ingress-контроллеры;
- подходит для single-node и простого масштабирования до нескольких узлов.
Если вам нужен минимальный, но полноценный Kubernetes на одном или паре серверов, k0s обычно проще и стабильнее, чем самостоятельный kubeadm с ручной сборкой компонентов.
План работ
Мы пройдём следующие шаги:
- Подготовим VDS: OS, sysctl, firewall, порты и swap.
- Установим k0s (single-node controller+worker на одном сервере).
- Выберем CNI и настроим MTU.
- Добавим динамическое хранилище для PVC (local-path/OpenEBS).
- Развернём ingress-nginx без внешнего LB (hostPort).
- Проверим деплой с тестовым сервисом и Ingress.
- Обсудим апгрейды, бэкапы и масштабирование до 2–3 узлов.
Требования и подготовка VDS
Минимальные ресурсы
- CPU: 2 vCPU (минимум), 4 vCPU комфортнее;
- RAM: 4 ГБ минимально, 8 ГБ комфортнее;
- Диск: 20–40 ГБ для базового кластера, SSD.
Рекомендуемые ОС: Ubuntu 22.04/24.04 LTS или Debian 12. Ядро с поддержкой cgroup v2 и nftables (по умолчанию есть в современных LTS).
Подготовка системы
Обновления и базовые пакеты:
sudo apt update
sudo apt -y upgrade
sudo apt -y install ca-certificates curl gnupg lsof jq ufw
Отключите swap (Kubernetes этого требует):
sudo swapoff -a
sudo sed -ri '/\sswap\s/s/^/#/' /etc/fstab
Сетевые sysctl для корректной работы CNI (мост и пересылка):
# /etc/sysctl.d/99-kubernetes.conf
net.bridge.bridge-nf-call-iptables=1
net.bridge.bridge-nf-call-ip6tables=1
net.ipv4.ip_forward=1
net.ipv6.conf.all.forwarding=1
sudo sysctl --system
Желательно убедиться, что загружены модули ядра для мостов и vxlan (если выберете Flannel или kube-router):
lsmod | egrep 'br_netfilter|vxlan'
Если пусто — загрузите:
echo br_netfilter | sudo tee /etc/modules-load.d/k8s.conf
echo vxlan | sudo tee -a /etc/modules-load.d/k8s.conf
sudo modprobe br_netfilter
sudo modprobe vxlan
Firewall и порты
Базовый набор для single-node с ingress на 80/443 и kube-router/Flannel:
- 22/tcp — SSH;
- 6443/tcp — Kubernetes API (нужен для join/администрирования);
- 10250/tcp — kubelet (внутренний, обычно открыт локально);
- 8472/udp — Flannel VXLAN (или иные порты для выбранного CNI);
- 80/tcp и 443/tcp — для ingress;
- 30000–32767/tcp,udp — NodePort (если будете использовать).
sudo ufw default deny incoming
sudo ufw default allow outgoing
sudo ufw allow 22/tcp
sudo ufw allow 6443/tcp
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
sudo ufw allow 8472/udp
sudo ufw enable
Если выберете Cilium — проверьте требования к портам и возможностям ядра (eBPF). Для Calico/Flannel — убедитесь, что UDP для оверлея не блокируется провайдером.

Установка k0s (single-node)
Штатный установщик k0s — это скрипт, который скачивает/обновляет бинарник:
curl -sSLf https://get.k0s.sh | sudo sh
Поставим контроллер и воркер на один узел:
sudo k0s install controller --single
sudo k0s start
Проверим статус:
sudo k0s status
Получим kubeconfig и настроим kubectl:
sudo mkdir -p /root/.kube
sudo cp /var/lib/k0s/pki/admin.conf /root/.kube/config
sudo chown root:root /root/.kube/config
kubectl get nodes -o wide
Через пару минут узел должен перейти в Ready.
Выбор и настройка CNI
k0s поддерживает несколько CNI. Для VDS практичны:
- kube-router — простой, быстрый, без «излишеств»;
- Flannel — «классика» для оверлея VXLAN;
- Cilium — eBPF, продвинутые политики, но требует более внимательной проверки ядра/MTU.
Сконфигурировать провайдер можно через файл кластера. Базовый пример с kube-router и заданной MTU (важно на облачных сетях с меньшим MTU):
# k0s.yaml
apiVersion: k0s.k0sproject.io/v1beta1
kind: ClusterConfig
metadata:
name: vds-k0s
spec:
network:
provider: kuberouter
mtu: 1450
kubeProxy:
mode: iptables
Применение конфига при установке с нуля:
sudo k0s stop
sudo k0s install controller --single --config k0s.yaml
sudo k0s start
Если меняете CNI на работающем кластере — планируйте короткое окно: изменение сетевого провайдера затрагивает все Pod-сети. Для Cilium дополнительно может потребоваться настройка eBPF (разрешение forwarding, корректная MTU, BPF FS).
Динамическое хранилище (Storage)
Для stateful-приложений нужны PVC с динамическим провиженингом. На одном VDS комфортнее всего:
- local-path-provisioner — простой провиженер, создающий PV в локальной файловой системе;
- OpenEBS LocalPV (hostpath/LVM) — гибче, удобно задавать директории/диски.
Минимальная стратегия — local-path. После установки провиженера назначьте его классом по умолчанию. Пример StorageClass (если используете local-path-provisioner):
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: local-path
annotations:
storageclass.kubernetes.io/is-default-class: "true"
provisioner: rancher.io/local-path
volumeBindingMode: WaitForFirstConsumer
Если хотите жёстко контролировать путь хранения, подойдёт OpenEBS LocalPV hostpath: он позволяет указать директорию для томов, например /var/lib/k0s/localpv. Для продакшна на одном узле используйте регулярные бэкапы PV (rsync или снапшоты LVM — зависит от реализации).
Ingress без внешнего балансировщика
На одиночном VDS обычно нет managed LoadBalancer. Самые практичные схемы:
- ingress-nginx с hostPort 80/443 на самом узле;
- ingress-nginx с hostNetwork=true;
- или внешний Nginx на «хосте» и проксирование в Service NodePort (требует отдельного сервисного Nginx и больше ручной поддержки).
Рассмотрим вариант с hostPort (самый «чистый» для одного узла):
kubectl create namespace ingress-nginx
helm repo add ingress-nginx https://kubernetes.github.io/ingress-nginx
helm repo update
helm upgrade --install ingress-nginx ingress-nginx/ingress-nginx --namespace ingress-nginx --set controller.hostPort.enabled=true --set controller.hostPort.ports.http=80 --set controller.hostPort.ports.https=443 --set controller.service.type=ClusterIP --set controller.kind=DaemonSet
Через DaemonSet контроллер будет слушать 80/443 на узле. Если кластер станет многонодовым, все узлы с контроллером будут открывать 80/443 — обычно достаточно оставить метки и nodeSelector, чтобы ограничить узел(-ы) приёма трафика. Для выбора между Nginx/Traefik/HAProxy посмотрите наш обзор вариантов ingress-контроллеров.
Далее — пробный Ingress-объект. Сначала деплоим echo-сервис:
kubectl create namespace demo
kubectl -n demo create deployment echo --image=nginxdemos/hello
kubectl -n demo expose deployment echo --port=80 --target-port=80
Теперь Ingress (замените example.com на ваш домен и укажите A-запись на IP VDS; при необходимости — регистрация доменов):
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: echo
namespace: demo
annotations:
nginx.ingress.kubernetes.io/proxy-body-size: "20m"
spec:
ingressClassName: nginx
rules:
- host: example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: echo
port:
number: 80
Проверьте доступность по HTTP. Для HTTPS используйте cert-manager или заранее подготовленный секрет TLS. Если нужен проверенный коммерческий сертификат, оформите SSL-сертификаты. Пример с TLS-секретом:
apiVersion: v1
kind: Secret
metadata:
name: echo-tls
namespace: demo
type: kubernetes.io/tls
data:
tls.crt: BASE64_CERT
tls.key: BASE64_KEY
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: echo
namespace: demo
spec:
ingressClassName: nginx
tls:
- hosts:
- example.com
secretName: echo-tls
rules:
- host: example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: echo
port:
number: 80

В многонодовом сценарии удобно поставить MetalLB в режиме L2 и использовать Service типа LoadBalancer для ingress-nginx. На одиночном VDS hostPort/hostNetwork остаётся самым простым и надёжным вариантом.
Масштабирование: добавляем worker-узлы
k0s упрощает join: создайте токен для воркеров на контроллере и выполните установку на новых узлах.
# На контроллере:
sudo k0s token create --role=worker --expiry=24h
На новом узле установите k0s бинарник и выполните:
sudo k0s install worker --token <скопированный_токен>
sudo k0s start
Через минуту узел появится в kubectl get nodes. Проверьте MTU и firewall между узлами для вашего CNI. Если узлы в разных сетях — удобно связать их через туннель, например WireGuard; мы разбирали практику поддержания связи в статье про роуминг и keepalive.
Апгрейды k0s и кластера
Обновление k0s по месту:
curl -sSLf https://get.k0s.sh | sudo K0S_VERSION=<target> sh
sudo k0s stop
sudo k0s start
k0s version
kubectl version --short
При минорных апгрейдах соблюдайте совместимость мажорных версий Kubernetes и CRD ваших компонентов (ingress, CSI/CNI). Рекомендуются «мелкие» ступени (например, 1.28 → 1.29), предварительный бэкап и проверка на staging.
Бэкапы и восстановление
На single-node кластере критичны:
- снимки etcd;
- бэкапы PV (в зависимости от выбранного провиженера: файловые копии, снапшоты LVM или экспорт).
Снимок etcd с контроллера:
sudo k0s etcd snapshot save /var/lib/k0s/etcd-snap-$(date +%F-%H%M).db
ls -lh /var/lib/k0s/
Храните бэкапы вне узла (объектное хранилище или другой сервер). Регулярно тестируйте восстановление — хотя бы на временном узле.
Наблюдаемость и базовый SRE-минимум
- metrics-server для
kubectl topи HPA; - логирование: fluent-bit → централизованное хранилище или локально в journald с ротацией;
- алертинг: минимум health-checks на API-сервер и HTTP 200 на ingress-домены.
Проверьте лимиты контейнеров: выставляйте resources.requests/limits, иначе одно приложение может «съесть» всю RAM/CPU узла. Для ingress-nginx задайте разумные таймауты (proxy-read-timeout, proxy-body-size) через аннотации/ConfigMap.
Частые проблемы и решения
- Pod в статусе CrashLoopBackOff: проверьте
kubectl logs, ресурсы, образ, переменные окружения. - Распадается сеть между узлами: проверьте MTU, открыты ли порты CNI, не режет ли провайдер UDP.
- Ingress 404/502: верен ли
ingressClassName(обычноnginx), совпадает ли host, существует ли Service/Endpoints. - DNS не резолвит: статус CoreDNS, проверка
kube-dnsService, сетевой плагин. - Проблемы с TLS: корректен ли секрет, совпадают ли CN/SAN и домен, нет ли лишних переносов при base64.
Продакшн-минимум для VDS-кластера
- Отдельный системный пользователь и SSH-ключи, fail2ban/защита SSH.
- Автообновления безопасности ОС и перезагрузка ядра в плановое окно.
- Мониторинг доступности API-сервера, ingress-доменов, диска и inode.
- Регулярные бэкапы etcd и PV, проверка восстановления.
- Ресурсные запросы/лимиты, Readiness/Liveness пробы в ваших Deployment.
- Разделение namespace, RBAC для сервисных аккаунтов, секреты через Secret/External Secrets.
Что дальше
Для нескольких узлов: MetalLB (L2) + Service LoadBalancer для ingress-nginx; Cilium eBPF для сетевых политик; OpenEBS LVM для предсказуемого локального хранения; cert-manager для автоматизации TLS; GitOps и Helm-чарты для повторяемых деплоев. Для миграций доменов и TLS-практик также будет полезна статья о HSTS и 301.
k0s даёт современный Kubernetes-опыт без перегруза — особенно на VDS. С правильным выбором CNI, storage и ingress ваш кластер будет достаточно лёгким для небольших бюджетов и достаточно гибким для роста.


