Сравнение дистрибутивов Kubernetes для хоумлаба из 3 узлов

Выбор лучшего варианта Kubernetes для нашего домашнего лабораторного стенда

Содержимое страницы

Я сравниваю варианты самонастраиваемых Kubernetes, подходящие для хоумлаба на основе Ubuntu с 3 узлами (16 ГБ ОЗУ, 4 ядра каждый), с акцентом на простоте установки и обслуживания, поддержке постоянных томов и LoadBalancers.

Сценарий: У нас есть три узла Ubuntu (16 ГБ ОЗУ, 4 ядра CPU каждый) в хоумлабе. Высокая доступность (HA) и поддержка ARM не являются приоритетами. Мы хотим легко установить и поддерживать кластер Kubernetes (либо одноузловой, либо трехузловой) с поддержкой Persistent Volumes (PV) и LoadBalancer (LB) сервисов (чтобы облачные приложения, требующие хранения или внешних IP, работали плавно). Мы сосредоточимся на вариантах трехузлового кластера без требований к HA или совместимости с процессорами ARM.

kubernetes homelab

Ниже мы сравниваем популярные легковесные распространения KubernetesK3s, MicroK8s, Minikube и kubeadm (чистый Kubernetes) – и как они соотносятся по ключевым критериям (функциональность, установка/обслуживание, поддержка PV/LB, требования к ресурсам, настройка кластера и инструменты). Также дадим рекомендации по выбору на основе сценария хоумлаба.

K3s (легковесный Kubernetes от Rancher)

Основные особенности: K3s – это сертифицированное CNCF распределение Kubernetes, разработанное для минимального использования ресурсов (может работать даже с 512 МБ ОЗУ). Оно упаковывает весь контрольный план Kubernetes в один бинарный файл и процесс, используя легковесные компоненты (например, SQLite в качестве хранилища данных по умолчанию вместо etcd, flannel для сетевых настроек). Включает разумные настройки по умолчанию, такие как встроенный контроллер входящего трафика (Traefik) и простой сервисный балансировщик нагрузки. K3s удаляет устаревшие/альфа-функции, чтобы уменьшить избыточность.

  • Простота установки и обслуживания: Очень простая - можно установить с помощью однострочного скрипта (curl ... | sh) или через инструменты вроде K3sup. Сервер запускается с компонентами по умолчанию. Добавление узлов простое (запуск агента K3s с токеном от сервера). Обновление легко (замена бинарного файла или использование скрипта установки для новой версии). Не требуется отдельная настройка etcd (если только не выбирается многомастерная HA-конфигурация). K3s разработан для минимального вмешательства после установки, что делает его популярным для IoT и хоумлабов.

  • Поддержка Persistent Volume: Встроенная. По умолчанию K3s поставляется с StorageClass Rancher’s local-path, который динамически создает PVs в файловой системе хоста для каждого PVC. Это означает, что любой PVC будет выполнен путем создания volume hostPath на узле автоматически. Это решение для хранения на одном узле (каждый том находится на диске одного узла), но работает из коробки для приложений с состоянием. Для более продвинутого хранения можно добавить что-то вроде Rancher’s Longhorn (распределенное блоковое хранилище), которое поддерживается K3s, но для хоумлаба обычно достаточно поставщика local-path по умолчанию.

  • Поддержка LoadBalancer: Встроенная. K3s включает легковесный контроллер под названием ServiceLB (ранее “Klipper LB”), который позволяет сервисам типа LoadBalancer получать IP/порт на хосте без внешнего облачного провайдера. Когда мы создаем сервис LoadBalancer, K3s развертывает DaemonSet из небольших LB-подов (svc-...) на каждом узле, которые используют порты хоста для перенаправления трафика на сервис. Суть в том, что K3s использует IP узла (внутренний или внешний) в качестве IP LB и применяет маршрутизацию iptables в LB-подах для отправки трафика на ClusterIP сервиса. Это работает без настройки – сервисы не будут оставаться в состоянии “ожидания” (в отличие от чистого K8s на голом металле). Компромисс заключается в том, что внешний IP LB будет одним из IP наших узлов (или всеми узлами), и мы должны убедиться, что порт свободен. Для большинства задач хоумлаба (открытие нескольких сервисов на портах HTTP/HTTPS), это вполне приемлемо. Если необходимо, мы можем отключить встроенный LB и установить MetalLB вручную, но большинство пользователей остаются с удобным решением по умолчанию.

  • Требования к ресурсам: Очень низкие. K3s может работать даже на слабом оборудовании. Официально, 512 МБ ОЗУ и несколько сотен МБ дискового пространства достаточно для серверного узла. На практике, небольшой кластер может использовать несколько сотен МБ памяти для контрольного плана. Его бинарный файл меньше 100 МБ. Нагрузка на CPU минимальна (K3s использует немного больше CPU в режиме простоя по сравнению с MicroK8s, но не на значительную величину). Наши узлы (по 16 ГБ каждый) более чем достаточно, чтобы комфортно запускать K3s.

  • Одноузловый vs Многоузловый: Подходит для обоих. K3s может работать в одноузловом режиме (весь контрольный план и рабочие нагрузки на одном компьютере) или в многоузловом. Для трехузловой конфигурации мы можем запустить 1 сервер (мастер) и 2 агента, или даже сделать все 3 серверами для HA (что не требуется в нашем случае, так как HA не является целью). Добавление агентов тривиально с помощью токена. Встроенное хранилище SQLite K3s работает для одного сервера; для многомастерной HA мы бы переключились на встроенный etcd (K3s может сделать это автоматически при запуске нескольких серверных узлов).

  • CLI & UI Инструменты: Мы взаимодействуем с K3s так же, как с любым Kubernetes – через kubectl. K3s включает свой собственный сборку kubectl (мы можем запустить k3s kubectl ... или просто использовать стандартный kubectl, указав ему kubeconfig K3s). Нет специального CLI для K3s, кроме команд установки; это намеренно минималистично. Встроенного веб-интерфейса нет (стандартная панель управления Dashboard не устанавливается по умолчанию). Однако мы можем вручную развернуть Kubernetes Dashboard или другие инструменты на K3s, как на любом стандартном кластере. Rancher (GUI-инструмент управления от той же компании) также можно установить поверх K3s, если требуется полноценный интерфейс, но он не является частью K3s. Суть в том, что K3s предоставляет основные API k8s, и мы добавляем дополнительные функции по мере необходимости (ингресс, хранилище и т.д. – некоторые из которых уже включены, как упоминалось).

