Следующая задача падала на
run.py:91 data = json.load(file)
json.decoder.JSONDecodeError: Expecting value: line 1 column 1 (char 0)
то есть снова читала пустой файл — на этот раз django-auth.json.
Аннотации пода показали, почему: VAULT_MOUNT_PATH у движка ОДИН НА ВСЕ
файлы. Он подставляет его в каждую аннотацию, меняя только имя ключа:
agent-inject-file-django-auth: django-auth.json
agent-inject-template-django-auth: {{- with secret
"secrets/data/apps/processing/yc-s3" -}}
Ключа django-auth.json в том секрете не было, агент отрендерил пустоту.
Поэтому путь переименован в secrets/apps/processing/job-files: имя yc-s3
описывало один из файлов и врало о содержимом. В секрет добавлен ключ
django-auth.json — объект {"token": "..."}, а не голая строка, потому что
задача читает файл целиком через json.load. Значение то же, что у
workspaces в DJANGO_BASIC_AUTH: base64 от логина и пароля администратора.
Правило на будущее: появился новый файл, который движок кладёт в под
задачи, — добавляется ключ в этот же секрет, с именем ровно как у файла.
310 lines
16 KiB
YAML
310 lines
16 KiB
YAML
---
|
||
apiVersion: kustomize.config.k8s.io/v1beta1
|
||
kind: Kustomization
|
||
namespace: processing
|
||
resources:
|
||
- ../base
|
||
|
||
patches:
|
||
# --- Состав: только api и engine-low ---------------------------------------
|
||
# engine удалён: в base у него replicaCount 0, то есть он и там выключен, а
|
||
# образ прибит к тегу с опечаткой в имени (workflows-endigne_prod). Рабочий
|
||
# обработчик — engine-low, он же на более свежем образе contour_*.
|
||
- target: {kind: HelmRelease, name: engine}
|
||
patch: |
|
||
$patch: delete
|
||
apiVersion: helm.toolkit.fluxcd.io/v2
|
||
kind: HelmRelease
|
||
metadata:
|
||
name: engine
|
||
namespace: processing
|
||
|
||
# frontend идёт из base без патчей. Адреса бэкендов вшиты в бандл на этапе
|
||
# сборки (константа __BUILD_ENV__), но сборка ugok2 обращается к тому же
|
||
# origin относительными путями — иначе в остальных кластерах не понадобился
|
||
# бы отдельный маршрут /workflows/api/ перед /workflows/. Поэтому фронтенд
|
||
# публикуется на домене платформы, а не на своём поддомене: маршруты в
|
||
# infrastructure/istio-config/aero, VirtualService platform.
|
||
|
||
# --- workflows-api ----------------------------------------------------------
|
||
- target: {kind: HelmRelease, name: workflows-api}
|
||
patch: |
|
||
# S3 приезжает из Vault отдельным ФАЙЛОМ, а не парой переменных:
|
||
# приложение читает по этому пути целый JSON. В base путь ведёт в
|
||
# /etc/sarex/yc-s3/, куда в контуре ничего не смонтировано.
|
||
- op: test
|
||
path: /spec/values/services/backend/envs/3/name
|
||
value: S3_SERVICE_ACCOUNT
|
||
- op: replace
|
||
path: /spec/values/services/backend/envs/3/value/_default
|
||
value: /vault/secrets/processing-s3
|
||
- op: add
|
||
path: /spec/values/services/backend/podAnnotations/_default/vault.hashicorp.com~1agent-inject-secret-processing-s3
|
||
value: secrets/data/minio/apps/processing
|
||
- op: add
|
||
path: /spec/values/services/backend/podAnnotations/_default/vault.hashicorp.com~1agent-inject-template-processing-s3
|
||
value: |-
|
||
{{- with secret "secrets/data/minio/apps/processing" -}}
|
||
{
|
||
"host": "{{ index .Data.data "host" }}",
|
||
"bucket": "{{ index .Data.data "bucket" }}",
|
||
"access_key_id": "{{ index .Data.data "access_key_id" }}",
|
||
"secret_access_key": "{{ index .Data.data "secret_access_key" }}",
|
||
"region": "{{ index .Data.data "region" }}",
|
||
"verify": false
|
||
}
|
||
{{- end -}}
|
||
|
||
# --- engine-low -------------------------------------------------------------
|
||
# Патчи адресуются по индексу, поэтому перед каждым replace идёт op: test на
|
||
# имя переменной. Если в base порядок envs изменится, сборка упадёт явно,
|
||
# вместо того чтобы молча перезаписать соседнее значение.
|
||
- target: {kind: HelmRelease, name: engine-low}
|
||
patch: |
|
||
# Sentry — внешний домен, из контура недостижим. Значение прокидывается
|
||
# ещё и в каждый под задачи, поэтому зануляем в одном месте.
|
||
- op: test
|
||
path: /spec/values/services/backend/envs/2/name
|
||
value: WORKFLOWS_SENTRY_DSN
|
||
- op: replace
|
||
path: /spec/values/services/backend/envs/2/value/_default
|
||
value: ""
|
||
|
||
# В base адрес django неверный даже для кластеров, где он есть: сервис
|
||
# называется backend-svc и слушает 80, а не backend:8000. У api то же
|
||
# значение уже правильное.
|
||
- op: test
|
||
path: /spec/values/services/backend/envs/5/name
|
||
value: DJANGO_HOST
|
||
- op: replace
|
||
path: /spec/values/services/backend/envs/5/value/_default
|
||
value: http://backend-svc.django.svc.cluster.local:80
|
||
|
||
# S3 — как у api выше.
|
||
- op: test
|
||
path: /spec/values/services/backend/envs/6/name
|
||
value: S3_SERVICE_ACCOUNT
|
||
- op: replace
|
||
path: /spec/values/services/backend/envs/6/value/_default
|
||
value: /vault/secrets/processing-s3
|
||
|
||
# SMTP выключаем целиком: почтового релея в контуре нет. Вместе с флагом
|
||
# убираем аннотацию инжекции secrets/vault/common/smtp_auth — секрета в
|
||
# Vault нет, а vault-agent-init на несуществующем секрете не отрендерит
|
||
# шаблон и оставит под в Init:Error, до флага дело не дойдёт.
|
||
- op: test
|
||
path: /spec/values/services/backend/envs/23/name
|
||
value: ENABLE_SMTP
|
||
- op: replace
|
||
path: /spec/values/services/backend/envs/23/value/_default
|
||
value: "0"
|
||
- op: remove
|
||
path: /spec/values/services/backend/podAnnotations/_default/vault.hashicorp.com~1agent-inject-secret-processing-smtp
|
||
- op: remove
|
||
path: /spec/values/services/backend/podAnnotations/_default/vault.hashicorp.com~1agent-inject-template-processing-smtp
|
||
|
||
# Смежные сервисы, которых в контуре нет: documentations (PDM,
|
||
# filestream), resources, bim-api, workspace, issues, comparisons,
|
||
# mailgun. Оставляем только S3 — единственное внешнее хранилище, которое
|
||
# в aero действительно есть.
|
||
- op: test
|
||
path: /spec/values/services/backend/envs/22/name
|
||
value: ENABLE_PDM_STORAGE
|
||
- op: replace
|
||
path: /spec/values/services/backend/envs/22/value/_default
|
||
value: "0"
|
||
- op: test
|
||
path: /spec/values/services/backend/envs/26/name
|
||
value: ENABLE_BIM_API_V2_DB
|
||
- op: replace
|
||
path: /spec/values/services/backend/envs/26/value/_default
|
||
value: "0"
|
||
- op: test
|
||
path: /spec/values/services/backend/envs/27/name
|
||
value: ENABLE_WORKSPACE_API_DB
|
||
- op: replace
|
||
path: /spec/values/services/backend/envs/27/value/_default
|
||
value: "0"
|
||
- op: test
|
||
path: /spec/values/services/backend/envs/28/name
|
||
value: ENABLE_ISSUE_API_DB
|
||
- op: replace
|
||
path: /spec/values/services/backend/envs/28/value/_default
|
||
value: "0"
|
||
- op: test
|
||
path: /spec/values/services/backend/envs/29/name
|
||
value: ENABLE_RESOURCES_API
|
||
- op: replace
|
||
path: /spec/values/services/backend/envs/29/value/_default
|
||
value: "0"
|
||
- op: test
|
||
path: /spec/values/services/backend/envs/31/name
|
||
value: ENABLE_PDM_API_DB
|
||
- op: replace
|
||
path: /spec/values/services/backend/envs/31/value/_default
|
||
value: "0"
|
||
- op: test
|
||
path: /spec/values/services/backend/envs/32/name
|
||
value: ENABLE_COMPARISONS_API_DB
|
||
- op: replace
|
||
path: /spec/values/services/backend/envs/32/value/_default
|
||
value: "0"
|
||
- op: test
|
||
path: /spec/values/services/backend/envs/33/name
|
||
value: ENABLE_MAIL_GUN
|
||
- op: replace
|
||
path: /spec/values/services/backend/envs/33/value/_default
|
||
value: "0"
|
||
|
||
# Планирование подов задач. engine работает kubernetes-исполнителем и сам
|
||
# создаёт Job'ы, подставляя им nodeSelector dedicated=processing и
|
||
# соответствующий toleration. Выделенных нод в контуре нет — все три
|
||
# равнозначны, — поэтому поды задач висли бы в Pending с
|
||
# didn't match Pod's node affinity/selector
|
||
# ровно как это было у postgresql (см. postRenderers в его релизе).
|
||
#
|
||
# ENABLE_TOLERATION ЗДЕСЬ НЕ ВЫКЛЮЧАТЬ. Сначала я поставил его в "0" — и
|
||
# это тихо сломало запуск задач совсем: в движке классы ресурсов
|
||
# регистрируются ПОД ЭТИМ ЖЕ ФЛАГОМ,
|
||
# if resCfg.EnableToleration { services[HighResources] = ... }
|
||
# (pkg/kube_services/services.go), поэтому задача с service_request
|
||
# "high-resources" падала не на планировании, а раньше — на разборе:
|
||
# ERROR create k8s job: create k8s job: unknown service
|
||
# Ни одного пода при этом не создавалось, и в логе не было ни слова про
|
||
# nodeSelector, так что связь с этим флагом неочевидна.
|
||
#
|
||
# Вместо выключения переводим селектор на метку, которая есть на всех
|
||
# нодах, — kubernetes.io/os=linux. Класс сервисов остаётся
|
||
# зарегистрированным, nodeSelector совпадает с любой нодой, а toleration
|
||
# на несуществующий taint безвреден. Запрашиваемые ресурсы трогать не
|
||
# надо: в base это 1 CPU и 1Gi.
|
||
#
|
||
# IGNORE_TAINTS_AND_NODE_SELECTOR (появился в base из master) полагаться
|
||
# на него не стоит: в master workflows-engine такой переменной нет. Образ
|
||
# при этом contour_a03d37da-dirty2 — ручная сборка, поднятая тем же
|
||
# коммитом master, что добавил переменную, так что она там, вероятно,
|
||
# поддержана. Проверить нечем, поэтому селектор задан явно, а не через
|
||
# неё; вреда от того, что она выставлена в base, нет.
|
||
- op: test
|
||
path: /spec/values/services/backend/envs/53/name
|
||
value: TOLERATION_KEY
|
||
- op: replace
|
||
path: /spec/values/services/backend/envs/53/value/_default
|
||
value: kubernetes.io/os
|
||
- op: test
|
||
path: /spec/values/services/backend/envs/54/name
|
||
value: TOLERATION_VALUE
|
||
- op: replace
|
||
path: /spec/values/services/backend/envs/54/value/_default
|
||
value: linux
|
||
- op: test
|
||
path: /spec/values/services/backend/envs/55/name
|
||
value: TOLERATION_KEY_HIGH_MEM
|
||
- op: replace
|
||
path: /spec/values/services/backend/envs/55/value/_default
|
||
value: kubernetes.io/os
|
||
- op: test
|
||
path: /spec/values/services/backend/envs/56/name
|
||
value: TOLERATION_VALUE_HIGH_MEM
|
||
- op: replace
|
||
path: /spec/values/services/backend/envs/56/value/_default
|
||
value: linux
|
||
- op: test
|
||
path: /spec/values/services/backend/envs/57/name
|
||
value: TOLERATION_KEY_PERSISTENT
|
||
- op: replace
|
||
path: /spec/values/services/backend/envs/57/value/_default
|
||
value: kubernetes.io/os
|
||
- op: test
|
||
path: /spec/values/services/backend/envs/58/name
|
||
value: TOLERATION_VALUE_PERSISTENT
|
||
- op: replace
|
||
path: /spec/values/services/backend/envs/58/value/_default
|
||
value: linux
|
||
- op: test
|
||
path: /spec/values/services/backend/envs/70/name
|
||
value: DEFAULT_NODE_SELECTOR_KEY
|
||
- op: replace
|
||
path: /spec/values/services/backend/envs/70/value/_default
|
||
value: kubernetes.io/os
|
||
- op: test
|
||
path: /spec/values/services/backend/envs/71/name
|
||
value: DEFAULT_NODE_SELECTOR_VALUE
|
||
- op: replace
|
||
path: /spec/values/services/backend/envs/71/value/_default
|
||
value: linux
|
||
|
||
# --- Vault для ПОДОВ ЗАДАЧ, а не для самого движка ----------------------
|
||
# В сборке contour_a03d37da-dirty2 движок умеет не монтировать в Job
|
||
# готовый Secret, а вешать на него аннотации vault-agent — тогда файл
|
||
# с кредами кладёт агент, и Secret в namespace задач не нужен вовсе.
|
||
# Именно так это работает в UGMK, где никакого yc-s3 в namespace нет.
|
||
#
|
||
# В master workflows-engine этого кода нет (сборка с невлитой ветки),
|
||
# поэтому набор переменных восстановлен по строкам бинарника:
|
||
# VAULT_ROLE, VAULT_SA, VAULT_MOUNT_PATH
|
||
# vault.hashicorp.com/{role,secret-volume-path,agent-inject-file-*,
|
||
# agent-inject-secret-*,agent-inject-template-*}
|
||
# yc-s3, yc-s3-service-account.json, /etc/sarex/yc-s3
|
||
#
|
||
# В base задан только VAULT_USE=true — остальных трёх нет НИ В ОДНОМ
|
||
# кластере репозитория, поэтому аннотации выходили неполными, агент в под
|
||
# задачи ничего не клал, и файл читался как пустой:
|
||
# ValueError: SERVICE_S3 is not valid
|
||
# Expecting value: line 1 column 1 (char 0)
|
||
#
|
||
# Переменных нет в base, поэтому op: add с "-" (добавление в конец
|
||
# списка), а не replace по индексу.
|
||
- op: add
|
||
path: /spec/values/services/backend/envs/-
|
||
value:
|
||
name: VAULT_ROLE
|
||
value:
|
||
_default: processing
|
||
- op: add
|
||
path: /spec/values/services/backend/envs/-
|
||
value:
|
||
name: VAULT_SA
|
||
value:
|
||
_default: processing-vault
|
||
# VAULT_MOUNT_PATH — вопреки имени НЕ корень KV, а ПОЛНЫЙ путь секрета:
|
||
# движок подставляет значение в шаблон целиком. Проверено по аннотациям
|
||
# созданного пода задачи:
|
||
# agent-inject-secret-yc-s3: <VAULT_MOUNT_PATH>
|
||
# agent-inject-template-yc-s3:
|
||
# {{- with secret "<VAULT_MOUNT_PATH>" -}}
|
||
# {{ index .Data.data "yc-s3-service-account.json" }}
|
||
# Отсюда два следствия: путь пишется в форме чтения KV v2 (с /data/), а в
|
||
# секрете обязан быть ключ с именем ФАЙЛА.
|
||
#
|
||
# Путь ОДИН НА ВСЕ ФАЙЛЫ, которые движок кладёт в поды задач: он
|
||
# подставляет VAULT_MOUNT_PATH в каждую аннотацию, меняя только имя
|
||
# ключа. Так, для django-auth аннотация ссылается на этот же путь и ищет
|
||
# в нём ключ django-auth.json. Поэтому имя пути нейтральное (job-files),
|
||
# а не по имени одного из файлов, — иначе оно врёт о содержимом.
|
||
# Сам секрет кладёт ansible, vault_app_secrets.
|
||
- op: add
|
||
path: /spec/values/services/backend/envs/-
|
||
value:
|
||
name: VAULT_MOUNT_PATH
|
||
value:
|
||
_default: secrets/data/apps/processing/job-files
|
||
|
||
# S3 из Vault, как у api.
|
||
- op: add
|
||
path: /spec/values/services/backend/podAnnotations/_default/vault.hashicorp.com~1agent-inject-secret-processing-s3
|
||
value: secrets/data/minio/apps/processing
|
||
- op: add
|
||
path: /spec/values/services/backend/podAnnotations/_default/vault.hashicorp.com~1agent-inject-template-processing-s3
|
||
value: |-
|
||
{{- with secret "secrets/data/minio/apps/processing" -}}
|
||
{
|
||
"host": "{{ index .Data.data "host" }}",
|
||
"bucket": "{{ index .Data.data "bucket" }}",
|
||
"access_key_id": "{{ index .Data.data "access_key_id" }}",
|
||
"secret_access_key": "{{ index .Data.data "secret_access_key" }}",
|
||
"region": "{{ index .Data.data "region" }}",
|
||
"verify": false
|
||
}
|
||
{{- end -}}
|