Files
sless/internal/config/config.go
T
“Naeel” e761439546 fix: immediate fixes from Opus review (v0.1.22)
- trigger: CronJob moved to deployNS (sless-fn-{userNS}), was tr.Namespace
  Reason: with NetworkPolicy default-deny, pod in user-ns can't reach
  Service in sless-fn-ns. Co-locating CronJob with Service guarantees
  connectivity regardless of NetworkPolicy configuration.
  handleTriggerDeletion updated consistently.

- trigger: pin curlimages/curl to 8.5.0 (was :latest)
  Reason: reproducibility, no unexpected behavior changes from image updates.

- function: sort env vars in buildDeployment (was non-deterministic map range)
  Reason: non-deterministic order caused k8s to detect container spec 'change'
  on every reconcile → unnecessary pod restarts. Sorted order is stable.

- function: cleanup kaniko Job in handleDeletion
  Reason: if Function deleted during Building phase, kaniko Job continued
  running, wasting CPU/memory and pushing an unused image.

- invoke: filter hop-by-hop headers in proxy response (RFC 2616 §13.5.1)
  Reason: Transfer-Encoding especially dangerous — forwarding it corrupts
  response body framing for the client.

- config: SLESS_API_TOKEN no longer required
  Reason: dead code — field loaded but never passed to any component.
  Auth uses validateJWT() middleware, not static token.

Namespace lifecycle: user namespaces preserved on destroy (not changed).
E2E: apply 4 resources + destroy clean. Operator v0.1.22 deployed.
2026-03-11 09:20:09 +04:00

133 lines
5.0 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// Изменено: 2026-03-11
// Конфигурация сервиса — читается из env переменных при старте.
// Все компоненты (API, builder, runner) получают конфиг через эту структуру.
// Используем env а не файлы конфигурации — стандарт для k8s (ConfigMap/Secret → env).
package config
import (
"fmt"
"os"
"strconv"
)
// Config — централизованная конфигурация всего сервиса.
type Config struct {
// APIPort — порт на котором слушает REST API сервер (default: 8080)
APIPort int
// PostgreSQL — параметры подключения к БД для хранения логов вызовов
PostgresDSN string
// S3 — параметры подключения к Ceph S3 для хранения кода функций
S3Endpoint string
S3AccessKey string
S3SecretKey string
S3Bucket string
S3UseSSL bool
// Registry — куда пушим собранные образы функций (DockerHub: "naeel", приватный: "host:port/prefix")
RegistryHost string
// RegistrySecret — имя k8s Secret типа kubernetes.io/dockerconfigjson
// Монтируется в kaniko Job для авторизации в registry.
// Создаётся через hack/create-registry-secret.sh
RegistrySecret string
// BuilderImage — образ для сборки функций (kaniko или buildah)
BuilderImage string
// IngressHost — базовый домен для HTTP триггеров (используется только
// если ExternalURL не задан, для обратной совместимости).
IngressHost string
// ExternalURL — публичный URL API сервера, например: https://sless-api.kube5s.ru
// Если задан, URL функции формируется как: {ExternalURL}/fn/{namespace}/{name}
// Это позволяет обойтись без wildcard DNS *.fn.
ExternalURL string
// APIToken — статический Bearer-токен (legacy, не используется после перехода на JWT).
// Поле сохранено для совместимости конфигурации.
// Аутентификация происходит в middleware/auth.go через validateJWT().
APIToken string
}
// Load читает конфиг из env переменных.
// Возвращает ошибку если обязательные переменные не заданы.
func Load() (*Config, error) {
cfg := &Config{
APIPort: 8080,
S3UseSSL: false,
BuilderImage: "gcr.io/kaniko-project/executor:latest",
}
// Опциональный порт API
if v := os.Getenv("API_PORT"); v != "" {
port, err := strconv.Atoi(v)
if err != nil {
return nil, fmt.Errorf("API_PORT must be a number: %w", err)
}
cfg.APIPort = port
}
// Обязательные параметры PostgreSQL
cfg.PostgresDSN = os.Getenv("POSTGRES_DSN")
if cfg.PostgresDSN == "" {
return nil, fmt.Errorf("POSTGRES_DSN is required")
}
// Обязательные параметры S3
cfg.S3Endpoint = os.Getenv("S3_ENDPOINT")
if cfg.S3Endpoint == "" {
return nil, fmt.Errorf("S3_ENDPOINT is required")
}
cfg.S3AccessKey = os.Getenv("S3_ACCESS_KEY")
if cfg.S3AccessKey == "" {
return nil, fmt.Errorf("S3_ACCESS_KEY is required")
}
cfg.S3SecretKey = os.Getenv("S3_SECRET_KEY")
if cfg.S3SecretKey == "" {
return nil, fmt.Errorf("S3_SECRET_KEY is required")
}
cfg.S3Bucket = os.Getenv("S3_BUCKET")
if cfg.S3Bucket == "" {
// Используем дефолтный бакет если не задан
cfg.S3Bucket = "sless-functions"
}
if v := os.Getenv("S3_USE_SSL"); v == "true" {
cfg.S3UseSSL = true
}
// Обязательный адрес registry
cfg.RegistryHost = os.Getenv("REGISTRY_HOST")
if cfg.RegistryHost == "" {
return nil, fmt.Errorf("REGISTRY_HOST is required")
}
// Secret с docker-кредами для kaniko (опционально — без него push в приватный registry упадёт)
cfg.RegistrySecret = os.Getenv("REGISTRY_SECRET")
if cfg.RegistrySecret == "" {
cfg.RegistrySecret = "sless-registry-auth"
}
// Опциональные параметры с дефолтами
if v := os.Getenv("BUILDER_IMAGE"); v != "" {
cfg.BuilderImage = v
}
// IngressHost — базовый домен для HTTP триггеров (fallback)
cfg.IngressHost = os.Getenv("INGRESS_HOST")
if cfg.IngressHost == "" {
cfg.IngressHost = "fn.kube5s.ru"
}
// ExternalURL — публичный URL сервиса для формирования URL функций
cfg.ExternalURL = os.Getenv("EXTERNAL_URL")
// APIToken — legacy поле, JWT от nubes читается напрямую из Authorization заголовка.
// Не required: auth middleware использует validateJWT, а не статический токен.
cfg.APIToken = os.Getenv("SLESS_API_TOKEN")
return cfg, nil
}