From 5c6a37313bce94ef3fc97d52b8adfe66a8e4025d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=80=9CNaeel=E2=80=9D?= Date: Wed, 11 Mar 2026 16:48:01 +0400 Subject: [PATCH] =?UTF-8?q?docs:=20=D0=BF=D0=B5=D1=80=D0=B5=D1=80=D0=B0?= =?UTF-8?q?=D0=B1=D0=BE=D1=82=D0=B0=D0=BD=20examples/README.md=20+=20?= =?UTF-8?q?=D0=BA=D0=BE=D0=BC=D0=BC=D0=B5=D0=BD=D1=82=D0=B0=D1=80=D0=B8?= =?UTF-8?q?=D0=B8=20function.tf?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- examples/.gitignore | 39 ++++++ examples/README.md | 180 ++++++++++++++++------------ examples/pg-list-python/function.tf | 28 ++--- 3 files changed, 157 insertions(+), 90 deletions(-) create mode 100644 examples/.gitignore diff --git a/examples/.gitignore b/examples/.gitignore new file mode 100644 index 0000000..138cb80 --- /dev/null +++ b/examples/.gitignore @@ -0,0 +1,39 @@ +# Created: 2026-03-11 +# Purpose: ignore generated artifacts for the `examples` repository + +# Terraform +.terraform/ +*.tfstate +*.tfstate.* +.terraform.lock.hcl +crash.log + +# Terraform plans / backups +*.tfplan +*.backup +*.bak + +# Provider plugins / caches +.terraform.d/ + +# Archives and build artifacts +*.zip +dist/ +build/ + +# Node / Python +node_modules/ +__pycache__/ +*.pyc +venv/ +.venv/ + +# Editor / OS files +.DS_Store +*.swp +*.swo + +# Environment files +.env +*.local +*.log diff --git a/examples/README.md b/examples/README.md index afe6564..30d3c0d 100644 --- a/examples/README.md +++ b/examples/README.md @@ -1,64 +1,119 @@ -# Примеры sless +# Примеры использования sless -## Что такое sless +## Обзор платформы -**sless** — платформа для запуска serverless-функций в Kubernetes-кластере. +**sless** — система управления serverless-функциями на базе Kubernetes. Разработчик загружает код функции, платформа собирает из него Docker-образ, разворачивает его в кластере и предоставляет HTTP-эндпоинт для вызова. Всё описывается декларативно через Terraform. -Код на Python или Node.js загружается в платформу, которая собирает Docker-образ, деплоит его в кластер и публикует HTTP-эндпоинт. Всё управляется через Terraform. +### Основные ресурсы провайдера -### Ресурсы - -| Ресурс | Что делает | +| Ресурс | Назначение | |---|---| -| `sless_function` | Загружает код и собирает Docker-образ. Сама по себе не принимает запросы — нужен триггер или джоб | -| `sless_trigger` | Публикует функцию — либо как HTTP-эндпоинт, либо по расписанию (cron) | -| `sless_job` | Запускает функцию один раз (например, для инициализации БД) и ждёт результата | +| `sless_function` | Описывает функцию: язык, точку входа, лимиты, переменные окружения. При создании загружает код и запускает его сборку в образ. Сама по себе недоступна снаружи — нужен триггер или задание. | +| `sless_trigger` | Публикует функцию: тип `http` создаёт публичный URL, тип `cron` — запуск по расписанию. | +| `sless_job` | Запускает функцию однократно и ожидает завершения. Используется для одноразовых операций: инициализация БД, миграции, пакетная обработка. | -**Типичный сценарий:** `sless_function` с кодом + `sless_trigger` с `type = "http"` → публичный URL вида `https://sless-api.kube5s.ru/fn/default/имя-функции`. +Стандартная связка для HTTP API: `sless_function` + `sless_trigger` с `type = "http"` — в результате функция доступна по URL вида `https://sless-api.kube5s.ru/fn//<имя-функции>`. --- -Примеры показывают различные сценарии использования serverless функций через Terraform провайдер `terra.k8c.ru/naeel/sless`. - ## Требования - Terraform >= 1.0 +- JWT-токен для аутентификации в sless API - Доступ к `https://sless-api.kube5s.ru` -## Провайдер +## Конфигурация провайдера -Во всех примерах `main.tf` содержит: +Во всех примерах файл `main.tf` содержит блок провайдера. Токен передаётся через переменную, значение которой задаётся в `terraform.tfvars`: ```hcl provider "sless" { - endpoint = "https://sless-api.kube5s.ru" - token = "dev-token-change-me" + endpoint = "https://sless-api.kube5s.ru" + token = var.token + nubes_endpoint = "https://deck-api.ngcloud.ru/api/v1" } ``` +Namespace функций вычисляется автоматически из JWT-токена: `sless-{sha256[:8]}`. + --- ## Примеры -### `simple-python` — джоб передаёт результат в HTTP-функцию (Python) +### `hello-node` — минимальный пример на Node.js -При `apply` запускается джоб, его вывод передаётся в HTTP-функцию через `env_vars`. +Две независимые функции: HTTP-функция, возвращающая приветствие, и одноразовое задание, суммирующее набор чисел. Хорошая отправная точка для знакомства с платформой. + +```bash +cd hello-node +terraform init +terraform apply -auto-approve + +# Вызов HTTP-функции с передачей имени: +curl -s -X POST https://sless-api.kube5s.ru/fn//hello-http \ + -H 'Content-Type: application/json' -d '{"name":"World"}' + +# Результат задания: +terraform output job_message +``` + +--- + +### `hello-go` — минимальный пример на Go 1.23 + +Аналог `hello-node`, но на Go. Демонстрирует поддержку Go-рантайма: HTTP-функция и одноразовое задание. Код пользователя оформляется как пакет `handler` с функцией `Handle(event)`. + +```bash +cd hello-go +terraform init +terraform apply -auto-approve + +terraform output job_message +terraform output trigger_url +``` + +--- + +### `pg-list-python` — выборка данных из PostgreSQL (Python) + +Минимальный пример работы с базой данных: одна HTTP-функция читает список записей из таблицы PostgreSQL и возвращает их в JSON. Таблица с тестовыми данными создаётся автоматически при первом вызове. Нет заданий, нет инициализации — только функция и триггер. + +**Переменные:** + +| Переменная | Описание | Значение по умолчанию | +|---|---|---| +| `pg_dsn` | Строка подключения к PostgreSQL | `postgres://sless:sless-pg-password@postgres.sless.svc.cluster.local:5432/sless?sslmode=disable` | + +```bash +cd pg-list-python +terraform init +terraform apply -auto-approve + +# URL функции выводится после применения: +terraform output catalog_url + +# Запрос к функции: +curl -s $(terraform output -raw catalog_url) +``` + +--- + +### `simple-python` — одноразовое задание передаёт данные в HTTP-функцию (Python) + +При `apply` выполняется задание, которое фиксирует текущее время. Результат передаётся в HTTP-функцию через переменные окружения и отображается при каждом запросе. ```bash cd simple-python terraform init terraform apply -auto-approve -# Что вернул джоб (время на момент деплоя): terraform output job_result - -# Проверить функцию: -curl -s https://sless-api.kube5s.ru/fn/default/simple-py-time-display +curl -s https://sless-api.kube5s.ru/fn//simple-py-time-display ``` --- -### `simple-node` — то же самое, но на Node.js 20 +### `simple-node` — то же самое на Node.js 20 ```bash cd simple-node @@ -66,95 +121,68 @@ terraform init terraform apply -auto-approve terraform output job_result -curl -s https://sless-api.kube5s.ru/fn/default/simple-node-time-display +curl -s https://sless-api.kube5s.ru/fn//simple-node-time-display ``` --- -### `hello-node` — минимальный пример на Node.js +### `notes-python` — CRUD API на Python с PostgreSQL -Две независимые функции: HTTP-функция (возвращает приветствие) и одноразовый джоб (суммирует числа). - -```bash -cd hello-node -terraform init -terraform apply -auto-approve - -# Проверить HTTP-функцию: -curl -s -X POST https://sless-api.kube5s.ru/fn/default/hello-http \ - -H 'Content-Type: application/json' -d '{"name":"World"}' - -# Посмотреть результат джоба: -terraform output job_message -``` - ---- - -### `notes-python` — CRUD API на Python + PostgreSQL - -Полноценное приложение: инициализация схемы БД через джобы, CRUD-функция, read-only функция для списка записей. +Полноценное приложение: инициализация схемы базы данных через задания, CRUD-функция для работы с записями, отдельная функция для получения списка. **Переменные:** -| Переменная | Описание | Дефолт | +| Переменная | Описание | Значение по умолчанию | |---|---|---| -| `pg_dsn` | DSN для подключения к PostgreSQL | `postgres://sless:sless-pg-password@postgres.sless.svc.cluster.local:5432/sless?sslmode=disable` | +| `pg_dsn` | Строка подключения к PostgreSQL | `postgres://sless:sless-pg-password@postgres.sless.svc.cluster.local:5432/sless?sslmode=disable` | ```bash cd notes-python terraform init - -# Опционально — переопределить DSN: -# export TF_VAR_pg_dsn="postgres://user:pass@host:5432/db?sslmode=disable" - terraform apply -auto-approve -# Проверить инициализацию БД: +# Статус инициализации базы данных: terraform output db_init_table_status terraform output db_init_index_status -# URL функций: -terraform output notes_url # CRUD -terraform output notes_list_url # список всех записей - # Создать запись: -curl -s -X POST "https://sless-api.kube5s.ru/fn/default/notes/add?title=Hello&body=World" +curl -s -X POST "$(terraform output -raw notes_url)/add?title=Hello&body=World" -# Список записей: -curl -s https://sless-api.kube5s.ru/fn/default/notes-list +# Получить список записей: +curl -s $(terraform output -raw notes_list_url) -# Обновить (id из предыдущего ответа): -curl -s -X POST "https://sless-api.kube5s.ru/fn/default/notes/update?id=1&title=Updated&body=New+body" +# Обновить запись (id из предыдущего ответа): +curl -s -X POST "$(terraform output -raw notes_url)/update?id=1&title=Updated&body=New+body" -# Удалить: -curl -s -X POST "https://sless-api.kube5s.ru/fn/default/notes/delete?id=1" +# Удалить запись: +curl -s -X POST "$(terraform output -raw notes_url)/delete?id=1" ``` --- -## Общие команды +## Полезные команды ```bash -# Посмотреть текущее состояние ресурсов: +# Посмотреть текущее состояние задеплоенных ресурсов: terraform show -# Пересоздать конкретный ресурс: -terraform apply -replace=sless_function.имя -auto-approve +# Принудительно пересобрать функцию (например, после изменения кода): +terraform apply -replace=sless_function.<имя> -auto-approve -# Повторно запустить джоб — увеличить run_id в .tf файле, затем: +# Повторно запустить задание: увеличить значение run_id в .tf-файле, затем: terraform apply -auto-approve # Удалить все ресурсы примера: terraform destroy -auto-approve ``` -## Структура каждого примера +## Структура примера ``` -пример/ -├── main.tf — провайдер -├── *.tf — ресурсы (функции, триггеры, джобы) -├── outputs.tf — URLs и статусы после apply -├── variables.tf — входные переменные (если есть) -└── code/ — исходный код функций +<пример>/ +├── main.tf — конфигурация провайдера +├── *.tf — ресурсы: функции, триггеры, задания +├── variables.tf — входные переменные +├── terraform.tfvars — значения переменных (не коммитится в git) +└── code/ — исходный код функций ``` diff --git a/examples/pg-list-python/function.tf b/examples/pg-list-python/function.tf index 6638c65..df1f7c2 100644 --- a/examples/pg-list-python/function.tf +++ b/examples/pg-list-python/function.tf @@ -2,28 +2,28 @@ # function.tf — HTTP-функция: читает из PostgreSQL и возвращает список записей. # Нет джобов, нет инициализации — только функция + HTTP триггер. -resource "sless_function" "product_catalog" { - name = "product-catalog" - runtime = "python3.11" - entrypoint = "catalog.list_products" - memory_mb = 128 - timeout_sec = 10 +resource "sless_function" "product_catalog" { # объявляем serverless-функцию; "product_catalog" — локальное имя в tf-state + name = "product-catalog" # имя функции в кластере; по нему формируется URL и имя k8s-объекта + runtime = "python3.11" # базовый образ рантайма; определяет как собирается и запускается код + entrypoint = "catalog.list_products" # файл.функция которую вызывает рантайм: catalog.py → def list_products(event) + memory_mb = 128 # лимит памяти пода в мегабайтах + timeout_sec = 10 # максимальное время выполнения одного запроса в секундах - source_dir = "${path.module}/code" + source_dir = "${path.module}/code" # директория с кодом функции; провайдер упакует её в zip и загрузит # DSN передаётся через env — функция не знает об инфраструктуре env_vars = { - PG_DSN = var.pg_dsn + PG_DSN = var.pg_dsn # строка подключения к PostgreSQL; берётся из переменной (variables.tf) } } -resource "sless_trigger" "product_catalog_http" { - name = "product-catalog-http" - type = "http" - function = sless_function.product_catalog.name - enabled = true +resource "sless_trigger" "product_catalog_http" { # триггер публикует функцию наружу; без него функция существует, но недоступна + name = "product-catalog-http" # имя триггера в кластере + type = "http" # тип триггера: "http" создаёт публичный URL; альтернатива — "cron" + function = sless_function.product_catalog.name # ссылка на имя функции выше; terraform гарантирует порядок создания + enabled = true # триггер активен сразу после создания } output "catalog_url" { - value = sless_trigger.product_catalog_http.url + value = sless_trigger.product_catalog_http.url # URL вида https://sless-api.../fn//; выводится после apply }