feat: go1.23 runtime support
- runtimes/go1.23/server.go: HTTP-wrapper + job-runner (SLESS_MODE=job) - runtimes/go1.23/go.mod: module sless/fn (изолирует от корневого go.mod) - runtimes/go1.23/Dockerfile: multi-stage build (golang:1.23-alpine → alpine:3.20) - internal/builder/context.go: go1.23 в runtimeBaseImage + generateDockerfile - controllers/functionjob_controller.go: go1.23 runner (nil cmd + SLESS_MODE=job env) - api/v1alpha1/function_types.go: enum go1.21 → go1.23 - config/crd/bases/...: CRD обновлён - terraform/provider: OneOf обновлён - examples/hello-go: HTTP + job примеры на go1.23 - deployments/k8s/operator.yaml: v0.1.25
This commit is contained in:
+45
-15
@@ -35,16 +35,19 @@ func PrepareContext(zipData []byte, runtime string) (*bytes.Buffer, error) {
|
||||
// Это знание принадлежит builder-у, не HTTP-хендлеру.
|
||||
hasRequirements := false // requirements.txt — python3.11: pip install
|
||||
hasPackageJSON := false // package.json — nodejs20: npm install
|
||||
hasGoMod := false // go.mod — go1.23: пользователь может дать свой go.mod
|
||||
for _, f := range zr.File {
|
||||
switch f.Name {
|
||||
case "requirements.txt":
|
||||
hasRequirements = true
|
||||
case "package.json":
|
||||
hasPackageJSON = true
|
||||
case "go.mod":
|
||||
hasGoMod = true
|
||||
}
|
||||
}
|
||||
|
||||
dockerfileContent, err := generateDockerfile(runtime, hasRequirements, hasPackageJSON)
|
||||
dockerfileContent, err := generateDockerfile(runtime, hasRequirements, hasPackageJSON, hasGoMod)
|
||||
if err != nil {
|
||||
// Ошибка здесь означает неподдерживаемый runtime — 400 на уровне handler'а.
|
||||
return nil, err
|
||||
@@ -66,33 +69,60 @@ func runtimeBaseImage(runtime string) (string, error) {
|
||||
return "naeel/sless-runtime-python3.11:v0.1.1", nil
|
||||
case "nodejs20":
|
||||
return "naeel/sless-runtime-nodejs20:v0.1.2", nil
|
||||
case "go1.23":
|
||||
// Go использует builder-образ (содержит golang:1.23 + server.go).
|
||||
// Конечный образ multi-stage — alpine без компилятора.
|
||||
return "naeel/sless-runtime-go1.23:v0.1.0", nil
|
||||
default:
|
||||
return "", fmt.Errorf("unsupported runtime: %q (supported: python3.11, nodejs20)", runtime)
|
||||
return "", fmt.Errorf("unsupported runtime: %q (supported: python3.11, nodejs20, go1.23)", runtime)
|
||||
}
|
||||
}
|
||||
|
||||
// generateDockerfile генерирует Dockerfile для kaniko.
|
||||
// Базовый образ содержит HTTP-обёртку (server.py / server.js).
|
||||
// Пользовательский код копируется в /app/function/ поверх базового образа.
|
||||
// Базовый образ содержит HTTP-обёртку (server.py / server.js) или builder (для Go).
|
||||
// Пользовательский код копируется в /app/function/ (или /app/handler/ для Go) поверх базового образа.
|
||||
// Зависимости устанавливаются ПОСЛЕ COPY — чтобы кеш слоёв работал при повторных сборках.
|
||||
func generateDockerfile(runtime string, hasRequirements bool, hasPackageJSON bool) ([]byte, error) {
|
||||
func generateDockerfile(runtime string, hasRequirements bool, hasPackageJSON bool, hasGoMod bool) ([]byte, error) {
|
||||
baseImage, err := runtimeBaseImage(runtime)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
content := fmt.Sprintf("FROM %s\nCOPY . /app/function/\n", baseImage)
|
||||
|
||||
switch runtime {
|
||||
case "python3.11":
|
||||
if hasRequirements {
|
||||
content += "RUN pip install --no-cache-dir -r /app/function/requirements.txt\n"
|
||||
}
|
||||
case "nodejs20":
|
||||
if hasPackageJSON {
|
||||
// cd нужен т.к. npm install читает package.json из текущей директории
|
||||
content += "RUN cd /app/function && npm install --omit=dev\n"
|
||||
case "go1.23":
|
||||
// Go: multi-stage build.
|
||||
// base-образ содержит: server.go (package main) + go.mod (module sless/fn).
|
||||
// kaniko копирует пользовательский код в handler/ (package handler).
|
||||
// go build видит: /app/server.go + /app/handler/*.go под одним модулем sless/fn.
|
||||
// Если у пользователя есть go.mod — он кладётся в /app/handler/go.mod (игнорируется).
|
||||
content := fmt.Sprintf(
|
||||
"FROM %s AS builder\n"+
|
||||
"WORKDIR /app\n"+
|
||||
"COPY handler/ /app/handler/\n"+
|
||||
"RUN CGO_ENABLED=0 go build -o /server .\n"+
|
||||
"FROM alpine:3.20\n"+
|
||||
"COPY --from=builder /server /server\n"+
|
||||
"EXPOSE 8080\n"+
|
||||
"CMD [\"/server\"]\n",
|
||||
baseImage,
|
||||
)
|
||||
return []byte(content), nil
|
||||
|
||||
default: // python3.11, nodejs20
|
||||
content := fmt.Sprintf("FROM %s\nCOPY . /app/function/\n", baseImage)
|
||||
switch runtime {
|
||||
case "python3.11":
|
||||
if hasRequirements {
|
||||
content += "RUN pip install --no-cache-dir -r /app/function/requirements.txt\n"
|
||||
}
|
||||
case "nodejs20":
|
||||
if hasPackageJSON {
|
||||
// cd нужен т.к. npm install читает package.json из текущей директории
|
||||
content += "RUN cd /app/function && npm install --omit=dev\n"
|
||||
}
|
||||
}
|
||||
return []byte(content), nil
|
||||
}
|
||||
return []byte(content), nil
|
||||
}
|
||||
|
||||
// zipToTarGz принимает уже распарсенный *zip.Reader и упаковывает содержимое + Dockerfile в tar.gz.
|
||||
|
||||
Reference in New Issue
Block a user