MicroK8s (легковесный Kubernetes от Canonical)

Основные особенности: MicroK8s – это легковесное распределение Kubernetes от Canonical, поставляемое в виде пакета snap. Оно устанавливает полностью соответствующий Kubernetes кластер (бинарные файлы из основного репозитория) с помощью одной команды и разработано для простоты использования (“низкие затраты на обслуживание”) на одном компьютере или небольшом кластере. Оно делает акцент на “все включено” – мы получаем множество опциональных функций, которые можно включить с помощью простых команд. MicroK8s по умолчанию предоставляет чистый Kubernetes (все стандартные API), но с удобными дополнениями для распространенных задач. Оно поддерживает как одноузловые, так и многоузловые развертывания (мы можем создать кластер, “присоединив” узлы), и даже имеет режим HA для контрольного плана (используя Dqlite – распределенный SQLite – когда у нас есть 3 мастера).

  • Простота установки и обслуживания: Очень простая – просто snap install microk8s --classic на машине с Ubuntu установит узел Kubernetes. Это один пакет, который включает все компоненты. MicroK8s обновляется через систему snap Ubuntu, что означает атомарные обновления, которые могут быть автоматическими (мы можем отслеживать канал для версий Kubernetes). Эта автоматическая обновляемость уникальна среди этих вариантов - мы можем подписаться на получение обновлений безопасности и незначительных обновлений через snap refreshes. Управление MicroK8s осуществляется через команду microk8s, которая имеет подкоманды для включения/отключения функций. В целом, это очень низкоуровневое решение: нет контейнеров или виртуальных машин для управления (работает нативно на хосте), и нет внешнего etcd для настройки (используется внутреннее хранилище данных). Обслуживание в основном сводится к обновлению snap при необходимости и использованию microk8s.status для мониторинга.

  • Поддержка Persistent Volume: Доступна через дополнение. По умолчанию MicroK8s не автоматически создает PVs, пока мы не включим дополнение “hostpath-storage”. Включение этого (microk8s enable hostpath-storage) создает StorageClass по умолчанию, который выделяет тома из директории на хосте. Это, по сути, динамический поставщик hostPath, аналогичный по концепции local-path K3s. После включения любой PVC будет привязан к hostpath PV на узле MicroK8s. (В многоузловом кластере MicroK8s hostpath PV будет находиться на одном узле – подходящий вариант для тестирования или использования в хоумлабе, но не для распределенного хранения). MicroK8s также предлагает Mayastor и другие дополнения для хранения, если нам нужно более продвинутое решение на нескольких узлах, но для простоты hostpath-хранилище работает хорошо. Примечание: Дополнение не включено по умолчанию (чтобы сохранить компактность), поэтому мы захотим включить его, чтобы PVC работали. Canonical отмечает, что это не для использования в производственной среде с высокой доступностью (поскольку оно не реплицируется), но для хоумлаба это идеально.

  • Поддержка LoadBalancer: Доступна через дополнение. MicroK8s не включает балансировщик нагрузки по умолчанию, но предоставляет MetalLB как простое дополнение. Запуск microk8s enable metallb:<start-IP>-<end-IP> развертывает MetalLB в режиме Layer 2 и позволяет нам указать пул IP из нашей локальной сети для сервисов LoadBalancer. После включения любой сервис типа LoadBalancer автоматически получит IP из этого диапазона (и MicroK8s будет рекламировать его через ARP в локальной сети). Это дает облачный опыт на голом металле. (Если мы не включим MetalLB, сервис LoadBalancer останется в состоянии ожидания, так как MicroK8s сам по себе не реализует его – как и стандартный Kubernetes.) В хоумлабе MetalLB прост в использовании и позволяет получать доступ к сервисам в локальной сети. Нам нужно будет выбрать свободный подсеть или диапазон IP в нашей сети для него. Команда enable MicroK8s делает настройку безболезненной, но это все же отдельный шаг. (В отличие от K3s, который работает из коробки для LB, но с ограничением использования IP/портов узлов.) Многие пользователи MicroK8s просто включают MetalLB в процессе начальной настройки для функционального LB.

  • Требования к ресурсам: MicroK8s довольно легковесный, хотя немного больше K3s по объему. Он запускает все основные сервисы (сервер API, контроллер, планировщик, kubelet, etcd или Dqlite) нативно. Потребление памяти в режиме простоя обычно составляет \ 500–600 МБ для контрольного плана, в зависимости от включенных дополнений. Canonical указывает \ 540 МБ памяти в качестве базового значения. Потребление CPU низкое в режиме простоя, и наши узлы с 16 ГБ имеют достаточно запаса. Требования к дисковому пространству небольшие (snap \ 200 МБ плюс данные etcd). В сумме, MicroK8s может работать на скромном оборудовании (его даже предлагают для Raspberry Pi), и в нашем сценарии машины легко его поддерживают. Если включено несколько дополнений (панель управления, мониторинг и т.д.), потребление ресурсов увеличится соответственно.

  • Одноузловый vs Многоузловый: MicroK8s хорошо работает для обоих. Мы можем использовать его для одноузлового кластера (например, на машине разработчика или одном сервере) или создать многоузловой кластер, “присоединив” узлы. Документация MicroK8s предоставляет команду для добавления узла (мы получаем токен присоединения с первого узла и используем его на других). В многоузловой конфигурации без HA один узел будет основным контрольным планом. С тремя узлами у нас также есть возможность включить режим ha-cluster (сделать контрольный план высокодоступным, запустив Dqlite на 3 узлах), хотя в нашем случае HA не требуется. Будь то один или три узла, опыт работы с Kubernetes API одинаковый. Многоузловой MicroK8s немного новее, чем подход K3s, но сейчас он довольно стабилен. Это хороший выбор, если мы хотим “микро-облако” из нескольких коробок Ubuntu с Kubernetes с минимальными усилиями.

  • CLI & UI Инструменты: MicroK8s поставляется с командной строкой microk8s, которая очень удобна. Например, microk8s enable <addon> переключает различные сервисы (DNS, ингресс, хранилище, metallb, панель управления и т.д.), и microk8s status показывает, что запущено. Он также включает встроенный kubectl: мы можем использовать microk8s kubectl ... (или создать псевдоним) для взаимодействия с кластером – это удобно, потому что не нужно настраивать kubeconfig. Для интерфейса MicroK8s предоставляет Kubernetes Dashboard как дополнение (microk8s enable dashboard), которое развернет стандартный веб-интерфейс. После включения мы можем получить к нему доступ (он работает на порту 10443 или через прокси). MicroK8s не имеет собственного пользовательского интерфейса – он полагается на Kubernetes Dashboard или другие инструменты – но простота его включения является плюсом. В итоге, MicroK8s делает акцент на одномаштинном опыте для распространенных задач и философии “просто работает”, абстрагируя много сложности (в ущерб скрытию некоторых внутренних деталей). Это делает его очень дружественным для хоумлабов тем, кто хочет кластер Kubernetes без ручной настройки каждого компонента.

