diff --git a/aero/roles/sarex_stack/defaults/main.yml b/aero/roles/sarex_stack/defaults/main.yml index 92c3c73..9c5f6bf 100644 --- a/aero/roles/sarex_stack/defaults/main.yml +++ b/aero/roles/sarex_stack/defaults/main.yml @@ -80,6 +80,7 @@ registry_secrets: # Образы vault-k8s и vault-agent для injector'а тоже лежат в cr.yandex. - {name: regcred, namespace: vault} - {name: regcred, namespace: local-path-provisioner} + - {name: regcred, namespace: postgresql} - {name: regcred, namespace: rabbitmq} - {name: regcred, namespace: minio} @@ -121,6 +122,7 @@ gitea_sync_paths: - infrastructure/istio-pilot - infrastructure/vault-injector - infrastructure/local-path-provisioner + - infrastructure/postgresql - infrastructure/rabbitmq - infrastructure/minio @@ -202,6 +204,7 @@ vault_role_ttl: 24h # vault.hashicorp.com/role, namespace — где живут его поды. Пополняется по мере # переезда приложений из compose в k3s. vault_k8s_roles: + - {name: postgresql, namespaces: [postgresql]} - {name: rabbitmq, namespaces: [rabbitmq]} - {name: minio, namespaces: [minio]} - {name: django, namespaces: [django]} @@ -214,6 +217,20 @@ vault_k8s_roles: # Пароли не хранятся в репозитории: берутся из sarex_secrets, который # генерирует и персистит в aero/.secrets задача "Сгенерировать/загрузить пароли". vault_app_secrets: + # Пароль администратора PostgreSQL. Имя ключа задано чартом + # (contour.vault.secretKey) — менять в отрыве от values нельзя. + - path: secrets/postgresql/admin + data: + postgres-password: "{{ sarex_secrets.SAREX_POSTGRES_PASSWORD }}" + # Пароли владельцев баз. Ключи сопоставляются с passwordKey каждой базы в + # contour.databases (см. infrastructure/postgresql/aero). Добавляешь базу — + # добавь сюда ключ, иначе бутстрап не сможет задать роли пароль. + - path: secrets/postgresql/users + data: + django: "{{ sarex_secrets.SAREX_DJANGO_DB_PASSWORD }}" + processing: "{{ sarex_secrets.SAREX_PROCESSING_DB_PASSWORD }}" + bim: "{{ sarex_secrets.SAREX_BIM_DB_PASSWORD }}" + workspace: "{{ sarex_secrets.SAREX_WORKSPACE_DB_PASSWORD }}" - path: secrets/rabbitmq/auth data: username: "{{ sarex_rabbitmq_k8s_user }}" diff --git a/clusters/aero/apps.yaml b/clusters/aero/apps.yaml index 88a1c15..5a83f02 100644 --- a/clusters/aero/apps.yaml +++ b/clusters/aero/apps.yaml @@ -12,7 +12,7 @@ metadata: name: apps namespace: flux-system spec: - interval: 10m0s + interval: 2m0s path: ./clusters/aero/apps prune: true wait: true diff --git a/clusters/aero/controllers/kustomization.yaml b/clusters/aero/controllers/kustomization.yaml index cc4e4b5..1851f23 100644 --- a/clusters/aero/controllers/kustomization.yaml +++ b/clusters/aero/controllers/kustomization.yaml @@ -22,7 +22,10 @@ resources: - ../../../infrastructure/dashboard/aero # Только Vault Agent Injector: сам Vault живёт в compose, а не в кластере. - ../../../infrastructure/vault-injector/aero - # Брокер и объектное хранилище. Креды берут из Vault через injector, поэтому - # идут после него. Админки выставлены наружу через istio-config/aero. + # СУБД, брокер и объектное хранилище. Креды берут из Vault через injector, + # поэтому идут после него. Админки rabbitmq и minio выставлены наружу через + # istio-config/aero; postgresql наружу не публикуется — доступ только изнутри + # кластера. + - ../../../infrastructure/postgresql/aero - ../../../infrastructure/rabbitmq/aero - ../../../infrastructure/minio/aero diff --git a/clusters/aero/infrastructure.yaml b/clusters/aero/infrastructure.yaml index d7da424..f727cfd 100644 --- a/clusters/aero/infrastructure.yaml +++ b/clusters/aero/infrastructure.yaml @@ -37,7 +37,11 @@ metadata: name: infra-controllers namespace: flux-system spec: - interval: 10m0s + # 2 минуты, а не дефолтные 10: интервал определяет, как быстро слой заметит + # новую ревизию и как быстро повторит попытку после неудачи. С 10 минутами + # цикл «правка → проверка» растягивался до получаса, а сломанный релиз + # держал слой всё это время. + interval: 2m0s path: ./clusters/aero/controllers prune: true wait: true @@ -52,7 +56,7 @@ metadata: name: infra-configs namespace: flux-system spec: - interval: 10m0s + interval: 2m0s path: ./clusters/aero/configs prune: true # dependsOn намеренно отсутствует — см. комментарий в начале файла. diff --git a/clusters/aero/kustomization.yaml b/clusters/aero/kustomization.yaml index 9a313ee..1912878 100644 --- a/clusters/aero/kustomization.yaml +++ b/clusters/aero/kustomization.yaml @@ -7,3 +7,26 @@ resources: - ./infrastructure.yaml # Слой приложений. Пока пуст — сюда приедут сервисы при переносе из compose. - ./apps.yaml + +# Корневая Kustomization применяет этот же каталог, поэтому здесь она правит +# сама себя — и это единственный способ задать ей интервал. +# +# Файл flux-system/gotk-sync.yaml генерирует `flux bootstrap` и помечает +# "DO NOT EDIT": правка руками затрётся на следующем прогоне. Флаг +# --interval=2m у bootstrap (см. docker-compose.yaml) тоже не помогает — он +# задаёт периодичность только GitRepository, а Kustomization оставляет +# дефолтные 10 минут. Патч же применяется поверх сгенерированного файла и +# переживает регенерацию. +# +# Без этого определения самих слоёв (infrastructure.yaml, apps.yaml) +# доезжали бы до кластера с задержкой до 10 минут, даже когда все нижние +# слои уже проверяются раз в 2 минуты. +patches: + - target: + kind: Kustomization + name: flux-system + namespace: flux-system + patch: | + - op: replace + path: /spec/interval + value: 2m0s diff --git a/docker-compose.yaml b/docker-compose.yaml index 4555f2c..90e2161 100644 --- a/docker-compose.yaml +++ b/docker-compose.yaml @@ -379,6 +379,13 @@ services: # Адрес источника — имя Service'а моста (flux-k8s-init), а не IP: так # адрес gitea задан ровно в одном месте — переменной GITEA_BRIDGE_IP. + # + # --interval=2m задаёт периодичность проверок у GitRepository и корневой + # Kustomization в clusters/aero/flux-system/gotk-sync.yaml. Задаётся + # именно флагом, потому что этот файл генерирует сам bootstrap и правка + # руками затирается при следующем прогоне (в нём так и написано: + # "DO NOT EDIT"). Дефолтные 10 минут растягивали цикл «правка → проверка» + # до получаса. flux bootstrap git \ --url="http://gitea.flux-system.svc.cluster.local:3000/$$GITEA_ORG/$$GITEA_REPO.git" \ --branch="$$AERO_GIT_BRANCH" \ @@ -386,7 +393,8 @@ services: --username="$$GITEA_ADMIN_USER" \ --password="$$GITEA_ADMIN_PASSWORD" \ --token-auth \ - --allow-insecure-http + --allow-insecure-http \ + --interval=2m # --------------------------------------------------------------------------- # Инфраструктурные зависимости apps/django (sarex-backend). diff --git a/infrastructure/dashboard/aero/dashboard.yaml b/infrastructure/dashboard/aero/dashboard.yaml index 7cc6e73..74dbd68 100644 --- a/infrastructure/dashboard/aero/dashboard.yaml +++ b/infrastructure/dashboard/aero/dashboard.yaml @@ -4,7 +4,7 @@ metadata: name: dashboard namespace: kubernetes-dashboard spec: - interval: 5m + interval: 2m timeout: 10m values: # Kong слушает 8000 открытым HTTP и ничего не знает про istio. Без этого diff --git a/infrastructure/istio-config/aero/istio-config.yaml b/infrastructure/istio-config/aero/istio-config.yaml index 8f77884..b94e536 100644 --- a/infrastructure/istio-config/aero/istio-config.yaml +++ b/infrastructure/istio-config/aero/istio-config.yaml @@ -4,7 +4,7 @@ metadata: name: istio-config namespace: default spec: - interval: 5m + interval: 2m timeout: 10m # disableWait РАЗРЫВАЕТ ДЕДЛОК, не украшательство. # diff --git a/infrastructure/local-path-provisioner/aero/local-path-provisioner.yaml b/infrastructure/local-path-provisioner/aero/local-path-provisioner.yaml index e619d1b..1133019 100644 --- a/infrastructure/local-path-provisioner/aero/local-path-provisioner.yaml +++ b/infrastructure/local-path-provisioner/aero/local-path-provisioner.yaml @@ -4,7 +4,7 @@ metadata: name: local-path-provisioner namespace: local-path-provisioner spec: - interval: 5m + interval: 2m timeout: 10m values: replicaCount: 1 diff --git a/infrastructure/minio/aero/minio.yaml b/infrastructure/minio/aero/minio.yaml index 173a141..be39ca5 100644 --- a/infrastructure/minio/aero/minio.yaml +++ b/infrastructure/minio/aero/minio.yaml @@ -4,7 +4,7 @@ metadata: name: minio namespace: minio spec: - interval: 5m + interval: 2m timeout: 10m values: nameOverride: "minio" diff --git a/infrastructure/postgresql/aero/kustomization.yaml b/infrastructure/postgresql/aero/kustomization.yaml new file mode 100644 index 0000000..8eb0c20 --- /dev/null +++ b/infrastructure/postgresql/aero/kustomization.yaml @@ -0,0 +1,10 @@ +--- +apiVersion: kustomize.config.k8s.io/v1beta1 +kind: Kustomization +resources: + - ../base +patches: + - path: postgresql.yaml + target: + kind: HelmRelease + name: postgresql diff --git a/infrastructure/postgresql/aero/postgresql.yaml b/infrastructure/postgresql/aero/postgresql.yaml new file mode 100644 index 0000000..6441075 --- /dev/null +++ b/infrastructure/postgresql/aero/postgresql.yaml @@ -0,0 +1,176 @@ +apiVersion: helm.toolkit.fluxcd.io/v2 +kind: HelmRelease +metadata: + name: postgresql + namespace: postgresql +spec: + interval: 2m + # Разворачиваем пустой инстанс: базы создаются с нуля, дампы не + # восстанавливаются. Поэтому таймауты обычные, а не двухчасовые как в + # yc-k8s-test — там они заданы под restoreFromDump. + # + # 10 минут, а не 20: таймаут — это ещё и цена одной неудачной итерации. + # Пока стояло 20, цикл «install → таймаут → откат → install» занимал по + # 20 минут на круг, и правка, приехавшая в середине круга, подхватывалась + # только на следующем. Здоровый инстанс поднимается примерно за две минуты, + # так что 10 — с большим запасом. + timeout: 10m + install: + timeout: 10m + remediation: + retries: 3 + upgrade: + timeout: 10m + remediation: + retries: 3 + # Снимаем nodeSelector, который чарт ставит по умолчанию. + # + # В дефолтах чарта (primary.nodeSelector) прописано dedicated: sts — расчёт на + # кластер с выделенным пулом нод под StatefulSet'ы. В контуре aero таких нод + # нет, все три равнозначны, и под навсегда повисал в Pending: + # 0/3 nodes are available: 3 node(s) didn't match Pod's node affinity/selector + # а следом застревал PVC, потому что у local-path режим WaitForFirstConsumer + # и том создаётся только после планирования пода. + # + # Через values это не снять: Helm сливает карты по ключам, поэтому и {}, и + # любая другая метка оставят dedicated: sts на месте. В yc-k8s-test дефолт не + # убирают, а перекрывают на dedicated: db — там выделенные ноды есть. + # Тут остаётся убрать ключ из уже отрендеренного манифеста. + # + # Tolerations чарта не трогаем: они разрешают taint dedicated=sts, которого на + # наших нодах нет, и ни на что не влияют. + postRenderers: + - kustomize: + patches: + - target: + kind: StatefulSet + name: postgresql + patch: | + - op: remove + path: /spec/template/spec/nodeSelector + values: + global: + security: + allowInsecureImages: true + defaultStorageClass: local-path + imagePullSecrets: + - regcred + postgresql: + auth: + # Пусто осознанно: пользователя и базу заводит не чарт-бутстрап + # bitnami, а contour-логика ниже (contour.databases). Оставь здесь + # значения — получишь лишнюю базу-пустышку. + username: "" + database: "" + secretKeys: + userPasswordKey: "postgres-password" + auth: + username: "" + database: "" + secretKeys: + userPasswordKey: "postgres-password" + image: + registry: cr.yandex/crp3ccidau046kdj8g9q + repository: contour/postgresql + tag: 17.0.7 + pullPolicy: IfNotPresent + metrics: + enabled: false + prometheusRule: + enabled: false + primary: + # Токен ServiceAccount нужен vault-agent'у для логина в Vault. + automountServiceAccountToken: true + containerSecurityContext: + readOnlyRootFilesystem: false + persistence: + storageClass: local-path + size: 20Gi + # В yc-k8s-test здесь nodeSelector/tolerations dedicated=db. В контуре + # aero выделенных под БД нод нет — все три равнозначны, ограничивать + # планировщик нечем и незачем. + customLivenessProbe: + exec: + command: + - /bin/sh + - -c + - exec pg_isready -U "postgres" -d postgres -h 127.0.0.1 -p 5432 + initialDelaySeconds: 30 + periodSeconds: 10 + timeoutSeconds: 5 + successThreshold: 1 + failureThreshold: 6 + customReadinessProbe: + exec: + command: + - /bin/sh + - -c + - exec pg_isready -U "postgres" -d postgres -h 127.0.0.1 -p 5432 + initialDelaySeconds: 5 + periodSeconds: 10 + timeoutSeconds: 5 + successThreshold: 1 + failureThreshold: 6 + customStartupProbe: + exec: + command: + - /bin/sh + - -c + - exec pg_isready -U "postgres" -d postgres -h 127.0.0.1 -p 5432 + initialDelaySeconds: 30 + periodSeconds: 10 + timeoutSeconds: 5 + successThreshold: 1 + failureThreshold: 6 + # contour-логика: создаёт роли, базы и расширения по списку ниже, пароли + # берёт из Vault через vault-agent-injector. + contour: + enabled: true + adminUser: "postgres" + vault: + enabled: true + role: postgresql + authPath: auth/kubernetes + # Пароль администратора. + secretPath: secrets/data/postgresql/admin + secretKey: postgres-password + # Пароли пользователей баз: ключи внутри секрета сопоставляются с + # passwordKey каждой базы. Чарт требует этот путь при vault.enabled. + # Секрет кладёт ansible (роль sarex_stack, vault_app_secrets). + usersSecretPath: secrets/data/postgresql/users + # timescaledb включён заранее, хотя нашим четырём базам он не нужен: + # shared_preload_libraries читается только при старте, и добавить его + # позже — значит перезапустить СУБД. Сервисы, которым он понадобится + # (issues, subscriptions, system-log), уже есть в списке на перенос. + sharedPreloadLibraries: "timescaledb,pg_stat_statements" + # Набор баз повторяет то, что сейчас провижинит postgres-init в + # docker-compose.yaml, — контур переезжает в k3s тем же составом. + # passwordKey должен совпадать с ключом в секрете Vault + # secrets/postgresql/users. + databases: + - name: sarex_db + user: django + passwordKey: django + extensions: + - ltree + restoreFromDump: false + - name: workflow_db + user: processing + passwordKey: processing + # Роль processing не суперпользователь, а её миграции делают + # CREATE EXTENSION — поэтому расширения создаёт бутстрап заранее. + extensions: + - uuid-ossp + - ltree + - hstore + restoreFromDump: false + - name: bim_db + user: bim + passwordKey: bim + extensions: [] + restoreFromDump: false + - name: workspace_db + user: workspace + passwordKey: workspace + extensions: [] + restoreFromDump: false diff --git a/infrastructure/rabbitmq/aero/rabbitmq.yaml b/infrastructure/rabbitmq/aero/rabbitmq.yaml index 3ecb76e..e6812a3 100644 --- a/infrastructure/rabbitmq/aero/rabbitmq.yaml +++ b/infrastructure/rabbitmq/aero/rabbitmq.yaml @@ -4,7 +4,7 @@ metadata: name: rabbitmq namespace: rabbitmq spec: - interval: 5m + interval: 2m timeout: 10m # Вырезаем ресурсы ПОСЛЕ рендера чарта. Через values это недостижимо: # * `null` до Helm не доезжает — kustomize нормализует его в {}; @@ -55,24 +55,16 @@ spec: global: security: allowInsecureImages: true - # Собственные VirtualService/Gateway/Certificate чарта отключаются НЕ здесь, - # а JSON6902-патчем в kustomization.yaml рядом. Причина — в противоположной - # семантике null у двух инструментов: + # Здесь НЕТ ключей virtualService/gateway/certificate, и это намеренно: + # через values дефолты чарта не убираются вообще никак. # # Helm : удалить дефолт можно ТОЛЬКО значением null; # {} он глубоко сливает с дефолтом, и дефолт остаётся; # kustomize : в strategic-merge-патче null означает УДАЛИТЬ КЛЮЧ, - # то есть до Helm он просто не доедет. + # в JSON6902 — нормализуется обратно в {}. # - # Значит ни `virtualService: null`, ни `virtualService: {}` здесь не - # работают: первое стирается kustomize, второе игнорируется Helm. Нужен - # JSON6902, где null — это именно значение, а не команда удаления. - # - # Цена ошибки не косметическая: чарт создавал rmq-gateway, rmq-virt-service - # и сертификат rmq-tls на посторонний домен rabbitmq.infra.sarex.io. - # Последний не проходит проверку ACME никогда, впустую жжёт лимиты - # Let's Encrypt, а релиз висит в install, ожидая его выпуска, и блокирует - # весь слой infra-controllers. + # То есть до Helm настоящий null не доходит ни одним путём. Поэтому ресурсы + # вырезаются postRenderers'ом выше, уже из отрендеренного манифеста. metrics: serviceMonitor: enabled: false diff --git a/infrastructure/vault-injector/base/helmrelease.yaml b/infrastructure/vault-injector/base/helmrelease.yaml index 04cbb1c..b9d2cd3 100644 --- a/infrastructure/vault-injector/base/helmrelease.yaml +++ b/infrastructure/vault-injector/base/helmrelease.yaml @@ -19,7 +19,7 @@ metadata: name: vault-injector namespace: vault spec: - interval: 10m + interval: 2m chart: spec: chart: vault-contour