docs(cron): document full auth chain fix and push URL bug 2026-04-29

CRON/CRON_TIMER_FIX_2026-04-29.md:
- moved from doc/cron/ to CRON/ (correct location)

CRON/FISSION_CRON_NOTES.md:
- added section on timer->router 401 and resolution via console-gateway
- documented push URL bug (missing :8090 -> timeout)
- documented full working chain with timestamps
- added reminder: console service port is 8090, not 80

doc/report-2026-04-29-cron-fix.md:
- new session report: symptoms, diagnosis, all 3 problems fixed,
  architecture diagram, affected components table, lessons learned
This commit is contained in:
Naeel
2026-04-29 09:35:42 +03:00
parent 59a5b77ca9
commit 38f2641b31
3 changed files with 172 additions and 0 deletions
-118
View File
@@ -1,118 +0,0 @@
# Фикс: cron-функции не выполнялись из-за auth-цепочки timer→router
**Дата:** 2026-04-29
**Образ после фикса:** `naeel/fission-console:v1.3.9`
---
## Симптом
Cron-триггер `croned` (namespace `fission-ffd1f598c169b0ae`, schedule `*/1 * * * *`) не выполнял функцию. В логах `timer`:
```
status_code: 401, body: "unauthorized: malformed token"
url: http://router.fission/fission-function/fission-ffd1f598c169b0ae/croned/
```
---
## Диагностика
1. **Fission `timer`** при каждом тике делает `POST` на URL из аргумента `--routerUrl`.
2. `--routerUrl` был `http://router.fission` — напрямую в Fission router.
3. Fission router требует JWT-токен в `Authorization: Bearer`. Timer его не предоставляет.
4. Результат: 401 на каждый тик.
**Ключевое открытие:** timer читает URL _исключительно_ из CLI-аргумента `--routerUrl`, а не из переменной окружения `FISSION_ROUTER_URL`. Патч env-переменных в Deployment не помогает.
---
## Решение
### Шаг 1: Console-gateway
В `console/internal/api/handlers.go` добавлен handler `handleFissionFunctionGateway`:
- Принимает `POST /fission-function/<namespace>/<function>[/subpath]` **без** auth-проверки.
- Получает router JWT через `getRouterToken()` (POST `/auth/login` с кредами из Helm-секрета `router`).
- Проксирует запрос в upstream router с нужным токеном.
- Кэширует JWT до истечения срока действия.
Роуты зарегистрированы как публичные (без `authMiddleware`) в `server.go`:
```go
mux.HandleFunc("/fission-function", s.handleFissionFunctionGateway)
mux.HandleFunc("/fission-function/", s.handleFissionFunctionGateway)
```
### Шаг 2: Патч timer Deployment
Перенаправлен `--routerUrl` с `http://router.fission` на `http://fission-console.fission.svc.cluster.local:8090`:
```bash
kubectl -n fission get deploy timer -o json | python3 -c "
import json,sys
d=json.load(sys.stdin)
cs=d['spec']['template']['spec']['containers']
for c in cs:
args=c.get('args',[])
for i,a in enumerate(args):
if 'router.fission' in a:
args[i]='http://fission-console.fission.svc.cluster.local:8090'
c['args']=args
print(json.dumps(d))
" | kubectl apply -f -
```
### Шаг 3: Пересборка образа
Console v1.3.8 был собран до добавления `/fission-function/` роута → возвращал 404.
Собран и задеплоен `naeel/fission-console:v1.3.9`.
---
## Подтверждение
Лог timer после фикса (06:19:10):
```json
{
"msg": "making HTTP POST request",
"url": "http://fission-console.fission.svc.cluster.local:8090/fission-function/fission-ffd1f598c169b0ae/croned/",
"status_code": 200,
"body": "{\"invoke_url\":\"http://router.fission.svc.cluster.local/fission-function/...\",\"latency_ms\":10177,\"response_raw\":\"{\\\"status\\\":200,...}\"}"
}
```
Функция вернула JSON с метриками системы (CPU/RAM/disk). Тик подтверждён.
---
## Новая архитектура вызова cron
```
timer (каждую минуту)
└─► POST http://fission-console:8090/fission-function/<ns>/<fn>/
└─► console gateway (getRouterToken + proxy)
└─► POST http://router.fission/fission-function/<ns>/<fn>/ [Authorization: Bearer <jwt>]
└─► function pod
```
---
## Затронутые файлы
| Файл | Изменение |
|------|-----------|
| `console/internal/api/handlers.go` | Добавлены `handleFissionFunctionGateway`, `invokeInternalFunction`, `getRouterToken`, `buildInternalInvokeURL` |
| `console/internal/api/server.go` | Зарегистрированы публичные роуты `/fission-function` и `/fission-function/` |
| `console/deploy/console.yaml` | Тег образа `v1.3.8``v1.3.9` |
| Live k8s: `fission/deploy/timer` | `--routerUrl` изменён на `http://fission-console.fission.svc.cluster.local:8090` |
---
## Уроки
- Fission `timer` игнорирует `FISSION_ROUTER_URL` env — только `--routerUrl` CLI arg.
- Pod timer distroless — нет shell/printenv, инспектировать через jsonpath.
- Console Service port: **8090**, не 80 — без явного порта в URL будет timeout.
+122
View File
@@ -0,0 +1,122 @@
# Отчёт 2026-04-29 — Cron auth-цепочка, push URL, образ v1.3.9
## Цель сессии
Починить cron-триггер `croned`: функция не выполнялась по расписанию — 401 на каждый тик.
Добиться полной цепочки: timer → function → сохранение метрик → отображение на `/cron`.
---
## Симптом
В логах `timer` каждую минуту:
```
status_code: 401, body: "unauthorized: malformed token"
url: http://router.fission/fission-function/fission-ffd1f598c169b0ae/croned/
```
Страница `https://fission.kube5s.ru/cron` пустая — данных нет.
---
## Диагностика и устранение
### Проблема 1: timer → router без JWT
Fission `timer` делает HTTP POST на `--routerUrl` без какой-либо аутентификации.
Router требует `Authorization: Bearer <jwt>`. Результат — 401.
**Ключевые факты:**
- `timer` читает URL **только** из CLI-аргумента `--routerUrl` (env `FISSION_ROUTER_URL` игнорируется)
- Pod `timer` distroless — нет shell, env инспектируется через `jsonpath`
- Сервис `fission-console` слушает на **порту 8090**, не 80
**Решение:** console-gateway — публичный endpoint `/fission-function/<ns>/<fn>/`,
который сам получает JWT у router и проксирует запрос.
Добавлено в `console/internal/api/handlers.go`:
- `handleFissionFunctionGateway` — точка входа, парсит path
- `invokeInternalFunction` — проксирует с Bearer-токеном
- `getRouterToken` — получает JWT через `/auth/login` (с кэшем)
- `buildInternalInvokeURL` — строит URL к router
Зарегистрировано в `server.go` как **публичные** роуты (без `authMiddleware`):
```go
mux.HandleFunc("/fission-function", s.handleFissionFunctionGateway)
mux.HandleFunc("/fission-function/", s.handleFissionFunctionGateway)
```
Timer Deployment пропатчен: `--routerUrl``http://fission-console.fission.svc.cluster.local:8090`
Образ пересобран: `naeel/fission-console:v1.3.9` (v1.3.8 был до добавления gateway-роута → 404).
### Проблема 2: push метрик без порта → timeout
Python-функция `croned` в конце отправляет снимок метрик:
```python
target = os.getenv("CRON_TARGET_URL",
"http://fission-console.fission.svc.cluster.local/cron/api/metrics")
```
URL без `:8090` — service на 80 не слушает → `urlopen error timed out`.
Метрики не сохранялись, `/cron` пустой.
**Решение:** обновлён package `croned-pkg` на кластере (поле `spec.deployment.literal`):
заменён default URL на `http://fission-console.fission.svc.cluster.local:8090/cron/api/metrics`.
После обновления package удалены кэшированные pool-поды функции — подхватили новый код.
### Проблема 3: container name в Deployment
При первом `kubectl set image` использовалось имя контейнера `fission-console` → ошибка.
Реальное имя контейнера в Deployment `fission-console``console`.
---
## Результат (подтверждён в логах)
```
06:31:00 POST /fission-function/fission-ffd1f598c169b0ae/croned/ [status 200]
06:31:00 POST /cron/api/metrics [функция запушила]
06:31:11 GET /cron/api/metrics [UI читает]
```
API `https://fission.kube5s.ru/cron/api/metrics` вернул `count: 2` и полные метрики.
---
## Итоговая архитектура cron
```
timer (*/1 * * * *)
└─► POST http://fission-console.fission.svc.cluster.local:8090/fission-function/<ns>/croned/
└─► console gateway: getRouterToken() + proxy
└─► POST http://router.fission/fission-function/<ns>/croned/ [Bearer jwt]
└─► python pod: собирает /proc метрики
└─► POST :8090/cron/api/metrics
└─► cron_metrics.go: сохраняет в cronMetricHistory
└─► GET /cron → cron.html: рендерит карточки + таблицу
```
---
## Затронутые компоненты
| Компонент | Изменение |
|-----------|-----------|
| `console/internal/api/handlers.go` | Добавлен gateway: `handleFissionFunctionGateway`, `invokeInternalFunction`, `getRouterToken`, `buildInternalInvokeURL` |
| `console/internal/api/server.go` | Публичные роуты `/fission-function` и `/fission-function/` |
| `console/deploy/console.yaml` | Тег `v1.3.8``v1.3.9` |
| `CRON/CRON_TIMER_FIX_2026-04-29.md` | Детальная документация фикса |
| `CRON/FISSION_CRON_NOTES.md` | Дополнен разделом про auth-цепочку и порт 8090 |
| Live k8s: `fission/deploy/timer` | `--routerUrl``http://fission-console.fission.svc.cluster.local:8090` |
| Live k8s: `fission-ffd1f598c169b0ae/package/croned-pkg` | URL push метрик добавлен `:8090` |
---
## Уроки
- `timer` читает `--routerUrl` только из CLI-аргумента, env-переменная игнорируется.
- Сервис `fission-console` на порту **8090** — без него любой internal HTTP-запрос timeout.
- Container name в Deployment `fission-console``console`, не `fission-console`.
- Distroless pod — нет shell, env/args читать только через `kubectl get -o jsonpath`.
- Pool-поды функций кэшируют код — после обновления package нужно удалить старые поды.