inquir.yaml — единый файл сборки функций. У него одинаковая структура для Node.js, Python и Go, и браузерный редактор, inquir deploy и деплой из Git читают его одинаково. В нём объявляются пакеты ОС, нужные функции (build.system), и её языковые пакеты (build.dependencies). Файл читается при деплое; отдельных настроек в консоли, флагов CLI или полей API для этого нет.
Где лежит файл#
Положите inquir.yaml в корень файлов функции: в папку функции в дереве файлов редактора или в каталог функции, который вы деплоите через CLI или из Git. Файл уезжает вместе с кодом, поэтому все способы деплоя читают один и тот же файл. Имя inquir.yml тоже подходит; если есть оба, выигрывает inquir.yaml. Размер файла — до 64 КиБ.
Проект может держать и один общий inquir.yaml в своём корне — для всех функций. Когда вы деплоите SDK-функцию из подкаталога (inquir deploy --asset <name>), корневого файла в её архиве нет, поэтому CLI (версии после 0.4.1) отправляет его вместе с архивом, и платформа читает его как файл проекта. Деплой из Git читает только файл в том каталоге, который он деплоит.
Контейнерные приложения используют то же имя файла: version и services — это манифест приложения (см. Контейнерные приложения). Функции читают только build и functions.
Полный пример#
Блок build в начале файла действует для всех функций, которые деплоятся из этого каталога или проекта. Запись functions.<name> заменяет его для одной функции. У функции одна среда выполнения, поэтому каждый список зависимостей пишите в синтаксисе её среды.
# inquir.yaml: the same file for Node.js, Python and Go functions build: # defaults for every function deployed from here system: presets: [ffmpeg] functions: thumbnails: # replaces the defaults for this function (no merge) build: system: presets: [imagemagick, fonts] packages: [poppler-utils] # Debian names; pin with name=version dependencies: [sharp@0.33.5] # Node.js: name@version ocr: build: system: presets: - name: tesseract langs: [deu, rus] dependencies: ["pytesseract==0.3.13"] # Python: a pip requirement ids: build: system: null # no system packages for this function dependencies: [github.com/google/uuid@v1.6.0] # Go: module@version
Справочник по ключам#
Все ключи необязательны. Неизвестные ключи отклоняются на верхнем уровне, в build, в build.system и в functions.<name>: опечатка вроде build.sytem проваливает деплой с подсказкой «возможно, вы имели в виду», а не теряет ваши пакеты молча. Браузерный редактор дополняет и проверяет файл по мере ввода.
| Ключ | Тип | Назначение |
|---|---|---|
build | словарь | Настройки сборки для всех функций, которые деплоятся из этого каталога или проекта. |
build.system | словарь или null | Пакеты ОС, устанавливаемые в образ функции (Debian bookworm). null или пустой блок означают «без пакетов». |
build.system.presets | список, до 8 | Пресеты платформы по имени. Параметры принимает только tesseract: { name: tesseract, langs: [deu, rus] }. |
build.system.packages | список, до 10 | Дополнительные пакеты Debian по имени в apt, при желании с версией: name=version. |
build.dependencies | список, до 200 | Языковые пакеты, которые читаются по правилам среды выполнения функции: name@version для Node.js, требование pip для Python, module@version для Go. Каждая запись — не длиннее 512 символов. |
functions.<name>.build | словарь | Тот же блок build для одной функции, по её имени. Он заменяет build файла поключево; списки никогда не объединяются. |
version, services | — | Манифест контейнерного приложения. Функции эти ключи не читают. |
Системные пакеты: build.system#
При деплое блок превращается в образ функции: компактная база Debian bookworm её среды выполнения плюс один слой с вашими пакетами, которые apt ставит из официальных репозиториев Debian bookworm. Ключ образа вычисляется по его содержимому, поэтому набор пакетов собирается один раз и используется всеми функциями, которые просят такой же набор, в любом рабочем пространстве, а деплой, меняющий только код, образ не пересобирает.
Пакеты ставятся только при сборке. Функции работают от непривилегированного пользователя и не могут выполнить apt-get install во время работы. Если убрать блок или сам файл, пакеты исчезнут при следующем деплое.
Системные пакеты доступны функциям на Node.js и Python. Для Go они скоро появятся: до тех пор деплой отклоняет build.system у Go-функции и сообщает об этом. Когда поддержка Go появится, менять файл и код не придётся.
Пресеты#
Пресет — это подобранный платформой версионированный набор пакетов Debian плюс переменные окружения, которых ждут его инструменты. Переменные зашиваются в образ; переменная окружения функции с тем же именем их переопределяет.
| Пресет | Что ставит | Окружение |
|---|---|---|
ffmpeg | ffmpeg: ffmpeg и ffprobe (FFmpeg 5.1) | FFMPEG_PATH=/usr/bin/ffmpegFFPROBE_PATH=/usr/bin/ffprobe |
imagemagick | imagemagick (ImageMagick 6: convert, identify), ghostscript, fonts-dejavu-core. Политика ImageMagick в Debian оставляет PDF и PostScript выключенными. | — |
libvips | libvips-tools, libvips42: команда vips и библиотека для pyvips (sharp в Node поставляет свою libvips) | — |
poppler | poppler-utils: pdftotext, pdftoppm, pdfinfo | — |
tesseract | tesseract-ocr 5 и tesseract-ocr-eng, плюс tesseract-ocr-<lang> для каждого элемента langs | TESSDATA_PREFIX=/usr/share/tesseract-ocr/5/tessdata |
ghostscript | ghostscript (gs), интерпретатор PostScript и PDF | — |
fonts | fonts-dejavu-core, fonts-liberation, fonts-noto-core, fonts-noto-cjk, fonts-noto-color-emoji — для рендеринга без экрана | — |
langs принимает до 8 кодов из списка: ara, bul, ces, chi-sim, chi-tra, dan, deu, ell, eng, est, fin, fra, heb, hin, hrv, hun, ind, ita, jpn, kat, kaz, kor, lav, lit, nld, nor, pol, por, ron, rus, slk, slv, spa, srp, swe, tha, tur, ukr, vie. Текущий каталог выводит inquir functions system presets.
Пакеты Debian: правила и ограничения#
- Пишите имена пакетов bookworm так, как их знает
apt: строчные буквы, цифры и+ . -, первый и последний символ — буква или цифра, без... Шаблоны apt и удаление пакетов так не записать; для компилятора C++ указывайтеbuild-essential, а неg++. Каждое имя должно быть настоящим пакетом: до установки сборка проверяет все имена черезapt-cache, а виртуальный пакет (тот, который только предоставляют другие пакеты) проваливает её с сообщением, что нужно указать пакет, который его предоставляет. - Версию фиксируют синтаксисом apt:
name=version(например,tesseract-ocr-deu=5.3.0-2). Если Debian больше не поставляет зафиксированную версию, сборка образа провалится; обновите или уберите версию. - Не больше 10 пакетов на функцию (пресеты в лимит не входят) и не больше 8 пресетов. Каждый указывается один раз.
- Демоны, инструменты повышения привилегий, ядра и пакетный инструментарий запрещены:
systemd*,init,sudo,sudo-ldap,doas,openssh-server,docker*,containerd*,podman*,runc,crun,linux-image-*,linux-headers-*,*-dkms,apt-transport-*,apt,dpkg,cron,anacron,rsyslog,udev,dbus. Сборка также проверяет, что установлены ровно запрошенные пакеты и что ни инструмент повышения привилегий, ни SSH-сервер, ни контейнерный движок, ни пакет ядра (sudo,doas,openssh-server,docker*,containerd*,podman*,runc,crun,linux-image-*,linux-headers-*,*-dkms) не пришёл как зависимость, и снимает с файлов образа биты setuid и setgid. - Добавленный слой — до 1 ГБ в сжатом виде, сборка образа — до 15 минут.
- Рабочее пространство может запросить не больше 10 новых наборов пакетов за 24 часа. Набор, который у платформы уже есть, потому что его раньше запрашивало любое рабочее пространство, не считается.
- Собственные шаги сборки (
system.run) недоступны.
Chromium без экрана для Puppeteer или Playwright#
Пресета для браузера нет: Chromium — это список пакетов, а его библиотеки apt подтянет сам. Запускайте /usr/bin/chromium с --no-sandbox (функции работают без привилегий), используйте puppeteer-core или playwright-core, чтобы браузер не скачивался, и дайте функции не меньше 1 ГБ памяти. Если библиотека читает PUPPETEER_EXECUTABLE_PATH, задайте его как переменную окружения функции со значением /usr/bin/chromium. Чтобы загружать внешние страницы, включите функции Сеть.
# inquir.yaml build: system: packages: [chromium, fonts-liberation, fonts-noto-color-emoji] dependencies: [puppeteer-core@^23.0.0] # no browser download; or list it in package.json
const puppeteer = require('puppeteer-core'); // Give the function at least 1 GB of memory and turn on Network. exports.handler = async (event) => { const browser = await puppeteer.launch({ executablePath: '/usr/bin/chromium', args: ['--no-sandbox', '--disable-dev-shm-usage'], }); try { const page = await browser.newPage(); await page.goto(event.url || 'https://example.com', { waitUntil: 'networkidle2' }); const pdf = await page.pdf({ format: 'A4' }); return { statusCode: 200, body: JSON.stringify({ pdfBase64: Buffer.from(pdf).toString('base64') }) }; } finally { await browser.close(); } };
Нативным модулям нужны -dev-пакеты#
Если у функции есть системные пакеты, установка её зависимостей (npm ci, npm install, pip install) идёт на её собственном образе, и нативные аддоны и исходные дистрибутивы компилируются с установленными библиотеками. Пресеты ставят только runtime-библиотеки, поэтому заголовочные файлы добавляйте сами: pycairo нужен packages: [libcairo2-dev, pkg-config], psycopg2 — libpq-dev. Аддону Node, который собирается через node-gyp, нужны ещё build-essential и python3.
Языковые пакеты: build.dependencies#
Один список и один ключ для всех сред выполнения. Функция читает его по правилам своей среды:
- Node.js:
name@version— имя npm-пакета с версией, диапазоном или dist-tag (sharp@0.33.5,zod@^3.23.0). Спецификации git, file, URL и алиасы оставьте вpackage.json. - Python: требование pip с ограничением версии (
requests==2.32.3,uvicorn[standard]>=0.30). Маркеры окружения и прямые ссылки по URL оставьте вrequirements.txt. - Go:
module@versionс точной версией или псевдоверсией (github.com/google/uuid@v1.6.0). Модулям версии v2 и выше нужен суффикс/vNв пути.
Деплой вливает список в сборочную копию исходников и никогда — в ваши файлы: редактор показывает ровно то, что вы написали. Записи Node.js попадают в dependencies файла package.json, записи Python — в requirements.txt, записи Go — в блок require в go.mod; недостающий файл создаётся. Затем платформа устанавливает пакеты — одинаково в handler- и web-режиме: npm ci --omit=dev при наличии lock-файла или npm install --omit=dev без него; pip install в .python_packages; для Go — go mod tidy и go mod vendor, после чего обработчик компилируется офлайн из vendor/. Обработчик на Node.js поставляет рядом с бандлом весь production-каталог node_modules и не включает установленные пакеты в бандл, поэтому нативные аддоны и пакеты, которые сами загружают свои файлы во время работы, работают ровно так, как установлены.
Задаче установки выделяется 1 ГБ памяти, 512 МиБ временного диска и 5 минут. Она обращается только к реестрам пакетов: npm (а также nodejs.org и GitHub, откуда нативные пакеты скачивают готовые бинарники), PyPI, прокси модулей Go и база контрольных сумм (proxy.golang.org, sum.golang.org; прямых загрузок из VCS нет). package.json, requirements.txt и go.mod продолжают работать, но объявлять пакеты стоит в inquir.yaml. Если пакет объявлен и там, и там с разными версиями, деплой проваливается, а не объединяет их молча; одинаковое объявление в обоих местах допустимо. pnpm-lock.yaml и yarn.lock не читаются: платформа ставит пакеты через npm и пишет об этом в логе деплоя.
Ещё деплой отклоняет — с сообщением, где названа запись:
- один и тот же пакет дважды в списке;
- добавленный пакет Node.js, который
package-lock.jsonилиnpm-shrinkwrap.jsonне фиксирует с той же спецификацией (обновите lock-файл или используйте точные версии без него); - пакет Node.js, который
package.jsonперечисляет вdevDependencies: установка пропускает dev-зависимости; requirements.txtс опциями pip (-r,-c,-e,--index-url,--hash…);go.mod, где перечисленный модуль заменён черезreplaceили исключён черезexcludeлибо строкаgoилиtoolchainтребует Go новее 1.22, версии среды выполнения;- исходники, в которых уже лежат
node_modules,.python_packagesилиvendor/.
Какое объявление действует#
build.system и build.dependencies ищутся по отдельности, в таком порядке. Действует первое найденное объявление; уровни и файлы никогда не объединяются.
functions.<name>.buildв собственномinquir.yamlфункцииbuildв собственномinquir.yamlфункцииfunctions.<name>.buildвinquir.yamlв корне проектаbuildвinquir.yamlв корне проекта- Ничего не найдено: у функции нет системных пакетов и дополнительных языковых пакетов.
Явные system: null, пустой блок или dependencies: [] — тоже объявление. Оно означает «ничего» и перекрывает значение по умолчанию из проекта.
Один файл, три среды выполнения: перекодирование через ffmpeg#
Один и тот же inquir.yaml подходит функциям на Node.js, Python и Go. Каждый обработчик берёт FFMPEG_PATH, который задаёт пресет, и уменьшает видео до 480p во временном каталоге.
# inquir.yaml (identical for Node.js, Python and Go) build: system: presets: [ffmpeg] # installs ffmpeg + ffprobe, sets FFMPEG_PATH and FFPROBE_PATH
Node.js#
const { execFile } = require('node:child_process'); const { promisify } = require('node:util'); const fs = require('node:fs/promises'); const os = require('node:os'); const path = require('node:path'); const run = promisify(execFile); exports.handler = async (event) => { const input = typeof event.body === 'string' ? JSON.parse(event.body || '{}') : event; const dir = await fs.mkdtemp(path.join(os.tmpdir(), 'transcode-')); try { const src = path.join(dir, 'in.mp4'); const out = path.join(dir, 'out.mp4'); await fs.writeFile(src, Buffer.from(input.videoBase64, 'base64')); await run(process.env.FFMPEG_PATH || 'ffmpeg', [ '-y', '-i', src, '-vf', 'scale=-2:480', '-c:v', 'libx264', '-preset', 'veryfast', out, ]); const mp4 = await fs.readFile(out); return { statusCode: 200, body: JSON.stringify({ mp4Base64: mp4.toString('base64') }) }; } finally { await fs.rm(dir, { recursive: true, force: true }); } };
Python#
import base64 import json import os import subprocess import tempfile def handler(event, context): raw = event.get("body") payload = json.loads(raw) if isinstance(raw, str) else event with tempfile.TemporaryDirectory(prefix="transcode-") as tmp: src = os.path.join(tmp, "in.mp4") out = os.path.join(tmp, "out.mp4") with open(src, "wb") as f: f.write(base64.b64decode(payload["videoBase64"])) subprocess.run( [os.environ.get("FFMPEG_PATH", "ffmpeg"), "-y", "-i", src, "-vf", "scale=-2:480", "-c:v", "libx264", "-preset", "veryfast", out], check=True, capture_output=True, ) with open(out, "rb") as f: mp4 = base64.b64encode(f.read()).decode() return {"statusCode": 200, "body": json.dumps({"mp4Base64": mp4})}
Go#
Системные пакеты для Go скоро появятся; сейчас деплой отклоняет этот файл у Go-функции. Среда выполнения Go уже работает на той же базе Debian bookworm, и этот обработчик задеплоится без изменений, когда поддержка Go появится.
package main import ( "encoding/base64" "encoding/json" "fmt" "os" "os/exec" "path/filepath" ) func Handler(event map[string]interface{}, ctx map[string]interface{}) (interface{}, error) { payload := event if s, ok := event["body"].(string); ok && s != "" { payload = map[string]interface{}{} if err := json.Unmarshal([]byte(s), &payload); err != nil { return nil, err } } video, _ := payload["videoBase64"].(string) in, err := base64.StdEncoding.DecodeString(video) if err != nil { return nil, err } dir, err := os.MkdirTemp("", "transcode-") if err != nil { return nil, err } defer os.RemoveAll(dir) src, out := filepath.Join(dir, "in.mp4"), filepath.Join(dir, "out.mp4") if err := os.WriteFile(src, in, 0o600); err != nil { return nil, err } ffmpeg := os.Getenv("FFMPEG_PATH") if ffmpeg == "" { ffmpeg = "ffmpeg" } cmd := exec.Command(ffmpeg, "-y", "-i", src, "-vf", "scale=-2:480", "-c:v", "libx264", "-preset", "veryfast", out) if log, err := cmd.CombinedOutput(); err != nil { return nil, fmt.Errorf("ffmpeg: %v: %s", err, log) } mp4, err := os.ReadFile(out) if err != nil { return nil, err } body, _ := json.Marshal(map[string]string{"mp4Base64": base64.StdEncoding.EncodeToString(mp4)}) return map[string]interface{}{"statusCode": 200, "body": string(body)}, nil }
Сборка, статус и лог деплоя#
Лог деплоя показывает, что выбрала платформа, — в строках, которые начинаются с [system]. Если образ уже есть в кэше, деплой идёт дальше сразу. Новый набор пакетов сначала собирается: деплой ждёт в очереди, не задерживая другие деплои, и продолжается, когда образ готов. Первая сборка занимает минуты (пресет ffmpeg собирается примерно за 2,5 минуты); все следующие деплои, которые просят тот же набор, из любой функции, используют готовый образ. Если есть более старая сборка тех же пакетов (например, после обновления базового образа платформы), деплой идёт на ней, а функция переходит на новый образ, когда тот будет готов. Пока образ собирается или если его сборка провалилась, текущий релиз продолжает работать.
$ inquir deploy --asset transcode [system] presets [ffmpeg] + packages [] from inquir.yaml (nodejs22, bookworm) [system] system image: cache hit registry.inquir.org/inquir-sys/nodejs22@sha256:… +118 MB (shared) … # Declared block, image state, size, serving image and package lock $ inquir functions system transcode # The preset catalog (and the package limit for your workspace) $ inquir functions system presets
inquir functions system <function> (в версии CLI после 0.4.1) показывает объявленный блок и файл, из которого он взят, состояние образа (queued, building, ready или failed), его размер, какой образ обслуживает функцию и lock-список пакетов — точную версию каждого пакета, добавленного сборкой. API отдаёт тот же статус по GET /functions/<id>/system-image, а каталог пресетов — по GET /functions/system-presets.
Чтобы повторить проваленную сборку образа, задеплойте ещё раз. Повторные попытки для одного набора пакетов идут с паузами 1, 5 и затем 30 минут.
Ошибки и как их исправить#
| Ошибка | Причина | Что сделать |
|---|---|---|
400 invalid_inquir_yaml | Файл — невалидный YAML, больше 64 КиБ, содержит неизвестный ключ или значение не той формы, либо запись build.dependencies некорректна или конфликтует с package.json, requirements.txt или go.mod. | Сообщение называет ключ или запись. Исправьте и задеплойте снова. |
400 invalid_system_packages | Неизвестный пресет или язык OCR, неизвестный ключ или значение не той формы внутри build.system, имя пакета не по правилам, запрещённый пакет, слишком много пакетов или повтор. | Исправьте имя, на которое указывает сообщение; для пресета с опечаткой оно предлагает ближайший. |
400 invalid_system_packages (Go) | build.system у Go-функции: системные пакеты для Go скоро появятся. | Пока уберите блок у Go-функции. |
400 system_packages_deploy_only | Запрос пытался задать системные пакеты через API функции, а не деплоем. | Объявите их в inquir.yaml и задеплойте. |
429 system_image_quota | Рабочее пространство запросило больше 10 новых наборов пакетов за 24 часа. | Используйте уже собранный набор пакетов или задеплойте позже. |
503 system_image_building | Вызван код, который ещё не деплоился (запуск из редактора), пока его образ собирается. | Повторите после интервала из Retry-After. |
409 system_image_failed | То же, но сборка образа провалилась. | Исправьте inquir.yaml и задеплойте снова; ошибку сборки показывает inquir functions system <function>. |
| Сборка образа провалилась | Пакета нет в bookworm или он виртуальный, зафиксированная версия пропала или добавленный слой больше 1 ГБ. | Проверьте имя для bookworm на packages.debian.org, обновите или уберите версию либо разнесите тяжёлые инструменты по разным функциям. Ошибку сборки показывает inquir functions system <function>. |
| Установка падает: «pkg-config not found», «pg_config executable not found» | Нативный пакет компилируется с библиотекой, заголовочные файлы которой не установлены. | Добавьте -dev-пакет: libcairo2-dev и pkg-config для pycairo, libpq-dev для psycopg2. |
runtimeVariant: full | Вариант образа Full (Chromium) выведен из употребления. | Уберите runtimeVariant и добавьте в inquir.yaml packages: [chromium, fonts-liberation, fonts-noto-color-emoji]. |
Варианты образов и слои#
У каждой среды выполнения теперь один компактный образ на Debian bookworm. Вариант Node.js Full (Chromium) выведен из употребления, а его переключатель убран из консоли. Запрос к API, который создаёт функцию с runtimeVariant: full или переводит функцию на него, отклоняется с 400 и подсказкой про inquir.yaml; если отправить то значение, которое у функции уже есть, запрос пройдёт. Chromium ставится списком пакетов, как показано выше.
Слои продолжают работать у функций, которые их используют, но это больше не рекомендуемый способ добавлять зависимости: языковые пакеты объявляйте в build.dependencies, пакеты ОС — в build.system.