fix: semaphore+singleflight for ensureUserNS, fix 504 on 10 parallel new users (v0.8.12)
This commit is contained in:
@@ -0,0 +1,81 @@
|
||||
# Мнения AI-моделей об архитектуре Fission Console — 2026-04-25
|
||||
|
||||
> ⚠️ Всё ниже — МНЕНИЯ (не факты). Проверять и применять критически.
|
||||
|
||||
---
|
||||
|
||||
## GEMINI — мнение (пересказ, апрель 2026)
|
||||
|
||||
**Контекст вопроса**: "написан сервис на основе Fission, многопользовательский, с Terraform"
|
||||
|
||||
**Что сказал:**
|
||||
|
||||
1. **Изоляция**: namespace-per-user — самый надёжный путь. Terraform при создании аккаунта создаёт Namespace + ResourceQuota + NetworkPolicy.
|
||||
|
||||
2. **Fission в multi-tenancy**: можно один инстанс Fission на весь кластер, но нужно патчить Router чтобы он понимал принадлежность Environment. Либо (сложнее) — отдельный инстанс Fission/пул экзекуторов на каждый namespace.
|
||||
|
||||
3. **Terraform как Control Plane**: кастомный провайдер должен управлять полным lifecycle — регистрация пользователя в БД, создание K8s ресурсов, создание Fission ресурсов. State изолирован между пользователями.
|
||||
|
||||
4. **poolmgr vs newdeploy**: poolmgr хорош для 100ms cold start, но при 1000 пользователей — RAM кончается (не масштабируется). Рекомендует NewDeploy + HPA для multi-tenant scale.
|
||||
|
||||
5. **Безопасность выполнения**: gVisor/Kata Containers (RuntimeClass=runsc). Для публичного облака — обязательно.
|
||||
|
||||
6. **Схема**: user → .tf файл → Terraform Worker → K8s Namespace+лимиты → Fission деплоит пакет → Router → внешний трафик в нужный Namespace.
|
||||
|
||||
**Оценка контекста**: Gemini отвечал на абстрактный вопрос "как строить managed serverless". Не знал деталей нашей реализации. Часть советов — для масштаба 1000+ пользователей.
|
||||
|
||||
---
|
||||
|
||||
## GPT-4.5 — мнение (апрель 2026)
|
||||
|
||||
**Контекст вопроса**: тот же — многопользовательский managed serverless на Fission
|
||||
|
||||
**Что сказал:**
|
||||
|
||||
*(Полный текст ответа не сохранён — пользователь описал его как "насочинял", детали были в чате)*
|
||||
|
||||
> ⚠️ Полный текст GPT-4.5 не задокументирован. Пользователь охарактеризовал ответ скептически ("насочинял"). Считать неверифицированным.
|
||||
|
||||
---
|
||||
|
||||
## Claude Sonnet 4.6 (я) — мнение (апрель 2026)
|
||||
|
||||
**Контекст**: знаю реальную реализацию (читал main.go, deploy/, repo memory)
|
||||
|
||||
**Для масштаба ~20 одновременных пользователей:**
|
||||
|
||||
**Что реально надо доделать:**
|
||||
|
||||
1. **ResourceQuota + LimitRange** на каждый user namespace — одна функция сейчас может сожрать все ресурсы кластера. Базовая безопасность, не опционально.
|
||||
|
||||
2. **NetworkPolicy** — без этого функции разных пользователей видят друг друга внутри кластера.
|
||||
|
||||
3. **`fission_simple_function` Terraform ресурс** — сейчас провайдер low-level: нужно вручную создавать Environment + Package + Function + HTTPTrigger. Нужен один высокоуровневый ресурс.
|
||||
|
||||
4. **Поверхность ошибок в UI** — при провале specialization пользователь видит "вероятно не удалось". Надо тянуть реальную причину (статус package, логи executor).
|
||||
|
||||
**Что НЕ нужно для 20 юзеров:**
|
||||
- gVisor — лишняя сложность для контролируемой среды
|
||||
- newdeploy вместо poolmgr — poolmgr нормально работает, достаточно подстроить poolsize
|
||||
- Отдельный billing service — достаточно логировать invoke в postgres
|
||||
|
||||
**Главный тезис**: Gemini описал правильную архитектуру для SaaS на 10k пользователей. Для 20 — текущая архитектура достаточна. Нужна доводка, не redesign.
|
||||
|
||||
---
|
||||
|
||||
## Текущее состояние реализации (факты, не мнение)
|
||||
|
||||
- namespace-per-user ✅
|
||||
- auth token → user namespace ✅
|
||||
- lazy environments per language ✅
|
||||
- RBAC для системных и локальных SA (fission-fetcher, fission-builder) ✅
|
||||
- TTL cleanup + reaper ✅
|
||||
- NSReconciler для FISSION_RESOURCE_NAMESPACES ✅
|
||||
- Route prefix per user ✅
|
||||
- Terraform provider (low-level CRD) ✅
|
||||
- ResourceQuota / LimitRange per namespace ❌ нет
|
||||
- NetworkPolicy per namespace ❌ нет
|
||||
- fission_simple_function Terraform ресурс ❌ не реализован
|
||||
- Нормальная поверхность ошибок в UI ❌ частично
|
||||
- gVisor/Kata ❌ нет (осознанное решение)
|
||||
- Billing/metering ❌ нет
|
||||
@@ -0,0 +1,271 @@
|
||||
# План доработки Fission Console — 2026-04-25
|
||||
|
||||
> Для нового чата. Масштаб: ~20 одновременных пользователей.
|
||||
> Текущая версия: `naeel/fission-console:v0.8.8`
|
||||
> Ветка: `feat/namespace-isolation`
|
||||
|
||||
---
|
||||
|
||||
## Контекст (кратко)
|
||||
|
||||
- Go-бэкенд `console/main.go` + embedded UI `console/ui/index.html`
|
||||
- Каждый пользователь → отдельный K8s namespace `fission-<hash(sub)>`
|
||||
- Fission core один на кластер, namespace регистрируется через NSReconciler
|
||||
- Terraform provider: низкоуровневый (Environment + Package + Function + HTTPTrigger)
|
||||
- API: `https://fission.kube5s.ru/console/api`, тест: `X-Test-Sub: livetest@test.local`
|
||||
- SSH: `ssh -i ~/.ssh/naeel_vm_id_ed25519 naeel@5.172.178.213`
|
||||
- sshfs: `/home/naeel/remote_dev/fission/` = `~/terra/fission/` на VM
|
||||
|
||||
---
|
||||
|
||||
## Задача 1: ResourceQuota + LimitRange на user namespace (ПРИОРИТЕТ 1)
|
||||
|
||||
**Зачем**: без квот одна функция может съесть весь CPU/RAM кластера.
|
||||
|
||||
**Где делать**: `console/main.go`, функция `ensureUserNamespace`.
|
||||
|
||||
**Что добавить**: при создании namespace применять два объекта:
|
||||
|
||||
```yaml
|
||||
# ResourceQuota
|
||||
apiVersion: v1
|
||||
kind: ResourceQuota
|
||||
metadata:
|
||||
name: user-quota
|
||||
namespace: fission-<hash>
|
||||
spec:
|
||||
hard:
|
||||
requests.cpu: "2"
|
||||
requests.memory: "2Gi"
|
||||
limits.cpu: "4"
|
||||
limits.memory: "4Gi"
|
||||
pods: "20"
|
||||
count/functions.fission.io: "20"
|
||||
count/packages.fission.io: "40"
|
||||
```
|
||||
|
||||
```yaml
|
||||
# LimitRange
|
||||
apiVersion: v1
|
||||
kind: LimitRange
|
||||
metadata:
|
||||
name: user-limits
|
||||
namespace: fission-<hash>
|
||||
spec:
|
||||
limits:
|
||||
- type: Container
|
||||
default:
|
||||
cpu: "500m"
|
||||
memory: "256Mi"
|
||||
defaultRequest:
|
||||
cpu: "100m"
|
||||
memory: "64Mi"
|
||||
max:
|
||||
cpu: "2"
|
||||
memory: "1Gi"
|
||||
```
|
||||
|
||||
**Детали реализации**:
|
||||
- Применять через `k8s dynamic client` или `core client` (уже есть в main.go)
|
||||
- Idempotent: если уже есть — не ошибаться, просто пропустить (patch или get+create)
|
||||
- Значения вынести в константы (или env vars) для удобной настройки
|
||||
|
||||
**Файлы**: `console/main.go`
|
||||
|
||||
**Тест**: создать нового пользователя, проверить `kubectl get resourcequota,limitrange -n fission-<hash>`
|
||||
|
||||
---
|
||||
|
||||
## Задача 2: NetworkPolicy на user namespace (ПРИОРИТЕТ 2)
|
||||
|
||||
**Зачем**: без NetworkPolicy функции разных юзеров могут напрямую обращаться друг к другу по cluster IP.
|
||||
|
||||
**Где делать**: `console/main.go`, функция `ensureUserNamespace` (вместе с задачей 1).
|
||||
|
||||
**Что создать**: два правила:
|
||||
|
||||
```yaml
|
||||
# Deny all ingress from other namespaces (кроме fission core)
|
||||
apiVersion: networking.k8s.io/v1
|
||||
kind: NetworkPolicy
|
||||
metadata:
|
||||
name: deny-cross-tenant
|
||||
namespace: fission-<hash>
|
||||
spec:
|
||||
podSelector: {}
|
||||
policyTypes:
|
||||
- Ingress
|
||||
ingress:
|
||||
- from:
|
||||
- namespaceSelector:
|
||||
matchLabels:
|
||||
kubernetes.io/metadata.name: fission # fission core может
|
||||
- podSelector: {} # внутри namespace — OK
|
||||
```
|
||||
|
||||
**Осторожно**: проверить что fission router/executor/fetcher namespace правильно лейблован. Если нет — добавить лейбл на namespace `fission` через kubectl.
|
||||
|
||||
**Тест**: поднять функцию в namespace A, попробовать curl из пода namespace B — должен fail.
|
||||
|
||||
---
|
||||
|
||||
## Задача 3: fission_simple_function Terraform ресурс (ПРИОРИТЕТ 3)
|
||||
|
||||
**Зачем**: сейчас юзер пишет 4 ресурса вместо одного. Это неудобно и error-prone.
|
||||
|
||||
**Ветка**: `feat/simple-function-resource` (создана, код не написан)
|
||||
|
||||
**Файл**: `terraform/provider/internal/resources/simple_function_resource.go`
|
||||
|
||||
**Целевой синтаксис для пользователя:**
|
||||
```hcl
|
||||
resource "fission_simple_function" "health" {
|
||||
name = "health"
|
||||
runtime = "nodejs"
|
||||
code_dir = "./code/health"
|
||||
url = "/ecom/health"
|
||||
methods = ["GET"]
|
||||
}
|
||||
```
|
||||
|
||||
**Что провайдер делает внутри:**
|
||||
1. Ищет существующий `fission_environment` для runtime → переиспользует или создаёт
|
||||
2. Zip-архивирует `code_dir` → создаёт `fission_package` (с ESM wrap для nodejs)
|
||||
3. Создаёт `fission_function`
|
||||
4. Создаёт `fission_http_trigger` (если указан `url`)
|
||||
|
||||
**Атрибуты ресурса:**
|
||||
```
|
||||
name string — имя функции
|
||||
runtime string — nodejs / python / go / ruby / perl / php
|
||||
code_dir string — путь к директории с кодом
|
||||
url string — HTTP route (опционально)
|
||||
methods []string — ["GET","POST"] (опционально, default GET)
|
||||
entrypoint string — имя точки входа (опционально, default "Handler")
|
||||
min_scale int — минимальный масштаб (опционально, default 0)
|
||||
max_scale int — максимальный масштаб (опционально, default 1)
|
||||
ttl int — TTL в секундах (опционально)
|
||||
```
|
||||
|
||||
**Computed атрибуты:**
|
||||
```
|
||||
invoke_url string — полный URL для вызова
|
||||
status string — статус package (building / succeeded / failed)
|
||||
```
|
||||
|
||||
**Особенности реализации:**
|
||||
- nodejs: ESM wrapper (`export default { Handler }`) — проверить формат как в Console
|
||||
- Go: нужен archive package (zip), не literal. BuildStatus polling.
|
||||
- Идемпотентность: Read → если уже есть все 3 ресурса, не пересоздавать
|
||||
- Delete: удалить trigger + function + package. Environment — только если unused.
|
||||
|
||||
**Регистрация**: добавить в `terraform/provider/internal/provider/provider.go` в `Resources()`
|
||||
|
||||
**Примеры**: обновить `examples/big-suite/` после реализации
|
||||
|
||||
**Тест**: `terraform apply` → `terraform plan` должен показать "no changes"
|
||||
|
||||
---
|
||||
|
||||
## Задача 4: Улучшение поверхности ошибок (ПРИОРИТЕТ 4)
|
||||
|
||||
**Зачем**: сейчас при провале specialization пользователь видит "timeout after 20s: function specialization likely failed" — не информативно.
|
||||
|
||||
**Что делать:**
|
||||
|
||||
### 4.1 Package build status в API response
|
||||
|
||||
При создании функции и при GET `/console/api/functions/:name` — тянуть и возвращать:
|
||||
```json
|
||||
{
|
||||
"name": "myfunc",
|
||||
"status": "building", // или "ready" / "failed"
|
||||
"buildError": "compilation failed: undefined reference to..."
|
||||
}
|
||||
```
|
||||
|
||||
`buildError` брать из `package.status.info` (Fission заполняет это поле).
|
||||
|
||||
### 4.2 Specialization error в invoke response
|
||||
|
||||
Сейчас invoke возвращает timeout. Надо после timeout:
|
||||
1. Проверить статус package → если `failed`, вернуть buildError
|
||||
2. Проверить поды namespace → если CrashLoopBackOff, вернуть причину
|
||||
3. Иначе — вернуть "specialization timeout, function pod not ready"
|
||||
|
||||
### 4.3 UI polling для build status
|
||||
|
||||
После создания Go-функции (или любой с builder) — polling `/console/api/functions/:name` каждые 3s, показывать статус:
|
||||
- "Сборка..." → "Готово" / "Ошибка сборки: <text>"
|
||||
|
||||
**Файлы**: `console/main.go` (API), `console/ui/index.html` (UI polling)
|
||||
|
||||
---
|
||||
|
||||
## Задача 5: Cleanup и housekeeping (ПРИОРИТЕТ 5)
|
||||
|
||||
**Что сделать:**
|
||||
|
||||
### 5.1 Reaper для пустых namespace
|
||||
Если namespace не имеет ни одной функции и не обращался больше N дней → удалить namespace + все ресурсы.
|
||||
Параметр: `NAMESPACE_TTL_DAYS` (env var, default 30).
|
||||
|
||||
### 5.2 Orphan package cleanup
|
||||
При удалении функции — проверить все packages namespace, удалить те, на которые нет ни одной функции.
|
||||
Сейчас `cleanupEnvironmentIfUnused` есть, нужен аналог для packages.
|
||||
|
||||
### 5.3 Soft limit на функции на пользователя
|
||||
`MAX_FUNCTIONS_PER_USER` (env var). При превышении → HTTP 429 с сообщением.
|
||||
Защита от случайного создания 1000 функций в loop.
|
||||
|
||||
---
|
||||
|
||||
## Порядок выполнения (рекомендованный)
|
||||
|
||||
```
|
||||
1. Задача 1 (ResourceQuota + LimitRange) — ~2-3 часа, высокий риск если не сделать
|
||||
2. Задача 2 (NetworkPolicy) — ~1-2 часа, вместе с задачей 1
|
||||
3. Задача 3 (fission_simple_function) — ~1-2 дня, основная фича
|
||||
4. Задача 4 (ошибки) — ~4-6 часов, UX improvement
|
||||
5. Задача 5 (cleanup) — ~3-4 часа, housekeeping
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Команды для нового чата
|
||||
|
||||
```bash
|
||||
# Текущий образ
|
||||
naeel/fission-console:v0.8.8
|
||||
|
||||
# Сборка нового образа (ОБЯЗАТЕЛЬНО сначала поменять тег в deploy/console.yaml!)
|
||||
ssh -i ~/.ssh/naeel_vm_id_ed25519 naeel@5.172.178.213 \
|
||||
'cd ~/terra/fission && docker build -t naeel/fission-console:v0.8.9 -f console/Dockerfile console/ && docker push naeel/fission-console:v0.8.9'
|
||||
|
||||
# Deploy
|
||||
ssh -i ~/.ssh/naeel_vm_id_ed25519 naeel@5.172.178.213 \
|
||||
'kubectl set image deployment/fission-console fission-console=naeel/fission-console:v0.8.9 -n fission'
|
||||
|
||||
# Тест после деплоя
|
||||
ssh -i ~/.ssh/naeel_vm_id_ed25519 naeel@5.172.178.213 \
|
||||
'bash ~/terra/fission/tests_v2.sh 2>&1 | tail -5'
|
||||
|
||||
# Проверка quota (после задачи 1)
|
||||
ssh -i ~/.ssh/naeel_vm_id_ed25519 naeel@5.172.178.213 \
|
||||
'kubectl get resourcequota,limitrange -n fission-c3fce59430e41b0f'
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Файлы проекта (ключевые)
|
||||
|
||||
| Файл | Назначение |
|
||||
|------|-----------|
|
||||
| `console/main.go` | Основная логика бэкенда |
|
||||
| `console/ui/index.html` | Embedded UI |
|
||||
| `console/deploy/console.yaml` | K8s deployment (тег образа) |
|
||||
| `console/deploy/rbac/console-ns-manager.yaml` | RBAC для fission-console SA |
|
||||
| `terraform/provider/internal/resources/` | Terraform ресурсы |
|
||||
| `terraform/provider/internal/provider/provider.go` | Регистрация ресурсов |
|
||||
| `tests_v2.sh` | Регресс-тесты (73 блока, все PASS) |
|
||||
| `doc/thinking/2026-04-25-ai-opinions.md` | Мнения AI моделей |
|
||||
Reference in New Issue
Block a user