feat(v0.1.58): ImageExists cache hit, timing analysis, in-cluster registry plan
This commit is contained in:
@@ -4,6 +4,68 @@
|
||||
|
||||
---
|
||||
|
||||
## 2026-03-22 — БАГ: CreateService/CreateFunction возвращает 409 при `terraform apply -replace` (ИСПРАВЛЕН)
|
||||
|
||||
### Симптом
|
||||
|
||||
```
|
||||
terraform apply -replace=sless_service.pg_info
|
||||
sless_service.pg_info: Destroying... [name=pg-info]
|
||||
sless_service.pg_info: Destruction complete
|
||||
sless_service.pg_info: Creating...
|
||||
Error: create service: status 409: {"error":"service already exists"}
|
||||
```
|
||||
|
||||
Все 22+ сервиса из `-replace` падают с 409 при пересоздании.
|
||||
|
||||
### Точная причина
|
||||
|
||||
**Цепочка событий** (воспроизводится только при наличии finalizer):
|
||||
|
||||
1. `terraform` вызывает `DELETE /services/pg-info`
|
||||
2. API делает `h.K8s.Delete(svc)` → k8s **НЕ удаляет объект** немедленно.
|
||||
Вместо этого — выставляет `DeletionTimestamp` на объекте и ждёт.
|
||||
3. `service_controller.go` (асинхронно!) обрабатывает удаление:
|
||||
- сносит Deployment, k8s Service, Ingress
|
||||
- затем вызывает `svc.Finalizers = removeString(svc.Finalizers, serviceFinalizerName)`
|
||||
- только после этого k8s реально удаляет CRD объект из etcd
|
||||
- **латентность: 1–5 секунд**
|
||||
4. `terraform` **немедленно** вызывает `POST /services/pg-info`
|
||||
5. API делает `h.K8s.Create(svc)` → etcd возвращает `IsAlreadyExists`
|
||||
6. Старый код проверял: `phase == Failed`? → нет, было `Ready` → `shouldRecreate=false` → **409**
|
||||
|
||||
**Ключевое: объект существует с `DeletionTimestamp != zero`, то есть он уже "мёртвый", но finalizer ещё не снят. Старый код этого не проверял.**
|
||||
|
||||
### Файл с багом
|
||||
|
||||
`internal/api/handler/services.go` → `CreateService()` — строка `shouldRecreate`
|
||||
`internal/api/handler/functions.go` → `CreateFunction()` — аналогичная логика
|
||||
|
||||
### Исправление
|
||||
|
||||
В обоих файлах добавлена проверка `!existing.DeletionTimestamp.IsZero()` **до** проверки `shouldRecreate`:
|
||||
|
||||
```go
|
||||
if getErr == nil && !existing.DeletionTimestamp.IsZero() {
|
||||
// Объект удаляется: polling каждую секунду до 30 сек
|
||||
for i := 0; i < 30; i++ {
|
||||
time.Sleep(1 * time.Second)
|
||||
if errors.IsNotFound(h.K8s.Get(...)) {
|
||||
// исчez — создаём
|
||||
}
|
||||
}
|
||||
// таймаут — возвращаем 409 с "try again later"
|
||||
}
|
||||
```
|
||||
|
||||
### Почему именно polling, а не Watch
|
||||
|
||||
`http.ResponseWriter` не поддерживает long-poll без дополнительного механизма.
|
||||
Watch на объект внутри HTTP handler — антипаттерн (использует goroutine leak при отмене).
|
||||
30 × 1s — достаточно для любого разумного кластера; terraform имеет свой retry.
|
||||
|
||||
---
|
||||
|
||||
## 2026-03-22 — ПОВЕДЕНИЕ: оператор выставляет Ready до готовности pod (known limitation)
|
||||
|
||||
### Симптом
|
||||
|
||||
+25
-1
@@ -1,6 +1,30 @@
|
||||
# Прогресс разработки
|
||||
|
||||
Последнее обновление: 2026-03-22
|
||||
Последнее обновление: 2026-03-23
|
||||
|
||||
---
|
||||
|
||||
## 2026-03-23 — Сессия 10: ImageExists + деплой v0.1.58
|
||||
|
||||
### Что сделано
|
||||
|
||||
- **ImageExists** — новый метод `Builder.ImageExists(ctx, imageRef) bool` в `internal/builder/builder.go`
|
||||
- Docker Registry v2 API: anonymous bearer token → HEAD `/v2/{repo}/manifests/{tag}`
|
||||
- timeout 5s, fallback false при любой ошибке (безопасный fallback → kaniko)
|
||||
- Приватные registry (Harbor и др.) → 401 → false → строим заново
|
||||
- **service_controller.go** `startServiceBuild()`: кеш-проверка перед Build(); cache hit → `Status.Phase=Ready` + `Status.ImageRef` без kaniko
|
||||
- **function_controller.go** `startBuild()`: аналогично
|
||||
- **functionjob_controller.go** `startJobBuild()`: аналогично; cache hit → Requeue для немедленного перехода к run
|
||||
- **v0.1.58** собран и задеплоен: `naeel/sless-operator:v0.1.58` Running, RESTARTS:0
|
||||
|
||||
### Статус
|
||||
✅ Код написан (no errors)
|
||||
✅ Docker build + push наDockerHub (sha256:7b0d48a01a29f2a5...)
|
||||
✅ kubectl rollout: `deployment "sless-operator" successfully rolled out`
|
||||
✅ Pod `sless-operator-85d4685c4b-6nxqw` Running v0.1.58
|
||||
|
||||
### Следующий шаг
|
||||
Протестировать cache hit: вернуть `.tf.disabled` → `.tf`, `terraform apply` — образы уже на DockerHub, должны восстановиться без kaniko за секунды.
|
||||
|
||||
---
|
||||
|
||||
|
||||
Reference in New Issue
Block a user