Get Rewarded! We will reward you with up to €50 credit on your account for every tutorial that you write and we publish!

Установка и настройка кластера Kubernetes + Flannel + Ingress Nginx Controller + Hetzner TLS балансировщик

profile picture
Author
Dmitry Tiunov
Published
2025-02-10
Time to read
9 minutes reading time

About the author- DevOps инженер проектов PeakVisor и Zentist

Вступление

Данное руководство содержит инструкции по установке кластера Kubernetes версии 1.30 используя такие инструменты как kubeadm и Helm. Предполагается, что все узлы кластера будут находится в одной локальной сети Hetzner, а запросы из Интернета к пользовательским приложениям будут осуществлятся через балансировщик нагрузки Hetzner. Данная конфигурация позволяет заблокировать входящие соединения из Интернета на узлы кластера, что делает кластер более безопасным.

На кластер будет установлен Flannel в качестве CNI (Container Network Interface) и CRI-O в качестве CRI (Container Runtime Interface).

Предпочтение CRI-O было отданно по следующим причинам:

  • CRI-O более безопасен чем containerd поскольку имеет меньшее количество свойств и внутренних компонентов, что значительно снижает поверхность для атаки
  • CRI-O имеет прозрачную структуру компонентов опубликованную в открытом доступе
  • У CRI-O активное сообщество

Устанавливая компоненты шаг за шагом вы научитесь собирать кластер как конструктор и управлять балансировщиком нагрузки Hetzner используя аннотации заданные в файле значений для контроллера входящего трафика.

Предварительные требования

  • 3 виртуальные машины в облаке Hetzner (одна для узла плоскости управления, две для рабочих узлов) с установленной на них операционной системой Ubuntu 24.04, подключенные к одной общей сети Hetzner
  • Helm установленный на одну из виртуальных машин
  • Токен для доступа к API Hetzner созданный через web-интерфейс Hetzner
  • TLS сертификат импортированный в web-интерфейсе Hetzner:
    https://console.hetzner.cloud/projects/<project_id>/security/certificates

Шаг 1 - Подключение репозиториев

На этом шаге мы добавим Kubernetes и CRI-O репозитории на все узлы будующего кластера.

Устанавливаем версию Kubernetes как переменную окружения

KUBERNETES_VERSION=v1.30

Добавляем ключ и репозиторий Kubernetes

curl -fsSL https://pkgs.k8s.io/core:/stable:/$KUBERNETES_VERSION/deb/Release.key | gpg --dearmor -o /etc/apt/keyrings/kubernetes-apt-keyring.gpg
echo "deb [signed-by=/etc/apt/keyrings/kubernetes-apt-keyring.gpg] https://pkgs.k8s.io/core:/stable:/$KUBERNETES_VERSION/deb/ /" | tee /etc/apt/sources.list.d/kubernetes.list

Добавляем ключ и репозиторий CRI-O

curl -fsSL https://pkgs.k8s.io/addons:/cri-o:/prerelease:/main/deb/Release.key | gpg --dearmor -o /etc/apt/keyrings/cri-o-apt-keyring.gpg
echo "deb [signed-by=/etc/apt/keyrings/cri-o-apt-keyring.gpg] https://pkgs.k8s.io/addons:/cri-o:/prerelease:/main/deb/ /" | tee /etc/apt/sources.list.d/cri-o.list

Шаг 2 - Установка пакетов

Следующим шагом будет установка пакетов CNI и компонентов Kubernetes на все узлы кластера.

Обновляет список доступных пакетов

apt update

Устанавливаем пакеты

apt install -y cri-o kubelet kubeadm kubectl
crio --version && kubelet --version && kubeadm version && kubectl version --client

Отключаем автоматическое обновление для только что установленных пакетов

apt-mark hold kubelet kubeadm kubectl

Шаг 3 - Настройка операционной системы

Kubernetes требует некоторых предварительных настроек операционной системы. Если вы используете образ Ubuntu 24.04 предоставленный Hetzner, тогда вам не требуется отключать SWAP, так как он он выключен по умолчанию. Просто выполните команды ниже на всех узлах кластера.

