Как установить и настроить k3s на VPS
Полноценный Kubernetes на VPS с двумя гигабайтами памяти не заводится: один kube-apiserver съедает больше, чем есть у машины. k3s решает ту же задачу одним бинарником на ~70 МБ, внутри которого уже лежат containerd, CoreDNS и Traefik. Разберём, как выглядит k3s установка на VPS от подготовки системы до приложения с HTTPS — с командами, текстами ошибок и граблями арендованной машины.
Содержание
- Что такое k3s и что он тянет за собой
- Готовим VPS: виртуализация, cgroup, swap и порты
- Установка сервера: config.yaml до запуска, а не после
- kubeconfig: доступ к кластеру снаружи и ошибка x509
- Воркер-ноды: как соединить несколько VPS в один кластер
- Первое приложение: Ingress, TLS, диск и реестр образов
- Какой сервер взять под k3s в MAATRIX
Обсудить статью, задать вопрос или начать новую тему
Есть вопрос по этой статье, идея для обсуждения или просто хотите поделиться опытом? Сообщество MAATRIX ждёт. Для общения, пожалуйста, зарегистрируйтесь в нашем личном кабинете.
Перейти в сообщество →Что такое k3s и что он тянет за собой
k3s — дистрибутив Kubernetes от SUSE, сертифицированный CNCF. Это не урезанная копия: те же манифесты, kubectl и Helm-чарты. Отличие в упаковке: вместо пяти сервисов и внешнего etcd — один бинарник и один юнит systemd, а внутри собрано то, что ставят обычно отдельно:
| Компонент | Что делает | Как отключить |
|---|---|---|
| flannel (VXLAN) | сеть подов, 10.42.0.0/16 | --flannel-backend=none |
| CoreDNS | DNS кластера на 10.43.0.10 | --disable=coredns |
| Traefik v3 | Ingress-контроллер на 80/443 | --disable=traefik |
| local-path-provisioner | PVC в /var/lib/rancher/k3s/storage | --disable=local-storage |
Главное отличие: состояние лежит не в etcd, а в SQLite через слой kine — файл /var/lib/rancher/k3s/server/db/state.db. Это экономит сотни мегабайт, но означает одно: отказоустойчивого control-plane на SQLite не бывает. Для HA нужен встроенный etcd: --cluster-init и три сервера.
Готовим VPS: виртуализация, cgroup, swap и порты
До установки проверьте тип виртуализации и версию cgroup. На OpenVZ и большинстве LXC-контейнеров k3s либо не стартует, либо ведёт себя непредсказуемо: нет своего ядра, не грузятся overlay и br_netfilter.
systemd-detect-virt
stat -fc %T /sys/fs/cgroup/
Первая должна ответить kvm, qemu или none; openvz или lxc — берите другой сервер. Вторая — cgroup2fs: на Ubuntu 24.04, Debian 12/13 и AlmaLinux 9/10 так из коробки, tmpfs означает cgroup v1 с худшими лимитами.
Swap выключаем: kubelet считает память без его учёта, и вытеснение подов становится случайным. Часы синхронизируйте через timedatectl set-ntp true — сертификаты кластера завязаны на время.
swapoff -a
sed -i '/ swap / s/^/#/' /etc/fstab
hostnamectl set-hostname k3s-uk-1
Уникальное имя хоста задавайте до установки: машины разворачивают из готового образа, и две ноды приезжают с одинаковым ubuntu-2204 — выстрелит это при добавлении воркера. Дальше фаервол:
ufw allow 22/tcp
ufw allow 6443/tcp
ufw allow 80,443/tcp
ufw allow from 10.42.0.0/16 to any
ufw allow from 10.43.0.0/16 to any
ufw --force enable
Две последние строки критичны и их постоянно забывают: без подсетей подов и сервисов ufw режет внутрикластерный трафик, и в логах появляется dial tcp 10.43.0.10:53: i/o timeout. Выглядит как «сломался CoreDNS», хотя сломан фаервол.
Развернуть за пару минут
Готовый образ на VPS MAATRIX: NVMe, AMD EPYC, root-доступ. Локации UK, США, Франция и РФ. Оплата картой РФ и по СБП.
Развернуть k3sУстановка сервера: config.yaml до запуска, а не после
Типовая инструкция предлагает curl -sfL https://get.k3s.io | sh - и разбираться потом. На VPS правильнее сначала положить конфиг: тогда первый запуск выпишет сертификаты с нужными именами.
mkdir -p /etc/rancher/k3s
cat >/etc/rancher/k3s/config.yaml <<'EOF'
node-name: k3s-uk-1
write-kubeconfig-mode: "0600"
tls-san:
- 185.203.11.42
- k3s.example.com
disable:
- metrics-server
EOF
Файл принимает имена флагов без двух дефисов. tls-san — дополнительные адреса в сертификате API-сервера: публичный IP и домен. metrics-server выключайте, если не нужен kubectl top: минус около 60 МБ. Версию не оставляйте на самотёк:
curl -s https://update.k3s.io/v1-release/channels | jq -r '.data[] | select(.name=="stable") | .latest'
curl -sfL https://get.k3s.io | INSTALL_K3S_CHANNEL=stable sh -
Первая ответит вроде v1.33.4+k3s1; нужна конкретная — передайте её в INSTALL_K3S_VERSION. Скрипт положит бинарник в /usr/local/bin/k3s, симлинки kubectl, crictl, ctr и юнит k3s.service. До состояния Ready на 2 vCPU — около 40 секунд.
k3s kubectl get nodes -o wide
NAME STATUS ROLES AGE VERSION INTERNAL-IP CONTAINER-RUNTIME
k3s-uk-1 Ready control-plane,master 62s v1.33.4+k3s1 10.0.0.5 containerd://2.0.5-k3s2
Самопроверка k3s check-config скажет, чего не хватает в ядре провайдера. Где что лежит: данные и БД — /var/lib/rancher/k3s/, kubeconfig — /etc/rancher/k3s/k3s.yaml, токен воркеров — /var/lib/rancher/k3s/server/node-token; YAML из /var/lib/rancher/k3s/server/manifests/ применяется при старте сам. По памяти: на тестовом VPS 2 vCPU / 2 ГБ free -m показывает порядка 600 МБ в покое, из них ~500 МБ — сам k3s; без Traefik и metrics-server — 430 МБ.
kubeconfig: доступ к кластеру снаружи и ошибка x509
На сервере проще работать через k3s kubectl. Если запустить голый kubectl, встретите классику:
The connection to the server localhost:8080 was refused - did you specify the right host or port?
kubectl просто не знает, где кластер, и идёт на localhost:8080. Лечится копией конфига — sudo install -o "$USER" -g "$USER" -m 600 /etc/rancher/k3s/k3s.yaml ~/.kube/config. Частый совет выставить write-kubeconfig-mode: "0644" вредный: в файле сертификат уровня cluster-admin, и 644 отдаёт полный доступ к кластеру любому пользователю машины. Чтобы управлять с ноутбука, конфиг забирают и подменяют адрес:
ssh root@185.203.11.42 cat /etc/rancher/k3s/k3s.yaml | sed 's/127.0.0.1/185.203.11.42/' > ~/.kube/k3s-uk.yaml
chmod 600 ~/.kube/k3s-uk.yaml && export KUBECONFIG=~/.kube/k3s-uk.yaml
И здесь вылезает ошибка, из-за которой кластер часто сносят заново:
Unable to connect to the server: tls: failed to verify certificate: x509: certificate is valid for 10.43.0.1, 127.0.0.1, 10.0.0.5, ::1, not 185.203.11.42
Сертификат выписан на внутренние адреса, а вы стучитесь по публичному — от этого и спасает tls-san. Добавьте адрес и выполните systemctl restart k3s; если ошибка осталась, старый сертификат никуда не делся — удалите его:
rm -f /var/lib/rancher/k3s/server/tls/serving-kube-apiserver.{crt,key}
systemctl restart k3s
Корневой CA не меняется, скопированный kubeconfig останется рабочим. И про безопасность: открытый в интернет 6443 будут сканировать — ограничьте источник через ufw allow from 203.0.113.7 to any port 6443 proto tcp либо ходите SSH-туннелем ssh -N -L 6443:127.0.0.1:6443 root@185.203.11.42.
Воркер-ноды: как соединить несколько VPS в один кластер
Токен лежит в /var/lib/rancher/k3s/server/node-token, вид у него такой: K10c9f3...::server:1a2b3c.... На втором VPS:
curl -sfL https://get.k3s.io | K3S_URL=https://185.203.11.42:6443 \
K3S_TOKEN='K10c9f3...::server:1a2b3c...' sh -s - agent \
--node-ip 91.198.174.12 --node-external-ip 91.198.174.12
Флаги --node-ip и --node-external-ip обязательны, когда ноды в разных дата-центрах: иначе агент объявит серверу приватный адрес внутренней сети, и поды на разных нодах не свяжутся. Дальше две ошибки из journalctl -u k3s-agent -f:
level=error msg="Failed to validate connection to cluster at https://185.203.11.42:6443: Get \"https://185.203.11.42:6443/cacerts\": dial tcp 185.203.11.42:6443: i/o timeout"
Это фаервол: 6443 закрыт для IP агента, откройте его адресно. Вторая ошибка — следствие клонирования VPS из снапшота:
Node password rejected, duplicate hostname or contents of '/etc/rancher/node/password' may not match server node-passwd entry
k3s привязывает пароль ноды к имени, а у вас две машины с одинаковым hostname. Лечение — уникальное имя и снос пароля на агенте и записи на сервере:
hostnamectl set-hostname k3s-uk-2
rm -f /etc/rancher/node/password
kubectl -n kube-system delete secret k3s-uk-2.node-password.k3s
systemctl restart k3s-agent
Порты кластера: 6443/tcp на серверы, 8472/udp между нодами (VXLAN flannel), 10250/tcp (метрики kubelet), 2379-2380/tcp между серверами при etcd, 51820/udp при WireGuard. И главное про ноды в разных ДЦ: flannel в режиме VXLAN не шифрует трафик — поды общаются по интернету открытым текстом. Ставьте первый сервер сразу со строкой flannel-backend: wireguard-native в config.yaml, на лету режим не переключается; плата — 10–15% пропускной способности. Следите за MTU: VXLAN отъедает 50 байт от кадра, и симптом просевшего MTU — зависающие TLS-рукопожатия при живом ping, проверка ping -M do -s 1372 91.198.174.12.
Первое приложение: Ingress, TLS, диск и реестр образов
Traefik уже слушает 80 и 443 через ServiceLB, свой балансировщик не нужен. Тег cert-manager сверьте с актуальным релизом.
kubectl create deployment web --image=nginx:1.29-alpine --replicas=2
kubectl expose deployment web --port=80
kubectl apply -f https://github.com/cert-manager/cert-manager/releases/download/v1.18.2/cert-manager.yaml
Выпускающий центр и ингресс одним манифестом:
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
name: letsencrypt-prod
spec:
acme:
server: https://acme-v02.api.letsencrypt.org/directory
email: admin@example.com
privateKeySecretRef: {name: letsencrypt-prod}
solvers: [{http01: {ingress: {class: traefik}}}]
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: web
annotations: {cert-manager.io/cluster-issuer: letsencrypt-prod}
spec:
ingressClassName: traefik
tls: [{hosts: [app.example.com], secretName: web-tls}]
rules:
- host: app.example.com
http:
paths:
- {path: /, pathType: Prefix, backend: {service: {name: web, port: {number: 80}}}}
Через минуту kubectl get certificate покажет READY True. Если False — kubectl describe challenge: почти всегда A-запись ещё не указывает на IP ноды либо закрыт 80-й порт, без которого HTTP-01 не пройдёт.
Диск: StorageClass local-path работает из коробки, данные ложатся в /var/lib/rancher/k3s/storage/. Ограничение существенное — том привязан к ноде, только ReadWriteOnce, репликации нет: потеряли ноду, потеряли данные. Для нескольких нод — Longhorn.
Реестр образов — частая внезапная проблема при установке с российского адреса:
Failed to pull image "nginx:1.29-alpine": failed to resolve reference "docker.io/library/nginx:1.29-alpine": unexpected status from HEAD request to https://registry-1.docker.io/v2/library/nginx/manifests/1.29-alpine: 403 Forbidden
Docker Hub отдаёт 403 на диапазоны российских провайдеров. Лечится зеркалом в /etc/rancher/k3s/registries.yaml; после правки обязателен systemctl restart k3s — файл читается только при старте.
mirrors:
docker.io:
endpoint:
- "https://mirror.gcr.io"
На ноде в Лондоне или Нью-Йорке этой возни нет: Docker Hub, ghcr.io и quay.io отдают образы напрямую. Из эксплуатации помните: обновление — повторный запуск установщика, сначала серверы, потом агенты; бэкап — k3s etcd-snapshot save или копия state.db на остановленном сервисе; чистка — k3s crictl rmi --prune, сам containerd образы не удаляет.
Какой сервер взять под k3s в MAATRIX
У k3s жёсткий пол: control-plane в покое занимает 500–600 МБ. На VPS с 1 ГБ на поды остаётся 300–400 МБ, и первая же сборка или миграция БД закончится OOMKilled с кодом 137.
| Сценарий | Конфигурация | Что реально помещается |
|---|---|---|
| Изучить, тестовый стенд | 2 vCPU / 2 ГБ / 30 ГБ NVMe | k3s и 3–5 лёгких подов |
| Один боевой узел | 4 vCPU / 8 ГБ / 80 ГБ NVMe | 15–25 подов: БД, кэш, 2–3 приложения, раннер CI |
| Сервер и два воркера | 4/8 ГБ + 2 × 2/4 ГБ | разнос нагрузки, обновление нод без простоя |
| HA control-plane | 3 × 4 vCPU / 8 ГБ / 80 ГБ | встроенный etcd, переживает падение одной ноды |
Три уточнения. Диск обязательно NVMe: SQLite и etcd упираются в задержку fsync, на медленном хранилище API-сервер сыплет etcdserver: request timed out. Объём берите с запасом — 20 ГБ уходят за пару месяцев деплоев на слои образов и логи в /var/log/pods. И не растягивайте HA-тройку по странам: etcd плохо переносит RTT выше 20–30 мс между членами кворума.
По локации для k3s мы обычно советуем UK, Лондон: 10–20 мс до европейских точек обмена, GDPR-периметр для клиентов из ЕС и чистый IP — образы из Docker Hub, ghcr.io и quay.io тянутся без 403 и зеркал, Let's Encrypt проходит HTTP-01 без сюрпризов. FR даёт то же для континентальной Европы, US в Нью-Йорке — если в кластере есть обращения к зарубежным ИИ-API, RU — когда данные обязаны лежать в России по 152-ФЗ. Оплата — картами РФ, по СБП, криптой или токеном MAAT.
Развернуть за пару минут
Готовый образ на VPS MAATRIX: NVMe, AMD EPYC, root-доступ. Локации UK, США, Франция и РФ. Оплата картой РФ и по СБП.
Развернуть k3sОбсудить статью, задать вопрос или начать новую тему
Есть вопрос по этой статье, идея для обсуждения или просто хотите поделиться опытом? Сообщество MAATRIX ждёт. Для общения, пожалуйста, зарегистрируйтесь в нашем личном кабинете.
Перейти в сообщество →Частые вопросы
Можно ли поставить k3s на VPS с 1 ГБ RAM?
Технически да, кластер поднимется. Но control-plane заберёт 500–600 МБ, и на контейнеры останется меньше половины гигабайта. Рабочий минимум — 2 ГБ, боевой — 4 ГБ.
k3s — настоящий Kubernetes?
Да, сертифицированный CNCF: те же манифесты, kubectl, Helm и операторы. Отличия в упаковке — один бинарник вместо набора сервисов и SQLite вместо etcd по умолчанию.
Как удалить k3s начисто?
Запустите /usr/local/bin/k3s-uninstall.sh на сервере или /usr/local/bin/k3s-agent-uninstall.sh на агенте. Скрипт удалит и /var/lib/rancher/k3s вместе с данными PVC — сначала сделайте копию нужного.
Нужны сами нейросети для контента?
Генерируйте изображения, видео и озвучку нейросетями на falapi.io — десятки моделей в одном окне. Оплата картой РФ и по СБП.