// Изменено: 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 }