doc: add detailed layer1 multi-tenant fix report
This commit is contained in:
@@ -0,0 +1,248 @@
|
||||
# 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 не работает".
|
||||
Reference in New Issue
Block a user