ОС Альт СП Kubernetes

Материал из ALT Linux Wiki

Используемые инструменты контейнеризации

В настоящее время для разворачивания решений контейнеризации используются два основных альтернативных инструментария:

  • dockerd, containerd (serverfull) - серверный вариант запуска контейнеров. Клиенты через CLI-команду docker обращаются к dockerd-демону, который через сервис containerd запускает контейнеры.
  • podman, cri-o (serverless) - CLI-команда podman и kubernetes-движок cri-o непосредственно запускают контейнеры бех обращения к серверу.

В рамках дистрибутива ALTLinux реализовано решение podman, cri-o по следующим причинам:

  • podman, cri-o поддерживают политики контейнеризации, позволяющие организовать группы пользователей с разными правами доступа к docker-образам при запуске контейнеров. Это обеспечивает поддержку «Требования по безопасности информации к средствам контейнеризации» приказа № 118 ФСТЭК России.
  • podman, cri-o по своей идеологии разработки (serverless) поддерживают rootless-режим запуска контейнеров.

Дерево используемых интсрументов контейнеризации

rootfull и rootless режим запуска контейнеров

podman

CLI команда podman является аналогом CLI команды docker и поддерживает аналогичный набор параметров. Команда docker для запуска контейнеров обращается к dockerd-демону, работающему на том же или другом компьютере. Контейнер запускается на том же узле, где работает демон dockerd обычно с правами root. В этом случае все контейнеры запускаются в rootfull режиме независимо от какого пользователя запущена CLI команда docker.

CLI команда podman запускает контейнеры на том же узле, где была запущена не обращаясь к отдельному демону. Контейнеры запускаются с правами того пользователя, от имени которого была запущена команда podman. Это позволяет организовать как rootfull, так и rooless режим запуска контейнера.

rootfull режим запуска контейнеров

До появления группы команд podsec, cri-o все контейнеры запускались в rootfull режиме.

Основное отличие rootfull режима от rottless - запуск образов в которых в качестве пользователя указан пользователь root.

# podman inspect <образ> | jq .[0].User
root

В rootfull режиме процесс работающий в контейнере работает от имени пользователя root с идентификатором (UID) 0. Причем и в рамках HOST-системы в которой запущен контейнер это процесс также имеет идентификатор UID=0. Если в контейнер примонтирован каталог HOST-системы, то злоумышленник через команду

podman exec -i <id_conteiner> rm -rf <каталог_монтирования> 

может удалить монтируемый каталог HOST-системы или изменить его. Podman rootfull.drawio.png

rootless режим запуска контейнеров

rootless режим запуска контейнеров позволяет запускать образы в которых в качестве пользователя указан пользователь root таким образом, что процесс работающий в контейнере работает от имени пользователя root с идентификатором (UID), а в рамках HOST системы этом процесс имеет идентификатор пользователя который запустил данный контейнер. Podman rootless1.png Данный режим доступен для пользователей входящих в группу podman. Он включается командой:

# control newgidmap podmanonly
# control newuidmap podmanonly

Эти команды для команд /usr/bin/newuidmap, /usr/bin/newguidmap устанавливают флаг cap_setuid=ep при котором они запускаются с правами root для пользователей, входящих в группу podman:

# ls -l /usr/bin/newuidmap /usr/bin/newgidmap
-rwx--x--- 1 root podman 41440 апр 26  2024 /usr/bin/newgidmap
-rwx--x--- 1 root podman 41440 апр 26  2024 /usr/bin/newuidmap
# getcap /usr/bin/newuidmap /usr/bin/newgidmap
/usr/bin/newuidmap cap_setuid=ep
/usr/bin/newgidmap cap_setgid=ep

kubernetes

Системные требования

Минимальные системные требования:

  • 2GB ОЗУ или больше;
  • 2 ядра процессора или больше;
  • Все машины должны быть доступны по сети друг для друга;
  • Все машины должны успешно разрешать имена hostname друг друга (через DNS или hosts);
  • Своп должен быть выключен.

Для разворачивания нижеописанных кластеров достаточно несколько (две и более) машин (nodes), одна из которых будет мастер (controlplane)-узлом. Остальные узлы будут рабочими (worker).

controlplane-узлы обеспечивают управление кластером и поддерживают по порту 6443 kubernetes API.

Работа с кластером (создание deployment's, replicasetreplicaset's, podreplicaset's, configmap's, ...) производится через этот API либо внешними приложениями либо через CLI команду kubeclt.

Если разворачивается более одного controlplane-узла, то необходимо либо вручную перераспределять запросы к ним, либо разворачивать в рамках кластера балансировщик для равномерного распределения API-запросов между controlplane-узлами кластера.

Все пользовательские POD'ы (контейнеры) разворачиваются на worker узлах. В связи с этим при необходимости для них можно выделить большее количество оперативной, дисковой памяти и большее число ядер процессора.

Если на controlplane-узлах не предполагается большой нагрузки, то их можно перестроить на поддержку в том числе и пользовательских POD'ов. В этом случае "kubernetes-кластер" можно развернуть и на одном узле.

Варианты разворачивания ОС Альт СП kubernetes

Режим работы пользователя root кластера:

  • rootfull режим - пользователь root кластера и контейнеров в нем имеет равные права с пользователем root HOST-системы.
  • rootless режим - пользователь root кластера и контейнеров в нем имеет права обычного пользователя в HOST-системе (fake-root).

Использование политик доступа:

  • В незащищенном режиме.
  • В защищенном режиме с использованием политик доступа.

Использование регистраторов:

  • внешний регистратор ;
  • внутренний регистратор registry.local или комбинированный вариант;

rootfull kubernetes

При разворачивании kubernetes кластера в rootfull режиме на каждом узле systemd-сервис kubelet разворачивается с привелегиями пользователя root. Остальные сервисы кластера, разворачиваемые сервисом kubelet из docker-образов kubernetes также разворачиваются с привелегиями пользователя root. Все PODы, запускаемые в рамках кластера от docker-образов с пользователем root (например стандартный образ nginx) также имеют привелегии пользователя root HOST-системы. Дерево процессов rootfull kubernetes

Работа в режиме rootfull несет определенные риски, так как злоумышленник может в POD'е с привелегиями root примонтировать каталог файловой системы HOST-узла (включая корневой) и получить доступ с правами root к файлам этого каталога вплоть до их удаления.

В kubernetes версии 1.33 и старше появилась возможность запуска POD'ов в rootless-режиме. Но это касается только POD'ов пользователя. Системные kubernetes POD'ы работают c приведениями пользователя root и при наличии в них уязвимостей злоумышленник может их использовать для атаки на kubernetes-кластер.

Для исключения этих уязвимостей есть возможность разворачивать кластер в rootless-режиме. Этот вариант разворачивания описал в главе [1]. Этот вариант разворачивания также позволяет:

  • Создавать пользователей классов:
  1. Администратор кластера - управление кластером, создание пользователей, мониторинг работы кластера.
  2. Создатель образов - создание образов, их подпись и помещение в docker-регистратор.
  3. Пользователь образов - запуск POD'ов подписанных образов только с ограниченного перечня docker-регистраторов.
  • Мониторить состояние кластере на предмет:
  1. наличия уязвимостей в образах и контейнерах;
  2. подозрительных изменений в каталогах работающего POD'аж
  3. изменения политик безопасности;
  4. подозрительных запросов к API-кластера;
  5. и другие

Перечисленные возможности также можно развернуть и в режиме rootfull. Далее рассматриваются все варианты разворачивания с их применением.

rootless Kubernetes (podsec-k8s)

RootlessTree.png При разворачивании kubernetes кластера в rootless режиме на каждом узле systemd-сервис kubelet разворачивается командой nsenter с окружении обычного пользователя u7s-admin. Остальные сервисы кластера, разворачиваемые сервисом kubelet из docker-образов kubernetes также разворачиваются командой rootlessctl в окружени пользователя u7s-admin. Все PODы, запускаемые в рамках кластера от docker-образов с пользователем root (например стандартный образ nginx) в рамках POD'а имеют владельца root с идентификтором UID=0, позволяющего работать с ядром системы с привелегиями суперпользователя. В рамках же HOST-системы POD работает с привелегиями обычного пользователя u7s-admin с идентификтором UID=486.

Дерево процессов rootless kubernetes

Это значительно снижает поверхность атаки на кластер, так как злоумышленник, войдя в контейнер может нарушить его работу, но в рамках HOST-системы имея права обычного пользователя он не сможет существенно нарушить работу системы.

Для разворачивание rootless кластера необходимо установить необходимые RPM-пакеты командой:

apt-get install podsec podsec-k8s podsec-inotify

Разворачивание rootless kubernetes возможно в следующих режимах:

  • На платформах c10f в защищенном режиме с ISO-диска в локальной сети без доступа в Интернет;
  • На платформах ALTLinux p10, p11, ... с использованием внешнего docker-регистратора kubernetes образов.

В свою очередь на платформах ALTLinux p10, p11, ... возможно разворачивание как в защищенном, так и незащищенном режиме.

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

  • Администратор - создание пользователей других классов, мониториг работы кластера.
  • Создатель образов - создание образов, их подписывание и размещение на локальном или внешнем регистраторе.
  • Пользователь образов - запуск POD'ов, Deployments, RepliceSets, ... на основе подписанных образов на локальном или внешнем регистраторе.

Пользователь образов и Администратор могут использовать в своей работе только подписанные образы и только с сконфигурированного регистратора. При ручной правке конфигураций есть возможность использовать нескольких регистраторов с образами подписанными несколькими пользователями класса Создатель образов.

При разворачивании rootless kubernetes с доступом в Интернет можно использовать различные регистраторы docker-образов:

  • ALTLinux - docker-регистратор registry.altlinux.org (по умолчанию);
  • Нативный kubernetes - docker-регистратор registry.k8s.io;
  • Другие docker-регистраторы образов kubernetes.

Балансироващик REST-запросов к кластеру

Установка балансировщика REST-запросов haproxy

Если в вышеописанных вариантах разворачивания rootfull Или rootless-кластера устанавливается более одного controlplane узла, то по умолчанию распределять API-запросы к этим узлам кластера необходимо вручную.

rootless kubernetes-кластер без балансировщика haproxy

Ручная балансировка запросов к API-интерфейсам master-узлов путем указания у клиентов адресов различных master-узлов довольно неудобна, так как не обеспечивает равномерного распределения запросов по узлам кластера и не обеспечивает автоматической отказоустойчивости при выходе из строя master-узлов.

Решает данную проблему установка балансировщика нагрузки haproxy.

rootless kubernetes-кластер без балансировщика haproxy

Перевод кластера в режим балансировки запросов через haproxy возможен, но данная процедура не гарантирует корректный перевод на всех версиях kubernetes и ее не рекомендуют применять на production кластерах.

Так что наиболее надежным способом создания кластера с балансировкой запросов является создание нового кластера.

Настройка балансировщика REST-запросов haproxy

Балансировщик REST-запросов haproxy можно устанавливать как на отдельный сервер, так на один из серверов кластера.

Variant haproxy master.drawio.png

Если балансировщик устанавливается на rootless сервер кластера, то для балансировщика необходимо выделить отдельный IP-адрес. Если на этом же сервере функционируют локальный регистратор (registry.local) и сервер подписей (sigstore.local), то IP-адрес балансировщика может совпадать c IP-адресами этих сервисов.

Если планируется создание отказоустойчивого решения на основе нескольких серверов haproxy, то для них кроме собственного IP-адреса необходимо будет для всех серверов haproxy выделить один общий IP-адрес, который будет иметь master-балансировщик.


Полная настройка отказоустойчивого кластера haproxy из 3-х узлов описана в документе ALT Container OS подветка K8S. Создание HA кластера.

Здесь же мы рассмотрим создание и настройка с одним сервером haproxy с балансировкой запросов на master-узлы.

Установите пакет haproxy:

# apt-get install haproxy

Отредактируйте конфигурационный файл /etc/haproxy/haproxy.cfg:

  • добавьте в него описание frontend’a main, принимающего запросы по порту 8443:
     frontend main
      bind *:8443
      mode tcp
      option tcplog
      default_backend apiserver
    
  • добавьте описание backend’а apiserver:
    backend apiserver
      option httpchk GET /healthz
      http-check expect status 200
      mode tcp
      option ssl-hello-chk
      balance     roundrobin
      server master01 <IP_или_DNS_начального_мастер_узла>:6443 check
      server master02 <IP_или_DNS_второго_мастер_узла>:6443 check
      ...
    
  • запустите haproxy:
# systemctl enable haproxy
# systemctl start haproxy

Настройка отказоустойчивого кластера серверов haproxy, keepalived

Масштабирование haproxy, установка пакетов

Если необходимо создать отказоустойчивое решение допускающее выход haproxy-севрера из строя установите haproxy на несколько серверов. Файлы конфигурации haproxy<.code> на всех сервервх должны быть идентичны.

Для контроля доступности haproxy и переназначений виртуального адреса дополнительно установите на каждом сервис keepalived:

# apt-get install haproxy keepalived

Конфигурирование keepalived

kubeenetes кластер с haproxy и keepalived

Создайте файл конфигурации 'keepalived' /etc/keepalived/keepalived.conf:

! /etc/keepalived/keepalived.conf
! Configuration File for keepalived
global_defs {
    router_id LVS_K8S
}
vrrp_script check_apiserver {
  script "/etc/keepalived/check_apiserver.sh"
  interval 3
  weight -2
  fall 10
  rise 2
}

vrrp_instance VI_1 {
    state MASTER
    interface br0
    virtual_router_id  51
    priority 101
    authentication {
        auth_type PASS
        auth_pass 42
    }
    virtual_ipaddress {
        10.150.0.160 
    }
    track_script {
        check_apiserver
    }
}

На одном из узлов установите параметр state в значение MASTER и параметр priority в значение 101. На остальных параметр state в значение BACKUP и параметр priority в значение 100.

Скрипт /etc/keepalived/check_apiserver.sh проверяет доступность балансировщика haproxy:

#!/bin/sh

errorExit() {
    echo "*** $*" 1>&2
    exit 1
}

APISERVER_DEST_PORT=8443
APISERVER_VIP=10.150.0.160
curl --silent --max-time 2 --insecure https://localhost:${APISERVER_DEST_PORT}/ -o /dev/null || errorExit "Error GET https://localhost:${APISERVER_DEST_PORT}/"
if ip addr | grep -q ${APISERVER_VIP}; then
    curl --silent --max-time 2 --insecure https://${APISERVER_VIP}:${APISERVER_DEST_PORT}/ -o /dev/null || errorExit "Error GET https://${APISERVER_VIP}:${APISERVER_DEST_PORT}/"
fi

Параметр APISERVER_DEST_PORT задает порт балансировщиков haproxy, параметр APISERVER_VIP виртуальный адрес, через который будут взаимодействовать master (control plane) узлы кластера k8s.

Скрипт проверяет работоспособность haproxy на локальной машине.

Подробности см. на [[1]] А если в настоящее время виртуальный адрес принадлежит текущему узлу, то и работоспособность haproxy через виртуальный адрес.

Добавьте флаг на выполнение скрипта:

chmod a+x /etc/keepalived/check_apiserver.sh

При работающем балансировщике и хотя бы одному доступному порту 6443 на master-узлах скрипт должен завершаться с кодом 0.

Подробности см. на Keepalived

Разворачивание rootless кластера

Выбор варианта разворачивания

При разворачивании в режиме rootless в зависимости от использования локального регистратора docker-образов и применения политик доступа к ним можно обеспечить следующие варианты разворачивания rootless-кластера:

Варианты разворачивания rootless кластера
Локальный регистратор Политики доступа Примечание
Да Да Стандартный вариант при использовании команд пакета podsec-k8s: Возможность разворачивания в локальной сети без доступа в Интернет с поддержкой классов пользователей с ограничением доступа к docker-регистраторам
Да Нет Возможность разворачивания в локальной сети без доступа в Интернет. Политики доступа расширены или отсутствуют.
Нет Да Поддержка классов пользователей с ограничением доступа к docker-регистраторам. Политики доступа стандартные или расширены.
Нет Нет Стандартный вариант разворачивания rootfull-решений, но в поддержкой работы узлов кластера в rootless-режиме