Подключаем модуль ядра br_netfilter

echo "br_netfilter" >> /etc/modules-load.d/modules.conf

Разрешаем переадресацию пакетов между разными сетями

sed -i 's/#net.ipv4.ip_forward=1/net.ipv4.ip_forward=1/g' /etc/sysctl.conf

Перезагружаем узел для применения настроек

reboot

Шаг 4 - Инициализация кластера

Инициализация кластера выполняется на узле предназначенном для плоскости управления (Control Plane node).

В данном руководстве предполагается использовать только 1 узел с ролью Control Plane, но если вы разворачиваете кластер в продуктивной среде, то для обеспечения должной отказоустойчивости рекомендуется использовать как минимум 3.

Получаем конфигурационный файл инциализации со значениями по умолчанию

kubeadm config print init-defaults > InitConfiguration.yaml

Вам необходимо добавить или изменить следующие значения внутри файла:

  • bootstrapTokens.token: abcdef.0123456789abcdef - вы можете получить токен начальной загрузки используя команду kubeadm token generate
  • localAPIEndpoint.advertiseAddress: 10.0.0.2 - этот параметр конфигурации позволяет вам определить, на каком IP-адресе и порту будет доступен локальный API сервер. По умолчанию kubeadm пытается автоматически определить IP-адрес интерфейса по умолчанию и использовать его. Установите здесь IP-адрес вашего узла управления внутри локальной сети Hetzner
  • nodeRegistration.criSocket: unix:///var/run/crio/crio.sock - путь к сокет-файлу CRI-O
  • nodeRegistration.kubeletExtraArgs.cloud-provider: external - необходимо установить значение external для запуска с внешними облачными провайдерами
  • nodeRegistration.kubeletExtraArgs.node-ip: 10.0.0.2 - IP адрес вашего узла управления внутри локальной сети Hetzner
  • nodeRegistration.name: your_host - имя узла управления
  • apiServer.certSANs: ['your_host.example.com', '10.0.0.2'] - SAN (Subject Alternative Names) для сертификата API. Вы можете использовать несколько значений. Например FQDN и локальный IP адрес узла управления
  • networking.podSubnet: 10.244.0.0/16 - подсеть для Pod'ов

Инициализируем кластер

kubeadm init --config InitConfiguration.yaml

Шаг 5 - Присоединение узлов к кластеру

Теперь мы можем добавить оставшиеся узлы к кластеру. Запустите команды ниже на всех остальных узлах.

Получаем конфигурационный файл со значениями по умолчанию

kubeadm config print join-defaults > JoinConfiguration.yaml

Вам необходимо добавить или изменить следующие значения внутри файла:

  • discovery.bootstrapToken.apiServerEndpoint: your_host.example.com:6443 - установите FQDN своего Control Plane узла
  • discovery.bootstrapToken.token: abcdef.0123456789abcdef - задайте значение аналогичное указанному в InitConfiguration.yaml файле
  • discovery.tlsBootstrapToken: abcdef.0123456789abcdef - задайте значение аналогичное указанному в InitConfiguration.yaml файле
  • nodeRegistration.criSocket: unix:///var/run/crio/crio.sock - путь к сокет-файлу CRI-O
  • nodeRegistration.kubeletExtraArgs.cloud-provider: external - необходимо установить значение external для запуска с внешним облачным провайдером
  • nodeRegistration.kubeletExtraArgs.node-ip: 10.0.0.3 - локальный IP адрес текущего сервера внутри сети Hetzner
  • nodeRegistration.name: your_host - имя рабочего узла

Присоединяем узел к кластеру

kubeadm join --config JoinConfiguration.yaml

Назначаем роли рабочем узлам, путём добавления соотвествующей метки. Запустите эти команды на узле управления

mkdir -p $HOME/.kube
cp /etc/kubernetes/admin.conf $HOME/.kube/config
kubectl get nodes
kubectl label node <имя первого рабочего узла>  node-role.kubernetes.io/worker=worker
kubectl label node <имя второго рабочего узла>  node-role.kubernetes.io/worker=worker

