From df540e6b81e9b243106239149701ff23b731a9a3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=80=9CNaeel=E2=80=9D?= Date: Sun, 8 Mar 2026 20:36:16 +0400 Subject: [PATCH] =?UTF-8?q?docs:=20=D0=BE=D0=B1=D0=BD=D0=BE=D0=B2=D0=BB?= =?UTF-8?q?=D0=B5=D0=BD=D0=B8=D0=B5=20doc/=20=D0=BF=D0=BE=20=D0=B8=D1=82?= =?UTF-8?q?=D0=BE=D0=B3=D0=B0=D0=BC=20=D1=81=D0=B5=D1=81=D1=81=D0=B8=D0=B8?= =?UTF-8?q?=202026-03-08?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- doc/decisions/log.md | 41 ++++++++++++++++ doc/errors/log.md | 110 +++++++++++++++++++++++++++++++++++++++++++ doc/progress.md | 2 +- 3 files changed, 152 insertions(+), 1 deletion(-) diff --git a/doc/decisions/log.md b/doc/decisions/log.md index 94186a6..534dd65 100644 --- a/doc/decisions/log.md +++ b/doc/decisions/log.md @@ -204,3 +204,44 @@ - operator: `naeel/sless-operator:v0.1.6` - provider: `terra.k8c.ru/naeel/sless v0.1.4` + +--- + +## 2026-03-08 — Переключение registry с Harbor на DockerHub + +**Проблема:** Harbor (`pearlharbor.registryk8s.services.ngcloud.ru`) — внешний сервис облачного провайдера. Нестабилен: `/v2/` периодически зависает на 10+ секунд или возвращает 504. Kaniko не мог завершить push образа. + +**Решение:** `REGISTRY_HOST=naeel` (DockerHub namespace). Образы функций пушатся как `naeel/sless-default-{namespace}-{name}:latest`. + +**Реализация:** +- `deployments/k8s/operator.yaml` — configmap `REGISTRY_HOST: "naeel"` +- Secret `sless-registry-auth` уже содержал DockerHub credentials → дополнительных изменений не потребовалось + +**Компромисс:** DockerHub — публичный registry. Образы функций пользователей публично видимы. Для production нужен приватный registry (Harbor, ECR, GCR и т.д.). + +**Версии:** +- operator: оператор не пересобирался, только configmap +- commit: `b69f795` + +--- + +## 2026-03-08 — FunctionJob polling вместо Owns watch + +**Проблема:** `Owns(&batchv1.Job{})` в `SetupWithManager` не работает cross-namespace. Job создаётся в `sless-fn-{ns}`, FunctionJob — в user namespace. Watch никогда не срабатывал. + +**Решение:** Убрать `Owns`. В `syncJobStatus` при Running статусе возвращать `ctrl.Result{RequeueAfter: 5 * time.Second}` — контроллер сам поллит k8s Job каждые 5 сек. + +**Версии:** +- operator: `naeel/sless-operator:v0.1.10` +- commit: `461ac09` + +--- + +## 2026-03-08 — code_hash: filesha256 вместо output_md5 + +**Проблема:** `hashicorp/archive v2.7.x` имеет баг: `output_md5` возвращает MD5 предыдущей версии zip. `output_sha` и `output_sha256` обновляются корректно. + +**Решение:** `code_hash = filesha256("${path.module}/code/handler.js")` — хэшируется исходный файл напрямую. + +**Правило проекта:** В `sless_function.code_hash` всегда использовать `filesha256(source_file)`, не `archive_file.output_md5`. + diff --git a/doc/errors/log.md b/doc/errors/log.md index 8ebf926..d11ec5b 100644 --- a/doc/errors/log.md +++ b/doc/errors/log.md @@ -131,6 +131,116 @@ deployment.Spec.Template.Annotations["kubectl.kubernetes.io/restartedAt"] = time --- +## 2026-03-08 — output_md5 archive провайдера не обновляется при изменении кода + +**Проблема:** `terraform plan` показывал "No changes" даже после изменения JS-файла функции. Функция отдавала старый код. + +**Причина:** `code_hash = data.archive_file.handler_http.output_md5` — атрибут `output_md5` в `hashicorp/archive v2.7.x` возвращает MD5 от **предыдущей** версии zip (баг порядка вычисления). `output_sha` и `output_sha256` от того же файла обновлялись корректно. + +**Решение:** Заменить `output_md5` на `filesha256("${path.module}/code/handler.js")` — хэшируется исходный файл напрямую, минуя archive провайдер. + +**Урок:** Не использовать `output_md5` из `archive_file`. Использовать `filesha256(source_file)`. + +--- + +## 2026-03-08 — FunctionJob зависал в Running навсегда + +**Проблема:** `terraform apply` висел на `sless_job.hello_run: Still creating...` бесконечно. k8s Job давно завершился (Complete), но FunctionJob оставался в `Running`. + +**Причина:** `SetupWithManager` использовал `Owns(&batchv1.Job{})` для watch событий Job. Но Job создавался в namespace `sless-fn-default`, а FunctionJob в `default` — cross-namespace OwnerReference не работают в k8s. Reconcile после завершения Job никогда не вызывался. + +**Решение:** Убрать `Owns(&batchv1.Job{})`. В `syncJobStatus` добавить `return ctrl.Result{RequeueAfter: 5 * time.Second}` когда Job ещё выполняется — polling каждые 5 сек. + +--- + +## 2026-03-08 — ImagePullBackOff: sless-registry-auth не копировался в sless-fn-* + +**Проблема:** Pod функции падал с `ImagePullBackOff` — не мог скачать образ из registry. + +**Причина:** `buildDeployment` в `function_controller.go` не устанавливал `imagePullSecrets` в PodSpec. Секрет `sless-registry-auth` существовал только в namespace `sless`, но не копировался в `sless-fn-default`. + +**Решение:** Добавить `ensureRegistrySecret()` — копирует секрет из `sless` в `sless-fn-*` при каждом reconcile. В `buildDeployment` добавить `ImagePullSecrets`. + +--- + +## 2026-03-08 — CrashLoopBackOff: Cannot find module handler.js + +**Проблема:** Pod функции падал: `Cannot find module '/app/function/handler.js'`. Entrypoint был `handler-http.handle` (файл `handler-http.js`), а server.js искал хардкоженный `handler.js`. + +**Причина:** `server.js` и `server.py` runtime-образов хардкодили имя модуля `handler`. Поле `SLESS_ENTRYPOINT` env var не использовалось. + +**Решение:** `server.js` и `server.py` переписаны: парсят `SLESS_ENTRYPOINT` (формат `"module.funcName"`), динамически загружают нужный модуль. Runtime пересобран как `v0.1.1`. + +--- + +## 2026-03-08 — Kaniko cache: пересобирал образ со старым server.js + +**Проблема:** После исправления `server.js` kaniko продолжал собирать образы с **старым** server.js из кэша. + +**Причина:** Base image тегирован как `:latest`. Kaniko кэшировал слои — `FROM naeel/sless-runtime-nodejs20:latest` не перечитывал обновлённый образ. + +**Решение:** Новый тег базового образа `v0.1.1`. В `upload.go` изменить `runtimeBaseImage("nodejs20")` → `naeel/sless-runtime-nodejs20:v0.1.1`. + +--- + +## 2026-03-08 — RBAC: secrets is forbidden: cannot list + +**Проблема:** Оператор падал: `secrets is forbidden: User "system:serviceaccount:sless:sless-operator" cannot list resource "secrets"`. + +**Причина:** В `rbac.yaml` для secrets были только `get;create`, нужны также `list;watch` для controller-runtime. + +**Решение:** Добавить `list;watch` в ClusterRole для `resources: ["secrets"]`. + +--- + +## 2026-03-08 — Harbor registry нестабилен (504 Gateway Timeout) + +**Проблема:** Kaniko падал: `GET https://pearlharbor.registryk8s.services.ngcloud.ru/v2/: unexpected status code 504 Gateway Timeout`. Периодически `/v2/` зависал на 10+ секунд или не отвечал вовсе. + +**Причина:** Harbor — внешний сервис облачного провайдера, нестабилен по независящим от нас причинам. Поведение не зависит от VPN. + +**Решение:** Переключить `REGISTRY_HOST` с Harbor на DockerHub (`naeel`). Образы функций теперь пушатся как `naeel/sless-default-{namespace}-{name}:latest`. + +--- + +## 2026-03-08 — Provider: inconsistent result — image_ref изменился после apply + +**Проблема:** После `terraform apply` ошибка: +``` +Provider produced inconsistent result after apply +.image_ref: was cty.StringVal("pearlharbor..."), but now cty.StringVal("naeel/...") +``` + +**Причина:** `image_ref` в схеме провайдера имел `UseStateForUnknown()`. При plan terraform брал значение из state (старый Harbor путь). После apply API возвращал новый DockerHub путь. Расхождение план vs результат. + +**Решение:** Убрать `UseStateForUnknown()` с `image_ref`. Теперь `image_ref` = `(known after apply)` при каждом apply — честно отражает что значение неизвестно до сборки. Провайдер `v0.1.5`. + +--- + +## 2026-03-08 — Provider: inconsistent result — phase Failed→Ready + +**Проблема:** +``` +Provider produced inconsistent result after apply +.phase: was cty.StringVal("Failed"), but now cty.StringVal("Ready") +``` + +**Причина:** При ошибке `WaitReady` (build failed) → `AddError` → `return`. `resp.State.Set` не вызывался → state не обновлялся → в state оставалось старое значение. Затем оператор замечал новый код, пересобирал → функция становилась Ready. Следующий `Read` возвращал `phase=Ready`, terraform видел расхождение. + +**Решение:** Убрать `UseStateForUnknown()` с `image_ref` (связанный фикс). Для `phase` — `UseStateForUnknown()` оставлен, т.к. при нормальном flow `Ready→Ready` предсказуем. + +--- + +## 2026-03-08 — Стейл-сервис hello-node блокировал proxy запросы + +**Проблема:** `GET /fn/default/hello-node` возвращал `operation not permitted` — `dial tcp 10.100.77.255:8080: connect: operation not permitted`. + +**Причина:** Сервис `hello-node` в `sless-fn-default` существовал 26h с ClusterIP `10.100.77.255` но без Deployment/Pod. iptables дропал пакеты на несуществующий endpoint. + +**Решение:** `kubectl delete svc hello-node -n sless-fn-default`. + +--- + ## 2026-03-07 — Docker credStore: exec "docker-credential-desktop.exe" **Проблема:** `docker push` падал с `exec: "docker-credential-desktop.exe": executable file not found`. diff --git a/doc/progress.md b/doc/progress.md index f80a9cc..716b58c 100644 --- a/doc/progress.md +++ b/doc/progress.md @@ -1,6 +1,6 @@ # Прогресс разработки -Последнее обновление: 2026-03-07 (operator v0.1.5, provider v0.1.3) +Последнее обновление: 2026-03-08 (operator v0.1.10, provider v0.1.5) ## Статусы: ✅ готово | 🔄 в процессе | ⏳ не начато