Разворачивание с локальным регистратора и с политиками доступа в rootless режиме

Основной особенностью при разворачивании rootless кластера с ISO-диска в защищённом режиме без доступа в Интернет является то, что docker-образы загружаются командой podsec-load-sign-oci в локальный регистратор registry.local из каталога /media/ALTLinux/containers/ примонтированного диска. InitRegistryFromDVD 1.drawio.png Каталог содержит два файла-архива слоев образов в формате OCI:

  • base_amd64.tar.xz - базовые образы для создания новых образов;
  • k8s_amd64.tar.xz - kubernetes-образы для разворачивания кластера.

Разворачивании rootless кластера как и rootfull кластера производится через команду kubeadm. Формат вызова команды на Master ControlPlane, остальных ControlPlane's и Worker's аналогичен. Основные отличия:

  • Для Master ControlPlane необходимо не один, а два IP-адреса.
  • На Master ControlPlane устанавливаются дополнительные сервисы.
  • Запускается не нативная команда kubeadm из каталога /usr/bin, а оболочка над ним, обеспечивающая создания rootless-окружения пользователя u7s-admin.

Дополнительные сервисы включают в себя:

  • регистратор docker-образов с доменом registry.local;
  • WEB-сервер открытых ключей и Container Network Policy с доменом sigstore.local;
  • сервер анализа уязвимостей trivy.

Установка пакетов

Установите пакеты podsec:

apt-get install podsec-k8s podsec podsec-k8s-rbac podsec-inotify trivy

Выделение IP адресов для Master ControlPlane

Из за особенностей rootless-режима для Master ControlPlane необходимо выделит два IP-адреса. Один адрес будет использоваться в rootless-окружения, второй для обращения к основным ControlPlane сервисам Master узла.

В качестве примера выделим два адреса (в общем случае метод выделения может быть другим):

  • 192.168.122.70 - IP-адрес для rootless окружения;
  • 192.168.122.80 - IP- адрес для обращения к основным ControlPlane сервисам Master узла.

Допустим мы имеем на узлу интерфейс enp1s0. В этом случае структура файлов каталога /etc/net/ifaces/enp1s0 описания интерфейса ensp1s0 будет выглядеть следующим образом:

Файл options:

BOOTPROTO=static
TYPE=eth
CONFIG_WIRELESS=no
SYSTEMD_BOOTPROTO=static
CONFIG_IPV4=yes
DISABLED=no
NM_CONTROLLED=no
SYSTEMD_CONTROLLED=no

Файл ipv4address:

192.168.122.70/24
192.168.122.80/24

Файл ipv4route:

default via 192.168.122.1

Файл resolv.conf:

nameserver 192.168.122.1

После конфигурации данных файлов необходимо перезагрузить узел.

Интерфейс для данных параметров после перезагрузки выглядит следующим образом:

# ip a show dev enp1s0
2: enp1s0:  mtu 1500 qdisc fq_codel state UP group default qlen 1000
    link/ether 52:54:00:db:e1:57 brd ff:ff:ff:ff:ff:ff
    inet 192.168.122.70/24 brd 192.168.122.255 scope global enp1s0
       valid_lft forever preferred_lft forever
    inet 192.168.122.80/24 brd 192.168.122.255 scope global secondary enp1s0
       valid_lft forever preferred_lft forever
    ...

Создание файлов конфигурации Container Network Policy на Master ControlPlane в rootless режиме

Для создания Container Network Policy на Master узле вызовите команду:

# podsec-create-policy 192.168.122.70 # ip-aдрес_регистратора и WEB-сервера подписей
Добавление привязки доменов registry.local sigstore.local trivy.local к IP-адресу 192.168.122.70
Создание группы podman
Инициализация каталога /var/sigstore/ и подкаталогов хранения открытых ключей и подписей образов
Создание каталога и подкаталогов  /var/sigstore/
Создание группы podman_dev
Создание с сохранением предыдущих файла политик /etc/containers/policy.json
Создание с сохранением предыдущих файл /etc/containers/registries.d/default.yaml описания доступа к открытым ключам подписантов
Добавление insecure-доступа к регистратору registry.local в файле /etc/containers/registries.conf
Настройка использования образа registry.local/k8s-c10f1/pause:3.9 при запуска pod'ов в podman (podman pod init)

KuberDeployment Master1.drawio.png

После выполнения команды:

  • файл /etc/host должен содержать строку:
...
192.168.122.70 registry.local sigstore.local trivy.local
  • файл /etc/containers/policy.json, являющийся symlink'ом к файлу /etc/containers/policy_YYYY-MM-DD_HH:mm:SS должен иметь содержимое (запрет доступа по всем ресурсам):
{
  "default": [
    {
      "type": "reject"
    }
  ],
  "transports": {
    "docker": {}
  }
}
  • файл /etc/containers/registries.d/default.yaml, являющийся symlink'ом к файлу /etc/containers/registries.d/default_YYYY-MM-DD_HH:mm:SS должен иметь содержимое (ю URLs доступа к серверу подписей):
default-docker:
  lookaside: http://sigstore.local:81/sigstore/
  sigstore: http://sigstore.local:81/sigstore/

Данные файлы конфигурируют сервис cri-o, который контролирует доступ к docker-образам согласно указанным политикам. На данный момент файл /etc/containers/policy.json запрещает доступ к образам по всем видам транспортов, кроме доступа к docker-регистраторам. На данный момент список регистраторов пуст.

Разворачивание дополнительных сервисов на Master ControlPlane в rootless режиме

KuberDeployment Master2+.drawio.png

Для разворачивание дополнительных сервисов на Master ControlPlane поднимите сервисы регистратора и WEB-сервера подписей командой:

# podsec-create-services

Synchronizing state of nginx.service with SysV service script with /lib/systemd/systemd-sysv-install. Executing: /lib/systemd/systemd-sysv-install enable nginx Created symlink /etc/systemd/system/multi-user.target.wants/nginx.service → /lib/systemd/system/nginx.service. registry Created symlink /etc/systemd/system/multi-user.target.wants/docker-registry.service → /lib/systemd/system/docker-registry.service.

Проверьте функционирование сервисов:

# netstat -nlpt
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address               Foreign Address             State       PID/Program name
...
tcp        0      0 0.0.0.0:81                  0.0.0.0:*                   LISTEN      14996/nginx -g daem
...
tcp        0      0 :::80                       :::*                        LISTEN      15044/docker-regist
...
tcp        0      0 :::4954                     :::*                        LISTEN      30864/trivy

...

Порт 81 должен слушать сервис nginx. Порт 80 ервис docker-registry. Порт 4954 сервис trivy.

Создание на Master ControlPlane пользователей различных классов

При разворачивании kubernetes в rootless режиме в системе могут существовать пользователи нескольких классов:

  • Администратор системы - пользователь root.
  • Создатель образов контейнеров.
  • Пользователь информационной системы.
  • Обычный пользователь.
Администратор системы

Роль администратора системы выполняет пользователь root:

  • имеющий права создавать других пользователей
  • имеющий права просматривать системные логи в том числе логи по безопасности;
  • не имеющий права создавать новые образы и
  • может (как и пользователь информационной системы) использовать только подписанные образы образы с регистратора registy.local.
Создание пользователя разработчика образов контейнеров

Разработчика образов контейнеров в отличие от других пользователей имеет доступ ко всем образам по всем протоколам. Это необходимо для возможности создания новых образов для локального регистратора registry.local. Кроме этого пользователь этого класса при создании формирует электронную подпись, которую может использовать при размещении образов на регистраторе registry.local.

Открытые ключи всех разработчиков образов для проверки подписи при их загрузке с регистратора registry.local хранятся в каталоге /var/sigstore/keys.

Для создания пользователя разработчик образов контейнеров выполните команду указав имя пользователя (обычно imagemaker):

# podsec-create-imagemakeruser <имя_пользователя_создателя образов>

Во время выполнения команды необходимо:

  • дважды ввести пароль для пользователя;
  • выбрать тип и длину GPG-ключа;
  • указать срок действия ключа;
  • ввести E-mail для ключа;
  • ввести пароль для подписывания образа.

Файл /etc/containers/policy.json, должен изменить symlink на другой файл /etc/containers/policy_YYYY-MM-DD_HH:mm:SS с содержимым (разрешение доступа к регистратору registry.local с открытым ключом пользователя imagemaker):

{
  "default": [
    {
      "type": "reject"
    }
  ],
  "transports": {
    "docker": {
      "registry.local": [
        {
          "type": "signedBy",
          "keyType": "GPGKeys",
          "keyPath": "/var/sigstore/keys/imagemaker.pgp"
        }
      ]
    }
  }
}

Должен появится каталог /var/sigstore/ со следующей структурой:

├── index.html
├── keys
│   ├── imagemaker.pgp
│   └── policy.json
└── sigstore

Проверьте доступ к этому каталогу через http:

# curl -s  http://sigstore.local:81/keys/ | jq
[
  {
    "name": "imagemaker.pgp",
    "type": "file",
    "mtime": "Tue, 23 May 2023 05:43:59 GMT",
    "size": 2436
  },
  {
    "name": "policy.json",
    "type": "file",
    "mtime": "Tue, 23 May 2023 05:43:25 GMT",
    "size": 276
  }
]

Команду podsec-create-imagemakeruser можно запускать без параметров или задать несколько пользователей этого класса.

При запуска без параметров создается пользователь с именем imagemaker.

При необходимости задания нескольких пользователей к имени каждого пользователя должен быть добавлен суффикс @registry.local для указания, что все подписанные ими образы помещаются в регистратор registry.local. Вызов в этом случае выглядит так:

# podsec-create-imagemakeruser <имя_пользователя1>@registry.local  <имя_пользователя2>@registry.local ...
Создание пользователя информационной системы

Пользователь информационной системы имеет право запускать только подписанные образы с локального регистраторв registry.local.

Для создания пользователя информационной системы вызовите команду:

# podsec-create-podmanusers <имя_пользователя_информационной_системы1> [<имя_пользователя_информационной_системы2> ...]

Во время выполнения команды необходимо дважды ввести пароль для пользователя

Обычный пользователь

Обычный пользователь также имеет право запускать только подписанные образы с локального регистраторв registry.local, но для него корректный запуск контейнеров командами podman, crictl, ... не гарантируется. Создается он обычными командами создания пользователей системы.

Доступ к OCI-архиву базовых и kubernetes образов

Методы получения OCI-архивов

OCI-архивы базовых и kubernetes образов располагаются на ISO-диске в каталоге containers под именами base_amd64.tar.xz и k8s_amd64.tar.xz соответственно. Их следует скопировать в домашний каталог пользователя разработчика образов контейнеров. Вы можете самостоятельно сформировать эти архивы для разворачивания последней доступной версии kubernetes.

Формирование OCI-архива kubernetes-образов с регистратора registry.altlinux.org

Для подъема регистратора docker-образов необходимо проверить наличие и при необходимости установить установить пакет podsec-dev и пакеты podsec-k8s podsec:

apt-get install podsec-dev podsec-k8s podsec

OCI-архив kubernetes-образов представляет собой сжатый командой xz tar-архив каталога kubernetes образов в формате OCI. Хранение в формате OCI позволяет минимизировать размер архива с нескольких гигабайт до 2-х сотен мегабайт. Это достигается за счет того, что OCI-каталоге образов каждый слой образов встречается однократно. А так как kubernetes-образы имеют много общих слоев, размер OIC-каталога в несколько раз меньше, чем суммарный объем архивов образов, сохраненных командой podman save. Кроме того образы, записываются в OCI-архив с несжатыми слоями. Это позволяет эффективно их сжимать компрессором xz.

Для формирования OCI-архива kubernetes-образов из под пользователя root:

  • перейдите в каталог /root
  • если в каталоге уже существует подкаталог k8s_amd64 переименуйте его или удалите;
  • вызовите команду:
podsec-k8s-save-oci k8s_amd64 amd64 
  • Первым параметром указывается имя каталога в который помещается архив amd64.tar.xz или arm64.tar.xz в зависимости от архитектуры.
  • Вторым - имя архитектуры (amd64 или arm64).

Команда:

  • устанавливает последние версии пакетов kubeadm, crio;
  • определяет список kubernetes-образов последней версии, включая образы etcd и flannel;
  • скачивает их с регистратора registry.altlinux.org и помещает в каталог /root/.local/share/usernetes/images/c10f/amd64/ в формате containers-storage;
  • копирует образы из каталога /root/.local/share/usernetes/images/c10f/amd64/ в каталог k8s_amd64/amd64 в формате oci;
  • по окончании копирования всех образов архивирует каталог k8s_amd64/amd64 командой tar, сжимает архив и помещает в файл amd64.tar.xz указанного каталога k8s_amd64.

Для архивации других образов (например базовых c10f/distroless-base, c10f docker-регистратора registry.altlinux.org) необходимо в переменной U7S_ALTREGISTRY указать имя docker-регистратора и вызвать команду podsec-save-oci.