Шаг 6 - Установка CNI плагина

В этом руководстве в качестве CNI используется Flannel. Если вы хотите использовать сетевые политики с целью организовать более высокий уровень безопасности, вам следует рассмотреть другие плагины.

Создаем пространство имён

kubectl create ns kube-flannel

Добавляем ему привелегий. Политика privileged не имеет ограничений, все Pod'ы в пространстве имён kube-flannel смогут обойти типичные механизмы изоляции контейнеров. Например, они смогут получить доступ к сети узла.

kubectl label --overwrite ns kube-flannel pod-security.kubernetes.io/enforce=privileged

Подключаем helm репозиторий

helm repo add flannel https://flannel-io.github.io/flannel/

Вы можете скачать values.yaml файл из оффицального репозитория kube-flannel. Для успешного запуска плагина вам необходимо установить значение podCidr аналогично значению networking.podSubnet в файле InitConfiguration.yaml.

Устанавливаем Flannel в ранее созданное пространство имён

helm install flannel flannel/flannel --values values.yaml -n kube-flannel

Компоненты в которых значение cloud-provider определенно как external, пометят узлы кластера как node.cloudprovider.kubernetes.io/uninitialized с эффектом NoSchedule. Эти метки устанавливают узлы в состояние ожидания повторной инициализации от облачного контроллера. Так как в нашем случае внешний контроллер ещё не установлен, узлы кластера не смогут планировать CoreDNS Pod'ы. Для снятия этого ограничения выполните команду ниже.

kubectl -n kube-system patch deployment coredns --type json -p '[{"op":"add","path":"/spec/template/spec/tolerations/-","value":{"key":"node.cloudprovider.kubernetes.io/uninitialized","value":"true","effect":"NoSchedule"}}]'

Шаг 7 - Установка облачного контроллера Hetzner

Облачный контроллер Hetzner отвечает за интеграцию кластера Kubernetes с Hetzner API. Установка облачного контроллера на кластер позволит использовать службы предоставляемые Hetzner. В нашем руководстве мы воспользуемся службой балансировки нагрузки Hetzner.

Создаем Kubernetes секрет содержащий ваш токен доступа к API Hetzner (смотрите пункт "Предварительные требования" в разделе Вступление) и некий идентификатор сети Hetzner. Идентификатором сети являются последние цифры взятые из URL вашей сети в web-интерфейсе облака Hetzner. Например, для URL https://console.hetzner.cloud/projects/98071/networks/2024666/resources это будет 2024666

kubectl -n kube-system create secret generic hcloud --from-literal=token=<токен доступа к Hetzner API> --from-literal=network=<идентификатор сети Hetzner>

Добавляем и обновляем helm репозиторий

helm repo add hcloud https://charts.hetzner.cloud
helm repo update hcloud

Устанавливаем облачный контроллер Hetzner

helm install hccm hcloud/hcloud-cloud-controller-manager -n kube-system

Шаг 8 - Установка контроллера входящего трафика

В этом руководстве мы будем использовать Nginx Ingress в качестве контроллера входящего трафика. TLS шифрование будет осуществляться балансировщиком нагрузки Hetzner, который в свою очередь будет автоматически создан во время установки контроллера входящего трафика.

Перед началом установки нам необходимо в ручную провести инициализацию рабочих узлов кластера

kubectl taint nodes <имя первого рабочего узла> node.cloudprovider.kubernetes.io/uninitialized=true:NoSchedule-
kubectl taint nodes <имя второго рабочего узла> node.cloudprovider.kubernetes.io/uninitialized=true:NoSchedule-

Добавляем и обновляем helm репозиторий

helm repo add ingress-nginx https://kubernetes.github.io/ingress-nginx
helm repo update