Сравнение K3s vs MicroK8s: Оба очень похожи по целям и возможностям – легковесные, простые, поддерживают многоузловые конфигурации. K3s склонен быть немного более “DIY” при добавлении дополнительных функций (полагаясь на Helm-чарты или ручные манифесты для того, что не включено), тогда как MicroK8s предлагает встроенные дополнения через свой CLI. MicroK8s также более “чистый” Kubernetes под капотом (компоненты из основного репозитория, просто упакованные как snap), тогда как K3s использует некоторые собственные бинарные файлы и один сервис для всего. Оба хороши для хоумлабов; выбор часто сводится к предпочтениям: если Ubuntu/snaps и интегрированный интерфейс предпочтительнее, MicroK8s отличный вариант, тогда как если мы предпочитаем минималистичный подход с возможностью немного большего ручного контроля, K3s отлично подходит. (Мы дадим рекомендации в конце.)

Minikube (Локальный Kubernetes на одном узле)

Основные особенности: Minikube в первую очередь это инструмент для запуска Kubernetes локально (часто на компьютере разработчика или ноутбуке), а не традиционного кластера на нескольких машинах. Он создает одноузловой кластер Kubernetes в виртуальной машине или контейнере на нашем устройстве. Minikube известен своей широкой поддержкой различных сред - он может работать на Linux, macOS, Windows и поддерживает различные гипервизоры (VirtualBox, KVM, Hyper-V, драйвер Docker и т.д.). Он поддерживается Kubernetes SIGs и часто используется для тестирования и обучения. Хотя Minikube может быть настроен в многозловом режиме, он в первую очередь предназначен для одноузловых кластеров (режим “многозлового” Minikube фактически просто запускает несколько узлов на одном хосте с использованием контейнерных runtime - полезно для симуляции кластера, но не для запуска на отдельных физических машинах).

  • Простота установки и использования: Minikube очень легко начать использовать на одном компьютере. Мы устанавливаем бинарный файл minikube, убеждаемся, что у нас есть драйвер виртуальной машины (или Docker), и запускаем minikube start. Это настроит локальную виртуальную машину/контейнер и запустит Kubernetes внутри него. Это, пожалуй, самый простой способ запустить кластер Kubernetes впервые. CLI (minikube) предоставляет команды для взаимодействия с виртуальной машиной (запуск, остановка, удаление) и для включения дополнительных модулей. Поскольку Minikube предназначен для локального использования, это не “долгоживущий” демон - мы обычно запускаем его, когда он нам нужен, и останавливаем, когда закончили, хотя мы можем оставить его работать непрерывно на сервере домашней лаборатории, если хотим. Обслуживание/обновления просты: просто обновите версию minikube и перезапустите кластер (Minikube также может обновить версию Kubernetes, которую он запускает, с помощью флага). Однако одним из ограничений является то, что Minikube по дизайну одноузловой (добавление дополнительных узлов означает запуск дополнительных экземпляров виртуальных машин на одном и том же хосте, а не присоединение реальных отдельных хостов). Таким образом, использование Minikube на трех отдельных физических узлах фактически означает запуск трех независимых одноузловых кластеров, что, вероятно, не то, что нам нужно. Minikube отлично подходит для разработки и тестирования на одном компьютере, но не предназначен для управления кластером, распределенным по нескольким физическим серверам.

  • Поддержка Persistent Volume: Встроенная (hostPath). Кластеры Minikube автоматически включают стандартный StorageClass, который использует провизионер hostPath. На самом деле, Minikube запускает небольшой контроллер, который динамически создает PVs hostPath внутри виртуальной машины при запросе PVCs. Это означает, что мы можем создавать PersistentVolumeClaims, и они будут удовлетворены с использованием хранилища на файловой системе виртуальной машины Minikube (обычно под /tmp/hostpath-provisioner или аналогично). Это работает из коробки - никакой конфигурации не требуется для базового использования PV. Например, стандартный StorageClass “standard” в Minikube отображается на хранилище hostPath на узле. Одно уточнение: если мы перезапустим или удалим виртуальную машину Minikube, эти volumes hostPath могут быть потеряны (Minikube пытается сохранять определенные каталоги между перезапусками - например, /data, /var/lib/minikube, /tmp/hostpath* сохраняются). Но в целом, для не производственной среды это нормально. Если мы хотим симулировать больше, Minikube также имеет дополнение CSI hostpath driver, которое поддерживает создание снимков и может работать в многозловом режиме, но это больше для экспериментов. Итог: Minikube поддерживает PVs по умолчанию через hostPath, что достаточно для тестирования stateful приложений в домашней лаборатории.

  • Поддержка LoadBalancer: Поддерживается через туннелирование (или дополнение MetalLB). В облаке сервис LoadBalancer получает облачный LB с внешним IP. В Minikube, конечно, нет поставщика облака, поэтому Minikube предоставляет два механизма:

    • Minikube Tunnel: Мы можем запустить minikube tunnel в отдельном процессе, который создаст маршрут сети на нашем хосте и назначит IP для нашего сервиса LoadBalancer. Суть в том, что он использует наш хост в качестве “внешнего LB”. Когда мы создаем сервис LoadBalancer, Minikube покажет “внешний IP” (обычно из подсети кластера), и процесс minikube tunnel будет маршрутизировать его к сервису. Это требует, чтобы процесс туннеля продолжал работать (и обычно требует прав root для создания маршрутов). Это немного ручной шаг, но Minikube выводит напоминание, если у нас есть сервис LoadBalancer без работающего туннеля (“External-IP pending” до тех пор, пока мы не запустим туннель).
    • Дополнение MetalLB: Более новые версии Minikube также включают дополнение MetalLB. Мы можем выполнить minikube addons enable metallb и настроить диапазон IP (Minikube предложит нам). Это фактически развертывает MetalLB внутри кластера Minikube, который затем обрабатывает сервисы LoadBalancer так же, как на любом bare-metal Kubernetes. Это более “внутри кластера” решение и не требует отдельного процесса туннеля после первоначальной настройки.

    Оба варианта работают, и выбор зависит от нас. Для быстрого предоставления доступа к одному сервису minikube tunnel быстрый и временный. Для более постоянной настройки можно включить дополнение MetalLB, чтобы LB получали реальные IP (например, мы можем выделить диапазон, такой как 10.0.0.240-250 на Minikube с мостовой сетью). Помните, что Minikube обычно одноузловой, поэтому в эффекте “балансировщик нагрузки” не балансирует между несколькими узлами - он просто предоставляет внешний доступ к сервису одного узла. Это нормально для разработки. В домашней лаборатории, если мы используем только один из наших узлов и запускаем Minikube на нем, мы можем использовать их для доступа к нашим приложениям. Но если мы хотим использовать все 3 узла, подход Minikube к LB не предназначен для этого сценария.

  • Требования к ресурсам: Minikube сам по себе легковесный, но так как он обычно запускает полный одноузловой Kubernetes (в виртуальной машине), потребление ресурсов аналогично обычному небольшому кластеру. Рекомендуемый минимум - 2 ГБ ОЗУ и 2 CPU для виртуальной машины. По умолчанию Minikube часто выделяет 2 ГБ ОЗУ для своей виртуальной машины. В нашем случае, с 16 ГБ на машину, это тривиально. В режиле простоя Minikube (Kubernetes) может использовать около 600 МБ памяти. Одно, что стоит учитывать, это то, что Minikube будет работать наверху нашей ОС - либо как виртуальная машина через гипервизор, либо как контейнер Docker - что добавляет некоторую накладную работу. Для сервера домашней лаборатории мы могли бы запустить Minikube с драйвером “none” (который устанавливает компоненты Kubernetes непосредственно на хост). Однако драйвер “none” (также известный как bare-metal) фактически аналогичен использованию kubeadm на этом узле и требует ручной очистки, поэтому он не так популярен. Большинство используют драйвер виртуальной машины или Docker. В итоге, любой из наших узлов домашней лаборатории может легко запускать Minikube. Единственное ограничение заключается в том, что Minikube не будет использовать ресурсы всех трех узлов - он будет ограничен одним хостом, на котором он работает (если не использовать экспериментальный многозловой режим на одном хосте).

  • Одноузловой vs Многозловой: В первую очередь одноузловой. Minikube идеален для одноузлового кластера на одном компьютере. У него есть функция для симуляции нескольких узлов (например, minikube start --nodes 3 с драйвером Docker запустит 3 узла Kubernetes как контейнеры на одном хосте), но это только для тестирования. Мы не можем использовать Minikube для создания реального многозлового кластера на трех отдельных физических серверах. Если у нас есть 3 машины, нам пришлось бы запустить 3 независимых экземпляра Minikube (не в одном кластере). Это не настоящий опыт кластера (они не будут знать друг о друге). Поэтому Minikube не рекомендуется, если наша цель - использовать все три узла в одном кластере Kubernetes - он лучше подходит для сценариев, когда у нас есть только один компьютер (наш ПК или один сервер) и мы хотим запустить K8s на нем. Он также отлично подходит для изучения основ Kubernetes и локальной разработки.

  • CLI & UI Инструменты: CLI minikube - это основной интерфейс. Мы используем его для запуска/остановки кластера, и у него есть удобные сокращения: например, minikube dashboard включит Kubernetes Dashboard и откроет его в нашем браузере. minikube addons enable <addon> может включить различные дополнительные компоненты (ingress, metallb, metrics-server и т.д.). Minikube автоматически настраивает доступ kubectl (он создает контекст “minikube” в нашем kubeconfig). Для интерфейса, как упоминалось, Kubernetes Dashboard легко доступен через команду dashboard. Minikube не имеет собственного уникального веб-интерфейса; он полагается на стандартные инструменты. Отладка Minikube также проста, так как мы можем minikube ssh для доступа к узловой виртуальной машине, если это необходимо. В целом, инструменты очень удобны для пользователя в одноузловом сценарии.

