From b64887f301925adc79c40050a231e1b1ad3ada21 Mon Sep 17 00:00:00 2001 From: vitya Date: Mon, 24 Aug 2026 07:56:32 +0300 Subject: [PATCH] =?UTF-8?q?wiki:=20sched=20docker-runner=20=D1=83=D1=80?= =?UTF-8?q?=D0=BE=D0=BA=20=E2=80=94=20config.json=20naming,=20docker-?= =?UTF-8?q?=D1=84=D0=BE=D1=80=D0=BC=D0=B0=D1=82=20=D0=BE=D0=B1=D1=80=D0=B0?= =?UTF-8?q?=D0=B7=D0=BE=D0=B2=20=D0=B4=D0=BB=D1=8F=20registry=202.8.3,=20h?= =?UTF-8?q?ost-GC=20=D0=BD=D0=B5=D1=86=D0=B5=D0=BB=D0=B5=D1=81=D0=BE=D0=BE?= =?UTF-8?q?=D0=B1=D1=80=D0=B0=D0=B7=D0=B5=D0=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .wiki/concepts/books-vds-no-gitea-actions.md | 8 ++++++++ .wiki/concepts/registry-oci-image-index-gc.md | 15 +++++++++++++++ .wiki/index.md | 4 ++-- .wiki/log.md | 1 + 4 files changed, 26 insertions(+), 2 deletions(-) diff --git a/.wiki/concepts/books-vds-no-gitea-actions.md b/.wiki/concepts/books-vds-no-gitea-actions.md index 7b5a4a5..ed89abb 100644 --- a/.wiki/concepts/books-vds-no-gitea-actions.md +++ b/.wiki/concepts/books-vds-no-gitea-actions.md @@ -38,3 +38,11 @@ GET /api/endpoints/1/docker/images/json # образ уже на VD ``` Смоук/верификация: `DELETE /api/fbs/pickingLists/:id` → `{taskId}`, статус `GET /api/fbs/tasks/`, run в sched daemon: `docker exec books-sched node -e 'fetch("http://localhost:3031/api/runs?task=&limit=3",{headers:{"Authorization":"Bearer "}})...'` (**curl в контейнере нет**, node fetch есть; ключ — из env стека). Nuxt-прокси `/admin/scheduler/**` для внешних проверок бесполезен: гейтится `requireAdmin` (JWT isAdmin), `?token=` API-ключ → 403. + +## Sched docker-runner: pull auth + mediaType (2026-08-23, разбор `createPickingListPdf`) + +**docker CLI читает креды ТОЛЬКО из `${DOCKER_CONFIG}/config.json`.** Файл `docker-config.json` (как велели старые доки) → игнорируется → pull без auth → 401 «no basic auth credentials». Фикс: `mv /opt/books/sched/docker-config.json /opt/books/sched/config.json` (bookva volume уже был правильный). Рестарт daemon не нужен — файл читается при каждом pull. + +**Вторая засада — mediaType образа.** Теги, запушенные buildx (и моим curl-флоу из OCI-save) = **OCI image-index**. registry 2.8.3 отдаёт их ТОЛЬКО на Accept с `application/vnd.oci.image.index.v1+json`; docker daemon (26.1.4) получает «manifest unknown», если child-манифест отсутствует (а он отсутствует после прежних host-GC — см. [[registry-oci-image-index-gc]]). Диагностика: `curl` манифеста тега с docker-only Accept → 404, с OCI-index → 200; child по digest → 404. **Фикс: перепуш образа как docker schema2-манифест** (mediaType `application/vnd.docker.distribution.manifest.v2+json`, config `application/vnd.docker.container.image.v1+json`, layers `application/vnd.docker.image.rootfs.diff.tar.gzip`) — блобы те же (content-addressed), только обёртка; pull снова работает. Сборка: `docker save` → OCI → взять amd64 child → трансформ mediaTypes → PUT в тег с docker Content-Type. Важно: docker config-манифест пишется `container.image.v1+json`, НЕ `distribution.image.config.v2+json` (последний docker не знает → «(unknown)» при pull). + +**Третий слой — конфиг daemon.** `createPickingListPdf` рендерит print-роут: env берётся из tasks.json на VDS; плейсхолдер `API_TOKEN: ""` = production-конфиг daemon'а не задеплоен в монтированную диру (в репо tasks.json — `${config:api.authToken}`). Конфиг-дир `/opt/books/sched/` должен содержать production-overrides (api.authToken, puppeteer.browserWSEndpoint, s3). diff --git a/.wiki/concepts/registry-oci-image-index-gc.md b/.wiki/concepts/registry-oci-image-index-gc.md index e579a2d..73fa2d5 100644 --- a/.wiki/concepts/registry-oci-image-index-gc.md +++ b/.wiki/concepts/registry-oci-image-index-gc.md @@ -75,3 +75,18 @@ Sub-manifest (и его слои) физически удалены, а **тег - [`registry-kzntsv-auth-model`](registry-kzntsv-auth-model.md) — auth/htpasswd, юзер books-ci, GC через v2 DELETE. - [`bindmount-config-edit-preserve-mode`](bindmount-config-edit-preserve-mode.md) — как клали кред books-ci в task-runner config (shadow + mode гочи). - Хост: [`books-vds`](../entities/books-vds.md) (task-runner), реестр на [`vds-kzntsv`](../entities/vds-kzntsv.md). + +## Обновление 2026-08-23: 2.8.3 vs OCI-index — docker pull «manifest unknown» + фикс docker-форматом + +**Симптом:** `docker pull registry.kzntsv.site/books-tool-create-picking-list-pdf:master` → `manifest unknown` (и «no basic auth credentials» до починки config.json — см. [[books-vds-no-gitea-actions]]). + +**Диагностика (curl к /v2//manifests/):** +- Accept docker-only (`manifest.v2+json`, `manifest.list.v2+json`) → **404** +- Accept c `application/vnd.oci.image.index.v1+json` → 200 (Content-Type: OCI index) +- child-манифест из index по digest → **404** (удалён прежним host-GC — dangling, как описано выше) + +→ registry 2.8.3 отдаёт OCI-index тег только на точный OCI-Accept; docker daemon 26.1.4 получает «manifest unknown». Запушенные buildx/curl-флоу теги = OCI index с **отсутствующим child** = сломанный pull. + +**Фикс (проверен): перепуш образа как docker schema2-манифест** — те же блобы (content-addressed), обёртка docker: mediaType `application/vnd.docker.distribution.manifest.v2+json`, config `application/vnd.docker.container.image.v1+json` (НЕ `distribution.image.config.v2+json` — docker его не знает, «(unknown)» на pull), layers `application/vnd.docker.image.rootfs.diff.tar.gzip`. Пути: `docker save` → OCI tar → amd64 child → трансформ mediaTypes → `PUT /v2//manifests/` с docker Content-Type. Pull снова работает. + +**Вывод для оператора:** на registry:2.8.3 избегать пуш OCI-формата (buildx по умолчанию), host-GC рвать children нельзя; 2026-08-23 dry-run GC: 67 «eligible», реально существующих файлов ~2.5МБ (остальное — уже удалённые ссылки) → host-GC на живом реестре нецелесообразен, риск > выгоды. Аккуратная чистка buildcache/старых тегов — index-aware инструментом books (`registryGc` в task-runner, v2 DELETE). diff --git a/.wiki/index.md b/.wiki/index.md index 260e17c..cd49ad4 100644 --- a/.wiki/index.md +++ b/.wiki/index.md @@ -21,7 +21,7 @@ Catalog of all wiki pages. One line per page, organized by type. Updated on ever - [windows-recovery-host](entities/windows-recovery-host.md) — Windows Recovery Host (рабочий PC пользователя) ## Concepts -- [books-vds-no-gitea-actions](concepts/books-vds-no-gitea-actions.md) — решение vitya 2026-08-23: Gitea Actions выпилены везде (books+vds-ops-mcp workflow удалены, раннер books-vds вычищен), сборка только локально (docker build+curl-upload, OCI-index→amd64 child; docker save сразу даёт OCI), деплой Portainer PUT (синхронный, тянет образ внутри запроса), смоук sched через docker exec node fetch; большие пуши через traefik умирают (Client Closed Request) +- [books-vds-no-gitea-actions](concepts/books-vds-no-gitea-actions.md) — решение vitya 2026-08-23: Gitea Actions выпилены везде (books+vds-ops-mcp workflow удалены, раннер books-vds вычищен), сборка только локально (docker build+curl-upload, OCI-index→amd64 child; docker save сразу даёт OCI), деплой Portainer PUT (синхронный, тянет образ внутри запроса), смоук sched через docker exec node fetch; большие пуши через traefik умирают (Client Closed Request); sched docker-runner: config.json vs docker-config.json, docker-формат образов для registry 2.8.3 - [registry-traefik-buffering-gotcha](concepts/registry-traefik-buffering-gotcha.md) — большие (>1.5GB) пуши в registry через traefik buffering middleware (4GB) умирают: traefik буферизует body в RAM (1GB free) + OOM на books-vds; обход — curl монолитными PUT / PATCH стримом + finalize, drop_caches перед большим ридом - [config-custom-env-mapping-in-mounted-dirs](concepts/config-custom-env-mapping-in-mounted-dirs.md) — npm config: env читается только если custom-environment-variables.json лежит в ПРИМОНТИРОВАННОМ конфиг-дире (маунт затеняет образ); mapping не создаёт свойство без env; проверка docker exec с правильным cwd - [sched-runtime-to-file-managed-migration](concepts/sched-runtime-to-file-managed-migration.md) — перевод sched slovo+bookva на file-managed (durable config, #991): почему runtime хрупкий (расписания в памяти демона, сироты без data), рецепт миграции (файл in-place → live-sync НЕ конвертирует runtime → DELETE /tasks+/schedules → verify), gotchas (id=taskName vs UUID, ghost-таски, task-runner config кэш→рестарт, SMTP from==auth, URL-encode) @@ -81,7 +81,7 @@ Catalog of all wiki pages. One line per page, organized by type. Updated on ever - [recovery-architecture-snapshot](concepts/recovery-architecture-snapshot.md) — текущая recovery architecture (2026-05-19/21, attempt 2) - [registry-gc-mount-and-modify-flag](concepts/registry-gc-mount-and-modify-flag.md) — Docker Registry GC mount layout + `-m` flag - [registry-kzntsv-auth-model](concepts/registry-kzntsv-auth-model.md) — registry.kzntsv.site = standalone registry:2 + htpasswd Basic (бинарный доступ, НЕ Gitea-packages, нет per-repo ACL/robot-токенов); как заводить htpasswd-юзеров (hot-reload), GC через v2 DELETE; юзеры vitya + books-ci -- [registry-oci-image-index-gc](concepts/registry-oci-image-index-gc.md) — books-* образы в registry = OCI image-index (buildx multi-manifest): top-level `.config`=null, дата `.created` живёт в платформенном sub-manifest; наивный GC по top-level дате → null у всех → no-op (keepLastN не применяется). DELETE по index-digest, дата из sub. + **dangling-индексы**: 16/19 тегов books-web — тег жив, sub-manifest `MANIFEST_UNKNOWN` (вычищен прежним host-GC); date-GC защищает их как null-dated → не чистит, хотя они и есть мусор. Зафиксировано на books registryGc dryRun 2026-06-18 +- [registry-oci-image-index-gc](concepts/registry-oci-image-index-gc.md) — books-* образы в registry = OCI image-index (buildx multi-manifest): top-level `.config`=null, дата `.created` живёт в платформенном sub-manifest; наивный GC по top-level дате → null у всех → no-op (keepLastN не применяется). DELETE по index-digest, дата из sub. + **dangling-индексы**: 16/19 тегов books-web — тег жив, sub-manifest `MANIFEST_UNKNOWN` (вычищен прежним host-GC); date-GC защищает их как null-dated → не чистит, хотя они и есть мусор. Зафиксировано на books registryGc dryRun 2026-06-18; 2026-08-23: registry 2.8.3 отдаёт OCI-index только на OCI-Accept (docker pull → «manifest unknown»), фикс — пуш docker schema2-манифестом, host-GC на живом реестре нецелесообразен (dry-run ~2.5МБ) - [rusonyx-vps-onboarding-quirks](concepts/rusonyx-vps-onboarding-quirks.md) — Rusonyx VPS onboarding quirks (Astra Облако / myvm.rusonyx.ru) - [traefik-acme-json-to-iis-cert-import](concepts/traefik-acme-json-to-iis-cert-import.md) — Экспорт LE certs из traefik acme.json в IIS (PFX + SNI bindings) - [traefik-file-watch-wsl2-broken](concepts/traefik-file-watch-wsl2-broken.md) — Traefik file-watch broken под Docker Desktop Windows (WSL2 9p mount) diff --git a/.wiki/log.md b/.wiki/log.md index f5d2c32..02b670c 100644 --- a/.wiki/log.md +++ b/.wiki/log.md @@ -13,6 +13,7 @@ ## [2026-08-12] implement | NEW concepts/keenetic-rci-api.md — разобрана автоматизация KeeneticOS 5.1.3 (RCI: GET /rci/show/*, POST /rci/ массив parse-команд). Через API добавлены DNS-записи git.kreknin.site/kreknin.site → 192.168.1.43 (решение сломанного hairpin). Проверено с LAN: всё 200. Правила порт-форвардинга в 5.x лежат в ip.static (to-host=MAC). ## [2026-08-12] implement | UPDATE entities/kreknin-synology.md — Gitea 1.27.1 + postgres 16 на kreknin (для Алексея), traefik починен (restart policy), LE-серт git.kreknin.site, проброс 80/443→8000/4443 на Keenetic. KeeneticOS Viva API закрыт — правила в GUI. NAT loopback сломан → нужен DNS-override git.kreknin.site→192.168.1.43. Пароли: pass kreknin/keenetic + pass kreknin/gitea. # Wiki op-log +## [2026-08-23] ingest | UPDATE concepts/books-vds-no-gitea-actions.md + concepts/registry-oci-image-index-gc.md — разбор sched docker-runner `createPickingListPdf`: (1) docker CLI читает креды только из `${DOCKER_CONFIG}/config.json`, не `docker-config.json` (rename на slovo); (2) теги buildx/curl = OCI image-index, registry 2.8.3 отдаёт только на OCI-Accept, docker daemon → «manifest unknown» при отсутствующем child (после прежних host-GC) — фикс: перепуш docker schema2-манифестом (config mediaType `container.image.v1+json`, не `distribution.image.config.v2+json`); (3) production-конфиг daemon должен лежать в монтированной конфиг-дире (иначе плейсхолдер `` в tasks.json). host-GC dry-run 2026-08-23: ~2.5МБ реклайма → нецелесообразен. ## [2026-08-23] ingest | UPDATE concepts/books-vds-no-gitea-actions.md — деплой books-web `master-a448cad` (фикс 8 embed-api роутов, оба тенанта, инцидент DELETE-404 закрыт). Уроки в ранбук: (1) `docker save` на Docker 29 сразу даёт OCI-layout (index.json+blobs) — конвертация не нужна, amd64 child manifest в `blobs/sha256/`; (2) `PUT /api/stacks/` синхронный, тянет образ ВНУТРИ запроса — клиентский таймаут рвёт ожидание, оп доделывается server-side, НЕ пере-PUT, проверять контейнеры через `/api/endpoints/1/docker/containers/json` + images/json; (3) смоук sched: `docker exec node -e fetch(localhost:3031/api/runs)` (curl в контейнере нет), Nuxt `/admin/scheduler/**` требует JWT isAdmin — `?token=` 403. Процедура сборки шаг 3 уточнён. ## [2026-08-23] ingest | NEW concepts/sched-ozon-creds-stub-contract.md — контракт кредов Ozon slovo/bookva: мисматч-пары в обеих БД — намеренные заглушки (анти-утечка после tenant-split). Урок: .admin «починил» заглушку (slovo seller 1 ← bookva-ключ) → откат 12:07Z по подтверждению владельца; зеркальная заглушка bookva seller 2 (12:15Z). Безопасность: break-on-error 2a38fb5 задеплоен (фейл-фаст без спина). verify по SHA2 (d6227b = slovo-ключ, f700f3 = bookva-ключ). НЕ чинить. Связано: инцидент 2026-08-23, перевод slovo → file-managed (887bbae). ## [2026-08-14] ingest | NEW concepts/snolla-smtp-mail-delivery-2026-08.md — postmortem SMTP-инцидента 12–14.08: 525 SMTP disabled (Яндекс 360, доменка) → переезд на e-16513832@yandex.ru (app-password); 554 SPAM на 2+ получателях от холодного ящика → @snolla/mailer@0.9.0 per-recipient (forms-api 0.2.0, web 0.44.0); 550 from not owned → mailSettings.from во всех production.json + шаблон pilorama98checkoutconfirm. Монитор SMTP на VDS (cron 08:00, ntfy) + parity-чек Portainer env. Рецепт деплоя тиража (порядок, гочи: ad-hoc контейнер vs Portainer, regex-парсинг image, yarn up -R data).