publishing.host | "example.org" | Основной домен для всех сервисов, создаваемых в Cozystack: dashboard, Grafana, Keycloak и других. |
publishing.apiServerEndpoint | "" | Используется для генерации kubeconfig-файлов для пользователей. Рекомендуется использовать маршрутизируемый FQDN или IP-адрес вместо адресов, доступных только локально. Пример: "https://api.example.org". |
publishing.exposedServices | [api, dashboard, vm-exportproxy, cdi-uploadproxy] | Список сервисов для публикации. Возможные значения: api, dashboard, cdi-uploadproxy, vm-exportproxy. |
publishing.ingressName | "tenant-root" | Ingress controller, используемый для публикации сервисов. |
publishing.externalIPs | [] | Список external IP, используемых указанным ingress controller. Если не задан, по умолчанию используется сервис LoadBalancer. |
publishing.ingressNameAdmin | "" | Имя отдельного административного ingress, к которому системные компоненты подключают свои административные маршруты (на данный момент только Keycloak) — например, привязанного к приватному IP и недоступного из интернета. На пути через Gateway значение — это namespace (для Gateway с именем cozystack); на пути через ingress-nginx это ingressClassName. Эти два варианта совпадают, потому что Cozystack называет каждый ingressClass по имени namespace тенанта. Пустое значение (по умолчанию) оставляет административные эндпоинты на publishing.ingressName. Два предостережения: Cozystack не создаёт административный Gateway — его нужно предварительно подготовить отдельно, иначе административные маршруты окажутся ни к чему не подключены; а также административные маршруты рендерятся только когда у Keycloak установлен ingress.adminHost, поэтому установка одного этого ключа сама по себе ничего не даёт. |
publishing.exposureClass.name | "" | Логическое имя кластерного ресурса ExposureClass, который нужно отрендерить. Пустое значение (по умолчанию) оставляет путь publishing.externalIPs без изменений. Когда значение задано, host ingress — при пустом publishing.externalIPs — публикует свой Service как type: LoadBalancer, а cozystack-controller транслирует класс в пул VIP выбранного backend и его анонсировщик. Это путь миграции с Service.spec.externalIPs, устаревшего начиная с Kubernetes v1.36 (KEP-5707). Удаление происходит поэтапно: feature gate AllowServiceExternalIPs поставляется включённым в v1.36, затем по умолчанию становится false (цель KEP: v1.40), после чего kube-proxy перестаёт программировать правила для этого поля — API всё ещё принимает его, поэтому Service выглядит здоровым, хотя трафик никуда не приходит. На последующих этапах gate блокируется в выключенном состоянии, а поддержка в kube-proxy полностью удаляется, и в итоге сам gate и admission-контроллер DenyServiceExternalIPs убираются. KEP указывает эти более поздние релизы как приблизительные, а объявление для v1.36 обещает лишь «будущий минорный релиз», поэтому переключение значения по умолчанию на false стоит воспринимать как дедлайн и мигрировать на класс до этого обновления, а не ориентироваться на конкретную версию. |
publishing.exposureClass.backend | "externalIPs" | Механизм LoadBalancer, стоящий за классом. externalIPs фиксирует IP узлов без пула или анонсировщика (историческое поведение); metallb рендерит IPAddressPool + L2Advertisement; cilium рендерит CiliumLoadBalancerIPPool + CiliumL2AnnouncementPolicy; robotlb использует облачный (Hetzner) load balancer, где выделение и анонсирование происходят вне кластера. Как только publishing.exposureClass.name задан, backend с пулом или облачный backend (metallb, cilium, robotlb) взаимно исключает непустой publishing.externalIPs — рендер платформы завершится явной ошибкой, а не отправит нерабочий вариант в production, потому что Service host ingress остался бы ClusterIP + externalIPs, никогда не стал бы type: LoadBalancer, а выделенный пул остался бы неиспользованным. |
publishing.exposureClass.addresses | [] | VIP CIDR или диапазоны вида start-end для backend’ов с пулом (metallb, cilium). |
publishing.exposureClass.l2 | true | Анонсирование L2 (ARP / NDP) для bare-metal backend’ов. |
publishing.exposureClass.isDefault | true | Делает этот класс используемым по умолчанию для любого ServiceExposure, который не указывает имя класса. ServiceExposure — это внутрикластерный ресурс, который cozystack-controller реконсилирует, чтобы опубликовать Service через backend класса; рабочие нагрузки не создают его напрямую. Поскольку по умолчанию это значение true, ручное создание второго ExposureClass без снятия у него флага default оставляет два класса по умолчанию, и контроллер тогда завершает с ошибкой AmbiguousDefaultClass каждый ServiceExposure без указанного имени — необходимо поддерживать ровно один класс по умолчанию. |
publishing.certificates.solver | "http01" | Тип ACME challenge solver для letsencrypt issuer по умолчанию. Возможные значения: http01, dns01. |
publishing.certificates.issuerName | "letsencrypt-prod" | Имя ClusterIssuer для TLS-сертификатов, используемых в системных Helm releases. |
publishing.certificates.wildcard | false | Опциональное включение общего wildcard-сертификата на пути ingress-nginx по умолчанию (gateway.enabled=false). Когда значение true при solver=dns01 и без указания publishing.certificates.wildcardSecretName, платформа выпускает один Certificate вида *.<root-host> + <root-host> через DNS-01 ClusterIssuer и использует его как SSL-сертификат по умолчанию для ingress-контроллера — таким образом системные сервисы перестают выпускать отдельный ACME-сертификат на каждый хост, что позволяет избежать лимитов Let’s Encrypt при масштабировании (аналогично поведению на пути Gateway API). Игнорируется при http01 (wildcard-сертификаты выпускать нельзя) и при gateway.enabled=true (в этом случае wildcard-сертификат выпускает контроллер TenantGateway). При включении имя выпущенного Secret передаётся в тот же канал значений кластера, что и publishing.certificates.wildcardSecretName, поэтому возникает та же проблема с дочерними тенантами и та же открытая ошибка (
cozystack/cozystack#3296): у всех тенантов системные ingress-ресурсы во всём кластере теряют собственный ACME-сертификат на каждый хост, но wildcard-сертификат обслуживается только контроллером публикации. Дочерний тенант, запускающий собственный ingress-контроллер (ingress: true), в результате остаётся без сертификата и обслуживается встроенным самоподписанным сертификатом ingress-nginx; наследующий дочерний тенант на общем контроллере вместо этого получает несовпадение имени хоста, поскольку однокомпонентный wildcard *.<root-host> не покрывает вложенный хост вида <service>.<tenant>.<root-host> или произвольный ingress.host на другом домене. Включайте эту опцию только тогда, когда покрыты все публикуемые хосты и ни один дочерний тенант не запускает собственный ingress-контроллер. По умолчанию отключено, чтобы кластер с dns01 никогда не переключался незаметно при обновлении. |
publishing.certificates.wildcardSecretName | "" | Wildcard TLS Secret, предоставленный оператором. Если задан, системные сервисы платформы и ingress/Gateway корневого тенанта используют этот заранее существующий Secret вместо выпуска отдельных ACME-сертификатов на каждый хост (по каналу значений передаётся только ИМЯ — но никогда сам ключевой материал), и этот параметр имеет приоритет над publishing.certificates.wildcard. Secret должен существовать в namespace публикации (по умолчанию tenant-root), содержать корректный PEM в полях tls.crt / tls.key (создан как kubernetes.io/tls, хотя проверяется только сам материал) и покрывать обслуживаемые хосты. Область действия ограничена корневым тенантом, но это не проверяется принудительно — имя достигает всех тенантов, из-за чего дочерний тенант, запускающий собственный ingress-контроллер, может остаться с самоподписанным сертификатом (
cozystack/cozystack#3296). Полное описание поведения и трёх случаев для дочерних тенантов см. в разделе
Gateway API → Certificates. Оставьте пустым, чтобы сохранить выпуск сертификатов через ACME. |
publishing.certificates.dns01.provider | "cloudflare" | DNS-01 provider, когда solver=dns01. Возможные значения: cloudflare, route53, digitalocean, rfc2136. Это значение читают и per-tenant Issuer (формируемый cozystack-controller из CR TenantGateway), и общекластерные ClusterIssuer letsencrypt-prod / letsencrypt-stage, используемые прежним ingress-механизмом. |
publishing.certificates.dns01.cloudflare.secretName | "cloudflare-api-token-secret" | Имя Secret с Cloudflare API token, имеющим права Zone:Read + Zone:DNS:Edit на apex-зону. |
publishing.certificates.dns01.cloudflare.secretKey | "api-token" | Ключ внутри Secret, содержащий API token. |
publishing.certificates.dns01.route53.region | "" | AWS-регион hosted zone Route53. Требуется, когда provider=route53. |
publishing.certificates.dns01.route53.accessKeyID | "" | IAM access key ID. Необязателен при работе с IRSA / instance profile. |
publishing.certificates.dns01.route53.secretName | "" | Имя Secret с IAM secret access key. Необязателен при работе с IRSA / instance profile. |
publishing.certificates.dns01.route53.secretKey | "secret-access-key" | Ключ внутри Secret Route53, содержащий secret access key. |
publishing.certificates.dns01.digitalocean.secretName | "digitalocean-api-token-secret" | Имя Secret с DigitalOcean API token, имеющим доступ на запись к apex-домену. |
publishing.certificates.dns01.digitalocean.secretKey | "access-token" | Ключ внутри Secret, содержащий DigitalOcean token. |
publishing.certificates.dns01.rfc2136.nameserver | "" | host:port авторитетного nameserver, принимающего динамические обновления RFC 2136. Требуется, когда provider=rfc2136. |
publishing.certificates.dns01.rfc2136.tsigKeyName | "" | Имя TSIG-ключа, авторизующего динамические обновления. Требуется, когда provider=rfc2136. |
publishing.certificates.dns01.rfc2136.tsigAlgorithm | "HMACSHA256" | HMAC-алгоритм TSIG. |
publishing.certificates.dns01.rfc2136.secretName | "" | Имя Secret с материалом TSIG-ключа. Требуется, когда provider=rfc2136. |
publishing.certificates.dns01.rfc2136.secretKey | "tsig-secret-key" | Ключ внутри Secret, содержащий TSIG-ключ. |
publishing.proxyProtocol | false | Включает PROXY-протокол на хост-инстансе ingress-nginx и автоматически развёртывает
ouroboros для устранения возникающей проблемы hairpin-NAT. Вышестоящий L4-балансировщик перед ingress-nginx должен уже внедрять заголовки PROXY-v1 до включения этого флага; см. связанную страницу для рецептов проверки и пути отключения. |
publishing.proxyProtocolAcknowledgeUnclean | false | Флаг подтверждения для асимметрии helm.sh/resource-policy: keep на пути отключения хоста. Переключение publishing.proxyProtocol с true обратно на false прекращает генерацию Package CR cozystack.ouroboros, но не удаляет уже существующий — рендеринг платформы завершается с ошибкой до тех пор, пока либо Package CR не будет удалён (что запускает pre-delete cleanup хук чарта), либо этот флаг не будет установлен в true, подтверждая, что оператор обработал асимметрию. См.
hairpin-proxy-protocol → Disable path для полной последовательности действий. |