10 KiB
Ошибки и решения
Сюда записываем проблемы с которыми столкнулись и как их решили.
Шаблон записи
## YYYY-MM-DD — Короткое описание проблемы
**Проблема:** ...
**Причина:** ...
**Решение:** ...
2026-03-07 — kaniko: unsupported protocol scheme ""
Проблема: kaniko Job падает с unsupported protocol scheme "" при доступе к S3.
Причина: В env S3_ENDPOINT передавался хост без схемы (s3.msk-1.ngcloud.ru), kaniko ожидает полный URL.
Решение: В builder.go добавить "https://" + b.s3Endpoint при формировании env для kaniko. Также добавить S3_FORCE_PATH_STYLE=true — Ceph требует path-style URLs.
2026-03-07 — Бесконечный цикл сборки (94 job'а)
Проблема: После upload оператор создавал сотни kaniko Job'ов.
Причина: Upload handler вызывал Status().Update(phase=Pending) ПОСЛЕ того как контроллер уже выставил Building. Контроллер видел Pending → создавал новый Job, upload снова сбрасывал → цикл.
Решение:
startBuild()СНАЧАЛА ставит аннотациюlast-built-s3key = spec.S3Key(idempotency guard), затем обновляет статус.- Reconcile запускает сборку только если
spec.S3Key != annotations["last-built-s3key"]. - Upload handler убран
Status().Update()— контроллер сам управляет фазой. IsAlreadyExistsпри создании Job не считается ошибкой (parallel reconcile).
2026-03-07 — upload.go: "object has been modified; please apply your changes"
Проблема: terraform apply падал при попытке upload кода функции:
status 500: {"error":"update function: Operation cannot be fulfilled on functions.sless.kube5s.ru "pg-query": the object has been modified; please apply your changes to the latest version and try again"}
Причина: В upload.go использовался h.K8s.Update(ctx, fn). Между Get() и Update() контроллер успевал изменить объект (выставить статус/аннотации) — resourceVersion в памяти устаревал, API-сервер отклонял обновление.
Решение: Заменить Update на Patch (strategic merge patch):
patch := client.MergeFrom(fn.DeepCopy())
fn.Spec.S3Key = s3Key
fn.Spec.S3Bucket = h.S3.Bucket()
h.K8s.Patch(ctx, fn, patch)
MergePatch передаёт только изменённые поля и не требует точного resourceVersion.
2026-03-07 — Terraform Provider: "provider produced inconsistent result" для schedule
Проблема: При создании sless_trigger с type=http (без поля schedule) terraform падал:
.schedule: was null, but now cty.StringVal("")
Причина: В trToModel() провайдера Schedule всегда возвращался как types.StringValue(tr.Schedule). Если schedule не задан, API возвращает пустую строку "", провайдер сохранял "" в state. Terraform видел расхождение: в плане было null (поле не задано в HCL), в state после apply стало "".
Решение: В trToModel() возвращать types.StringNull() когда schedule пустая строка:
schedule := types.StringNull()
if tr.Schedule != "" {
schedule = types.StringValue(tr.Schedule)
}
Правило: для Optional computed-полей пустая строка из API → null в state.
2026-03-07 — Terraform Provider: "Resource Import Not Implemented"
Проблема: После failed terraform apply (Function создалась, Trigger упал) state не содержал созданных ресурсов. Повторный apply падал с status 409: function already exists. terraform import тоже не работал:
This resource does not support import. Please contact the provider developer
Причина: В провайдере не реализован ImportState для ресурса sless_function.
Решение (краткосрочное): Удалить ресурсы из кластера вручную (kubectl delete) и повторить apply с чистым state.
Решение (долгосрочное / TODO): Реализовать ImportState для sless_function и sless_trigger:
func (r *FunctionResource) ImportState(ctx context.Context, req resource.ImportStateRequest, resp *resource.ImportStateResponse) {
// ID формат: "namespace/name"
resource.ImportStatePassthroughID(ctx, path.Root("name"), req, resp)
}
2026-03-07 — handler.py: column "started_at" does not exist
Проблема: При вызове функции pg-query в логах пода:
psycopg2.errors.UndefinedColumn: column "started_at" does not exist
Причина: В examples/pg-query/handler.py использовалось имя колонки started_at, но в схеме migrations/001_initial.sql таблицы invocations колонка называется created_at.
Решение: Исправить select и dict() в handler.py: started_at → created_at.
Урок: При написании примеров всегда сверяться со схемой в migrations/.
2026-03-07 — Deployment не перезапустил pod после re-build образа
Проблема: После terraform apply (re-upload + kaniko пересборка) pod продолжал использовать старый код — curl возвращал ошибку started_at.
Причина: Образ тегируется как :latest. Kubernetes не перезапускает pod автоматически если тег не изменился — даже если образ на DockerHub обновился. imagePullPolicy по умолчанию IfNotPresent для non-digest образов, только Always гарантирует pull при каждом запуске.
Решение (краткосрочное): Явный kubectl rollout restart deployment/pg-query -n sless-fn-default.
Решение (долгосрочное / TODO): В function_controller.go после успешной сборки добавить rollout restart аннотацию:
// Форсируем rollout через аннотацию kubectl.kubernetes.io/restartedAt
deployment.Spec.Template.Annotations["kubectl.kubernetes.io/restartedAt"] = time.Now().Format(time.RFC3339)
Либо использовать версионированные теги образов вместо :latest (:v{timestamp}).
2026-03-07 — Docker credStore: exec "docker-credential-desktop.exe"
Проблема: docker push падал с exec: "docker-credential-desktop.exe": executable file not found.
Причина: В ~/.docker/config.json осталась запись "credsStore": "desktop.exe" от Docker Desktop.
Решение: Удалить поле credsStore из ~/.docker/config.json, оставить только auths с base64 credentials.
2026-03-07 — controller-gen v0.11.1 паникует с Go 1.23
Проблема: operator-sdk create api падает с panic в controller-gen при make generate.
Причина: controller-tools v0.11.1 несовместим с Go 1.23 (nil pointer dereference в go/types).
Решение: В Makefile заменить CONTROLLER_TOOLS_VERSION ?= v0.11.1 на v0.14.0.
2026-03-07 — Dockerfile: operator не находит migrations/ при старте
Проблема: Оператор в кластере сразу падает в CrashLoopBackOff:
level=ERROR msg="read migration file" err="open migrations/001_initial.sql: no such file or directory"
Причина: Оригинальный Dockerfile копировал только api/, controllers/, main.go. Директории internal/ и migrations/ в образ не попадали.
Решение: Добавить в оба stage Dockerfile:
COPY internal/ internal/ # в builder stage
COPY migrations/ migrations/ # и в builder, и в финальный alpine stage
migrations/ нужен в финальном образе — оператор читает SQL-файлы в runtime при каждом старте.
2026-03-07 — Dockerfile: golang:1.23 несовместим с go.mod (требует 1.25)
Проблема: docker build падает на go mod download:
go: go.mod requires go >= 1.25 (running go 1.23.12; GOTOOLCHAIN=local)
Причина: В go.mod указан go 1.25, Dockerfile использовал golang:1.23-alpine.
Решение: FROM golang:1.23-alpine → FROM golang:1.25-alpine.
2026-03-07 — go.mod: прямые зависимости помечены как indirect
Проблема: gopls показывал ошибки в go.mod:
github.com/gorilla/mux should be direct
github.com/lib/pq should be direct
github.com/minio/minio-go/v7 should be direct
k8s.io/api should be direct
Причина: Пакеты получили // indirect несмотря на прямые импорты — побочный эффект scaffold-генерации operator-sdk.
Решение: go mod tidy автоматически расставил правильные аннотации.