Kubeadm (Чистый Kubernetes на наших собственных узлах)

Основные особенности: Kubeadm - это не “дистрибутив”, а официальный набор инструментов для создания кластера Kubernetes с нуля. Использование kubeadm означает, что мы развертываем стандартные компоненты Kubernetes на наших машинах. Это, по сути, способ “собрать свой собственный” кластер, следуя лучшим практикам, но без дополнительных функций, которые включают дистрибутивы. Kubeadm настроит узел управления (запускающий etcd, API сервер, контроллер-менеджер, планировщик) и присоединит рабочие узлы к нему. Результат - полностью стандартный кластер Kubernetes, идентичный тому, который мы получили бы на виртуальных машинах в облаке. Этот подход дает нам полный контроль и гибкость - мы выбираем сетевой плагин, провизионер хранилища и т.д. - но также требует наибольших начальных ручных усилий и знаний. Он часто используется в производственных или учебных средах для изучения внутренностей Kubernetes.

  • Простота установки и обслуживания: По сравнению с другими, kubeadm требует наибольших усилий. Нам нужно вручную установить зависимости (контейнерный runtime, например, containerd, kubeadm, kubelet, kubectl) на каждом узле. Затем запустить kubeadm init на мастере, и kubeadm join на рабочих узлах с токеном, который он дает. Также нужно настроить CNI (сетевой плагин) после инициализации (Calico, Flannel и т.д.), так как kubeadm не устанавливает его по умолчанию. Есть хорошо документированные шаги для всего этого (процесс не сложный, но много шагов) - в сущности, kubeadm дает нам стартовый кластер, но ожидает, что мы будем управлять дополнительными модулями. В плане обслуживания мы отвечаем за обновления (kubeadm имеет команду обновления, но нам нужно сливать узлы, обновлять бинарные файлы и т.д. вручную), а также за мониторинг состояния etcd, обновление сертификатов и т.д. Короче говоря, kubeadm мощный, но ручной. Его часто называют “сложным способом” (хотя не таким сложным, как сборка из исходников). Для хоббиста домашней лаборатории, который любит учиться, kubeadm - отличный способ глубоко понять Kubernetes. Но если наш приоритет - “простота и низкое обслуживание”, kubeadm потребует больше усилий, чем K3s/MicroK8s. Каждое обновление или изменение потребует ручного вмешательства. Тем не менее, после настройки это настоящая вещь: стандартный кластер Kubernetes без скрытых абстракций.

  • Поддержка Persistent Volume: Нет по умолчанию (должно быть добавлено вручную). Кластер, установленный с помощью kubeadm, по сути, это чистый Kubernetes - он не включает стандартный StorageClass или динамический провизионер из коробки. В облачных средах поставщик облака обычно предоставляет стандартный StorageClass (например, AWS EBS и т.д.), но в среде bare-metal домашней лаборатории нам нужно будет установить свое собственное решение. Распространенные подходы:

    • HostPath Provisioner: Мы можем воспроизвести то, что делают K3s/Minikube, установив что-то вроде Rancher Local Path Provisioner (это небольшой контроллер + StorageClass, который создает PVs hostPath). Это простое дополнение (просто манифест YAML) и дает нам локальное динамическое хранилище.
    • NFS или NAS: Некоторые пользователи домашних лабораторий настраивают сервер NFS (или используют NAS) и затем используют статические PVs или драйвер NFS CSI для провизионирования.
    • OpenEBS/Longhorn/Ceph: Есть более сложные варианты, такие как развертывание Longhorn или Ceph RBD через Rook, если мы хотим распределенное хранилище между узлами. Эти варианты требуют больших ресурсов и сложности.

    Ключевой момент заключается в том, что kubeadm не “решает” проблему хранилища для нас - мы должны решить и настроить это. Если простота является приоритетом, самый простой путь - развернуть провизионер hostPath или использовать NFS. Например, local-path provisioner от Rancher можно установить за несколько команд kubectl apply и он будет имитировать поведение K3s (создавая тома под /var/lib/rancher/ на любом узле). Но это ручной шаг. Пока мы этого не сделаем, любой PVC, который мы создадим, будет находиться в состоянии Pending, потому что Kubernetes не имеет стандартного провизионирования. Таким образом, хотя kubeadm, конечно, поддерживает Persistent Volumes (это полный Kubernetes), поддержка динамического PV столь же хороша, насколько мы приложили усилий для его настройки.

  • Поддержка LoadBalancer: Нет по умолчанию (должно быть добавлено вручную). Аналогичная ситуация здесь: в традиционном on-prem кластере у нас нет встроенной реализации LoadBalancer. Если мы создадим сервис типа LoadBalancer на обычном кластере kubeadm, он будет находиться в состоянии pending навсегда, пока мы не развернем контроллер для его обработки. Обычное решение - установить MetalLB самостоятельно. MetalLB можно установить через манифест или Helm chart - мы бы настроили диапазон IP, и он затем выделит эти IP для сервисов LoadBalancer (как в MicroK8s). Существует много руководств по установке MetalLB на кластерах kubeadm. Альтернативой, которую некоторые используют, является kube-vip для VIP управления и сервисных LB, но MetalLB проще для сервисов. В сущности, с kubeadm у нас есть свобода (или бремя) настроить любой механизм балансировки нагрузки, который соответствует нашим потребностям. Если мы не настроим ни одного, мы ограничены сервисами NodePort для внешнего доступа. Для домашней лаборатории установка MetalLB сильно рекомендуется - это просто и дает нам функциональность облачных сервисных IP. Но снова, это дополнительный шаг, который мы должны выполнить (в отличие от K3s, который работает из коробки, или MicroK8s с простым включением).

  • Требования к ресурсам: Стандартный Kubernetes немного тяжелее, чем обрезанные версии. Каждый узел будет запускать kubelet и kube-proxy, а мастер будет запускать etcd и компоненты управления. Один узел управления может работать на 2 ГБ ОЗУ, но обычно мы хотим немного больше для комфорта, если запускаем поды на нем. Руководство padok рекомендует 2 ГБ для мастера, 2 ГБ для рабочего узла в качестве минимума. В нашем сценарии (16 ГБ на узел) это нормально. В режиме простоя etcd и API сервер могут использовать несколько сотен МБ памяти каждый. Нет большой разницы в работе между кластером kubeadm и MicroK8s - в конце концов, MicroK8s это те же самые компоненты. Разница только в том, что запускается по умолчанию (MicroK8s может включить DNS и хранилище по умолчанию, тогда как в kubeadm мы бы установили их). Таким образом, с точки зрения ресурсов kubeadm может быть таким же легковесным или тяжелым, как мы его настроим. Без дополнительных установок он может быть довольно легковесным. С типичной настройкой (например, если мы добавим CoreDNS, Dashboard и т.д.), ожидайте около 1 ГБ или около того для системных накладных расходов. У нас достаточно ОЗУ, поэтому ресурсы не проблема. Это больше вопрос человеческих усилий/ресурсов, необходимых для управления им, чем CPU/ОЗУ.

  • Одноузловой vs Многозловой: Kubeadm может делать и то, и другое, с полной гибкостью. Мы можем инициализировать одноузловой кластер (и даже сказать kubeadm позволить одному узлу запускать рабочие нагрузки, сняв с него метку мастера). Или у нас может быть один мастер и два рабочих узла (распространенная настройка с тремя узлами). Мы даже могли бы настроить 3 мастера и 3 рабочих узла и т.д. - любую топологию. В нашем случае, вероятная настройка kubeadm будет состоять из 1 узла управления и 2 рабочих узлов (поскольку HA не требуется, нам не нужны несколько мастеров). Это даст нам функциональный 3-узловой кластер. Процесс для многозлового режима хорошо документирован: в сущности, установите Kubernetes на всех, инициализируйте один, присоедините остальные. Результат идентичен тому, что дает управляемый кластер или другой дистрибутив: наши 3 узла отображаются в kubectl get nodes и т.д. Таким образом, kubeadm определенно соответствует требованию “можно использовать все 3 узла”.

  • CLI & UI Инструменты: С kubeadm единственный специальный CLI - это kubeadm сам по себе, используемый для шагов установки и (позже) обновления. В повседневной работе используйте kubectl для управления кластером. Нет интегрированного управления CLI помимо того, что предоставляет Kubernetes. Для интерфейса ничего не включено по умолчанию - мы можем вручную развернуть Kubernetes Dashboard или любой другой инструмент (как в любом кластере). В сущности, kubeadm дает нам чистый холст Kubernetes. Это мы должны “раскрасить” - что включает установку удобств, таких как dashboard, контроллеры ingress, storage classes и т.д. Многие сторонние панели управления (Lens, Octant и т.д.) также могут подключаться к кластеру kubeadm, если мы хотим опыт управления через GUI, но это внешние инструменты. В итоге, с kubeadm мы получаем чистую среду Kubernetes - максимальная гибкость, но также необходимость настраивать все так, как если бы это был производственный кластер.

  • Kubespray См. также как установить этот вариант Kubernetes с Kubespray.

