fix: migrate sless endpoint from sless-api.kube5s.ru to sless.kube5s.ru (new cluster ingress 185.247.187.147)
This commit is contained in:
@@ -5,7 +5,7 @@
|
|||||||
# - Secret: секретные данные (S3 keys, postgres DSN, API token, Harbor pass)
|
# - Secret: секретные данные (S3 keys, postgres DSN, API token, Harbor pass)
|
||||||
# - Deployment: оператор naeel/sless-operator:v0.1.23 в namespace sless
|
# - Deployment: оператор naeel/sless-operator:v0.1.23 в namespace sless
|
||||||
# - Service: ClusterIP :9090 (REST API)
|
# - Service: ClusterIP :9090 (REST API)
|
||||||
# - Ingress: sless-api.kube5s.ru → :9090 (внешний доступ с TLS)
|
# - Ingress: sless.kube5s.ru → :9090 (внешний доступ с TLS)
|
||||||
#
|
#
|
||||||
# Чтобы сменить registry — менять только REGISTRY_HOST в ConfigMap.
|
# Чтобы сменить registry — менять только REGISTRY_HOST в ConfigMap.
|
||||||
# Чтобы сменить Harbor-аккаунт — менять HARBOR_USER в ConfigMap + HARBOR_PASS в Secret.
|
# Чтобы сменить Harbor-аккаунт — менять HARBOR_USER в ConfigMap + HARBOR_PASS в Secret.
|
||||||
@@ -32,7 +32,7 @@ data:
|
|||||||
INGRESS_HOST: "fn.kube5s.ru"
|
INGRESS_HOST: "fn.kube5s.ru"
|
||||||
# EXTERNAL_URL — если задан, URL функции = EXTERNAL_URL/fn/{namespace}/{name}
|
# EXTERNAL_URL — если задан, URL функции = EXTERNAL_URL/fn/{namespace}/{name}
|
||||||
# Позволяет обойтись без wildcard DNS *.fn.kube5s.ru
|
# Позволяет обойтись без wildcard DNS *.fn.kube5s.ru
|
||||||
EXTERNAL_URL: "https://sless-api.kube5s.ru"
|
EXTERNAL_URL: "https://sless.kube5s.ru"
|
||||||
---
|
---
|
||||||
# Secret создаётся отдельно через kubectl (не коммитить секреты в git!)
|
# Secret создаётся отдельно через kubectl (не коммитить секреты в git!)
|
||||||
# Описание ключей:
|
# Описание ключей:
|
||||||
@@ -72,7 +72,7 @@ spec:
|
|||||||
containers:
|
containers:
|
||||||
- name: operator
|
- name: operator
|
||||||
# При обновлении версии оператора — менять тег здесь (не latest!)
|
# При обновлении версии оператора — менять тег здесь (не latest!)
|
||||||
image: naeel/sless-operator:v0.1.28
|
image: naeel/sless-operator:v0.1.31
|
||||||
# Always — чтобы всегда тянуть по точному тегу (не кешировать старый)
|
# Always — чтобы всегда тянуть по точному тегу (не кешировать старый)
|
||||||
imagePullPolicy: Always
|
imagePullPolicy: Always
|
||||||
ports:
|
ports:
|
||||||
@@ -133,7 +133,7 @@ metadata:
|
|||||||
spec:
|
spec:
|
||||||
ingressClassName: nginx
|
ingressClassName: nginx
|
||||||
rules:
|
rules:
|
||||||
- host: sless-api.kube5s.ru
|
- host: sless.kube5s.ru
|
||||||
http:
|
http:
|
||||||
paths:
|
paths:
|
||||||
- path: /
|
- path: /
|
||||||
@@ -145,5 +145,5 @@ spec:
|
|||||||
number: 9090
|
number: 9090
|
||||||
tls:
|
tls:
|
||||||
- hosts:
|
- hosts:
|
||||||
- sless-api.kube5s.ru
|
- sless.kube5s.ru
|
||||||
secretName: sless-operator-tls
|
secretName: sless-operator-tls
|
||||||
|
|||||||
@@ -0,0 +1,3 @@
|
|||||||
|
# 2026-03-17 00:00
|
||||||
|
# requirements.txt — зависимости для функции запуска SQL.
|
||||||
|
psycopg2-binary==2.9.9
|
||||||
@@ -0,0 +1,39 @@
|
|||||||
|
# 2026-03-17 00:00
|
||||||
|
# sql_runner.py — функция для выполнения SQL-операторов из входного события.
|
||||||
|
import os
|
||||||
|
import psycopg2
|
||||||
|
|
||||||
|
|
||||||
|
def run_sql(event):
|
||||||
|
# Выполняет список SQL-операторов в одной транзакции для атомарной инициализации схемы.
|
||||||
|
# Параметры подключения передаются раздельно, чтобы избежать ошибок парсинга DSN при спецсимволах.
|
||||||
|
pg_host = os.environ["PGHOST"]
|
||||||
|
pg_port = os.environ.get("PGPORT", "5432")
|
||||||
|
pg_database = os.environ["PGDATABASE"]
|
||||||
|
pg_user = os.environ["PGUSER"]
|
||||||
|
pg_password = os.environ["PGPASSWORD"]
|
||||||
|
pg_sslmode = os.environ.get("PGSSLMODE", "require")
|
||||||
|
statements = event.get("statements", [])
|
||||||
|
|
||||||
|
if not statements:
|
||||||
|
return {"error": "no statements provided"}
|
||||||
|
|
||||||
|
connection = psycopg2.connect(
|
||||||
|
host=pg_host,
|
||||||
|
port=pg_port,
|
||||||
|
dbname=pg_database,
|
||||||
|
user=pg_user,
|
||||||
|
password=pg_password,
|
||||||
|
sslmode=pg_sslmode,
|
||||||
|
)
|
||||||
|
try:
|
||||||
|
cursor = connection.cursor()
|
||||||
|
for statement in statements:
|
||||||
|
cursor.execute(statement)
|
||||||
|
connection.commit()
|
||||||
|
return {"ok": True, "executed": len(statements)}
|
||||||
|
except Exception as error:
|
||||||
|
connection.rollback()
|
||||||
|
return {"error": str(error)}
|
||||||
|
finally:
|
||||||
|
connection.close()
|
||||||
@@ -0,0 +1,73 @@
|
|||||||
|
|
||||||
|
# resource "nubes_lucee" "app1" {
|
||||||
|
# # Lucee-приложение, зависит от Postgres
|
||||||
|
# resource_name = "lucy_teststand_0"
|
||||||
|
# # resource_realm = "k8s-3.ext.nubes.ru"
|
||||||
|
# resource_realm = nubes_postgres.db2.resource_realm
|
||||||
|
# # resource_realm = "k8s-4-sandbox-nubes-ru"
|
||||||
|
# domain = "web-test-stand"
|
||||||
|
|
||||||
|
# git_path = "https://gitea-naeel.giteak8s.services.ngcloud.ru/naeel/testlucee"
|
||||||
|
|
||||||
|
# json_env = jsonencode({
|
||||||
|
# # 🔗 Настройки Data Source 'testds' для Lucee (Application.cfc)
|
||||||
|
# testds_class = "org.postgresql.Driver" # 📂 Драйвер БД
|
||||||
|
# testds_bundleName = "org.postgresql.jdbc" # 📦 Имя бандла JDBC
|
||||||
|
# testds_bundleVersion = "42.6.0" # 🔢 Версия драйвера
|
||||||
|
# testds_connectionString = "jdbc:postgresql://${nubes_postgres.db2.state_out_flat["internalConnect.master"]}:5432/postgres?sslmode=require" # 🚀 Строка подключения
|
||||||
|
# testds_username = nubes_postgres_user.db2_user.username # 👤 Логин
|
||||||
|
# testds_password = jsondecode(nubes_postgres.db2.vault_secrets["users"])[nubes_postgres_user.db2_user.username]["password"] # 🔑 Пароль
|
||||||
|
# testds_connectionLimit = "5" # 🚦 Лимит соединений
|
||||||
|
# testds_liveTimeout = "15" # ⏳ Таймаут жизни
|
||||||
|
# testds_validate = "false" # ✅ Валидация при запросе
|
||||||
|
# })
|
||||||
|
|
||||||
|
# resource_c_p_u = 300
|
||||||
|
# resource_memory = 512
|
||||||
|
# resource_instances = 1
|
||||||
|
# app_version = "5.4"
|
||||||
|
|
||||||
|
# depends_on = [nubes_postgres.db2]
|
||||||
|
# }
|
||||||
|
|
||||||
|
# resource "nubes_nodejs" "app3" {
|
||||||
|
# # NodeJS демо, работающий с тем же Postgres.
|
||||||
|
# resource_name = "node_01"
|
||||||
|
# resource_realm = nubes_postgres.db2.resource_realm
|
||||||
|
# domain = "node07"
|
||||||
|
# git_path = "https://gitea-naeel.giteak8s.services.ngcloud.ru/naeel/testnode.git"
|
||||||
|
# health_path = "/healthz"
|
||||||
|
# app_version = "23"
|
||||||
|
|
||||||
|
# json_env = jsonencode({
|
||||||
|
# # Переменные подключения к Postgres.
|
||||||
|
# PGHOST = nubes_postgres.db2.state_out_flat["internalConnect.master"]
|
||||||
|
# PGPORT = "5432"
|
||||||
|
# PGUSER = nubes_postgres_user.db2_user.username
|
||||||
|
# PGPASSWORD = jsondecode(nubes_postgres.db2.vault_secrets["users"])[nubes_postgres_user.db2_user.username]["password"]
|
||||||
|
# PGDATABASE = nubes_postgres_database.db2_app.db_name
|
||||||
|
# PGSSLMODE = "require"
|
||||||
|
# DATABASE_URL = format(
|
||||||
|
# "postgresql://%s:%s@%s:5432/%s?sslmode=require",
|
||||||
|
# nubes_postgres_user.db2_user.username,
|
||||||
|
# jsondecode(nubes_postgres.db2.vault_secrets["users"])[nubes_postgres_user.db2_user.username]["password"],
|
||||||
|
# nubes_postgres.db2.state_out_flat["internalConnect.master"],
|
||||||
|
# nubes_postgres_database.db2_app.db_name
|
||||||
|
# )
|
||||||
|
# })
|
||||||
|
|
||||||
|
# resource_c_p_u = 300
|
||||||
|
# resource_memory = 256
|
||||||
|
# resource_instances = 1
|
||||||
|
|
||||||
|
# depends_on = [nubes_postgres.db2]
|
||||||
|
# }
|
||||||
|
|
||||||
|
# output "pg_vault_secrets" {
|
||||||
|
# value = nubes_postgres.db2.vault_secrets
|
||||||
|
# sensitive = true
|
||||||
|
# }
|
||||||
|
|
||||||
|
# terraform output -json pg_vault_secrets
|
||||||
|
|
||||||
|
|
||||||
@@ -0,0 +1,58 @@
|
|||||||
|
// 2026-03-17 17:05
|
||||||
|
// main.tf — провайдеры и переменные для Nubes + sless.
|
||||||
|
terraform {
|
||||||
|
required_providers {
|
||||||
|
nubes = {
|
||||||
|
source = "terra.k8c.ru/nubes/nubes"
|
||||||
|
version = "5.0.19"
|
||||||
|
}
|
||||||
|
sless = {
|
||||||
|
source = "terra.k8c.ru/naeel/sless"
|
||||||
|
version = "~> 0.1.18"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
variable "api_token" {
|
||||||
|
type = string
|
||||||
|
sensitive = true
|
||||||
|
description = "Nubes API token"
|
||||||
|
}
|
||||||
|
variable "s3_uid" {
|
||||||
|
type = string
|
||||||
|
sensitive = true
|
||||||
|
description = "Nubes S3 UID"
|
||||||
|
}
|
||||||
|
variable "realm" {
|
||||||
|
type = string
|
||||||
|
sensitive = true
|
||||||
|
description = "resource_realm parameter for nubes_postgres resource"
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2026-03-18 — pg_user/pg_password помечены optional (default="") для сверки.
|
||||||
|
// Реальные credentials берутся из vault_secrets через locals в resources.tf.
|
||||||
|
variable "pg_user" {
|
||||||
|
type = string
|
||||||
|
sensitive = true
|
||||||
|
default = ""
|
||||||
|
description = "Только для сверки. Реальный username из nubes_postgres_user.pg_user.username. Должен совпадать с vault."
|
||||||
|
}
|
||||||
|
|
||||||
|
variable "pg_password" {
|
||||||
|
type = string
|
||||||
|
sensitive = true
|
||||||
|
default = ""
|
||||||
|
description = "Только для сверки. Реальный пароль из vault_secrets. Должен совпадать с tfvars."
|
||||||
|
}
|
||||||
|
|
||||||
|
provider "nubes" {
|
||||||
|
api_token = var.api_token
|
||||||
|
api_endpoint = "https://deck-api-test.ngcloud.ru/api/v1/index.cfm"
|
||||||
|
}
|
||||||
|
|
||||||
|
provider "sless" {
|
||||||
|
endpoint = "https://sless.kube5s.ru"
|
||||||
|
token = var.api_token
|
||||||
|
nubes_endpoint = "https://deck-api-test.ngcloud.ru/api/v1"
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,97 @@
|
|||||||
|
// 2026-03-18 — добавлены locals для извлечения credentials из vault_secrets (без хардкода).
|
||||||
|
// Для сверки хардкод остаётся в terraform.tfvars на этапе разработки.
|
||||||
|
// sless_function и sless_job закомментированы — сначала проверяется сетевое соединение.
|
||||||
|
|
||||||
|
# Актуальные credentials из vault_secrets (authoritatively) — vault синхронизирован с кластером.
|
||||||
|
# Структура vault_secrets["users"]: JSON-строка {"username": {"password": "...", "username": "..."}}
|
||||||
|
locals {
|
||||||
|
pg_creds_map = jsondecode(nubes_postgres.npg.vault_secrets["users"])
|
||||||
|
pg_username = nubes_postgres_user.pg_user.username
|
||||||
|
pg_password = local.pg_creds_map[local.pg_username]["password"]
|
||||||
|
pg_host = nubes_postgres.npg.state_out_flat["internalConnect.master"]
|
||||||
|
pg_database = nubes_postgres_database.db.db_name
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "nubes_postgres" "npg" {
|
||||||
|
resource_name = "teststand-pg-2"
|
||||||
|
# s3_uid = "s01325"
|
||||||
|
s3_uid = var.s3_uid
|
||||||
|
resource_realm = var.realm
|
||||||
|
resource_instances = 1
|
||||||
|
resource_memory = 512
|
||||||
|
resource_c_p_u = 500
|
||||||
|
resource_disk = "1"
|
||||||
|
app_version = "17"
|
||||||
|
json_parameters = jsonencode({
|
||||||
|
log_connections = "off"
|
||||||
|
log_disconnections = "off"
|
||||||
|
})
|
||||||
|
enable_pg_pooler_master = false
|
||||||
|
enable_pg_pooler_slave = false
|
||||||
|
allow_no_s_s_l = false
|
||||||
|
auto_scale = false
|
||||||
|
auto_scale_percentage = 10
|
||||||
|
auto_scale_tech_window = 0
|
||||||
|
auto_scale_quota_gb = "1"
|
||||||
|
need_external_address_master = false
|
||||||
|
|
||||||
|
# suspend_on_destroy = false
|
||||||
|
operation_timeout = "11m"
|
||||||
|
adopt_existing_on_create = true
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "nubes_postgres_user" "pg_user" {
|
||||||
|
postgres_id = nubes_postgres.npg.id
|
||||||
|
username = "u-user0"
|
||||||
|
role = "ddl_user"
|
||||||
|
adopt_existing_on_create = true
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "nubes_postgres_database" "db" {
|
||||||
|
postgres_id = nubes_postgres.npg.id
|
||||||
|
db_name = "db_terra"
|
||||||
|
db_owner = nubes_postgres_user.pg_user.username
|
||||||
|
adopt_existing_on_create = true
|
||||||
|
# suspend_on_destroy = false
|
||||||
|
}
|
||||||
|
|
||||||
|
# Служебная функция выполняет SQL-операторы из event_json.
|
||||||
|
# Credentials берутся из locals (vault_secrets) — без хардкода.
|
||||||
|
# Для сверки хардкод остаётся в terraform.tfvars.
|
||||||
|
resource "sless_function" "postgres_sql_runner_create_table" {
|
||||||
|
name = "pg-create-table-runner"
|
||||||
|
runtime = "python3.11"
|
||||||
|
entrypoint = "sql_runner.run_sql"
|
||||||
|
memory_mb = 128
|
||||||
|
timeout_sec = 30
|
||||||
|
|
||||||
|
env_vars = {
|
||||||
|
PGHOST = local.pg_host
|
||||||
|
PGPORT = "5432"
|
||||||
|
PGDATABASE = local.pg_database
|
||||||
|
PGUSER = local.pg_username
|
||||||
|
PGPASSWORD = local.pg_password
|
||||||
|
PGSSLMODE = "require"
|
||||||
|
# Для сверки (должно совпадать с vault):
|
||||||
|
# PGUSER = var.pg_user
|
||||||
|
# PGPASSWORD = var.pg_password
|
||||||
|
}
|
||||||
|
|
||||||
|
source_dir = "${path.module}/code/sql-runner"
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "sless_job" "postgres_table_init_job" {
|
||||||
|
name = "pg-create-table-job-main-v13"
|
||||||
|
function = sless_function.postgres_sql_runner_create_table.name
|
||||||
|
wait_timeout_sec = 180
|
||||||
|
run_id = 13
|
||||||
|
|
||||||
|
event_json = jsonencode({
|
||||||
|
statements = [
|
||||||
|
"CREATE TABLE IF NOT EXISTS terraform_demo_table (id serial PRIMARY KEY, title text NOT NULL, created_at timestamp DEFAULT now())"
|
||||||
|
]
|
||||||
|
})
|
||||||
|
|
||||||
|
depends_on = [nubes_postgres_database.db]
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,51 @@
|
|||||||
|
# 2026-03-18 — debug pod для проверки psql-соединения из namespace функций.
|
||||||
|
# Запускается разово. Подключается к тому же postgres, что и sless_function.
|
||||||
|
# kubectl apply -f /tmp/pg-debug-pod.yaml
|
||||||
|
# kubectl logs -n sless-fn-sless-ffd1f598c169b0ae pg-debug-pod
|
||||||
|
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Pod
|
||||||
|
metadata:
|
||||||
|
name: pg-debug-pod
|
||||||
|
namespace: sless-fn-sless-ffd1f598c169b0ae
|
||||||
|
labels:
|
||||||
|
purpose: debug-postgres-connectivity
|
||||||
|
spec:
|
||||||
|
restartPolicy: Never
|
||||||
|
containers:
|
||||||
|
- name: psql
|
||||||
|
image: postgres:17-alpine
|
||||||
|
command:
|
||||||
|
- sh
|
||||||
|
- -c
|
||||||
|
- |
|
||||||
|
echo "=== Testing TCP connectivity to postgres ==="
|
||||||
|
nc -zv -w5 $PGHOST 5432 && echo "TCP OK" || echo "TCP FAILED"
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo "=== Testing psql connection ==="
|
||||||
|
PGCONNECT_TIMEOUT=10 psql \
|
||||||
|
"host=$PGHOST port=$PGPORT dbname=$PGDATABASE user=$PGUSER sslmode=$PGSSLMODE" \
|
||||||
|
--command="SELECT current_user, current_database(), version();" \
|
||||||
|
2>&1
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo "=== Listing tables ==="
|
||||||
|
PGCONNECT_TIMEOUT=10 psql \
|
||||||
|
"host=$PGHOST port=$PGPORT dbname=$PGDATABASE user=$PGUSER sslmode=$PGSSLMODE" \
|
||||||
|
--command="\dt" \
|
||||||
|
2>&1
|
||||||
|
env:
|
||||||
|
- name: PGHOST
|
||||||
|
value: "postgresqlk8s-master.36875359-dcea-48c4-a593-b4531f20fe96.svc.cluster.local"
|
||||||
|
- name: PGPORT
|
||||||
|
value: "5432"
|
||||||
|
- name: PGDATABASE
|
||||||
|
value: "db_terra"
|
||||||
|
- name: PGUSER
|
||||||
|
value: "u-user0"
|
||||||
|
- name: PGPASSWORD
|
||||||
|
# Актуальный пароль из vault_secrets (совпадает с tfvars.pg_password на 2026-03-18)
|
||||||
|
value: "M03O6fRsngWcVHB2YGivyLfbfxoii2R21nyh2A2r7WSZS5deLwBgLKkc9Wk24Zyl"
|
||||||
|
- name: PGSSLMODE
|
||||||
|
value: "require"
|
||||||
@@ -0,0 +1,40 @@
|
|||||||
|
# 2026-03-17 13:05
|
||||||
|
# read_pg_user_secret.py — читает пароль пользователя managed PostgreSQL из k8s Secret.
|
||||||
|
# Используется из Terraform external data source, чтобы apply сам получал актуальный пароль
|
||||||
|
# даже для уже существующего пользователя, созданного вне текущего state.
|
||||||
|
|
||||||
|
import base64
|
||||||
|
import json
|
||||||
|
import subprocess
|
||||||
|
import sys
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
# Читаем query от Terraform external provider из stdin.
|
||||||
|
query = json.load(sys.stdin)
|
||||||
|
namespace = query["namespace"]
|
||||||
|
secret_name = query["secret"]
|
||||||
|
|
||||||
|
# kubectl уже настроен на удалённой машине; читаем ровно поле data.password.
|
||||||
|
result = subprocess.run(
|
||||||
|
[
|
||||||
|
"kubectl",
|
||||||
|
"get",
|
||||||
|
"secret",
|
||||||
|
"-n",
|
||||||
|
namespace,
|
||||||
|
secret_name,
|
||||||
|
"-o",
|
||||||
|
"jsonpath={.data.password}",
|
||||||
|
],
|
||||||
|
check=True,
|
||||||
|
capture_output=True,
|
||||||
|
text=True,
|
||||||
|
)
|
||||||
|
|
||||||
|
password = base64.b64decode(result.stdout.strip()).decode()
|
||||||
|
json.dump({"password": password}, sys.stdout)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
+6
-6
@@ -12,7 +12,7 @@
|
|||||||
| `sless_trigger` | Публикует функцию: тип `http` создаёт публичный URL, тип `cron` — запуск по расписанию. |
|
| `sless_trigger` | Публикует функцию: тип `http` создаёт публичный URL, тип `cron` — запуск по расписанию. |
|
||||||
| `sless_job` | Запускает функцию однократно и ожидает завершения. Используется для одноразовых операций: инициализация БД, миграции, пакетная обработка. |
|
| `sless_job` | Запускает функцию однократно и ожидает завершения. Используется для одноразовых операций: инициализация БД, миграции, пакетная обработка. |
|
||||||
|
|
||||||
Стандартная связка для HTTP API: `sless_function` + `sless_trigger` с `type = "http"` — в результате функция доступна по URL вида `https://sless-api.kube5s.ru/fn/<namespace>/<имя-функции>`.
|
Стандартная связка для HTTP API: `sless_function` + `sless_trigger` с `type = "http"` — в результате функция доступна по URL вида `https://sless.kube5s.ru/fn/<namespace>/<имя-функции>`.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -20,7 +20,7 @@
|
|||||||
|
|
||||||
- Terraform >= 1.0
|
- Terraform >= 1.0
|
||||||
- JWT-токен для аутентификации в sless API
|
- JWT-токен для аутентификации в sless API
|
||||||
- Доступ к `https://sless-api.kube5s.ru`
|
- Доступ к `https://sless.kube5s.ru`
|
||||||
|
|
||||||
## Конфигурация провайдера
|
## Конфигурация провайдера
|
||||||
|
|
||||||
@@ -28,7 +28,7 @@
|
|||||||
|
|
||||||
```hcl
|
```hcl
|
||||||
provider "sless" {
|
provider "sless" {
|
||||||
endpoint = "https://sless-api.kube5s.ru"
|
endpoint = "https://sless.kube5s.ru"
|
||||||
token = var.token
|
token = var.token
|
||||||
nubes_endpoint = "https://deck-api-test.ngcloud.ru/api/v1"
|
nubes_endpoint = "https://deck-api-test.ngcloud.ru/api/v1"
|
||||||
}
|
}
|
||||||
@@ -56,7 +56,7 @@ terraform init
|
|||||||
terraform apply -auto-approve
|
terraform apply -auto-approve
|
||||||
|
|
||||||
# Вызов HTTP-функции с передачей имени:
|
# Вызов HTTP-функции с передачей имени:
|
||||||
curl -s -X POST https://sless-api.kube5s.ru/fn/<namespace>/hello-http \
|
curl -s -X POST https://sless.kube5s.ru/fn/<namespace>/hello-http \
|
||||||
-H 'Content-Type: application/json' -d '{"name":"World"}'
|
-H 'Content-Type: application/json' -d '{"name":"World"}'
|
||||||
|
|
||||||
# Результат задания:
|
# Результат задания:
|
||||||
@@ -114,7 +114,7 @@ terraform init
|
|||||||
terraform apply -auto-approve
|
terraform apply -auto-approve
|
||||||
|
|
||||||
terraform output job_result
|
terraform output job_result
|
||||||
curl -s https://sless-api.kube5s.ru/fn/<namespace>/simple-py-time-display
|
curl -s https://sless.kube5s.ru/fn/<namespace>/simple-py-time-display
|
||||||
```
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
@@ -127,7 +127,7 @@ terraform init
|
|||||||
terraform apply -auto-approve
|
terraform apply -auto-approve
|
||||||
|
|
||||||
terraform output job_result
|
terraform output job_result
|
||||||
curl -s https://sless-api.kube5s.ru/fn/<namespace>/simple-node-time-display
|
curl -s https://sless.kube5s.ru/fn/<namespace>/simple-node-time-display
|
||||||
```
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|||||||
@@ -0,0 +1,194 @@
|
|||||||
|
# Примеры использования sless
|
||||||
|
|
||||||
|
## Обзор платформы
|
||||||
|
|
||||||
|
**sless** — система управления serverless-функциями на базе Kubernetes. Разработчик загружает код функции, платформа собирает из него Docker-образ, разворачивает его в кластере и предоставляет HTTP-эндпоинт для вызова. Всё описывается декларативно через Terraform.
|
||||||
|
|
||||||
|
### Основные ресурсы провайдера
|
||||||
|
|
||||||
|
| Ресурс | Назначение |
|
||||||
|
|---|---|
|
||||||
|
| `sless_function` | Описывает функцию: язык, точку входа, лимиты, переменные окружения. При создании загружает код и запускает его сборку в образ. Сама по себе недоступна снаружи — нужен триггер или задание. |
|
||||||
|
| `sless_trigger` | Публикует функцию: тип `http` создаёт публичный URL, тип `cron` — запуск по расписанию. |
|
||||||
|
| `sless_job` | Запускает функцию однократно и ожидает завершения. Используется для одноразовых операций: инициализация БД, миграции, пакетная обработка. |
|
||||||
|
|
||||||
|
Стандартная связка для HTTP API: `sless_function` + `sless_trigger` с `type = "http"` — в результате функция доступна по URL вида `https://sless.kube5s.ru/fn/<namespace>/<имя-функции>`.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Требования
|
||||||
|
|
||||||
|
- Terraform >= 1.0
|
||||||
|
- JWT-токен для аутентификации в sless API
|
||||||
|
- Доступ к `https://sless.kube5s.ru`
|
||||||
|
|
||||||
|
## Конфигурация провайдера
|
||||||
|
|
||||||
|
Во всех примерах файл `main.tf` содержит блок провайдера. Токен передаётся через переменную, значение которой задаётся в `terraform.tfvars`:
|
||||||
|
|
||||||
|
```hcl
|
||||||
|
provider "sless" {
|
||||||
|
endpoint = "https://sless.kube5s.ru"
|
||||||
|
token = var.token
|
||||||
|
nubes_endpoint = "https://deck-api-test.ngcloud.ru/api/v1"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Namespace функций вычисляется автоматически из JWT-токена: `sless-{sha256[:8]}`.
|
||||||
|
|
||||||
|
> **Перед запуском любого примера** откройте файл `terraform.tfvars` в директории примера и впишите свой токен Nubes API:
|
||||||
|
> ```hcl
|
||||||
|
> token = "ваш токен Nubes API"
|
||||||
|
> ```
|
||||||
|
> Токен выдаётся в личном кабинете Nubes. Файл `terraform.tfvars` добавлен в `.gitignore` — он не попадёт в репозиторий.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Примеры
|
||||||
|
|
||||||
|
### `hello-node` — минимальный пример на Node.js
|
||||||
|
|
||||||
|
Две независимые функции: HTTP-функция, возвращающая приветствие, и одноразовое задание, суммирующее набор чисел. Хорошая отправная точка для знакомства с платформой.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd hello-node
|
||||||
|
terraform init
|
||||||
|
terraform apply -auto-approve
|
||||||
|
|
||||||
|
# Вызов HTTP-функции с передачей имени:
|
||||||
|
curl -s -X POST https://sless.kube5s.ru/fn/<namespace>/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.kube5s.ru/fn/<namespace>/simple-py-time-display
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### `simple-node` — то же самое на Node.js 20
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd simple-node
|
||||||
|
terraform init
|
||||||
|
terraform apply -auto-approve
|
||||||
|
|
||||||
|
terraform output job_result
|
||||||
|
curl -s https://sless.kube5s.ru/fn/<namespace>/simple-node-time-display
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### `notes-python` — CRUD API на Python с PostgreSQL
|
||||||
|
|
||||||
|
Полноценное приложение: инициализация схемы базы данных через задания, CRUD-функция для работы с записями, отдельная функция для получения списка.
|
||||||
|
|
||||||
|
**Переменные:**
|
||||||
|
|
||||||
|
| Переменная | Описание | Значение по умолчанию |
|
||||||
|
|---|---|---|
|
||||||
|
| `pg_dsn` | Строка подключения к PostgreSQL | `postgres://sless:sless-pg-password@postgres.sless.svc.cluster.local:5432/sless?sslmode=disable` |
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd notes-python
|
||||||
|
terraform init
|
||||||
|
terraform apply -auto-approve
|
||||||
|
|
||||||
|
# Статус инициализации базы данных:
|
||||||
|
terraform output db_init_table_status
|
||||||
|
terraform output db_init_index_status
|
||||||
|
|
||||||
|
# Создать запись:
|
||||||
|
curl -s -X POST "$(terraform output -raw notes_url)/add?title=Hello&body=World"
|
||||||
|
|
||||||
|
# Получить список записей:
|
||||||
|
curl -s $(terraform output -raw notes_list_url)
|
||||||
|
|
||||||
|
# Обновить запись (id из предыдущего ответа):
|
||||||
|
curl -s -X POST "$(terraform output -raw notes_url)/update?id=1&title=Updated&body=New+body"
|
||||||
|
|
||||||
|
# Удалить запись:
|
||||||
|
curl -s -X POST "$(terraform output -raw notes_url)/delete?id=1"
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Полезные команды
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Посмотреть текущее состояние задеплоенных ресурсов:
|
||||||
|
terraform show
|
||||||
|
|
||||||
|
# Принудительно пересобрать функцию (например, после изменения кода):
|
||||||
|
terraform apply -replace=sless_function.<имя> -auto-approve
|
||||||
|
|
||||||
|
# Повторно запустить задание: увеличить значение run_id в .tf-файле, затем:
|
||||||
|
terraform apply -auto-approve
|
||||||
|
|
||||||
|
# Удалить все ресурсы примера:
|
||||||
|
terraform destroy -auto-approve
|
||||||
|
```
|
||||||
|
|
||||||
|
## Структура примера
|
||||||
|
|
||||||
|
```
|
||||||
|
<пример>/
|
||||||
|
├── main.tf — конфигурация провайдера
|
||||||
|
├── *.tf — ресурсы: функции, триггеры, задания
|
||||||
|
├── variables.tf — входные переменные
|
||||||
|
├── terraform.tfvars — значения переменных (не коммитится в git)
|
||||||
|
└── code/ — исходный код функций
|
||||||
|
```
|
||||||
@@ -10,7 +10,7 @@ variable "token" {
|
|||||||
variable "sless_endpoint" {
|
variable "sless_endpoint" {
|
||||||
description = "Endpoint sless API"
|
description = "Endpoint sless API"
|
||||||
type = string
|
type = string
|
||||||
default = "https://sless-api.kube5s.ru"
|
default = "https://sless.kube5s.ru"
|
||||||
}
|
}
|
||||||
|
|
||||||
variable "nubes_endpoint" {
|
variable "nubes_endpoint" {
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ terraform {
|
|||||||
}
|
}
|
||||||
|
|
||||||
provider "sless" {
|
provider "sless" {
|
||||||
endpoint = "https://sless-api.kube5s.ru"
|
endpoint = "https://sless.kube5s.ru"
|
||||||
token = var.token
|
token = var.token
|
||||||
nubes_endpoint = "https://deck-api-test.ngcloud.ru/api/v1"
|
nubes_endpoint = "https://deck-api-test.ngcloud.ru/api/v1"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ terraform {
|
|||||||
}
|
}
|
||||||
|
|
||||||
provider "sless" {
|
provider "sless" {
|
||||||
endpoint = "https://sless-api.kube5s.ru"
|
endpoint = "https://sless.kube5s.ru"
|
||||||
token = var.token
|
token = var.token
|
||||||
nubes_endpoint = "https://deck-api-test.ngcloud.ru/api/v1"
|
nubes_endpoint = "https://deck-api-test.ngcloud.ru/api/v1"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ terraform {
|
|||||||
|
|
||||||
# sless провайдер подключается к API кластера.
|
# sless провайдер подключается к API кластера.
|
||||||
provider "sless" {
|
provider "sless" {
|
||||||
endpoint = "https://sless-api.kube5s.ru"
|
endpoint = "https://sless.kube5s.ru"
|
||||||
token = var.token
|
token = var.token
|
||||||
nubes_endpoint = "https://deck-api-test.ngcloud.ru/api/v1"
|
nubes_endpoint = "https://deck-api-test.ngcloud.ru/api/v1"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ terraform {
|
|||||||
}
|
}
|
||||||
|
|
||||||
provider "sless" {
|
provider "sless" {
|
||||||
endpoint = "https://sless-api.kube5s.ru"
|
endpoint = "https://sless.kube5s.ru"
|
||||||
token = var.token
|
token = var.token
|
||||||
nubes_endpoint = "https://deck-api-test.ngcloud.ru/api/v1"
|
nubes_endpoint = "https://deck-api-test.ngcloud.ru/api/v1"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ terraform {
|
|||||||
}
|
}
|
||||||
|
|
||||||
provider "sless" {
|
provider "sless" {
|
||||||
endpoint = "https://sless-api.kube5s.ru"
|
endpoint = "https://sless.kube5s.ru"
|
||||||
token = var.token
|
token = var.token
|
||||||
nubes_endpoint = "https://deck-api-test.ngcloud.ru/api/v1"
|
nubes_endpoint = "https://deck-api-test.ngcloud.ru/api/v1"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ terraform {
|
|||||||
}
|
}
|
||||||
|
|
||||||
provider "sless" {
|
provider "sless" {
|
||||||
endpoint = "https://sless-api.kube5s.ru"
|
endpoint = "https://sless.kube5s.ru"
|
||||||
token = var.token
|
token = var.token
|
||||||
nubes_endpoint = "https://deck-api.ngcloud.ru/api/v1"
|
nubes_endpoint = "https://deck-api-test.ngcloud.ru/api/v1"
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user