Привет, Хабр!

Сегодня будем разбираться с FissionGo — фреймворком, который обещает избавить нас от работы с деплоями, контейнерами и YAML‑манифестами.

Допустим, нам нужно запустить функцию — небольшой кусок кода, который что‑то делает (парсит JSON, отвечает на запрос, обрабатывает webhook). План работы был бы примерно таким:

  1. Написать код

  2. Запихнуть его в контейнер

  3. Написать манифесты

  4. Настроить сервисы

  5. Объяснить Kubernetes, как всем этим управлять

  6. Надеяться, что всё не упадёт в проде

А Fission убирает пункты 2–6. Просто пишем функцию, загружаем в Fission, привязываем HTTP‑триггер — и всё.

FissionGo — это Go‑специфичная среда для работы в Fission, которая компилирует Go‑код на лету, загружает его как плагин и исполняет в Kubernetes.

Установим

Первым делом — ставим Fission в Kubernetes.

kubectl create ns fission
kubectl apply -f https://github.com/fission/fission/releases/latest/download/fission.yaml

Ждём минутку, проверяем, что всё завелось:

fission version

Теперь добавляем Go‑окружение, чтобы можно было писать код.

fission environment create --name go \
  --image ghcr.io/fission/go-env-1.23 \
  --builder ghcr.io/fission/go-builder-1.23 --version 3

Первая Go-функция на Fission

Напишем простейший обработчик HTTP‑запросов.

package main

import (
    "net/http"
)

func Handler(w http.ResponseWriter, r *http.Request) {
    w.Write([]byte("Привет, Fission!"))
}

Загружаем в Fission:

fission fn create --name hello --env go --src hello.go --entrypoint Handler

Привязываем HTTP‑триггер:

fission httptrigger create --method GET --url "/hello" --function hello

Проверяем:

curl http://$FISSION_ROUTER/hello

Ожидаемый результат:

Привет, Fission!

Никакого Docker, никакого kubectl apply -f deployment.yaml, просто код → Fission → работающий HTTP‑эндпоинт.

Еще один пример

Напишем обработчик, который принимает JSON, меняет данные и отправляет ответ.

package main

import (
    "encoding/json"
    "net/http"
)

type Request struct {
    Name string `json:"name"`
}

type Response struct {
    Message string `json:"message"`
}

func Handler(w http.ResponseWriter, r *http.Request) {
    var req Request
    if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
        http.Error(w, "Invalid request", http.StatusBadRequest)
        return
    }

    response := Response{Message: "Привет, " + req.Name + "!"}
    w.Header().Set("Content-Type", "application/json")
    json.NewEncoder(w).Encode(response)
}

Загружаем в fission:

zip -r json_handler.zip json_handler.go
fission fn create --name json-handler --env go --src json_handler.zip --entrypoint Handler
fission httptrigger create --method POST --url "/json" --function json-handler
curl -X POST http://$FISSION_ROUTER/json -d '{"name": "Хабр"}' -H "Content-Type: application/json"

Ожидаемый ответ:

{"message": "Привет, Хабр!"}

Всё так же просто.

Ограничиваем ресурсы

Когда вы запускаете серверлес‑функцию, по умолчанию она может занять столько ресурсов, сколько ей захочется. В тестовой среде это не страшно, но в проде кто‑то запустит тяжёлый запрос, Kubernetes выделит под него кучу CPU, и... всё. У других сервисов просто не останется ресурсов.

Используем опции --mincpu, --maxcpu, --minmemory, --maxmemory. Они задают гарантированный минимум и максимальный предел использования ресурсов.

fission fn create --name optimized --env go --src function.zip --entrypoint Handler \
  --mincpu 100 --maxcpu 500 --minmemory 256 --maxmemory 1024

--mincpu 100 — минимальный лимит 100 millicores CPU (0.1 ядра). Даже если кластер загружен, Fission выделит минимум 0.1 ядра на выполнение функции.

--maxcpu 500 — если сервер загружен не полностью, функция может использовать до 500 millicores (0.5 ядра).

--minmemory 256 — минимальный гарантированный объём памяти — 256 MB.

--maxmemory 1024 — максимальный объём памяти — 1024 MB (1 GB).

Есть командаkubectl top pod, чтобы увидеть, сколько CPU и RAM реально использует функция:

kubectl top pod -l functionName=optimized

Вывод примерно такой:

NAME                          CPU(cores)   MEMORY(bytes)  
optimized-xyz123              250m         500Mi  

Окей, 250 millicores CPU и 500 MB памяти — значит, держимся в рамках.

Кэшируем ответы через Redis

Запросы к функции — это здорово. Но если много запросов с одинаковыми данными, было бы неплохо не пересчитывать одно и то же каждый раз.

Допустим, есть функция, которая считает сложные данные. Сначала без кэша:

package main

import (
    "fmt"
    "net/http"
    "time"
)

func Handler(w http.ResponseWriter, r *http.Request) {
    time.Sleep(2 * time.Second) // Имитируем тяжелый расчёт
    fmt.Fprintf(w, "Рассчитали ответ!")
}

Запускаем 10 запросов, и все ждут по 2 секунды.

Используем Redis, чтобы кешировать результат:

package main

import (
    "fmt"
    "github.com/go-redis/redis/v8"
    "context"
    "net/http"
    "time"
)

var ctx = context.Background()
var client = redis.NewClient(&redis.Options{
    Addr: "redis:6379",
})

func Handler(w http.ResponseWriter, r *http.Request) {
    cached, err := client.Get(ctx, "result").Result()
    if err == nil {
        fmt.Fprintf(w, "Из кеша: %s", cached)
        return
    }

    // Эмуляция тяжелого расчёта
    time.Sleep(2 * time.Second)
    result := "Рассчитали ответ!"

    client.Set(ctx, "result", result, 10*time.Minute) // Кладём в кэш на 10 минут

    fmt.Fprintf(w, result)
}

Теперь первый запрос посчитает результат и положит его в Redis. Остальные просто будут его брать из кэша. А еще у Redis можно настроить автоочистку кеша, чтобы старые данные не занимали память.

Если у вас Kubernetes, но вам лень возиться с контейнерами и манифестами, FissionGo — хороший вариант.

Fission существует и на другие ЯП. Ознакомиться можно здесь.


Напоследок рекомендую обратить внимание на открытый урок «Управление зависимостями в Go — продвинутые техники и корпоративные паттерны». Вы узнаете, как эффективно управлять зависимостями, использовать прокси и локальный кэш, а также обеспечивать безопасность проектов при помощи контроля сумм. Записывайтесь по ссылке.

Список всех бесплатных уроков можно посмотреть в календаре.

Комментарии (0)