Сравнительная таблица

Ниже представлено сравнение четырех вариантов по ключевым аспектам:

Аспект K3s (Легковесный Rancher K8s) MicroK8s (Canonical “Low-Ops” K8s) Minikube (Одиночный узел для разработки K8s) Kubeadm (Чистый Kubernetes)
Установка Однострочный скрипт установки (один бинарный файл). Работает как один системный сервис. Очень быстрая настройка. Один командный установки через snap на Ubuntu. Все компоненты включены. Легкое кластеризация с microk8s join. Установка CLI minikube, затем minikube start для запуска локального VM/контейнера. Кроссплатформенный и дружелюбный для новичков. Ручная установка kubeadm, kubelet и т.д. на каждом узле. Запуск kubeadm init + kubeadm join с предварительными требованиями. Включает несколько шагов (рантайм, сетевой плагин и т.д.).
Обслуживание и обновления Ручные обновления (замена бинарного файла или использование скрипта установки для новой версии). Просто, так как это один бинарный файл; мало что нужно управлять. Нет автообновлений. Snap обновления (могут быть автоматическими). Дополнения и кластерные сервисы управляются через CLI microk8s. В целом low-ops; доступны автообновления. Легко удалять/создавать кластер для разработки. Обновления путем обновления версии minikube и перезапуска кластера. Предназначен для временного использования (меньше акцента на долговечность обновлений на месте). Пользователь отвечает за все обновления. Используйте kubeadm upgrade, но нужно сливать узлы, обрабатывать резервное копирование etcd и т.д. Полный контроль, но вы выполняете работу (нет автоматических обновлений).
Версия K8s Следует за основным потоком довольно близко (часто используется в релизах edge). CNCF сертифицирован. Некоторые функции отключены по умолчанию (альфа/устаревшие). Следует за основными релизами (каналы snap для 1.27, 1.28 и т.д.). CNCF сертифицирован. По сути, бинарные файлы vanilla K8s. Можно выбрать версию Kubernetes при запуске (например, minikube start --kubernetes-version=v1.27). По умолчанию последняя стабильная версия. Любая версия, которую мы хотим (установка конкретных версий kubeadm/kubelet). Полный основной Kubernetes – мы решаем версию и когда обновляться.
Встроенные функции Встроенные по умолчанию: Flannel CNI, CoreDNS, Traefik ingress, service LB, локальный класс хранения, metrics-server и т.д. (Все можно отключить, если не нужны). Минимальная конфигурация для функциональности. Минимальные по умолчанию: DNS обычно включен, остальное опционально. Легкие однокомандные дополнения для ingress (NGINX), MetalLB, hostpath хранения, dashboard и т.д. Можно включить HA режим на 3+ узлах. Встроенные в VM: обычно включает Docker/containerd runtime, Kubernetes с добавками по умолчанию, такими как StorageProvisioner и DNS. Опциональные добавки (ingress, dashboard и т.д.) включаются через CLI. Нет мультиузлов по умолчанию. Голый: Ничего, кроме основного Kubernetes. Нет ingress, нет хранения или LB по умолчанию, нет dashboard, пока мы их не установим. Мы выбираем CNI плагин (нужно установить один для сетевого взаимодействия). По сути, DIY кластер.
Поддержка Persistent Volume Да – из коробки. Включен динамический провизионер Rancher local-path, который создает hostPath PVs на узле для любого PVC. Класс хранения по умолчанию “local-path” использует локальный диск автоматически. Да – простое дополнение. Включите hostpath-storage, чтобы получить класс хранения по умолчанию для динамических PV с использованием hostPath. До включения нет провизера PV по умолчанию. Дополнение не для мультиузлового производства, но подходит для домашнего использования. Да – из коробки. Класс хранения по умолчанию использует провизера hostPath внутри VM minikube. PVC выполняются простым контроллером, который создает hostPath PV на файловой системе узла. Данные сохраняются после перезапуска в определенных директориях. Нет (ручное). Нет провизера по умолчанию – кластер не будет иметь класса хранения изначально. Пользователь должен установить решение для хранения (например, local path провизер, NFS, Ceph и т.д.). Базовый подход: применить YAML провизера hostPath, чтобы имитировать то, что делают K3s/Minikube. До этого PVC остаются в ожидании.
Поддержка LoadBalancer Да – встроенный ServiceLB. Контроллер servicelb K3s (Klipper) следит за сервисами LoadBalancer и развертывает поды на узлах для их экспорта. Использует IP узла и хост-порты для перенаправления трафика. Работает из коробки без конфигурации. Подходит для небольших кластеров; использует внутренний/внешний IP узла для сервиса. Да – через дополнение MetalLB. Включите metallb с диапазоном IP для выделения. Предоставляет истинный Layer-2 балансировщик нагрузки на голом железе. Не включен по умолчанию. После включения каждый сервис LoadBalancer получает уникальный IP из нашего пула. Требует небольшой начальной конфигурации (диапазон IP). Да – через туннель или MetalLB. Нет облачного LB, но можно запустить minikube tunnel, чтобы назначить внешний IP сервисам LoadBalancer (создает маршрут на хосте). Альтернативно, включите дополнение MetalLB в minikube для автоматических IP LB. По умолчанию сервисы LB будут в состоянии “pending”, пока мы не используем один из этих методов. Нет (ручное). Нет встроенного LB. Обычно устанавливается MetalLB вручную для функциональности балансировщика нагрузки на голом железе. После настройки MetalLB (или другого контроллера LB) сервисы LoadBalancer работают. Без него сервисы LB остаются в состоянии “pending” бесконечно.
Сетевое взаимодействие (CNI) По умолчанию = Flannel (overlay сетевое взаимодействие). K3s также поддерживает замену CNI при необходимости. Включает CoreDNS для DNS кластера. Traefik ingress включен по умолчанию (можно отключить). По умолчанию = Calico (для последних версий в HA режиме) или нечто простое. (MicroK8s исторически использовал flannel; теперь склоняется к Calico для строгого ограничения). CoreDNS включен по умолчанию. NGINX ingress доступен через дополнение (microk8s enable ingress). По умолчанию = kubenet/bridge (зависит от драйвера; часто использует простую NAT сеть). CoreDNS работает по умолчанию. Можно включить дополнение NGINX ingress при необходимости. Сетевое взаимодействие ограничено одним VM; NodePort доступен через minikube ip. Выбор CNI. Kubeadm не устанавливает плагины CNI – нужно развернуть один (Calico, Flannel, Weave и т.д.). Полный контроль. Большинство руководств предполагают, что мы применяем YAML Calico после kubeadm init. CoreDNS устанавливается kubeadm по умолчанию как DNS кластера. Контроллер ingress – выбираем и устанавливаем сами (например, NGINX или Traefik через манифесты/Helm).
Мультиузловое кластеризация Да. Предназначен для мультиузлов. Легкое присоединение с токеном. Можно использовать внешнюю БД или встроенный etcd для мультимастеров. Отлично подходит для 2-3+ узлов в домашних лабораториях. Нет дополнительных зависимостей – K3s имеет встроенное кластеризацию. Да. Поддерживает кластеризацию нескольких узлов MicroK8s (с microk8s join). Можно включить HA с 3+ мастерами (Dqlite). Очень просто сформировать кластер, особенно если все узлы работают на Ubuntu + snap. Нет (физическое). Одиночный узел по дизайну. Можно симулировать мультиузлы на одном компьютере (несколько узлов в Docker контейнерах), но нельзя охватить несколько физических хостов в одном кластере. Используйте отдельные инстансы Minikube для отдельных кластеров. Да. Полностью поддерживает мультиузлы (это цель). Можно иметь 1 мастера + много воркеров, или даже несколько мастеров (хотя настройка HA kubeadm сложнее). Нет встроенных ограничений на размер кластера.
Нагрузка на ресурсы Очень низкая. Управляющая плоскость \ <0.5 ГБ памяти в режиме ожидания. Один процесс для управляющей плоскости дает небольшой след. Эффективен на CPU (хотя может использовать немного больше CPU в режиме ожидания, чем MicroK8s по некоторым отчетам). Идеален для низкоэнергетических или с большим запасом мощности систем. Низкая. \ 0.5–0.6 ГБ памяти для управляющей плоскости в режиме ожидания. Немного выше базовой памяти, чем у K3s, но остается стабильной. Использует Ubuntu snap (может иметь некоторый оверхед). Все еще легковесный по сравнению с полным Kubernetes. Умеренная. VM по умолчанию 2 ГБ выделено (использование \ 0.6 ГБ в режиме ожидания). Запускает полный одноузловой Kubernetes, плюс слой VM. Не проблема на системах с 16 ГБ, но по сути потребляет ресурсы небольшого кластера на одном компьютере. Умеренная. Одиночный мастер с одним воркером может использовать \ 1 ГБ в режиме ожидания после добавления типичных дополнений. Каждый дополнительный узел добавляет минимальный оверхед (только kubelet, proxy). Похоже на запуск Kubernetes в облачных VM аналогичного размера. На 3 узлах с 16 ГБ каждый оверхед незначителен в контексте.
Инструменты CLI Используйте k3s для установки и как обертку для kubectl (или используйте стандартный kubectl). Нет отдельного управления CLI (K3s в основном “установил и забыл”). Некоторые вспомогательные скрипты (например, k3s-killall.sh). GUI Rancher можно добавить сверху, если нужно. Богатый CLI microk8s: например, microk8s enable/disable <addon>, microk8s status. Также включает microk8s kubectl. Предназначен для упрощения обычных задач (не нужно прямо редактировать системные манифесты для базовых задач). CLI minikube для запуска/остановки кластера, управления конфигурацией и дополнениями, а также для получения информации (IP, URL сервиса, логи). Также предоставляет удобные команды, такие как minikube dashboard. Взаимодействие с кластером через kubectl (конфигурация автоматически установлена для контекста minikube). Только kubeadm для начальной настройки и обновлений. Ежедневные операции через стандартный kubectl и другие инструменты Kubernetes. Нет специфичного для дистрибутива CLI, кроме загрузки. Вы будете работать с сырыми командами Kubernetes и, возможно, инструментами ОС для обслуживания.
UI / Dashboard Не включен по умолчанию. Можно вручную установить Kubernetes Dashboard или использовать внешние инструменты (ничего специфичного для Rancher, если не добавляем Rancher отдельно). K3s фокусируется на headless операции. Не включен по умолчанию, но доступен через одну команду: microk8s enable dashboard развертывает стандартный UI Dashboard. Легкий доступ к кластеру через microk8s dashboard-proxy. Также хорошо интегрируется с GUI Lens от Canonical, если нужно (Lens может напрямую подключаться к MicroK8s). Не включен по умолчанию, но команда minikube dashboard развернет и откроет веб-UI Dashboard для нас. Это предназначено для удобства в локальной разработке – одна команда и у нас есть GUI для просмотра рабочих нагрузок. Не включен. Можно установить Dashboard (применить YAML), если хотим. В противном случае используйте CLI или сторонние приложения Dashboard. В домашней лаборатории можно установить Dashboard и создать NodePort или использовать kubectl proxy для просмотра. Kubeadm не занимается UI.