Файл значений можно найти в оффициальном репозитории Ingress Nginx. Измените следующие значения в файле:

  • controller.dnsPolicy: ClusterFirstWithHostNet

  • controller.hostNetwork: true- по умолчанию при использовании параметра hostNetwork в значении true, для разрешения имен используется DNS узла. Если вы хотите, чтобы контроллер входящего трафика продолжал разрешать имена внутри сети Kubernetes используйте hostNetwor совместно с ClusterFirstWithHostNet

  • controller.kind: DaemonSet - устанавливаем контроллер как DaemonSet

  • controller.service.annotations - аннотации ниже задают параметры конфигурации для балансировщика нагрузки Hetzner. Полный список и описание доступных параметров можно найти в оффицальном репозитории облачного контроллера Hetzner

    Пример
    controller:
      [...]
      service:
        [...]
        annotations:
          load-balancer.hetzner.cloud/name: "k8s-test-lb"
          load-balancer.hetzner.cloud/location: "fsn1"
          load-balancer.hetzner.cloud/type: "lb11"
          load-balancer.hetzner.cloud/ipv6-disabled: "true"
          load-balancer.hetzner.cloud/use-private-ip: "true"
          load-balancer.hetzner.cloud/protocol: "https"
          load-balancer.hetzner.cloud/http-certificates: "certificatename"
          load-balancer.hetzner.cloud/http-redirect-http: "true"
    • load-balancer.hetzner.cloud/name: "k8s-test-lb" - здесь мы указываем имя балансировщика нагрузки. Имя будет отображаться в соотвествующем разделе web-интерфейса облака Hetzner
    • load-balancer.hetzner.cloud/location: "fsn1" - указываем местонахождение дата-центра в котором будет создан балансировщик. Для данного руководства местонахождение должно совпадать с местонахождением виртуальных машин вашего кластера Kubernetes
    • load-balancer.hetzner.cloud/type: "lb11" - определяем тип блансировщика
    • load-balancer.hetzner.cloud/ipv6-disabled: "true" - отключаем использование протокола IPv6
    • load-balancer.hetzner.cloud/use-private-ip: "true" - указываем балансировщику использовать локальные IP адреса внутри Hetzner сети для обращения к узлам кластера
    • load-balancer.hetzner.cloud/protocol: "https" - назначаем протокол по которому будет работать балансировщик
    • load-balancer.hetzner.cloud/http-certificates: "certificatename" - список идентификаторов или имён сертификатов, которые будут использоваться для шифрования трафика между клиентам из Интернета и балансировщиком (смотрите пункт "Предварительные требования" в разделе Вступление)
    • load-balancer.hetzner.cloud/http-redirect-http: "true" - включаем перенаправление HTTP на HTTPS
  • controller.service.enableHttp: false - отключаем HTTP для Kubernetes служб контроллера

  • controller.service.targetPorts.https: http - порт контроллера входящего трафика на который будет перенаправлять запроы балансировщик. Нам нет необходимости использовать шифрование трафика между балансировщиком и кластером Kubernetes, поэтому мы можем указать HTTP (80) порт

Устанавливаем контроллер входящего трафика

helm install ingress-nginx-controller ingress-nginx/ingress-nginx -f values.yaml -n kube-system

Шаг 9 - Установка CSI драйвера (Опционально)

На момент написания статьи, у Hetzner доступно подключение томов только в режиме ReadWriteOnce. Всё же это может быть полезным, поэтому я рекомендую установить CSI драйвер.

Добавляем и обновляем helm репозитории

helm repo add hcloud https://charts.hetzner.cloud
helm repo update hcloud

Устанавливаем CSI драйвер предоставленный Hetzner

helm install hcloud-csi hcloud/hcloud-csi -n kube-system

Заключение

В резльтате мы имеем кластер состоящий из одного узла управления и двух рабочих узлов, с подключенным к нему баласировщиком нагрузки.

Теперь вы можете заблокировать весь входящий трафик из Интернета на всех узлах кластера Kubernetes и приступить к установке вашего приложения.

License: MIT
Want to contribute?

Get Rewarded: Get up to €50 in credit! Be a part of the community and contribute. Do it for the money. Do it for the bragging rights. And do it to teach others!

Report Issue
Try Hetzner Cloud

Get €20/$20 free credit!

Valid until: 31 December 2025 Valid for: 3 months and only for new customers
Get started
Want to contribute?

Get Rewarded: Get up to €50 credit on your account for every tutorial you write and we publish!

Find out more