export U7S_ALTREGISTRY=registry.altlinux.org  
podsec-save-oci base_amd64 amd64 '' c10f/distroless-base c10f/alt
  • Первым параметром указывается имя каталога в который помещается архив amd64.tar.xz.
  • Вторым - имя архитектуры (amd64 или arm64).
  • Третьим - тип транспорта (по умолчанию docker://).
  • В последующих параметрах указываются список архивируемых образов.

Команда:

  • устанавливает последние версии пакетов kubeadm, crio;
  • принимает список архивируемых образов;
  • скачивает их с указанного переменной среды U7S_ALTREGISTRY регистратора и помещает в каталог /root/.local/share/usernetes/images/c10f/amd64/ в формате containers-storage;
  • копирует образы из каталога /root/.local/share/usernetes/images/c10f/amd64/ в каталог k8s_amd64/amd64 в формате oci;
  • по окончании копирования всех образов архивирует каталог k8s_amd64/amd64 командой tar, сжимает архив и помещает в файл amd64.tar.xz указанного каталога base_amd64.

Если Вам необходимо архивировать образы архитектуры arm64 укажите вторым параметром команд arm64.

Полученные OCI-архивы следует скопировать в домашний каталог пользователя разработчика образов контейнеров.

Подписывание образов и размещения на локальном регистраторе

KuberDeployment Master3.drawio.png

Загрузите kubernetes-образы от пользователя imagemaker.

$ podsec-load-sign-oci <имя_файла_OCI-архива> amd64 <E-mail_подписанта>

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

Внимание: Данную команду нельзя запускать путем получения прав пользователя через команду su - imagemaker, так как устанавливаются не все переменные среды. Сделайте полный заход под пользователем, например по протоколу ssh:

# ssh imagemaker@localhost

или через machinectl:

# machinectl shell imagemaker@

После выполнения скрипта проверьте наличие образов в регистраторе:

# curl -s registry.local/v2/_catalog | jq
{
  "repositories": [
    "c10f/coredns",
    "c10f/etcd",
    "c10f/flannel",
    "c10f/flannel-cni-plugin",
    "c10f/kube-apiserver",
    "c10f/kube-controller-manager",
    "c10f/kube-proxy",
    "c10f/kube-scheduler",
    "c10f/pause",
    "k8s-c10f2/coredns",
    "k8s-c10f2/etcd",
    "k8s-c10f2/flannel",
    "k8s-c10f2/flannel-cni-plugin",
    "k8s-c10f2/kube-apiserver",
    "k8s-c10f2/kube-controller-manager",
    "k8s-c10f2/kube-proxy",
    "k8s-c10f2/kube-scheduler",
    "k8s-c10f2/pause"
  ]
}

Внимание: Кроме образов с префиксом c10f/ в результате запроса могкт быть отображены образы с префиксами k8s-c10f1, k8s-c10f2. Это связано с обеспечением совместимости предыдущего способа именования префикса образов k8s-c10f1<N> и текущего c10f.

Проверьте наличие подписей в каталоге /var/sigstore/sigstore/k8s-c10f2:

# tree /var/sigstore/sigstore/c10f/
/var/sigstore/sigstore/c10f/
├── coredns@sha256=...
│   └── signature-1
├── etcd@sha256=...
│   └── signature-1
├── flannel-cni-plugin@sha256=...
│   └── signature-1
├── flannel@sha256=...
│   └── signature-1
├── kube-apiserver@sha256=...
│   └── signature-1
├── kube-controller-manager@sha256=...
│   └── signature-1
├── kube-proxy@sha256=...
│   └── signature-1
├── kube-scheduler@sha256=...
│   └── signature-1
└── pause@sha256=...
    └── signature-1

Число подкаталогов должно совпадать с числом образов в регистраторе и каждый подкаталог должен иметь файл signature-1.

Создание дополнительных образов и размещение их в локальном регистраторе

Копирование образов с других регистраторов

Для копирования образа (например nginx) с внешнего регистратора загрузите его в пользователе разработчика образов контейнеров:

[imagemaker@master1 ~]$ podman pull registry.altlinux.org/c10f/nginx:1.26.3
Trying to pull registry.altlinux.org/c10f/nginx:1.26.3...
Getting image source signatures
Copying blob 1bc1a80e4a16 done   | 
Copying blob 82e02127e2b4 skipped: already exists  
Copying blob 98ed66316f15 done   | 
Copying blob a2bb93664add skipped: already exists  
Copying blob b43be2116c2b done   | 
Copying blob 4df9de94b01c done   | 
Copying blob 5c2c8c67033f done   | 
Copying config d8a1de134d done   | 
Writing manifest to image destination
d8a1de134d2ea60956f987b6c47acdac0e8dcc863c6a98e16210f9a82e860932

Навешайте на него тег с именем локального регистратора registry.local:

[imagemaker@master1 ~]$ podman tag registry.altlinux.org/c10f/nginx:1.26.3 registry.local/c10f/nginx:1.26.3

Поместите образ в локальный регистратор, указав в флаге --sign-by E-mail пользователя введенные при создании ключей пользователя:

[imagemaker@master1 ~]$ podman push --tls-verify=false --sign-by="..." registry.local/c10f/nginx:1.26.3

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

Getting image source signatures
Copying blob f0e31397ae37 done   | 
Copying blob 60204c5adf60 done   | 
Copying blob 9a0fa9f6d6ea done   | 
Copying blob 5957b6b3c861 done   | 
Copying blob f06afe809992 done   | 
Copying blob e268fece4a97 done   | 
Copying blob 6cb900dcc924 done   | 
Copying config d8a1de134d done   | 
Writing manifest to image destination
Creating signature: Signing image using simple signing
Storing signatures
Создание собственных образов

Создайте каталог (например net-tools) для хранения артефактов образа и перейдите в него:

[imagemaker@master1]$ mkdir  net-tools
[imagemaker@master1]$ cd  net-tools

Сформируйте Dockerfile:

FROM registry.altlinux.org/c10f/alt

RUN apt-get update && \
    apt-get install -y tcpdump nmap bind-utils

Создайте от образа registry.altlinux.org/c10f/alt дочерний образ registry.local/net/net-tools:

[imagemaker@master1 net-tools]$ podman build -t registry.local/net/net-tools .
STEP 1/2: FROM registry.altlinux.org/c10f/alt
STEP 2/2: RUN apt-get update &&     apt-get install -y tcpdump nmap bind-utils
Get:1 http://update.altsp.su c10f2/branch/x86_64 release [3576B]
...
Fetched 46.1MB in 11s (3845kB/s)
Reading Package Lists...
Building Dependency Tree...
Reading Package Lists...
Building Dependency Tree...
The following extra packages will be installed:
...
Done.
COMMIT registry.local/net/net-tools
--> 06c7112c2901
Successfully tagged registry.local/net/net-tools:latest

Поместите образ в локальный регистратор, указав в флаге --sign-by E-mail пользователя введенные при создании ключей пользователя:

podman push --tls-verify=false --sign-by="kaf@basealt.ru" registry.local/net/net-tools:latest

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

Getting image source signatures
Copying blob 9a0fa9f6d6ea done   | 
Copying blob 08347d1dc3ae done   | 
Copying blob 5957b6b3c861 done   | 
Copying config 06c7112c29 done   | 
Writing manifest to image destination
Creating signature: Signing image using simple signing
Storing signatures

Разворачивание Master ControlPlane узла

Инициализация

KuberDeployment Master4.drawio.png

Измените переменную PATH:

export PATH=/usr/libexec/podsec/u7s/bin/:$PATH

Запустите команду:

# kubeadm -v 9 init  --apiserver-advertise-address 192.168.122.80

При запуске в параметре --apiserver-advertise-address укажите IP-адрес API-интерфейса kube-apiserver. Этот адрес должен отличаться от IP-адреса регистратора и WEB-сервера подписей.

Внимание: По умолчанию уровень отладки устанавливается в 0. Если необходимо увеличить уровень отладки укажите перед подкомандой init флаг -v n. Где n принимает значения от 0 до 9-ти.

Внимание: При запуске с балансировщиком запросов haproxy необходимо дополнительно указать параметр --control-plane-endpoint:

# kubeadm init --apiserver-advertise-address 192.168.122.80 --control-plane-endpoint <IP_адрес_haproxy>:<PORT_haproxy>

После:

  • генерации сертификатов в каталоге /etc/kuarnetes/pki,
  • загрузки образов, -генерации conf-файлов в каталоге /etc/kubernetes/manifests/, /etc/kubernetes/manifests/etcd/
  • запуска сервиса kubelet и Pod'ов системных kubernetes-образов

инициализируется kubernet-кластер из одного узла.

По окончании скрипт выводит строки подключения master(Control Plane) и worker-узлов:

You can now join any number of control-plane nodes by copying certificate authorities
and service account keys on each node and then running the following as root:

kubeadm join xxx.xxx.xxx.xxx:6443 --token ... --discovery-token-ca-cert-hash sha256:.. --control-plane

Then you can join any number of worker nodes by running the following on each as root:

kubeadm join xxx.xxx.xxx.xxx:6443 --token ... --discovery-token-ca-cert-hash sha256:...

Запомните команды kubeadm join ... подключения controplane и worker узлов.


Для проверки состояния kubernetes из одного master-узла выполните команды:

# kubectl get daemonsets.apps -A
NAMESPACE      NAME              DESIRED   CURRENT   READY   UP-TO-DATE   AVAILABLE   NODE SELECTOR            AGE
kube-flannel   kube-flannel-ds   1         1         1       1            1           <none>                   102s
kube-system    kube-proxy        1         1         1       1            1           kubernetes.io/os=linux   8h

Число READY каждого daemonset должно быть равно числу DESIRED и должно быть равно числу узлов кластера.

# kubectl get nodes
NAME       STATUS   ROLES           AGE     VERSION
host-...    Ready    control-plane   ...   v1.xx.x

Проверьте работу всех ресурсов:

# kubectl get all -A
NAMESPACE     NAME                                   READY   STATUS    RESTARTS   AGE
kube-system   pod/coredns-c7df5cd6c-5pkkm            1/1     Running   0          19m
kube-system   pod/coredns-c7df5cd6c-cm6vf            1/1     Running   0          19m
kube-system   pod/etcd-host-212                      1/1     Running   0          19m
kube-system   pod/kube-apiserver-host-212            1/1     Running   0          19m
kube-system   pod/kube-controller-manager-host-212   1/1     Running   0          19m
kube-system   pod/kube-proxy-lqf9c                   1/1     Running   0          19m
kube-system   pod/kube-scheduler-host-212            1/1     Running   0          19m

NAMESPACE     NAME                 TYPE        CLUSTER-IP   EXTERNAL-IP   PORT(S)                  AGE
default       service/kubernetes   ClusterIP   10.96.0.1    <none>        443/TCP                  19m
kube-system   service/kube-dns     ClusterIP   10.96.0.10   <none>        53/UDP,53/TCP,9153/TCP   19m

NAMESPACE     NAME                        DESIRED   CURRENT   READY   UP-TO-DATE   AVAILABLE   NODE SELECTOR            AGE
kube-system   daemonset.apps/kube-proxy   1         1         1       1            1           kubernetes.io/os=linux   19m

NAMESPACE     NAME                      READY   UP-TO-DATE   AVAILABLE   AGE
kube-system   deployment.apps/coredns   2/2     2            2           19m

NAMESPACE     NAME                                DESIRED   CURRENT   READY   AGE
kube-system   replicaset.apps/coredns-c7df5cd6c   2         2         2       19m

Состояние всех Pod’ов должны быть в 1/1.

Проверьте состояние дерева rootless-процессов:

# pstree
...
├─systemd─┬─(sd-pam)
│         ├─dbus-daemon
│         ├─nsenter.sh───nsenter───_kubelet.sh───kubelet───11*[{kubelet}]
│         └─rootlesskit.sh───rootlesskit─┬─exe─┬─conmon───kube-controller───7*[{kube-controller}]
│                                        │     ├─conmon───kube-apiserver───8*[{kube-apiserver}]
│                                        │     ├─conmon───kube-scheduler───7*[{kube-scheduler}]
│                                        │     ├─conmon───etcd───8*[{etcd}]
│                                        │     ├─conmon───kube-proxy───4*[{kube-proxy}]
│                                        │     ├─2*[conmon───coredns───8*[{coredns}]]
│                                        │     ├─rootlesskit.sh───crio───10*[{crio}]
│                                        │     └─7*[{exe}]
│                                        ├─slirp4netns
│                                        └─8*[{rootlesskit}]
...

Процесс kubelet запускается как сервис в user namespace процесса rootlesskit.

Все остальные процессы kube-controller, kube-apiserver, kube-scheduler, kube-proxy, etcd, coredns запускаются как контейнеры от соответствующих образов в user namespace процесса rootlesskit. Обеспечение запуска обычных POD’ов на мастер-узле

Установка режима запуска на Controlplane пользовательских POD'ов

По умолчанию на master-узле пользовательские Podы не запускаются. Если необходимо снять это ограничение наберите команду:

# kubectl taint nodes <host> node-role.kubernetes.io/control-plane:NoSchedule-
node/<host> untainted

Где <host> - имя master-узла, отображаемое в выводе команды:

# kubectl get nodes

Подключение ControlPlane и Worker узлов

Установка пакетов

Установите пакеты podsec необходимые для функционировния узла.

# apt-get install podsec-k8s podsec podsec-inotify
Создание файлов конфигурации Container Network Policy на ControlPlane или Worker в rootless режиме

KuberDeployment5.drawio.png Для создание файлов конфигурации подключаемого узла вызовите команду:

# podsec-create-policy <IP_адрес_MASTER_Controlplane_узла>
Добавление привязки доменов registry.local sigstore.local trivy.local к IP адресу 192.168.122.70
Создание группы podman
Инициализация /var/sigstore/ каталога /var/sigstore/ и подкаталогов хранения открытых ключей и подписей образов
Создание каталога и подкаталогов /var/sigstore/
Создание с сохранением предыдущего файла политик /etc/containers/policy.json
Создание с сохранением предыдущего файла /etc/containers/registries.d/default.yaml описания доступа к открытым ключам подписантов
Добавление insecure-доступа к регистратору registry.local в /etc/containers/registries.conf file

Команда произведен действия аналогичные действиям команды на Master ControlPlane узле, но файл конфигурации /etc/containers/policy.json скопирует с Master узла.

Подключение узла к кластеру

Измените переменную PATH:

export PATH=/usr/libexec/podsec/u7s/bin/:$PATH

KuberDeployment6.drawio.png Для подключения Controlplane или Worker узла к кластеру скопируйте строку подключения kubeadm join ... из логов команды инициализации Master Controlplane узла.

# kubeadm join ...

После завершения выполнения команды проверьте по отображаемым на мониторе логам ее успешность и запустите на Master ControlPlane узле команду:

# kubectl get nodes
NAME       STATUS   ROLES           AGE     VERSION
host-xxx    Ready    control-plane  ---     v1....
host-yyy    Ready    <none>         ---     v1....

Подключенный узел должен отображаться в списке с состоянием Ready.

Другие способы разворачивания rootless кластера

Разворачивание с локальным регистратора с расширенными политиками доступа или без них

Политики доступа описываются в файле /etc/containers/policy.json. ФОрмат этого файла описан в документе containers-policy.json - syntax for the signature verification policy file. Ниже описаны методы корректировки данного файла с помощью команды jq, обеспечивающей корректность структуры json-файла. При необходимости Вы можете править этот файл текстовым редактором соблюдая корректность JSON-структуры. Если Вы корректируете данный файл на Master Conrolplane узле ДО разворачивания остальный узлов скопируей его в каталог /var/sigstore/keys/. В этом случае это файл автоматически скопируется в каталог /etc/containers/ разворачиваемого узла. Если узлы развернуты скопируйте этот файл в каталог /etc/containers/ развернтых узлов.

По умолчанию файл /etc/containers/policy.json политик доступа к docker-образам настраивается на максимальные ограничения:

{
  "default": [
    {
      "type": "reject"
    }
  ],
  "transports": {
    "docker": {
      "registry.local": [
        {
          "type": "signedBy",
          "keyType": "GPGKeys",
          "keyPath": "/var/sigstore/keys/imagemaker.pgp"
        }
      ]
    }
  }
}

Пользователям разрешается доступ только к образам на локальном регистраторе registry.local, подписанными ключом пользователя imagemaker.

При необходимости Вы можете расширить политику:

  • указав дополнительные допустимые ключи подписи;
  • расширив список доступных docker-регистраторов;
  • расширив список доступных транспортов.
Добавление нового пользователя разработчика образов контейнеров

В описанной выше схеме создается только один пользователь разработчика образов контейнеров. Вы можете, используя скрипт podsec-create-imagemakeruser создавать неограниченое число пользователей данного класса. К сожалению в версиях podsec <= 1.1.20 при добавлении нового пользователя список предыдущих пользователей в файле /etc/containers/policy.json обнуляется. Ниже приведена последовательность действия для поддержания корректного списка пользователей.

Файл /etc/containers/policy.json является символической ссылкой на файл политик с именем по дате создания политики. Например:

# ls -l /etc/containers/policy*
-rw-r--r-- 1 root root 256 авг 28  2024 /etc/containers/policy_2025-10-29_12:53:52
-rw-r--r-- 1 root root  98 окт 30 12:53 /etc/containers/policy_2025-10-30_12:53:52
-rw-r--r-- 1 root root 276 окт 30 13:23 /etc/containers/policy_2025-10-30_13:23:00
lrwxrwxrwx 1 root root  26 ноя 10 14:20 /etc/containers/policy.json -> policy_2025-10-30_13:23:00

Данный подход позволяет хранить историю политик для данного узла и при необходимости переключать текущие политики перелинковкой файла policy.json:

 
# cd /etc/containers; ln -sf policy_<время_создания_политики> policy.json

Запомните в переменной oldPolicyFile имя файла текущей политики.

# policyFile='policy.json'
# oldPolicyFile=$(readlink $policyFile)

В данном примере oldPolicyFile будет хранить имя файла policy_2025-10-30_13:23:00 в каталоге /etc/containers/. Файл содержит JSON-объект описания политики:

{
  "default": [
    {
      "type": "reject"
    }
  ],
  "transports": {
    "docker": {
      "registry.local": [
        {
          "type": "signedBy",
          "keyType": "GPGKeys",
          "keyPath": "/var/sigstore/keys/imagemaker.pgp"
        }
      ]
    }
  }
}

Создайте нового пользователя:

# podsec-create-imagemakeruser imagemaker2

В процессе создания пользователя создастся новый файл политик с именем /etc/containers/policy_2025-11-10_14:19:00 и файл политик /etc/containers/policy.json залинкуется на него.

# ls -l /etc/containers/policy*
-rw-r--r-- 1 root root 256 авг 28  2024 /etc/containers/policy_2025-10-29_12:53:52
-rw-r--r-- 1 root root  98 окт 30 12:53 /etc/containers/policy_2025-10-30_12:53:52
-rw-r--r-- 1 root root  98 окт 30 13:22 /etc/containers/policy_2025-10-30_13:22:40
-rw-r--r-- 1 root root 276 окт 30 13:23 /etc/containers/policy_2025-10-30_13:23:00
-rw-r--r-- 1 root root 277 ноя 10 14:19 /etc/containers/policy_2025-11-10_14:19:00
lrwxrwxrwx 1 root root  26 ноя 10 14:20 /etc/containers/policy.json -> policy_2025-11-10_14:19:00

Новый файл /etc/containers/policy_2025-11-10_14:19:00 в элементе .transports.docker."registry.local" содержит массив с описанием тропы до открытого ключа нового пользователя :

{
  "default": [
    {
      "type": "reject"
    }
  ],
  "transports": {
    "docker": {
      "registry.local": [
        {
          "type": "signedBy",
          "keyType": "GPGKeys",
          "keyPath": "/var/sigstore/keys/imagemaker2.pgp"
        }
      ]
    }
  }
}

Приведенные ниже команды объединять массивы:

# cd /etc/containers; 
# registryArray=$(jq -sc '.[0].transports.docker."registry.local" + .[1].transports.docker."registry.local"' $policyFile $oldPolicyFile)
# newPolicyFile=policy_$(date '+%Y-%m-%d_%H:%M:%S')
# jq '.transports.docker."registry.local"|='$registryArray $policyFile > $newPolicyFile
# ln -sf $newPolicyFile policy.json

Файл /etc/containers/policy.json будет содержать массив со всеми открытым ключами пользователей:

{
  "default": [
    {
      "type": "reject"
    }
  ],
  "transports": {
    "docker": {
      "registry.local": [
        {
          "type": "signedBy",
          "keyType": "GPGKeys",
          "keyPath": "/var/sigstore/keys/imagemaker2.pgp"
        },
        {
          "type": "signedBy",
          "keyType": "GPGKeys",
          "keyPath": "/var/sigstore/keys/imagemaker.pgp"
        }
      ]
    }
  }
}

Вы можете не использовать данные команды, а поправить файл /etc/containers/policy.json в текстовом редакторе.

Добавление нового регистратора

Вы можете добавить в файле /etc/containers/policy.json новый регистратор в объект .transports.docker. Например registry.altlinux.org:

№ cd /etc/containers; 
# newPolicyFile=policy_$(date '+%Y-%m-%d_%H:%M:%S')
# jq '.transports.docker."registry.altlinux.org"|=[{type:"insecureAcceptAnything"}]' policy.json > $newPolicyFile
# ln -sf $newPolicyFile policy.json

В данном примере политика доступа insecureAcceptAnything для регистратора registry.altlinux.org разрешает досступ к нему без ограничений. Вы можете поменять политику доступа на другую. Файл /etc/containers/policy.json будет иметь вид:

{
  "default": [
    {
      "type": "reject"
    }
  ],
  "transports": {
    "docker": {
      "registry.local": [
        ...
      ],
      "registry.altlinux.org": [
        {
          "type": "insecureAcceptAnything"
        }
      ]
    }
  }
}

В этом случае загрузка образов с регистратора registry.altlinux.org будет производится без проверки подписи:

# podman pull registry.altlinux.org/alt/alt
Trying to pull registry.altlinux.org/alt/alt:latest...
Getting image source signatures
Copying blob c549b474d68c done   | 
Copying blob 8d382247a69f done   | 
Copying config 97c70e35e5 done   | 
Writing manifest to image destination
97c70e35e5754c99e2739a341746ab94e4f118e9c63ceaba806e369af80075e9
Расширение списка доступных транспортов

Политики доступа к образам поддерживают несколько типов транспорта:

  • atomic - Образ располагается в регистраторе типа atomic.
  • containers-storage - образы хранятся в каталоге файловой системы в формате драйвера (например для podman/cri-o: [overlay@/var/lib/containers/storage]).
  • dir - Образ располагается в локальном каталоге;
  • docker - Образ располагается в docker-регистраторе поддерживающий протокол "Docker Registry HTTP API V2".
  • docker-archive - Образ в виде tar-архива созданный командами docker save, podman save, ...
  • oci -Образ располагается в локальном каталоге в формате "Open Container Image Layout Specification". В таком формате в виде сжатого tar-архива хранятся kubernetes-образы на ISO диске дистрибутива;
  • tarball - Заархивированная (tar) файловая система образа.
  • ...

Рассмотрим пример добавления транспорта docker-archive. Текущая политика запрещает получать образы их архивного файла, полученными командами docker save, podman save.

# podman load -i /tmp/nginx.tar
 * docker-archive: Source image rejected: Running image docker-archive:/tmp/nginx.tar:registry.altlinux.org/c10f/nginx:latest is rejected by policy.

Для обеспечения возможности получать образы из архивов этого формата добавим транспорт docker-archive с типом insecureAcceptAnything:

№ cd /etc/containers; 
# newPolicyFile=policy_$(date '+%Y-%m-%d_%H:%M:%S')
# jq '.transports."docker-archive"."".[0].type="insecureAcceptAnything"' policy.json > $newPolicyFile
# ln -sf $newPolicyFile policy.json

Файл /etc/containers/policy.json получит вид:

{
  "default": [
    {
      "type": "reject"
    }
  ],
  "transports": {
    "docker": {
        ...
    },
    "docker-archive": {
      "": {
        "policy": [
          {
            "type": "insecureAcceptAnything"
          }
        ]
      }
    }
  }
}

После этого из архива /tmp/nginx.tar экспортируется образ registry.altlinux.org/c10f/nginx:latest:

# podman load -i /tmp/nginx.tar 
Getting image source signatures
Copying blob f0e31397ae37 skipped: already exists  
Copying blob 9a0fa9f6d6ea skipped: already exists  
Copying blob f06afe809992 skipped: already exists  
Copying blob 5957b6b3c861 skipped: already exists  
Copying blob e268fece4a97 skipped: already exists  
Copying blob 60204c5adf60 skipped: already exists  
Copying blob 6cb900dcc924 skipped: already exists  
Copying config d8a1de134d done   | 
Writing manifest to image destination
Loaded image: registry.altlinux.org/c10f/nginx:latest
Отключение политик доступа

Сформируйте новый файл политик:

# cd /etc/containers
# newPolicyFile=policy_$(date '+%Y-%m-%d_%H:%M:%S')
# echo '{"default":[{"type":"insecureAcceptAnything"}],"transports":{"docker-daemon":{"":[{"type":"insecureAcceptAnything"}]}}}' | jq > $newPolicyFile
# ln -sf $newPolicyFile policy.json

Текущий файл политик будет иметь следующую структуру:

{
  "default": [
    {
      "type": "insecureAcceptAnything"
    }
  ],
  "transports": {
    "docker-daemon": {
      "": [
        {
          "type": "insecureAcceptAnything"
        }
      ]
    }
  }
}

При этой конфигурации поддерживаются все виде транспортов и загрузка образов со всех регистраторов.

Расширение политик доступа к docker-образам для конкретных пользователей
Описание пользовательских файлов политик доступа к docker-образам

Кроме общесистемного файла описания политик доступа /etc/containers/policy.json к docker-образам в домашнем каталоге пользователя в подкаталоге .config/containers/ может располагаться пользовательский файл policy.json. Дерево файлов описания политик доступа Политики доступа этого файла перекрывают политики доступа общесистемного файла /etc/containers/policy.json.

Для пользователей класса "Создатель образов" файл .config/containers/policy.json обеспечивает выключение политик для данного пользователя:

{
  "default": [
    {
      "type": "reject"
    }
  ],
  "transports": {
    "docker": {
        ...
    },
    "docker-archive": {
      "": {
        "policy": [
          {
            "type": "insecureAcceptAnything"
          }
        ]
      }
    }
  }
}

Пользователи класса "Пользователь образов" содержит каталог .config/containers с запретом записи в него файлов.

# lsattr .config
----i---------e------- .config/containers

Таким образом пользователи данного класса используют общесистемный файл описания политик доступа /etc/containers/policy.json и не могут создать свой альтернативный файл .config/containers/policy.json.

Образы и контейнеры запускаемые из суперпользователя root располагаются в каталоге /var/lib/containers. Образы и контейнеры запускаемые из обычных пользователей располагаются в каталоге ~/.local/share/containers.

Kubernetes-образы и kubernetes-контейнеры запускаемые из под пользователя u7s-admin располагаются в каталоге ~u7s-admin/.local/share/usernetes/containers/. Причем каталог ~u7s-admin/.local/share/containers/ придинкован к этому каталогу. Это обеcпечивает единый каталог хранения образов и контейнеров запускаемых командой podsec и запускаемых движком cri-o rootless kubernetes.

Конфигурирование пользовательских файлов политик доступа к docker-образам

Конфигурирование пользовательских файлов ~/.config/containers/poliсy.json политик доступа к docker-образам ничем не отличается от конфигурирования общесистемного файла /etc/containers/policy.json, описанного в разделе Разворачивание с локальным регистратора с расширенными политиками доступа или без них.

Разворачивание без локального регистратора с политиками доступа

При разворачивании без локального регистратора kubernetes-образы берутся с регистратора registry.altlinux.org. В связи с этим необходимо в файле политик обеспечить доступ к этому регистратору командами:

# cd /etc/containers
# newPolicyFile=policy_$(date '+%Y-%m-%d_%H:%M:%S')
# jq '.transports.docker|={"registry.altlinux.org":[{"type":"insecureAcceptAnything"}]}' policy.json 
# ln -sf $newPolicyFile policy.json

Файл политик /etc/containers/poliсy.json будет иметь вид:

{
  "default": [
    {
      "type": "reject"
    }
  ],
  "transports": {
    "docker": {
      "registry.altlinux.org": [
        {
          "type": "insecureAcceptAnything"
        }
      ]
    }
  }
}

Для разворачивания kubernetes-кластера с регистратора registry.altlinux.org перед запуском команды инициализации Master Controlplane узла kubeadm init ... или команды присоединения узла kubeadm join ... необходимо установить переменные определяющие регистратор с которого загружаются образы и версию kubernetes. Регистратор с которого загружаются образы задается переменной U7S_REGISTRY.

# export U7S_REGISTRY=registry.altlinux.org

Список доступных версий kubernetes можно получить командой:

# curl -ks https://$U7S_REGISTRY/v2/c10f/kube-apiserver/tags/list | 
  jq -r '.tags|map(select(.|startswith("v")))[]'
v1.26.3
v1.26.6
v1.26.10
v1.26.11
v1.26.14
v1.26.15
v1.27.12
v1.27.14
v1.27.16
v1.28.8
v1.28.10
v1.28.12
v1.28.13
v1.28.14
v1.28.15
v1.29.8
v1.29.9
v1.29.14
v1.29.15
v1.30.4
v1.30.5
v1.30.10
v1.30.12
v1.30.14
v1.31.1
v1.31.6
v1.31.8
v1.31.10
v1.31.12
v1.32.4
v1.32.6
v1.32.8
v1.33.2
v1.33.4

Версия разворачивания kubernetes определяется командой U7S_KUBEVERSION:

# export U7S_KUBEVERSION=v1.33.4

После установки переменных U7S_REGISTRY, U7S_KUBEVERSION на Master Controlplane узле вызывается команда инициализации узла кластера:

# export PATH=/usr/libexec/podsec/u7s/bin/:$PATH
# kubeadm init  ...

На остальных подключаемых узлов кластера:

# export PATH=/usr/libexec/podsec/u7s/bin/:$PATH
# kubeadm join  ...

Разворачивание без локального регистратора и без политик доступа

Если при функционировании кластера нет необходимости в поддержке политик доступа её можно выключить как описано выше командой:

# cd /etc/containers
# newPolicyFile=policy_$(date '+%Y-%m-%d_%H:%M:%S')
# echo '{"default":[{"type":"insecureAcceptAnything"}],"transports":{"docker-daemon":{"":[{"type":"insecureAcceptAnything"}]}}}' | jq > $newPolicyFile
# ln -sf $newPolicyFile policy.json

Далее, как описано в предыдущем разделе определяются переменные U7S_REGISTRY, U7S_KUBEVERSION и разворачиваются Controlplane и Worker узлы кластера.

Разворачивание rootfull кластера

Выбор варианта разворачивания

При разворачивании в режиме rootfull в зависимости от использования локального регистратора docker-образов и применения политик доступа к ним можно обеспечить следующие варианты разворачивания rootfull-кластера:

Варианты разворачивания rootfull кластера
Локальный регистратор Политики доступа Примечание
Нет Нет Стандартный вариант
Да Да Возможность разворачивания в локальной сети без доступа в Интернет с поддержкой классов пользователей с ограничением доступа к docker-регистраторам
Да Нет Возможность разворачивания в локальной сети без доступа в Интернет
Нет Да Поддержка классов пользователей с ограничением доступа к docker-регистраторам

Разворачивание без локального регистратора и политик доступа

Данный вариант является наиболее общеприменимым, но он не позволяет:

  • разворачивать kubernetes-кластер в локальной сети без доступа в Интернет;
  • ограничивать доступ к внешним docker-регистраторам с потенциальными уязвимостями в поддерживаемых образах пользователям различных классов.

Развертывание Master ControlPlane узла

Установка RPM-пакетов

Необходимо установить следующие пакеты:

# apt-get update
# apt-get -y install \
    kubernetes<minorKubeVerison>-kubeadm \
    kubernetes<minorKubeVerison>-kubelet \
    kubernetes<minorKubeVerison>-crio \
    cri-tools<kminorKubeVerison> \
    jq yq

Где <minorKubeVerison> - любая доступная в репозитории минорная версия >=1.26 без начального символа v. Список доступных минорных версий можно посмотреть запросом:

# curl -ks https://registry.altlinux.org/v2/c10f/kube-apiserver/tags/list |   
jq -r '.tags|map(select(.|startswith("v")))|map(.[1:5])|map(select(.>"1.25"))[]' |
sort -uV

Где <платформа> - ALTLinux-платформа на которой разворачивается кластер (sisyphus, p10, c10f, p11, ...). См. файл /etc/os-release.

На текущий момент (26.10.2025) список доступных минорных версий для платформы c10f:

# curl -ks https://registry.altlinux.org/v2/c10f/kube-apiserver/tags/list |    
jq -r '.tags|map(select(.|startswith("v")))|map(.[1:5])|map(select(.>"1.25"))[]' | 
sort -uV
1.26
1.27
1.28
1.29
1.30
1.31
1.32
1.33

Желательно устанавливать минорную версию с максимальным номером.

Команда установки пакетов kubernetes версии 1.33 будет выглядеть следующим образом:

# apt-get update
# apt-get -y install \
    kubernetes1.33-kubeadm \
    kubernetes1.33-kubelet \
    kubernetes1.33-crio \
    cri-tools1.33 \
    jq yq
Запуск сервисов

После установки пакетов выбранной версии нужно активировать сервисы crio, kubelet и запустить сервис crio:

# systemctl enable --now crio
# systemctl enable kubelet
Инициализация Master ControlPlane узла

Для инициализация Master ControlPlane узла после установки пакетов и запуска сервисов выполните на узле под пользователем root команду:

# kubeadm init \
   -v <DebugLevel> \
   --control-plane-endpoint <IP> \
   --upload-certs \
   --pod-network-cidr=<POD_NET> \
   --image-repository=registry.altlinux.org/<платформа> \
   --kubernetes-version=<kubeversion> 

Где:

  • <DebugLevel> - Уровень отладки в интервале 0-9;
  • <IP> - IP адрес узра приема API-запросов. Если в кластере один Controlplane узел, то это адрес этого узла. Если в кластере несколько Controlplane узлов - адрес haproxy балансировщика запросов.
  • <POD_NET> - Диапазон IP-адресов, используемый для организации внутренеей kuberbetes сети для взаимодействия POD'ов. Этот диапазон зависит от типа CNI (см. ниже):
   flannel - 10.244.0.0/16;
   calico - 192.168.0.0/16.  
  • <платформа> - ALTLinux-платформа на которой разворачивается кластер (sisyphus, p10, c10f, p11, ...). См. файл /etc/os-release;
  • <kubeVerison> - любая доступная в репозитории в рамках выбранной минорной версии полная (patch) версия без начального символа v. Список доступных полных (patch) версий можно посмотреть запросом:
curl -ks https://registry.altlinux.org/v2/<платформа>/kube-apiserver/tags/list | 
jq -r '.tags | map(select(.[1:5]=="<minorKubeVerison>")) | map(.[1:])[]' |
sort -uV

Например на текущий момент (26.10.2025) список доступных полных (patch) версий для минорной версии 1.33 платформы p11:

# curl -ks https://registry.altlinux.org/v2/p11/kube-apiserver/tags/list | 
jq -r '.tags | map(select(.[1:5]=="1.33")) | map(.[1:])[]' |
sort -uV
1.33.1
1.33.2
1.33.3
1.33.4

Желательно устанавливать версию с максимальным номером.

Например команда инициализации Master Controlplane узла на платформе p11 версии kubernetes 1.33.4 c CNI flannel будет выглядеть следующим образом:

# kubeadm init \
   -v 9 \
   --control-plane-endpoint <EndpointIP> \
   --upload-certs \
   --pod-network-cidr=10.244.0.0/16 \
   --image-repository=registry.altlinux.org/p11 \
   --kubernetes-version=1.33.4 2>&1 | 
tee /tmp/kubeadm.log

В данном примере вывод команды kubeadm в stdout, stderr объединяются и записываются в файл /tmp/kubeadm.log для возможного последующего анализа.

В случае успешного разворачивания вывод команды закачивается текстом:

Your Kubernetes control-plane has initialized successfully!
...
You can now join any number of control-plane nodes running the following command on each as root:

kubeadm join <EndpointIP>:6443 --token <token> \
        --discovery-token-ca-cert-hash sha256:<hash> \
        --control-plane --certificate-key <key>
...
Then you can join any number of worker nodes by running the following on each as root:

kubeadm join <EndpointIP>:6443 --token <token> \
        --discovery-token-ca-cert-hash sha256:<hash> 

Первая команда используется для подключения controlplane-узлов. Вторая команда - для подключения worker-узлов. Обратите внимание, что первая команда отличается от второй только наличием флагов --control-plane --certificate-key <key>.

Для тех пользователей, которые будут работать с kubernetes-кластером (включая пользователя root) необходимо в домашнем каталоге пользователя создать подкаталог .kube, скопировать в него файл /etc/kubernetes/admin.conf под именем config и установить владельца каталога и файла.

# user=<имя_пользователя_с_доступом_в_кластер>
# userhome=$(getent passwd "$user" | cut -d: -f6)
# mkdir -p $userhome/.kube
# cp -i /etc/kubernetes/admin.conf $userhome/.kube/config
# chown -R $user:$user $userhome/.kube

Для пользователя root можно не копируя файл конфигурации указать его в переменной KUBECONFIG:

# export KUBECONFIG=/etc/kubernetes/admin.conf

Разворачивание kubernetees на master controlplane узле производится в течении нескольких минут. По окончании разворачивании вывод команды

# kubectl get all -A

должен выглядить следующим образом:

NAMESPACE     NAME                                  READY   STATUS    RESTARTS   AGE
kube-system   pod/coredns-84c9f8566b-mg2wf          0/1     Pending   0          ...
kube-system   pod/coredns-84c9f8566b-zhrqr          0/1     Pending   0          ...
kube-system   pod/etcd-host-98                      1/1     Running   0          ...
kube-system   pod/kube-apiserver-host-98            1/1     Running   0          ...
kube-system   pod/kube-controller-manager-host-98   1/1     Running   0          ...
kube-system   pod/kube-proxy-d55w6                  1/1     Running   0          ...
kube-system   pod/kube-scheduler-host-98            1/1     Running   0          ...

NAMESPACE     NAME                 TYPE        CLUSTER-IP   EXTERNAL-IP   PORT(S)                  AGE
default       service/kubernetes   ClusterIP   10.96.0.1    <none>        443/TCP                  67m
kube-system   service/kube-dns     ClusterIP   10.96.0.10   <none>        53/UDP,53/TCP,9153/TCP   67m

NAMESPACE     NAME                        DESIRED   CURRENT   READY   UP-TO-DATE   AVAILABLE   NODE SELECTOR            AGE
kube-system   daemonset.apps/kube-proxy   1         1         1       1            1           kubernetes.io/os=linux   67m

NAMESPACE     NAME                      READY   UP-TO-DATE   AVAILABLE   AGE
kube-system   deployment.apps/coredns   0/2     2            0           67m

NAMESPACE     NAME                                 DESIRED   CURRENT   READY   AGE
kube-system   replicaset.apps/coredns-84c9f8566b   2         2         0       67m

Вывод для всех POD'ов имеет в поле READY значение 1/1 за исключением двух POD'ов pod/coredns-..., имеющих значение 0/1. Значение 1/1 для этих двух POD'ов установится после настройка внутренней сети кластера (CNI).

Команда

# kubectl get nodes -o wide

выводит список из одного узла:

NAME      STATUS     ROLES           AGE   VERSION   INTERNAL-IP      EXTERNAL-IP   OS-IMAGE                        KERNEL-VERSION      CONTAINER-RUNTIME
host-98   NotReady   control-plane   8h    v1.33.4   192.168.122.98   <none>        ALT Server 11.0 (Mendelevium)   6.12.27-6.12-alt1   cri-o://1.33.4

Состояние NotReady сменится на Ready после настройка внутренней сети кластера (CNI).

Подключение Worker узлов

Для добавления Worker узла установите пакеты

# apt-get update
# apt-get -y install \
    kubernetes<kubeVerison>-kubeadm \
    kubernetes<kubeVerison>-kubelet \
    kubernetes<kubeVerison>-crio \
    cri-tools<kubeVerison>

и активируйте сервисы

# systemctl enable --now crio
# systemctl enable kubelet

Скопируйте строку подключения Worker узла и выполните ее на подключаемом узле:

kubeadm join <EndpointIP>:6443 --token <token> \
        --discovery-token-ca-cert-hash sha256:<hash> 2>&1 |
tee /tmp/kubeadm.log

В случае возникновении ощибок разворачивания логи можно будет посмотреть в файле /tmp/kubeadm.log.

Подключение ControlPlane узлов

Добавлять ControlPlane узел имеет смысл только в том случае когда у Вас установлен балансировщик API-запросов к кластеру.

Для добавления ControlPlane узла установите пакеты

# apt-get update
# apt-get -y install \
    kubernetes<kubeVerison>-kubeadm \
    kubernetes<kubeVerison>-kubelet \
    kubernetes<kubeVerison>-crio \
    cri-tools<kubeVerison>

и активируйте сервисы

# systemctl enable --now crio
# systemctl enable kubelet

Скопируйте строку подключения ControlPlane узла и выполните ее на подключаемом узле:

kubeadm join <EndpointIP>:6443 --token <token> \
        --discovery-token-ca-cert-hash sha256:<hash> \
        --control-plane --certificate-key <key>


Настройка внутренней сети кластера в различных CNI

Сетевые плагины CNI (Container Network Interface) обеспечивают создание оверлейной сети kubernetes-кластера в рамках которой производится обмен данными между PO'ами и через POS'ы coredns поддерживается свой DNS-сервис. Существует множество сетевых плагинов CNI, основные из которых:

  • flannel - Простой. легко разворачиваемый плагин обеспечивающий создание оверлейной сети в диапазоне IP-алресов 10.244.0.0/16.
  • calico - Сетевой плагин обеспечивающий создание оверлейной сети в диапазоне IP-алресов 192.168.0.0/16 и использующий eBPF ((Extended Berkeley Packet Filter), поддерживающий обработку IP-пакетов кластера на уровне ядра операционный системы.
  • cilium - Сетевой плагин обеспечивающий создание оверлейной сети в диапазоне IP-алресов 10.244.0.0/16, использующий eBPF и множество дополнительных сервисов по обработке IP-пакетов и защите сетевого трафика.
CNI flannel

Для Flannel с использованием образов на базе ALT: Манифесты находятся по адресу https://altlinux.space/cloud/manifests/src/branch/master/flannel/<платформа>. Где <платформа> на текущий момент (25.10.2024): sisyphus, p10, c10f. Каждый каталог платформы содержит каталоги

 
├── <major>
│   ├── <minor>
│   │   └── <patch>
│   │       └── kube-flannel.yml
...
└── latest
    └── kube-flannel.yml

Выберите для Вашей платформы (например c10f) установленной версии kubernetes необходимую версию flannel (например 0.27.3) и наберите команду разворачивания:

$ kubectl apply -f https://altlinux.space/cloud/manifests/raw/branch/master/flannel/c10f/0/27/3/kube-flannel.yml

Для последних версий kubernetes можно использовать последнюю версию flannel (тег latest):

$ kubectl apply -f https://altlinux.space/cloud/manifests/raw/branch/master/flannel/c10f/latest/kube-flannel.yml
CNI calico
Перед запуском calico-манифестов перейдите в каталог /etc/cni/net.d/:
# cd /etc/cni/net.d/
и создайте файл 100-crio-bridge.conflist
# cp 100-crio-bridge.conflist.sample 100-crio-bridge.conflist
Запустите POD'ы из calico-манифестов:
$ kubectl create -f https://raw.githubusercontent.com/projectcalico/calico/master/manifests/tigera-operator.yaml
$ kubectl apply -f https://raw.githubusercontent.com/projectcalico/calico/master/manifests/custom-resources.yaml
CNI cilium

В настоящее время (18.11.2025) идет создание docker-образов для регистратора registry.altlinux.org.

Разворачивание нативного CNI cilium описано на странице Cilium Quick Installation: Cilium 1.18.4 documentation

Другие способы разворачивания rootfull кластера

Остальные варианты разворачивания rootfull-кластера с поддержкой локального регистратора и политик доступа требует установки группы пакетов podsec:

apt-get install podsec-k8s podsec podsec-inotify

После установки пакетов необходимо, как и в случае rootless кластера на Master ControlPlane:

  • создать файлы конфигурации Container Network Policy;
  • развернуть дополнительные сервисы.

В дальнейшем в зависимости от варианта разворачивания возможно:

  • создание на Master ControlPlane пользователей различных классов;
  • установка и настройка мониторинга безопасности системы.
Создание файлов конфигурации Container Network Policy на Master ControlPlane в rootfull режиме

Для создания Container Network Policy на Master узле вызовите команду:

# podsec-create-policy <IP> # ip-aдрес_регистратора и WEB-сервера подписей

Где:

  • <IP> - IP-адрес основного интерфеса узла

Проверка файлов конфигурации Container Network Policy подробно описана в разделе разворачивания rootless-kubernetes Создание файлов конфигурации Container Network Policy на Master ControlPlane в rootless режиме

Разворачивание дополнительных сервисов на Master ControlPlane в rootfull режиме

Для разворачивание дополнительных сервисов на Master ControlPlane поднимите сервисы регистратора и WEB-сервера подписей командой:

# podsec-create-services

Вывод команды и проверка функционирование сервисов подробно описана в разделе разворачивания rootless-kubernetes Разворачивание дополнительных сервисов на Master ControlPlane в rootless режиме

Разворачивание без локального регистратора с политиками доступа

Данный вариант разворачивания позволит ограничить список docker-регистриторов к которым имеют доступ пользователи.


Разворачивание с локальным регистратора без политик доступа

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

Первоначально необходимо сформировать oci-архивы kubernetes-образов. Если у Вас есть ISO-oбраз дистрибутива C10F, то архив можно взять с этого диска. Он располагается в каталоге /containers/ под именем k8s_amd64.tar.xz.

Если у Вас ISO-образа нет или Вы планируете установить последнюю версию образов, то Вы можете сформировать архив с регистратора registry.altlinux.org.

Описание формирования архива OIC-образов Вы можете найти в разделе Формирование OCI-архива kubernetes-образов с регистратора registry.altlinux.org .

Необходимые команды команды описаны в разделах разворачивания rootless-kubernetes: Подписывание образов и размещения на локальном регистраторе

После создание пользователя разработчика образов контейнеров выполните команды:

cd /etc/containers
newPolicyFile=policy_$(date '+%Y-%m-%d_%H:%M:%S')
jq '.default[0].type|="insecureAcceptAnything"' /etc/containers/policy.json > $newPolicyFile
ln -sf $newPolicyFile policy.json

или в текстовом редакторе подправить значения поля default[0].type c reject на insecureAcceptAnything.

Это отключит контроль политик использования docker-образов.

Подписывание архивированных образов и помещение их в регистратор

В качестве oci-архива kubetnetes образов можно взять либо файл /containers/k8s_amd64.tar.xz расположенный на ISO-образе C10F, либо сформировать собственный архив. Процесс создания сжатого OCI-архива образов описан в разделе Формирование OCI-архива kubernetes-образов с регистратора registry.altlinux.org

Необходимые команды команды описаны в разделах разворачивания rootless-kubernetes: Подписывание образов и размещения на локальном регистраторе

Разворачивание с локальным регистратора и с политиками доступа

Поддержка управление доступом на основе ролей (RBAC)

Поддержку управления доступом на основе ролей (RBAC) обеспечивает пакет podsec-k8s-rbac.

В пакет podsec-k8s-rbac входит набор скриптов для работы с RBAC - Role Based Access Control:

  • podsec-k8s-rbac-create-user - создание RBAC-пользователя;
  • podsec-k8s-rbac-create-kubeconfig - создание ключей, сертификатов и файла конфигурации RBAC-пользователя;
  • podsec-k8s-rbac-create-remoteplace - создание удаленного рабочего места;
  • podsec-k8s-rbac-bindrole - привязывание пользователя к кластерной или обычной роли;
  • podsec-k8s-rbac-get-userroles - получить список кластерные и обычных ролей пользователя;
  • podsec-k8s-rbac-unbindrole - отвязывание пользователя от кластерной или обычной роли.

podsec-k8s-rbac-create-user - создание RBAC-пользователя

Формат:

podsec-k8s-rbac-create-user имя_пользователя

Описание:

Скрипт:

  • создает RBAC пользователя
  • создает в домашнем директории каталог .kube
  • устанавливаются соответствующие права доступа к каталогам.

podsec-k8s-rbac-create-kubeconfig - создание ключей, сертификатов и файла конфигурации RBAC-пользователя

Формат:

podsec-k8s-rbac-create-kubeconfig имя_пользователя[@<имя_удаленного_пользователя>] [группа ...]

Описание: Скрипт должен вызываться администратором безопасности средства контейнеризации.

Для rootless решения имя удаленного пользователя принимается u7s-admin.

Для rootfull решения необходимо после символа @ указать имя удаленного пользователя.

Скрипт в каталоге ~имя_пользователя/.kube производит:

  • Создании личного (private) ключа пользователя (файл имя_пользователя.key).
  • Создание запроса на подпись сертификата (CSR) (файл имя_пользователя.key).
  • Запись запроса на подпись сертификата CSR в кластер.
  • Подтверждение запроса на подпись сертификата (CSR).
  • Создание сертификата (файл имя_пользователя.crt).
  • Проверку корректности сертификата
  • Формирование файла конфигурации пользователя (файл config)
  • Добавление контекста созданного пользователя

podsec-k8s-rbac-create-remoteplace - создание удаленного рабочего места

Формат:

podsec-k8s-rbac-create-remoteplace ip-адрес

Описание:

Скрипт производит настройку удаленного рабочего места пользователя путем копирования его конфигурационного файла.

podsec-k8s-rbac-bindrole - привязывание пользователя к кластерной или обычной роли

Формат:

podsec-k8s-rbac-bindrole имя_пользователя role|role=clusterrole|clusterrole роль имя_связки_роли [namespace]

Описание:

Скрипт производит привязку пользователя к обычной или кластерной роли используя имя_связки_роли.

Параметры:

  • имя_пользователя должно быть создано командой podsec-k8s-rbac-create-user и сконфигурировано на доступ к кластеру командой podsec-k8s-rbac-create-kubeconfig;
  • тип роли может принимать следующие значения:
   * role - пользователь привязывется к обычной роли с именем <роль> (параметр namespace в этом случае обязателен);
   * role=clusterrole - пользователь привязывется к обычной роли используя кластерную роль с именем <роль> (параметр namespace в этом случае обязателен);
   * clusterrole - пользователь привязывется к кластерной роли используя кластерную роль с именем <роль> (параметр namespace в этом случае должен отсутствовать).
  • роль - имя обычной или кластерной роли в зависимости от предыдущего параметра;
  • имя_связки_роли - имя объекта класса rolebindings или clusterrolebindings в зависимости от параметра тип роли. В рамках этого объекта к кластерной или обычной роли могут быть привязаны несколько пользователей.
  • namespace - имя namespace для обычной роли.

podsec-k8s-rbac-get-userroles - получить список кластерные и обычных ролей пользователя

Формат:

podsec-k8s-rbac-get-userroles имя_пользователя [showRules]

Описание:

Скрипт формирует список кластерные и обычных ролей которые связаны с пользователем. При указании флага showRules, для каждой роли указывается список правил ("rules:[...]"), которые принадлежат каждой роли пользователя.

Результат возвращается в виде json-строки формата:

{
  "": {
    "clusterRoles": [...],
    "roles": {
      "allNamespaces": [...],
      "namespaces": [
        {
          "": [...],
          ...
        }
    }
  }
}

Где [...] - массив объектов типа:

{
  "bindRoleName": "",
  "bindedRoleType": "ClusterRole|Role",
  "bindedRoleName": "",
  "unbindCmd": "podsec-k8s-rbac-unbindrole ..."
}

podsec-k8s-rbac-unbindrole - отвязывание пользователя от кластерной или обычной роли

Формат:

podsec-k8s-rbac-unbindrole имя_пользователя role|clusterrole роль имя_связки_роли [namespace]

Описание:

Скрипт производит отвязку роли от кластерной или обычной роли, созданной командой podsec-k8s-rbac-bindrole. Полный текст команды можно получить в выводе команды podsec-k8s-rbac-get-userroles в поле unbindCmd. Если в указанном имя_связки_роли объекте класса rolebindings или clusterrolebindings еще остаются пользователи - объект модифицируется. Если список становится пуст - объект удаляется.

Параметры:

  • имя_пользователя должно быть создано командой podsec-k8s-rbac-create-user и сконфигурировано на доступ к кластеру командой podsec-k8s-rbac-create-kubeconfig;
  • тип роли может принимать следующие значения:
   * role - пользователь отвязывается от обычной роли с именем <роль> (параметр namespace в этом случае обязателен);
   * clusterrole - пользователь отвязывается от кластерной роли используя кластерную роль с именем <роль> (параметр namespace в этом случае должен отсутствовать).
  • роль - имя обычной или кластерной роли в зависимости от предыдущего параметра;
  • имя_связки_роли - имя объекта класса rolebindings или clusterrolebindings в зависимости от параметра тип роли. В рамках этого объекта к кластерной или обычной роли могут быть привязаны несколько пользователей.
  • namespace - имя namespace для обычной роли.

Мониторинг безопасности системы

Мониторинг безопасности системы обеспечивает пакет podsec-inotify.

В пакет podsec-inotify входит набор скриптов для мониторинга безопасности системы:

  • podsec-inotify-check-policy - проверка настроек политики контейнеризации на узле;
  • podsec-inotify-check-containers - проверка наличия изменений файлов в директориях rootless контейнерах;
  • podsec-inotify-check-images - проверка образов на предмет их соответствия настройки политикам контейнеризации на узле;
  • podsec-inotify-check-kubeapi - мониторинг аудита API-интерфейса kube-apiserver control-plane узла;
  • podsec-inotify-check-vuln - мониторинг docker-образов узла сканером безопасности trivy.

Настройка сервиса trivy

Часть скриптов мониторинга для обнаружения уязвимостей использует сканер trivy.

Сканер безопасности trivy работает как клиент сервера trivy принимающего соединения по порту 4954 на узле с доменом trivy.local. Если Ваш узел работает в составе кластера, то необходимо:

  • на одном из узлов кластера поднять сервер trivy командой:
systemctl enable --now trivy
  • на всех узлах кластера прописать в файле /etc/hosts строку
<IP-адрес_узла_сервера_trivy> trivy.local

Если Ваш узел вне кластера необходимо:

  • на узле поднять сервер trivy командой:
systemctl enable --now trivy
  • прописать в файле /etc/hosts строку
127.0.0.1 trivy.local

На платформе c10f сервер trivy запускается автоматически скриптом podsec-create-services на мастер-сервере кластера, привязка домена trivy.local к IP-адресу сервера производится автоматически скриптом podsec-create-policy.

Мониторинг сообщений об уязвимостей через nagwad

Все сообщения об обнаруженных уязвимостях скрипты записывают в системный лог в следующем формате:

<месяц> <день> <время> <host> <имя_скрипта>[<id>]: <уровень_уязвимости>: <текст_сообщения>

Посмотреть эти сообщения можно командой:

journalctl  -t <имя_скрипта>

Например:

journalctl  -t podsec-inotify-check-vuln
июл 16 06:22:36 host-136 podsec-inotify-check-vuln[383501]: Critical: В образе registry.altlinux.org/k8s-sisyphus/kube-apiserver:v1.30.1 пользователя u7s-admin обнаружены критические и высокие уязвимости.
...

Для передачи сообщений серверу мониторинга общей инфраструктуры icigna необходимо поднять сервис nagwad:

# apt-get install nagwad-service
# systemctl enable --now nagwad

В файловой системе создастся каталог /var/log/nagwad/<boot_uid>/podsec/. Все сообщения об уязвимостях сервис nagwad будет записывать из системного лога в данный каталог в файлы под именем podsec.<message_id>.<level>.

Например /var/log/nagwad/3c22e4b3-d4d7-4975-a49c-f630a15c041d/podsec/:

CRITICAL: podsec-inotify-check-vuln(Critical) В образе registry.altlinux.org/k8s-sisyphus/kube-apiserver:v1.30.1 пользователя u7s-admin обнаружены критические и высокие уязвимости.

Эти файлы в дальнейшем передаются серверу мониторинга общей инфраструктуры icigna.

podsec-inotify-check-policy - проверка настроек политики контейнеризации на узле

Формат:

podsec-inotify-check-policy [-v[vv]] [-a интервал] [-f интервал] -c интервал -h интервал [-m  интервал] х-w интервалъ [-l интервал] [-d интервал]

Описание: Плугин проверяет настройки политики контейнеризации на узле.

Проверка идет по следующим параметрам:

  • файл policy.json установки транспортов и политик доступа к регистраторам:
Параметр контроля пользователей Вес метрики
имеющих defaultPolicy != reject, но не входящих в группу podman_dev 102
не имеющих не имеющих registry.local в списке регистраторов для которых проверяется наличие электронной подписи образов 103
имеющих в политике регистраторы для которых не проверяется наличие электронной подписи образов 104
имеющих в списке поддерживаемых транспорты отличные от docker (транспорт получения образов с регистратора) 105


  • файлы привязки регистраторов к серверам хранящим электронные подписи (файл привязки о умолчанию default.yaml и файлы привязки регистраторов *.yaml каталога registries.d). Наличие (число) пользователей:
Параметр контроля пользователей Вес метрики
не использующих хранилище подписей http://sigstore.local:81/sigstore/ как хранилище подписей по умолчанию 106
  • контроль групп пользователей
  1. наличие пользователей имеющих образы, но не входящих в группу podman:
Параметр контроля пользователей Вес метрики
наличие пользователей имеющих образы, но не входящих в группу podman 101
  1. наличие пользователей группы podman (за исключением входящих в группу podman_dev):
Параметр контроля пользователей Вес метрики
входящих в группу wheel 101
имеющих каталог .config/containers/ открытым на запись и изменения 90 * доля_нарушителей
не имеющих файла конфигурации .config/containers/storage.conf 90 * доля_нарушителей

доля_нарушителей считается как: число_нарушителей / число_пользователей_группы_podman

Все веса метрик суммируются и формируется итоговая метрика.

podsec-inotify-check-containers - проверка наличия изменений файлов в директориях rootless контейнерах

Формат:

podsec-inotify-check-containers

Описание:

Скрипт:

  • создаёт список директорий rootless контейнеров, существующих в системе,
  • запускает проверку на добавление,удаление, и изменение файлов в директориях контейнеров,
  • отсылает уведомление об изменении в системный лог.

podsec-inotify-check-images - проверка образов на предмет их соответствия настройки политикам контейнеризации на узле

Формат:

podsec-inotify-check-images [-v[vv]] [-a интервал] [-f интервал] -c интервал -h интервал [-m  интервал] х-w интервалъ [-l интервал] [-d интервал]

Описание:

Плугин проверяет образы на предмет их соответствия настройки политикам контейнеризации на узле. Проверка идет по следующим параметрам:

Параметр контроля пользователей Вес метрики
наличие в политике пользователя регистраторов не поддерживающие электронную подпись 101
наличие в кэше образов неподписанных образов 101
наличие в кэше образов вне поддерживаемых политик 101

Все веса метрик суммируются и формируется итоговая метрика.

podsec-inotify-check-kubeapi - мониторинг аудита API-интерфейса kube-apiserver control-plane узла

Формат:

podsec-inotify-check-kubeapi [-d]

Описание: Скрипт производит мониторинг файла /etc/kubernetes/audit/audit.log аудита API-интерфейса kube-apiserver.

Политика аудита располагается в файле /etc/kubernetes/audit/policy.yaml:

apiVersion: audit.k8s.io/v1
kind: Policy
omitManagedFields: true
rules:
# do not log requests to the following 
- level: None
  nonResourceURLs:
  - "/healthz*"
  - "/logs"
  - "/metrics"
  - "/swagger*"
  - "/version"
  - "/readyz"
  - "/livez"

- level: None
  users:
    - system:kube-scheduler
    - system:kube-proxy
    - system:apiserver
    - system:kube-controller-manager
    - system:serviceaccount:gatekeeper-system:gatekeeper-admin

- level: None
  userGroups:
    - system:nodes
    - system:serviceaccounts
    - system:masters

# limit level to Metadata so token is not included in the spec/status
- level: Metadata
  omitStages:
  - RequestReceived
  resources:
  - group: authentication.k8s.io
    resources:
    - tokenreviews

# extended audit of auth delegation
- level: RequestResponse
  omitStages:
  - RequestReceived
  resources:
  - group: authorization.k8s.io
    resources:
    - subjectaccessreviews

# log changes to pods at RequestResponse level
- level: RequestResponse
  omitStages:
  - RequestReceived
  resources:
  - group: "" # core API group; add third-party API services and your API services if needed
    resources: ["pods"]
    verbs: ["create", "patch", "update", "delete"]

# log everything else at Metadata level
- level: Metadata
  omitStages:
  - RequestReceived

Текущие настройки производят логирование всех обращений "несистемных" пользователей (в том числе анонимных) к ресурсам kubernetes.

Скрипт производит выборку всех обращений, в ответ на которые был сформирован код более 400 - запрет доступа. Все эти факты записываются в системный журнал и накапливаются в файле логов /var/lib/podsec/u7s/log/kubeapi/forbidden.log, который периодически передается через посту системному адмиристратору.

Параметры:

  • -d - скирпт запускается в режиме демона, производящего онлайн мониторинг файла /etc/kubernetes/audit/audit.log и записывающего факты запросов с запретом доступа в системный журнал и файл логов /var/lib/podsec/u7s/log/kubeapi/forbidden.log.
  • при запуске без параметров скрипт посылает файл логов /var/lib/podsec/u7s/log/kubeapi/forbidden.log почтой системному администратору (пользователь root) и обнуляет файл логов.

В состав пакета кроме этого скрипта входят:

  • файл описания сервиса /lib/systemd/system/podsec-inotify-check-kubeapi.service. Для его запуска екобходимо выполнить команды:
 
  # systemctl enable  podsec-inotify-check-kubeapi.service
  # systemctl start  podsec-inotify-check-kubeapi.service
  
  • файл для cron /etc/podsec/crontabs/podsec-inotify-check-kubeapi. Файл содержит единственную строку с описанием режима запуска скрипта podsec-inotify-check-kubeapi для передачи почты системному администратору.
 Скрипт запускается один раз в 10 минут.
 Во время установки пакета строка файла (в случае ее отсутствия) дописыватся в crontab-файл /var/spool/cron/root пользователя root.   
 Если необходимо изменить режим запуска скрипта или выключить его это можно сделать командой редактирования crontab-файла:
  #  crontab -e
  

podsec-inotify-check-vuln - мониторинг docker-образов узла сканером безопасности trivy

Формат:

podsec-inotify-check-vuln

Описание:

Скрипт производит мониторинг docker-образов узла сканером безопасности trivy:

  • Если скрипт запускается от имени пользователя root скрипт:
  1. проверяет сканером trivy rootfull образы;
  2. для всех пользователей каталога /home/ проверяется наличие rootless-образов. При их наличии проверяет сканером trivy эти образы.
  • Если скрипт запускается от имени обычного пользователя проверяется наличие rootless-образов. При их наличии проверяет сканером trivy эти образы.

Результат анализа посылается в системный лог. Если при анализе образа число обнаруженных угроз уровня HIGH больше 0, результат посылается почтой системному администратору (root).

Параметры:

Отсутствуют.

Периодический запуск скрипта

В состав пакета кроме этого входит systemd/timers файл /usr/lib/systemd/system/podsec-inotify-check-vuln.timer.

При его активации командой:

systemctl enable podsec-inotify-check-vuln.timer

каждый час запускается скрипт мониторинга.

Период запуска можно указать в описателе OnCalendar вышеуказанного systemd/timers файла.

Установка и настройка ingress-контролера

Ingress-контроллер обеспечивает переадресацию http(s) запросов по указанным шаблонам на внутренние сервисы kubernetes-кластера. Для bare-metal решений и решений на основе виртуальных машин наиболее приемлимым является ingress-nginx контроллер.

При применении Ingress-контроллера нет необходимости создавать Nodeport-порты и пробрасывать их из namespace пользователя u7s-admin. Ingress-контроллер переадресует http{s) запрос через сервис непосредственно на порты Pod'ов входящих в реплики deployment.

Установка и настройка ingress-nginx-контролера в кластере

Ingress NGINX — это самый популярный контроллер для Kubernetes, но он не всегда является лучшим выбором для конкретных сценариев (например, когда нужна максимальная производительность, расширенные функции API Gateway или интеграция с service mesh). По состоянию на текущий момент (март 2026 года) Ingress NGINX поддерживает стандарт Ingress Resource. Планируется переход на поддержку стандарта **Gateway API**:

  • Ingress Resource (Устаревающий стандарт): Ресурс `Ingress` (API `networking.k8s.io/v1`) считается технологически ограниченным. Он слишком прост для сложных сценариев маршрутизации.
  • Gateway API (Будущее): Сообщество Kubernetes активно продвигает **Gateway API** (ранее Service API). Это более мощная и гибкая замена Ingress.
  • Поддержка классического ресурса `Ingress` будет сохраняться еще долго (обратная совместимость в K8s священна), но новых фич туда добавляться почти не будет.
  • Ingress NGINX уже реализуют поддержку Gateway API.
  • В долгосрочной перспективе (3-5 лет) ожидается миграция экосистемы с `Ingress` на `Gateway`.
Использование ingress-контроллера

Для установки Ingress-контроллера скопируйте его YAML-манифест:

curl https://raw.githubusercontent.com/kubernetes/ingress-nginx/controller-v1.8.0/deploy/static/provider/baremetal/deploy.yaml -o ingress-nginx-deploy.yaml

Выберите свободный порт в диапазона 30000 - 32767 (например 31000) и добавьте его в элемент spec.ports.appProtocol==http Yaml-описании kind==Service:

...
---
kind: Service
spec:
  ports:
  - appProtocol: http
    ...
    nodePort: 31000
...

Если в Вашем решении используется ТОЛЬКО локальный регистратор registry.local

  • создайте алиасы образам nginx:
podman tag registry.k8s.io/ingress-nginx/controller:v1.8.0@sha256:744ae2afd433a395eeb13dc03d3313facba92e96ad71d9feaafc85925493fee3 registry.local/ingress-nginx/controller:v1.8.0
podman tag registry.k8s.io/ingress-nginx/kube-webhook-certgen:v20230407@sha256:543c40fd093964bc9ab509d3e791f9989963021f1e9e4c9c7b6700b02bfb227b registry.local/ingress-nginx/kube-webhook-certgen:v20230407

и поместите их в локальный регистратор:

podman push --tls-verify=false --sign-by='<EMAIL>' registry.local/ingress-nginx/controller
podman push --tls-verify=false --sign-by='<EMAIL>' registry.local/ingress-nginx/kube-webhook-certgen
  • исправьте имена образов в скачанном нанифесте на имена образов в локальном регистраторе.

Запустите Ingress-nginx-контролер:

kubectl apply -f ingress-nginx-deploy.yaml

На одном или нескольких kubernet-узлах (эти узла в дальнейшем нужно прописать в файле конфигурации балансировщика haproxy) пробросьте порт nginx-контроллера (31000) из namespace пользователя u7s-admin в сеть kubernetes:

nsenter_u7s rootlessctl add-ports 0.0.0.0:31000:31000/tcp

Настройка Ingress-правил

Kubernetes поддерживает манифесты типа Ingress (kind: Ingress) описывающие правила переадресации запросов URL http-запррса на внутренние порты сервисов (kind: Service) kubernetes. Сервисы в свою очередь перенаправляют запросы на реплики Pod'ов, входящих в данный сервис.

Общий вид Ingress-манифеста:

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: <ingress_имя>
spec:
  ingressClassName: nginx          
  rules:
  - host: <домен_1>
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: <имя_сервиса_1>
            port:
              number: 80
      - path: /<тропа_1>
        pathType: Prefix
        backend:
          service:
            name: <имя_сервиса_2>
            port:
              number: 80
  - host: <домен_2>
    ...

Где:

  • host: <домен_1>, <домен_2>, ... - домены WEB-серверов на которых приходит запрос;
  • path:/>, path:/<тропа_1> - тропы (префиксы запросов после домена)
  • pathType: Prefix - тип троп: Prefix или Exact;
  • service: - имя сервиса на который перенаправляется запрос, если полученный запрос соответсвует правилу;
  • port - номер порта на который перенаправляется запрос.

Если запросу соответствует несколько правил, выбирается правило с наиболее длинным префиксом.

Подробности смотри в Kubernetes: Ingress

Настройка haproxy и DNS

Добавьте в файлы конфигурации haproxy /etc/haproxy/haproxy.conf переадресацию запросов на порт 80 (http) по IP-адресу балансировщика haproxy на IP-адреса kubernet-узлов на которых выбранный порт nginx-контроллера (31000) проброшен из namespace пользователя u7s-admin в сеть kubernetes:

frontend http
    bind *:80
    mode tcp
    option tcplog
    default_backend http

backend http
    mode tcp
    balance     roundrobin
        server <server1> <ip1>:31000 check
        server <server2> <ip2>:31000 check

Заведите DNS-запись связывающую DNS-имя http-сервиса с IP-адресам haproxy-сервера.

Разворачиваие контролееров других типов

Ingress NGINX — это самый популярный контроллер для Kubernetes, но он не всегда является лучшим выбором для конкретных сценариев (например, когда нужна максимальная производительность, расширенные функции API Gateway или интеграция с service mesh).

Обратите внимание: Пример конфигурации Ingress NGINX есть на ISO-лиске решений C10F. Если пользователь выбирает описанные в этом разделе контроллеры, то он должен самостоятельно сформировать все файлы конфигурации и загрузить все необходимые образы и артефакты для выбранного контроллера. Приведенные в конце описания каждого контроллера ссылки являются лишь рекомендациями.

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

1. Популярные Open Source контроллеры

Traefik

Один из главных конкурентов NGINX. Ориентирован на простоту и динамическую конфигурацию. Плюсы:

  • Автоматическое обнаружение сервисов (Service Discovery).
  • Встроенный красивый Dashboard и UI для настройки.
  • Легкая настройка Let's Encrypt (SSL).
  • Написан на Go, один бинарник.

Минусы:

  • Меньше возможностей для сложной маршрутизации по сравнению с NGINX/Kong.
  • В версии v2 изменилась конфигурация, что вызвало сложности при миграции.

Для кого: Для средних проектов, стартапов, команд, которым важна простота настройки.

Пример настроек можно посмотреть в документе Организация работы Traefik Ingress Controller.


HAProxy Ingress

Контроллер на базе легендарного балансировщика HAProxy. Плюсы:

  • Очень высокая производительность и стабильность (battle-tested).
  • Гибкая конфигурация (можно использовать конфиги HAProxy).
  • Отличная поддержка TCP/UDP (не только HTTP).

Минусы:

  • Конфигурация может быть сложнее, чем у Traefik.
  • Меньше "cloud-native" фич из коробки по сравнению с другими.

Для кого: Для высоконагруженных систем, где важна стабильность и работа с TCP.

Пример настроек можно посмотреть в документе Организация работы HAProxy Ingress Controller.


Contour (на базе Envoy)

Разрабатывается VMware (Tanzu). Использует Envoy Proxy в качестве плоскости данных. Плюсы:

  • Использует мощный Envoy под капотом.
  • Отличная поддержка спецификации Gateway API (будущий стандарт).
  • Разделение конфигурации (Contour управляет Envoy).
  • Встроенная поддержка gRPC.

Минусы:

  • Архитектура сложнее (два компонента: Contour + Envoy).
  • Меньше комьюнити, чем у NGINX или Traefik.

Для кого: Для тех, кто хочет перейти на Gateway API и использует Envoy.

Пример настроек можно посмотреть в документе Организация работы Contour Ingress Controller.


==== 2. API Gateway (Расширенный функционал)

Если вам нужен не просто роутинг, а аутентификация, лимитирование, трансформация запросов:


Kong Ingress Controller

Один из самых популярных API Gateway с открытым кодом. Плюсы:

  • Огромная экосистема плагинов (Auth, Rate Limiting, WAF, Logging).
  • Поддержка гибридного режима (Control Plane + Data Plane).
  • Активное развитие.

Минусы:

  • Тяжелее, чем простой Ingress (требует больше ресурсов).
  • Некоторые продвинутые плагины доступны только в Enterprise версии.

Для кого: Для микросервисов, где нужна сложная политика доступа и управление API.

Пример настроек можно посмотреть в документе Организация работы Kong Ingress Controller (KIC).


Apache APISIX

Быстрорастущий проект, позиционируемый как наследник Kong с лучшей производительностью. Плюсы:

  • Очень высокая производительность (на базе OpenResty/Nginx + Lua).
  • Динамическая горячая перезагрузка плагинов и маршрутов без рестарта.
  • Полностью Open Source (в отличие от части фич Kong).
  • Поддержка протоколов (HTTP, gRPC, WebSocket, MQTT).

Минусы:

  • Экосистема моложе, чем у Kong.
  • Требует знания Lua для написания кастомных плагинов.

Для кого: Для высоконагруженных API, где нужна динамика и открытость.

Пример настроек можно посмотреть в документе Организация работы Apache APISIX Ingress Controller.


3. Современные и eBPF решения

eBPF решения более эффективны, так как часть кода работает непосредствено я ядре Linux что существенно ускоряет работу контроллеров. Но следует учесть, что ти протоколы не работают в rootless решениях.


Cilium Ingress

Часть проекта Cilium (сетевая безопасность и наблюдение на базе eBPF). Плюсы:

  • Максимальная производительность (работает на уровне ядра Linux через eBPF).
  • Единое решение для сети, безопасности (Network Policies) и Ingress.
  • Нативная поддержка Gateway API.

Минусы:

  • Требует поддержки eBPF ядром (не все старые ОС/Cloud подходят).
  • Высокий порог входа (сложнее в отладке).

Для кого: Для современных кластеров, где уже используется Cilium CNI, и нужна максимальная скорость.

Пример настроек можно посмотреть в документе Организация работы Cilium Ingress Controller.

4. Service Mesh (Входная точка)

Istio Ingress Gateway

Если у вас уже развернут Istio.

  • Плюсы: Единая конфигурация для ingress и service-to-service трафика, мощный mTLS.
  • Минусы: Очень сложный в настройке и поддержке. Избыточен, если нужен только входной трафик.


Сводная таблица для выбора

Решение Основная фишка Сложность Производительность Сценарий
NGINX' Стандарт де-факто Средняя Высокая Универсальный выбор
Traefik Простота, UI Низкая Средняя Стартапы, малые кластеры
HAProxy Стабильность, TCP Средняя Очень высокая Highload, TCP трафик
Kong Плагины, API Mgmt Высокая Средняя Управление API, Auth
APISIX Динамика, Скорость Средняя Очень высокая Современный API Gateway
Contour Gateway API, Envoy Средняя Высокая Будущее-проф (Gateway API)
Cilium eBPF, Ядро Высокая Максимальная Продвинутая сеть/безопасность
Cloud ALB Managed, NoOps Низкая Зависит от облака Работа в одном облаке


Важное примечание про Gateway API

Сейчас индустрия постепенно отходит от ресурса `Ingress` (который ограничен) к новому стандарту Kubernetes Gateway API. Если вы выбираете новый контроллер сегодня, обратите внимание на те, которые имеют зрелую поддержку Gateway API (например, Contour, Cilium, Kong, Envoy Gateway). Это обеспечит лучшую совместимость в будущем.

Что выбрать?

1. Нужно просто и быстро: Traefik.

2. Нужна максимальная надежность и TCP: HAProxy.

3. Нужен API Gateway (Auth, Rate Limit): Kong или APISIX.

4. Хотите быть на передовой (Gateway API): Contour или Cilium.

5. Работаете в AWS/GCP/Azure: Попробуйте нативный контроллер облака, чтобы снизить операционные затраты.


Обновление кластера kubernetes

Версии ПО kubernetes

Программное обеспечение kubernetes постоянно обновляется. После каждой группы обновлений фиксируется новая версия ПО.

Версия имеет следующий формат: v<major>.<minor>.<patch>. Где:

  • <major> - мажорный номер версии (в настройящее время 1);
  • <minor> - минорный номер (26, 27, ..., 33, ...);
  • <patch> - патч номер (1, 2, ...);

Патч обновления производятся при обнаружении ошибок (BugFix), уязвимостей (Security) и т.п. в текущей минорной версии.

Минорные обновления производятся при реализации нового функционала, изменении текущего функционала.

Порядок обновления минорных версий

Обновление узлов кластера kubernetes всегда должно производиться последовательно по минорным версиям. Нельзя в версии `1.26.xx` перепрыгнуть на версию v1.28.zz. Необходимо предварительно перевести узлы кластера с версии v1.26.xx на версию v1.27.yy, а затем с версии v1.27.yy перейти на версию v1,28.zz. При этом если версия v1.26.xx не последняя патч версия, то предварительно рекомендуется перейти с версии v1.26.xx на последнюю патч версию и при дальнейшем переходе на минорные версии v1.27, v1.28 переходить на последние доступные патч версии этих минорных версий.

Узнать список версий kubernetes на registry.altlinux.org для платформы можно командой:

curl -k https://registry.altlinux.org/v2/<платформа>/kube-apiserver/tags/list | 
yq .tags

Где <платформа> - имя платформы: p10, c10f, p11, sisyphus.

На текущий момент (26.03.2026) список версий для платформы c10f таков:

v1.22.17
v1.23.17
v1.24.17
v1.25.15, v1.25.16
v1.26.3, v1.26.6, v1.26.10, v1.26.11, v1.26.14, v1.26.15
v1.27.12, v1.27.14, v1.27.16
v1.28.8, v1.28.10, v1.28.12, v1.28.13, v1.28.14, v1.28.15
v1.29.8, v1.29.9, v1.29.14, v1.29.15
v1.30.4, v1.30.5, v1.30.10, v1.30.12, v1.30.14
v1.31.1, v1.31.6, v1.31.8, v1.31.10, v1.31.12, v1.31.14
v1.32.4, v1.32.6, v1.32.8, v1.32.10
v1.33.2, v1.33.4, v1.33.6

Таким образом, чтобы обновить узлы кластера например с версии v1.26.3 до v1.33.6 необходимо провести последовательное обновление по патч-версиям:

v1.26.3 -> 
v1.26.15 -> 
v1.27.16 -> 
v1.28.15 -> 
v1.29.15 -> 
v1.30.14 -> 
v1.31.14 -> 
v1.32.10 -> 
v1.33.6

Порядок обновления до следующей минорной версии

Начальные действия

Перед началом обновления сделайте BackUp критически важных данных (баз данных, ...). Хотя как правило обновления проходят без проблем сохранение критически важных данных является хорошей практикой.

Если обновление производится через несколько минорных версий копирование критически важных данных необходимо делать только на первом этапе.

Обновление через большое количество версий (4 и более) может занять достаточно большое время. В этом случае есть смысл вместо обновления по минорным версиям при наличии мощностей поднять параллельно новый кластер на целевой версии и обеспечить миграцию на новые кластер.

Шаги обновления

Обновление до следующей минорной версии проводится по следующей схеме:

  • Прочитайте внимательно CHANGELOG'и для каждой минорной версии. Каждый набор CHANGELOGов имеет имя: CHANGELOG-<minor_versiom>.md. По каждой PATCH-версии обратите внимание на секции Changes since, Changes by Kind, Dependencies.
  • Обновите до следующей минорной версии основной Controlplane узел.
  • Обновите до следующей минорной версии остальные Controlplane узлы.
  • Обновите до следующей минорной версии Worker узлы.

Дополнительная информация

  • Перед обновлением узла (узлов) его надо командой kubectl перевести в DRAIN режим. Прочитайте внимательно документ Safely Drain a Node. При переводе в этот режим все работающие POD'ы узла переводятся на другие работающие узлы. Controlplane узлы поддерживают сервисы DNS, kube-api, и т.п. В связи с этим необходимо в кластере иметь не менее 3-х Controlplane узлов и обновлять их желательно по одному. Обновлять Worker узлы можно параллельно, но надо следить, чтобы оставшиеся работающие Worker узлы могли поддержать все работающие в кластере PODы.
  • Если Worker узлов недостаточно для поддержки всех PODов можно перевести часть (или все) Controlpane узлов в режим поддержки обычных PODов командой:
kubectl taint nodes <NODENAME> node-role.kubernetes.io/control-plane:NoSchedule-
  • Проект Kubernetes рекомендует использовать одинаковые версии kubelet и kubeadm. Вместе с тем допускается использовать предыдущие версии kubelet по отношении к версии kubeadm, при условии, что она находится в диапазоне поддерживаемых версий. Более подробную информацию можно найти в документации kubeadm's skew against the kubelet.
  • Чтобы убедиться в успешном перезапуске службы kubelet после обновления kubelet, можно выполнить команду systemctl status kubelet или просмотреть журналы службы с помощью journalctl -xeu kubelet.
  • Команда kubeadm upgrade поддерживает параметр --config с типом UpgradeConfiguration API, который можно использовать для настройки процесса обновления.

Ссылки на страницы обновления кластера по версиям

Образы, официально поддерживаемые разработчиками kubernetes:

Образы, срок поддержки которых разработчиками kubernetes истёк:

Обновление rootless kubernetes в режиме без доступа в Интернет

Режим rootless kubernetes без доступа в Интернет имеет следующие особенности:

  • нет доступа к RPM-пакетам промежуточных версий kubernetes;
  • нет доступа к kubernetes образам промежуточных версий;
  • команды обновления версий (kubeadm, etc...) надо запускать в rootless окружении пользователя u7s-admin.

Доступ к RPM-пакетам и образам промежуточных версий

В связи с этим артефакты, перечисленные в первых двух пунктах выложены на https://ftp.altlinux.org/pub/distributions/ALTLinux/c10f2/kubernetes. Указанный каталог имеет следующую структуру:

pub/distributions/ALTLinux/c10f2/kubernetes
├── OCIS
│   ├── v1.26.15
│   ├── v1.27.16
│   ├── v1.28.15
│   ├── v1.29.15
│   ├── v1.30.14
│   ├── v1.31.14
│   ├── v1.32.10
│   └── v1.33.6
└── RPMS
    ├── aarch64
    │   ├── base
    │   └── RPMS.classic
    ├── noarch
    │   ├── base
    │   └── RPMS.classic
    └── x86_64
        ├── base
        └── RPMS.classic

Каталог OCIS содержит OCI-архивы версий kubernetes для архитектур amd64 и arm64. Каждый подкаталог версии OCIS/<version> содержит два файла-архива:

amd64.tar.xz
arm64.tar.xz

Каталог RPMS содержит RPM-файлы версий kubernetes для архитектур aarch64, x86_64 и общие для обоих архитектур RPM-пакеты в каталоге noarch:

Данные артефакты:

  • скачиваются на сервере с доступом в Интернет;
  • помещаются на сменямый носитель (флешку);
  • переносятся на master-сервер (первый Controlplane) kubernetes;
 - RPM-пакеты устанавливаются в каталог /var/sigstore/kubernetes_upgrade, доступный WEB-серверу, прослушивающий порт 81 для поддержки возможности установки RPM-пакетов необходимых версия на узлах кластера;
 - OCI-архивы образов необходимых версий разворачиваются и размещаются на локальном docker-регистриаторе registry.local.

Установка RPM-пакетов промежуточных версий

На master-сервере в каталоге /var/sigstore/ создается подкаталог /var/sigstore/kubernetes_upgrade/ и в него переносятся:

  • для архитектуры amd64(x86_64) подкаталоги noarch, x86_64 каталога kubernetes/RPMS/ сменного носителя. Целевая структура каталогов:
/var/sigstore/kubernetes_upgrade/
├── noarch
│   ├── base
│   └── RPMS.classic
└── x86_64
    ├── base
    └── RPMS.classic
  • для архитектуры arm64(aarch64) подкаталоги noarch, x86_64 каталога kubernetes/RPMS/ сменного носителя. Целевая структура каталогов:
/var/sigstore/kubernetes_upgrade/
├── noarch
│   ├── base
│   └── RPMS.classic
└── aarch64
    ├── base
    └── RPMS.classic

На всех узлах вызываются команды:

apt-repo add 'rpm http://sigstore.local:81/kubernetes_upgrade x86_64 classic'
apt-repo add 'rpm http://sigstore.local:81/kubernetes_upgrade noarch classic'

Данные команды добавляют RPM-репозиторий расположенный на master-узле в файл /etc/apt/sources.list.

После этого на всех узлах вызывается команда:

apt-get update

Загрузка docker-образов промежуточных версий в локальный регистратор registry.local

Загрузку docker-образов в локальный регистратор можно производить непосредственно со сменного носителя, содержащего архивы amd64.tar.xz (arm64.tar.xz) образов.


Для загрузки зайдите в пользователя imagemaker и запустите скрипт разворачивания архивов:

for archive in .../OCIS/v*/amd64.tar.xz
do 
  echo $archive 
  podsec-load-sign-oci $archive amd64 kaf@basealt.ru
  podman rmi -f $(podman images -q)
done

Для экономии места в конце загрузки образов каждой версии и размещения их в локальном регистраторе загруженные и подписанные образы удаляются, так как они в дальнейшем не будет использоваться в рамках пользователя imagemaker.

Во время загрузки образов для версий с префиском c10f-cert будет выводиться сообщение

Текущая платформа c10f не совпадает c устанавливаемой c10f-cert
Продолжать (y/N)?

Отвечайте y.

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

$ curl -s registry.local/v2/_catalog | jq
{
  "repositories": [
    "c10f/coredns",
    "c10f/etcd",
    "c10f/flannel",
    "c10f/flannel-cni-plugin",
    "c10f/kube-apiserver",
    "c10f/kube-controller-manager",
    "c10f/kube-proxy",
    "c10f/kube-scheduler",
    "c10f/pause",
    "k8s-c10f2/coredns",
    "k8s-c10f2/etcd",
    "k8s-c10f2/flannel",
    "k8s-c10f2/flannel-cni-plugin",
    "k8s-c10f2/kube-apiserver",
    "k8s-c10f2/kube-controller-manager",
    "k8s-c10f2/kube-proxy",
    "k8s-c10f2/kube-scheduler",
    "k8s-c10f2/pause"
  ]
}

Так так в процессе формирования образов с версии 1.26 до версии 1.33 префикс образов сменился с k8s-c10f2/ на c10f в регистраторе хранятся образы под обоими префиксами. Дополнительное место дубли не занимают, так как они являются всего лишь ссылками на стеки слоев образа.

Проверить конкретные версии хранимых в регистраторе образов можно командой:

curl -s registry.local/v2/<имя_образа>/tags/list | jq

Например образ c10f/kube-apiserver хранится в следующих версиях:

curl -s registry.local/v2/c10f/kube-apiserver/tags/list | jq
{
  "name": "c10f/kube-apiserver",
  "tags": [
    "v1.26.3",
    "v1.26.15",
    "v1.27.16",
    "v1.28.15",
    "v1.29.15",
    "v1.30.14",
    "v1.31.14",
    "v1.32.10",
    "v1.33.6"
  ]
}

Запуск команд в rootless-окружении пользователя u7s-admin

Для перехода в rootless-окружение выполните команду:

# machinectl shell u7s-admin@ \
    /usr/libexec/podsec/u7s/bin/nsenter_u7s \
    /bin/bash
Connected to the local host. Press ^] three times within 1s to exit session.
[INFO] Entering RootlessKit namespaces: OK
#

Другой вариант доступа к rootless-окружению:

  • задайте однократно пароль для u7s-admin:
# passwd u7s-admin
  • зайдите в пользователя u7s-admin:
ssh u7s-admin@localhost
$
  • зайдите в его rootless-окружение
$ nsenter_u7s 
[INFO] Entering RootlessKit namespaces: OK
#

В rootless-окружении Вы можете запускать базовые команды crictl, ... для просмотра состояния узла:

Получение списка образов:

# crictl images
IMAGE                                         TAG                 IMAGE ID            SIZE
registry.local/c10f/coredns                   v1.12.0             cbcabd8e1bf68       201MB
registry.local/c10f/coredns                   v1.9.3              4c50f61969911       182MB
registry.local/c10f/etcd                      3.5.10-0            1f6adb6261393       223MB
registry.local/c10f/etcd                      3.5.24-0            8efb15892159b       177MB
registry.local/c10f/flannel-cni-plugin        v1.7.1-flannel1     2e2e7f4c24499       137MB
registry.local/c10f/flannel                   v0.28.2             5ac9f058df58e       242MB
registry.local/c10f/kube-apiserver            v1.26.3             638f5325645c6       482MB
registry.local/c10f/kube-apiserver            v1.33.6             449232cc35f02       451MB
...

Просмотр контейнеров:

# crictl ps
CONTAINER           IMAGE                                                              CREATED             STATE               NAME                      ATTEMPT             POD ID              POD
998b3431c595e       4c50f6196991104279df4a1c18e2fcff14649a76b0318b53d04d60cc2df6794d   36 hours ago        Running             coredns                   0                   7808cfedc70bd       coredns-9b5bb5547-x6n24
b07a7c7304e55       4c50f6196991104279df4a1c18e2fcff14649a76b0318b53d04d60cc2df6794d   36 hours ago        Running             coredns                   0                   e4a08d29a2ffa       coredns-9b5bb5547-rrh8h
3060163e7d377       5ac9f058df58e81241053b2d7b6cda51ae1ee8da21f7d6b5a825bafa5b31d46e   36 hours ago        Running             kube-flannel              1                   860eed937d0fe       kube-flannel-ds-g8khm
c8ca946eb2745       9f65fb1fcead0135e8e1840b3c918c002bc0eba38da9c59627bc92287e281463   36 hours ago        Running             kube-proxy                0                   a6e79be33fca2       kube-proxy-cr2ns
305572f402432       b8042b50d411c7491b55dbb23269cfe440f512fe8910fe7b9dcfe16661ba3f5a   36 hours ago        Running             kube-controller-manager   1                   2bdab5381702c       kube-controller-manager-host-70
31ec7e7dd9c54       1f6adb62613932765f9f007714fdb779e328039fd7df145bcdf2c304288b489a   36 hours ago        Running             etcd                      1                   2688c7ddf519d       etcd-host-70
e93d1d9b685e7       638f5325645c6893d9069d3124f6aebefca69b08fcd3b7d87584dafd69764e97   36 hours ago        Running             kube-apiserver            0                   103b33ae93875       kube-apiserver-host-70
eb209442e0adf       4bbfae0aa6cceaf22181d2b11883abf390ea18a484ee9c8143a834c59b36efa4   36 hours ago        Running             kube-scheduler            1                   55fd9d329f351       kube-scheduler-host-70

Обновление кластера

Перед обновлением кластера убедитесь, что на всех узлах Вы добавили локальный RPM-репозиторий (описание в разделе Установка RPM-пакетов промежуточных версий) и обновили базу командой

apt-get update


Начинать необходимо с управляющих (Controlplane) узлов. После обновления всех управляющих узлов необходимо обновить рабочие (worker) узлы.

Если в Вас в кластере мало (один, два) рабочих (worker) узла и при выводе одного узла работающие на нем PODы не смогут поддержать оставшиеся узлы, то есть смысл на время обновления позволить управляющим (Controlplane) узлам поднимать выводимые PODы. Для этого на всех или части PODы узлов надо запустить команду:

kubectl taint nodes <host> node-role.kubernetes.io/control-plane:NoSchedule-

После окончания обновления эти узлы надо вернуть в исходное состояние командой:

kubectl taint nodes <host> node-role.kubernetes.io/control-plane:NoSchedule

Если у Вас в текущий момент узла кластер работают не на последней patch-версии то рекомендуется обновиться в рамках текущей минорной версии до последней patch-версии.

Пример1: Обновление кластера с patch-версии v1.26.3 до patch-версии v1.26.15

Рассмотрим пример обновление кластера в рамках минорной версии 1.26 с patch-версии v1.26.3 до patch-версии v1.26.15.


Обновление Controlplane узлов

Начнем с начального (master) Controlplane узла. Если у нас мало Worker узлов удалим режим NoSchedule командой:

kubectl taint nodes <host> node-role.kubernetes.io/control-plane:NoSchedule-

Версия kubeadm в момент установки может не совпадать с последней версией в RPM-пакете. Так что предварительно обновите версию kubeadm до последней патчевой в минорной версии v1.26:

apt-get install kubernetes1.26-kubeadm

Для получения плана обновления запустите команду:

/usr/bin/kubeadm upgrade plan

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

Результат выполнения команды:

[upgrade/versions] Cluster version: v1.26.3
[upgrade/versions] kubeadm version: v1.26.15
I0417 15:56:57.656902   59501 version.go:256] remote version is much newer: v1.35.4; falling back to: stable-1.26
[upgrade/versions] Target version: v1.26.15
[upgrade/versions] Latest version in the v1.26 series: v1.26.15

Upgrade to the latest version in the v1.26 series:

COMPONENT                 CURRENT    TARGET
kube-apiserver            v1.26.3    v1.26.15
kube-controller-manager   v1.26.3    v1.26.15
kube-scheduler            v1.26.3    v1.26.15
kube-proxy                v1.26.3    v1.26.15
CoreDNS                   v1.9.3     v1.9.3
etcd                      3.5.10-0   3.5.10-0

You can now apply the upgrade by executing the following command:

        kubeadm upgrade apply v1.26.15
_____________________________________________________________________

The table below shows the current state of component configs as understood by this version of kubeadm.
Configs that have a "yes" mark in the "MANUAL UPGRADE REQUIRED" column require manual config upgrade or
resetting to kubeadm defaults before a successful upgrade can be performed. The version to manually
upgrade to is denoted in the "PREFERRED VERSION" column.

API GROUP                 CURRENT VERSION   PREFERRED VERSION   MANUAL UPGRADE REQUIRED
kubeproxy.config.k8s.io   v1alpha1          v1alpha1            no
kubelet.config.k8s.io     v1beta1           v1beta1             no

Вывод команды описывает версии текущих образов и образов после обновления и команду обновления. Данную команду необходимо запускать в rootless-режиме пользователя u7s-admin>/code>. Для входа в этот режим войдите (задав предварительно для него пароль командой passwd) в пользователя u7s-admin>/code>. Например через ssh:

ssh u7s-admin@localhost
$ 

и вызовите команду

$ nsenter_u7s 
[INFO] Entering RootlessKit namespaces: OK
#

Для обновления узла кластера вызовите указанную выше команду с полной тропой:

/usr/bin/kubeadm upgrade apply v1.26.15 

Если Вы планируете получать больше отладочной информации и игнорировать ошибки добавьте при вызове соответствующие флаги:

/usr/bin/kubeadm upgrade apply v1.26.15 -v 9 --ignore-preflight-errors=all  

По окончании обновления выводится сообщение:

...
[upgrade/successful] SUCCESS! Your cluster was upgraded to "v1.26.15". Enjoy!

Вернитесь из rootless режима пользователя u7s-admin в системного пользователя root:

# exit
$ exit
Connection to localhost closed.
#

Перезапустите сервис u7s:

 
/sbin/systemctl restart u7s

и дождитесь перезапуска всех POD'ов узла просматривая их состояние командой:

kubectl get -A pods  -o wide | grep "<имя_узла>"

Где имя_узла - имя узла, выводимое командой

kubectl get nodes

Повторите описанную процедуру для всех Controlplane-узлов.

Обновление worker-узлов

Запустите команду обновления kubernetes-пакетов текущей минорной версии:

apt-get install kubernetes1.26-kubeadm

Для входа в в rootless-режиме пользователя u7s-admin>/code> войдите (задав предварительно для него пароль командой passwd) в пользователя u7s-admin>/code>. Например через ssh:

ssh u7s-admin@localhost
$ 

и вызовите команду

$ nsenter_u7s 
[INFO] Entering RootlessKit namespaces: OK
#

Для обновления worker-узла вызоваите команду:

# /usr/bin/kubeadm upgrade node 

Протокол обновления:

[upgrade] Reading configuration from the cluster...
[upgrade] FYI: You can look at this config file with 'kubectl -n kube-system get cm kubeadm-config -o yaml'
[preflight] Running pre-flight checks
[preflight] Skipping prepull. Not a control plane node.
[upgrade] Skipping phase. Not a control plane node.
[kubelet-start] Writing kubelet configuration to file "/var/lib/kubelet/config.yaml"
[upgrade] The configuration for this node was successfully updated!
[upgrade] Now you should go ahead and upgrade the kubelet package using your package manager.

Вернитесь из rootless режима пользователя u7s-admin в системного пользователя root:

# exit
$ exit
Connection to localhost closed.
#

Перезапустите сервис u7s:

 
/sbin/systemctl restart u7s

и дождитесь перезапуска всех POD'ов узла просматривая их состояние командой:

kubectl get -A pods  -o wide | grep "<имя_узла>"

После обновления всех worker-узлов не забудьте вернуть controlplane-узлы в стандартное состояние командой:

kubectl taint nodes <host> node-role.kubernetes.io/control-plane:NoSchedule
Пример2: Обновление кластера с минорной-версии v1.26.15 до минорной-версии v1.27.16

Рассмотрим пример обновление кластера между минорными версиями 1.26 и 1.27 с patch-версии v1.26.15 до patch-версии v1.27.16.

При обновлении минорной версии узла рекомендуется до обновления RPM-пакета kubeadm вызвать следующие команды:

# 1. Запрещаем размещение новых подов
kubectl cordon <имя_узла>

# 2. Эвакуируем поды
kubectl drain <имя_узла> --ignore-daemonsets --delete-emptydir-data

# 3. Обновляем пакеты
apt-get update
apt-get install -y kubernetes<версия>-kubeadm

После обновления в rootless-окружении пользователя u7s-admin узла кластера командой

kubeadm upgrade apply <новая_версия>

верните узел в работу командами:

# 4. Перезапускаем kubelet
systemctl daemon-reload
systemctl restart kubelet

# 5. Возвращаем узел в работу
kubectl uncordon <имя_узла>

В остальном процесс обновления минорных версий совпадает с процессом обновления патчевых версий описанный выше.


Замечание по обновлению кластера etcd

Поскольку статический POD kube-apiserver работает постоянно (даже если вы отключили узел), при выполнении команды обновления kubeadm, включающей обновление etcd, выполняющиеся запросы к серверу будут приостановлены, пока новый статический POD etcd перезапускается. В качестве обходного пути можно остановить процесс kube-apiserver за несколько секунд до запуска команды kubeadm upgrade apply. Это позволяет завершить выполняющиеся запросы и закрыть существующие соединения, а также минимизировать последствия простоя etcd. Это можно сделать следующим образом на Controlplane узлах:

killall -s SIGTERM kube-apiserver 
sleep 20 
kubeadm upgrade ... 
  1. ...