Источники: Данные выше синтезированы из официальных документов и руководств пользователей: например, показатели памяти из собственного сравнения MicroK8s, хранение по умолчанию в документации K3s, поведение сервиса LB K3s из документации K3s, детали дополнений MicroK8s из документов Canonical, PV и туннель Minikube из документации Kubernetes, а также общие отчеты об опыте. (См. Ссылки для полных цитат.)

Рекомендации

Учитывая приоритеты (простота настройки/обслуживания и встроенная поддержка хранилища и балансировщиков нагрузки) и сценарий (3 узла Ubuntu, без особого внимания к отказоустойчивости):

  • Лучшие варианты: K3s или MicroK8s наиболее подходят для хоумлаба с 3 узлами:

    • Оба очень легко установить (одна команда на каждом узле) и требуют минимального обслуживания. Они скрывают большую часть сложности работы с кластером.
    • Оба поддерживают мультиузловую кластеризацию из коробки (можно объединить наши 3 узла и получить единый кластер).
    • Каждый из них предоставляет решение для Persistent Volumes и LoadBalancers без особых усилий: K3s включает их по умолчанию (Local Path storage, Klipper LB), а MicroK8s делает их доступными через простые команды enable. Это означает, что мы можем развернуть типичные приложения (базы данных с PVC, сервисы с type=LoadBalancer) с минимальными ручными настройками.
    • K3s может быть привлекательным, если мы хотим максимально маленький footprint и не против использовать его встроенные настройки по умолчанию (Traefik ingress и т.д.). Это подход “установил и работает” с опциональными настройками. Он также очень популярен в сообществе хоумлабов за свою простоту. Мы будем использовать в основном стандартный kubectl и сможем настроить или отключить встроенные компоненты при необходимости. K3s может быть предпочтительным, если мы не используем Ubuntu или если нам нравится экосистема Rancher (или планируем использовать интерфейс управления Rancher позже).
    • MicroK8s может быть привлекательным, если мы предпочитаем решение с поддержкой Ubuntu и идею включения функций одной командой. Это по сути стандартный Kubernetes под капотом, что некоторые считают проще расширять. Дополнения (например, microk8s enable ingress dns storage metallb) могут дать нам полностью функциональный “микро-облако” за несколько минут. MicroK8s также грациозно обрабатывает обновления через snaps, что может быть удобно для поддержания актуальности кластера без ручного вмешательства (мы можем отключить это или управлять каналом, чтобы избежать сюрпризов). Если мы уже используем Ubuntu на всех узлах (что мы и делаем) и не против snaps, MicroK8s - отличный выбор для кластера с минимальным обслуживанием.

    Короче говоря: Сложно ошибиться, выбрав K3s или MicroK8s для этого сценария. Оба дадут нам простой, дружелюбный для хоумлаба Kubernetes с нужными функциями. Многие пользователи сообщают о положительном опыте использования обоих в настройках с 2-3 узлами. MicroK8s может иметь небольшое преимущество в простоте использования (из-за дополнений и интеграции), в то время как K3s может иметь небольшое преимущество в компактности и простоте под капотом.

  • Когда выбирать Minikube: Если бы мы работали только на одном компьютере или хотели быстрый временный dev-кластер, Minikube отлично подходит для этого. Это самый простой способ развернуть Kubernetes на ноутбуке или одном узле для тестирования. Однако для постоянного кластера из 3 узлов Minikube не подходит - он не объединит эти 3 узла в один кластер. Мы бы недопользовали наше оборудование или управляли 3 отдельными кластерами, что нежелательно. Поэтому в этом хоумлабе с несколькими узлами Minikube не рекомендуется как основное решение. Мы можем использовать Minikube на нашем личном компьютере для тестирования перед развертыванием в кластер хоумлаба, но для самого кластера использовать что-то вроде K3s/MicroK8s.

  • Когда выбирать Kubeadm: Если наша цель - изучить внутренности Kubernetes или получить полный контроль и “продовольственную” настройку, kubeadm - хороший вариант. Он заставит нас понять, как устанавливать CNI, хранилище и т.д., и мы фактически соберем кластер по частям. В плане простоты использования, однако, kubeadm - самый ручной. Каждую нужную функцию (например, хранилище или LB) нужно настраивать вручную. Для хоумлаба, ориентированного на обучение, это может быть плюсом (образовательно); для хоумлаба “просто заработай” - это минус. Также обслуживание будет более сложным (особенно при обновлениях). Если мы специально хотим стандартный опыт Kubernetes для обучения или специальных нужд, использование K3s или MicroK8s сэкономит нам много времени и головной боли в среде хоумлаба. Тем не менее, некоторые опытные пользователи предпочитают kubeadm даже дома, чтобы избежать специфичных особенностей поставщиков и иметь все под контролем. Все зависит от того, сколько усилий мы готовы прилагать. Для большинства kubeadm - избыточность для небольшого кластера, где отказоустойчивость не важна.

  • Другие варианты: Есть несколько других легких дистрибутивов Kubernetes, таких как k0s (от Mirantis) и инструменты вроде kind (Kubernetes в Docker). Для полноты картины:

    • k0s - еще один дистрибутив Kubernetes в одном бинарном файле, с похожими целями, что и K3s/MicroK8s, который фокусируется на гибкости и минимальном footprint. Он относительно новый, но имеет поклонников в сообществе хоумлабов. Он также может легко работать на наших 3 узлах. Пока что он не имеет такого большого пользовательского сообщества, как K3s/MicroK8s, но это вариант, за которым стоит следить (особенно если нравится идея открытого исходного кода, настраиваемого, минимального Kubernetes - некоторые отчеты даже показывают, что k0s использует немного меньше ресурсов в режиме простоя, чем K3s/MicroK8s в аналогичных настройках).
    • kind в основном предназначен для тестирования кластеров Kubernetes в контейнерах Docker (часто используется для CI-конвейеров). Это не то, что мы будем запускать как наш постоянный кластер хоумлаба - это больше для быстрых временных кластеров на одном компьютере (похоже на цель Minikube).
    • Rancher Kubernetes Engine (RKE) или K3d или другие также существуют, но они либо ориентированы на контейнеризированные кластеры (k3d запускает кластер K3s в Docker), либо более сложные сценарии развертывания. В хоумлабе K3s и MicroK8s стали де-факто простыми решениями.

Заключение: Для хоумлаба с 3 хорошими узлами MicroK8s или K3s - рекомендуемые варианты для получения функционального кластера Kubernetes с минимальными хлопотами. Они позволят нам использовать все наши узлы в одном кластере и предоставить встроенную поддержку для постоянных томов и сервисов LoadBalancer, что именно то, что нам нужно. Если мы предпочитаем более готовое решение с интеграцией Ubuntu, выбирайте MicroK8s. Если мы предпочитаем сверхлегкое, проверенное решение с поддержкой Rancher, выбирайте K3s. В любом случае у нас будет рабочий кластер за несколько минут. После запуска мы можем развернуть Kubernetes Dashboard или другие инструменты для управления им и начать размещать наши приложения с постоянным хранилищем и простой экспозицией сервисов. Наслаждайтесь нашим путешествием по Kubernetes в хоумлабе!

Домашние страницы дистрибутивов Kubernetes

Другие полезные ссылки