249 lines
10 KiB
Markdown
249 lines
10 KiB
Markdown
# 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 не работает".
|