Files
fission-src/doc/thinking/2026-04-26-layer1-pass-detailed.md
T

249 lines
10 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 2026-04-26 - Layer1 multi-tenant NSWatcher: полный разбор до 5/5 PASS
## Цель
Довести `test_layer1.sh` до `PASS=5 FAIL=0` для сценария:
1. создаётся новый namespace
2. namespace получает label `fission.io/managed=true`
3. Fission без рестарта подхватывает namespace
4. в namespace создаются `Environment`, `Function`, `HTTPTrigger`
5. функция успешно вызывается через router
Ключевое требование: всё должно происходить без rolling restart Fission-компонентов.
## Исходный симптом
Первый устойчивый симптом был таким:
- `test_layer1.sh` стабильно доходил до `4/5`
- шаг вызова функции падал
- в user namespace наблюдалось:
- `FailedCreate`
- `serviceaccount "fission-fetcher" not found`
Это означало, что poolmgr deployment для environment уже создаётся, но pod не может стартовать без `fission-fetcher` ServiceAccount.
## Что уже было исправлено до RBAC-этапа
Кодовая часть hot-registration была уже внедрена ранее:
- `pkg/utils/serviceaccount.go`
- добавлена `EnsureNamespaceSA(...)`
- `pkg/executor/multitenant/ns_watcher.go`
- при регистрации нового namespace вызывается `EnsureNamespaceSA(...)`
- образ `naeel/fission-bundle:v1.22.0-multi-ns-8` уже был собран и задеплоен
То есть логика в коде уже существовала; сбой был не в отсутствии вызова, а в невозможности выполнить его успешно в кластере.
## Диагностика 1: executor не может создать ServiceAccount/Role/RoleBinding
Была проведена проверка прав service account `fission-executor`.
Подтверждено:
- код `EnsureNamespaceSA` вызывается
- `ns_watcher` регистрирует namespace
- executor не имеет достаточных RBAC-прав для provisioning ресурсов в новом namespace
Первый явный пробел:
- отсутствовали права на:
- `serviceaccounts`
- `roles`
- `rolebindings`
После начального RBAC fix было видно, что `ServiceAccount/fission-fetcher` уже создаётся, но этого оказалось недостаточно.
## Диагностика 2: initial RBAC fix оказался неполным
После расширения прав на `serviceaccounts/roles/rolebindings` тест перестал падать на отсутствии SA, но при детальной диагностике выяснилось, что `EnsureNamespaceSA` всё ещё не может полностью создать `Role` для fetcher.
Ключевой лог executor:
```text
error while creating role for sa fission-fetcher in namespace diag-ns-82702
... is attempting to grant RBAC permissions not currently held:
{APIGroups:[""], Resources:["events"], Verbs:["create"]}
```
И дополнительный лог перед этим:
```text
localsubjectaccessreviews.authorization.k8s.io is forbidden
```
### Что это означает
Функция `setupSAAndRoleBindings()` делает две важные вещи:
1. пытается проверить уже существующие права через `LocalSubjectAccessReview`
2. если прав нет, создаёт `Role` с нужными permission-ами
Следовательно executor должен иметь не только право создавать `Role/RoleBinding`, но и:
- `authorization.k8s.io/localsubjectaccessreviews:create`
- все permission-ы, которые он пытается делегировать через создаваемую `Role`
В нашем случае fetcher получает право:
- `events:create`
По правилам Kubernetes нельзя создать `Role`, выдающую право, которого нет у самого вызывающего субъекта. Поэтому executor должен был сам иметь `events:create`.
### Реальный root cause на этом этапе
`fission-executor` не имел:
- `events.create`
- `localsubjectaccessreviews.create`
Из-за этого:
- `ServiceAccount` создавался
- но `Role` и `RoleBinding` создавались не полностью или не создавались вовсе
- downstream specialization ломалась
## Исправление 1: полный executor RBAC для dynamic SA provisioning
В `deploy/multitenant/rbac.yaml` был добавлен и затем расширен `ClusterRole`:
- `fission-executor-sa-provisioner`
Итоговый набор прав для него:
- core:
- `serviceaccounts`: `get`, `list`, `watch`, `create`, `update`, `patch`
- `events`: `create`
- `authorization.k8s.io`:
- `localsubjectaccessreviews`: `create`
- `rbac.authorization.k8s.io`:
- `roles`: `get`, `list`, `watch`, `create`, `update`, `patch`
- `rolebindings`: `get`, `list`, `watch`, `create`, `update`, `patch`
После применения этого манифеста было подтверждено:
- `kubectl auth can-i create events --as=system:serviceaccount:fission:fission-executor` -> `yes`
- `kubectl auth can-i create localsubjectaccessreviews.authorization.k8s.io --as=system:serviceaccount:fission:fission-executor` -> `yes`
И в новом test namespace автоматически появлялись:
- `ServiceAccount/fission-fetcher`
- `Role/fission-fetcher-role-*`
- `RoleBinding/fission-fetcher-rolebinding-*`
## Изменение симптома после executor-fix
После полного executor RBAC fix шаг 5 перестал падать с `500` timeout от executor.
Новый симптом:
- постоянный `HTTP 404`
- router не видел route/function в новом namespace
Это был важный индикатор того, что executor-path уже работает лучше, а оставшаяся проблема находится в router-path.
## Диагностика 3: router NSWatcher не мог watch/list namespaces
Лог router показал прямую ошибку:
```text
failed to list *v1.Namespace: namespaces is forbidden:
User "system:serviceaccount:fission:fission-router" cannot list resource
"namespaces" at the cluster scope
```
При этом код router уже содержал dynamic namespace watcher:
- `pkg/router/ns_watcher.go`
То есть логика была, но RBAC для `fission-router` отсутствовал.
### Реальный root cause на этом этапе
`fission-router` не имел cluster-scope прав:
- `namespaces:list`
- `namespaces:watch`
Из-за этого:
- router не подхватывал новые labeled namespaces
- `HTTPTriggerSet.AddNamespace(...)` не вызывался
- HTTP trigger не попадал в router runtime map
- вызов функции возвращал `404`
## Исправление 2: router RBAC для NSWatcher
В тот же `deploy/multitenant/rbac.yaml` добавлены:
- `ClusterRole/fission-router-ns-watcher`
- `ClusterRoleBinding/fission-router-ns-watcher`
С правами:
- core `namespaces`: `list`, `watch`
После применения подтверждено:
- `kubectl auth can-i list namespaces --as=system:serviceaccount:fission:fission-router` -> `yes`
- `kubectl auth can-i watch namespaces --as=system:serviceaccount:fission:fission-router` -> `yes`
## Финальная проверка
После обоих RBAC fixes повторный запуск `test_layer1.sh` дал:
```text
ИТОГ: PASS=5 FAIL=0
```
На шаге 5 функция успешно ответила:
```text
HTTP 200 - hello from layer1
```
## Что именно оказалось правдой по итогу
Итоговая проблема состояла из двух последовательных RBAC-дырок:
1. executor не мог полностью provision-ить `fission-fetcher` в динамическом namespace
2. router не мог подхватить новый namespace из-за отсутствия namespace watch/list
То есть код hot-registration в целом был правильный, но runtime contract в Kubernetes RBAC был реализован не полностью.
## Итоговые изменения
### Код и манифесты
- `deploy/multitenant/rbac.yaml`
- executor namespace watch
- executor SA provisioning RBAC
- router namespace watch RBAC
### Документация
- `doc/progress.md`
- `doc/thinking/2026-04-26-rbac-fix.md`
- `doc/thinking/2026-04-26-layer1-pass-detailed.md`
### Коммиты по ходу исправления
- `161de70` - `multi-tenant: EnsureNamespaceSA + ns_watcher SA provisioning (v8)`
- `8ccc9fb` - первый RBAC commit
- `f617913` - полный executor RBAC fix для fetcher role provisioning
- `7faaa9d` - router namespace watch RBAC
## Практический вывод
Для hot namespace onboarding в Fission недостаточно просто добавить informer-ы в коде.
Нужно обеспечить весь runtime contract:
- executor видит namespace
- executor может provision-ить service accounts и RBAC в tenant namespace
- executor может делегировать все требуемые permission-ы
- router видит namespace и подписывается на triggers/functions в нём
Если хотя бы одно из этих звеньев отсутствует, поведение выглядит как "код вроде есть, но dynamic namespace не работает".