Fission es un framework serverless de código abierto para Kubernetes: escribes solo el código de la función y Fission lo carga en un contenedor de un entorno de ejecución (Python, Node.js, Go...) que mantiene precalentado, de modo que la primera invocación tarda del orden de milisegundos en lugar de segundos. En esta guía instalarás Fission con Helm, crearás funciones en Python y Node.js, una de ellas con dependencias, las expondrás con rutas HTTP, programarás una con un trigger de tipo cron y ajustarás el comportamiento de escalado.
Requisitos previos
- Un clúster de Kubernetes y
kubectlconfigurado con permisos de administrador. Para un único servidor sirve k3s sobre Ubuntu 24.04, por ejemplo en un VPS de CubePath con al menos 4 GB de RAM y 2 vCPU. - Un usuario no root con privilegios
sudoen la máquina desde la que gestionas el clúster. - Helm 3 instalado. En Ubuntu 24.04 puedes instalarlo con
sudo snap install helm --classic. - El paquete
zippara empaquetar funciones con dependencias:sudo apt install zip.
Comprueba el acceso al clúster antes de empezar:
kubectl get nodes
helm version --short
Paso 1: Instalar Fission con Helm
Define la versión que vas a instalar. Esta guía usa la 1.21.0; consulta la página de versiones por si hay una más reciente y usa la misma en todos los comandos:
export FISSION_VERSION=v1.21.0
export FISSION_NAMESPACE=fission
Desde la versión 1.18, el chart de Helm no instala las definiciones de recursos (CRD); se aplican primero con kubectl:
kubectl create -k "github.com/fission/fission/crds/v1?ref=${FISSION_VERSION}"
Añade el repositorio de charts de Fission e instala el chart fission-all en su propio namespace:
kubectl create namespace "$FISSION_NAMESPACE"
helm repo add fission-charts https://fission.github.io/fission-charts/
helm repo update
helm install fission fission-charts/fission-all \
--version "$FISSION_VERSION" \
--namespace "$FISSION_NAMESPACE" \
--set serviceType=NodePort,routerServiceType=NodePort
Espera a que los componentes estén listos:
kubectl wait --for=condition=Available deployment --all -n fission --timeout=300s
kubectl get pods -n fission
NAME READY STATUS RESTARTS AGE
buildermgr-5d8f9b7c6d-9kx2p 1/1 Running 0 70s
controller-7c9b8d6f5c-h4mzt 1/1 Running 0 70s
executor-6f7d9c8b5d-wq7ln 1/1 Running 0 70s
kubewatcher-5b8c7d9f6c-2xkqz 1/1 Running 0 70s
router-7d6c9b8f5d-l9tqm 1/1 Running 0 70s
storagesvc-6c8d7b9f5c-m2vxp 1/1 Running 0 70s
timer-5f9c8d7b6c-r8kzn 1/1 Running 0 70s
...
Los componentes principales son el router, que recibe las peticiones HTTP y las envía a la función; el executor, que gestiona los pods de las funciones; el buildermgr y storagesvc, que compilan y almacenan los paquetes con dependencias; y el timer, que ejecuta los triggers programados.
Paso 2: Instalar la CLI de Fission
La CLI fission es la forma habitual de crear entornos, funciones y triggers. Descarga el binario de la misma versión que el chart (en ARM, cambia amd64 por arm64):
curl -fsSLo fission "https://github.com/fission/fission/releases/download/${FISSION_VERSION}/fission-${FISSION_VERSION}-linux-amd64"
sudo install -m 755 fission /usr/local/bin/fission
rm fission
fission version
La salida muestra la versión del cliente y la del servidor; deben coincidir.
Para probar las funciones necesitas llegar al router. La forma más sencilla, que no expone nada a Internet, es un port-forward en segundo plano:
kubectl port-forward svc/router 8888:80 -n fission >/dev/null 2>&1 &
export FISSION_ROUTER=127.0.0.1:8888
Más adelante verás cómo publicarlo con un dominio.
Paso 3: Crear un entorno de Python
Un entorno es la imagen de contenedor con el runtime de un lenguaje. Fission mantiene un pool de pods de cada entorno ya arrancados y, al invocar una función por primera vez, carga su código en uno de ellos: por eso el arranque en frío es tan corto. La imagen builder es opcional y solo se usa para compilar paquetes con dependencias.
fission env create --name python \
--image ghcr.io/fission/python-env \
--builder ghcr.io/fission/python-builder \
--poolsize 3
--poolsize 3 indica cuántos pods precalentados mantiene el pool. Comprueba el entorno y sus pods:
fission env list
kubectl get pods -l environmentName=python -A
Los pods del pool aparecen en estado Running tras descargar la imagen.
Paso 4: Crear y probar una función en Python
El entorno de Python ejecuta la función main() del archivo y se basa en Flask, así que puedes leer la petición con flask.request. Crea la función:
mkdir -p ~/fission && cd ~/fission
nano hola.py
from flask import request
def main():
nombre = request.args.get("nombre", "mundo")
return f"Hola, {nombre}, desde Fission\n"
Regístrala en Fission y pruébala directamente, sin crear todavía una ruta HTTP:
fission function create --name hola --env python --code hola.py
fission function test --name hola
Hola, mundo, desde Fission
La primera invocación carga el código en un pod del pool; las siguientes reutilizan ese pod mientras siga activo.
Paso 5: Exponer la función con una ruta HTTP
Un trigger HTTP (en la CLI, route o httptrigger) asocia un método y una URL del router a una función:
fission route create --name hola --method GET --url /hola --function hola
fission route list
Llama a la función a través del router:
curl "http://${FISSION_ROUTER}/hola?nombre=CubePath"
Hola, CubePath, desde Fission
Para publicar las funciones en Internet, en lugar del port-forward crea un Ingress que apunte al servicio router del namespace fission con el controlador de ingress de tu clúster, y protégelo con HTTPS (por ejemplo, con cert-manager). El router no tiene autenticación propia: cualquier función con una ruta publicada es accesible para quien conozca la URL.
Paso 6: Crear una función con dependencias
Cuando la función necesita librerías externas, se empaqueta el código junto a un requirements.txt y un script de compilación. El builder del entorno instala las dependencias dentro del clúster y guarda el resultado como un paquete. Como ejemplo, una función que usa la librería humanize para formatear tamaños:
mkdir -p ~/fission/tamano && cd ~/fission/tamano
nano main.py
import humanize
from flask import request
def main():
try:
num_bytes = int(request.args.get("bytes", "0"))
except ValueError:
return "El parámetro bytes debe ser un número entero\n", 400
return f"{num_bytes} bytes son {humanize.naturalsize(num_bytes)}\n"
Declara la dependencia:
echo "humanize" > requirements.txt
Crea el script de compilación. El builder define SRC_PKG (el código fuente) y DEPLOY_PKG (el directorio que se desplegará):
nano build.sh
#!/bin/sh
pip3 install -r "${SRC_PKG}/requirements.txt" -t "${SRC_PKG}" && cp -r "${SRC_PKG}" "${DEPLOY_PKG}"
Hazlo ejecutable, empaqueta los tres archivos en la raíz del zip y crea el paquete:
chmod +x build.sh
zip -j tamano.zip main.py requirements.txt build.sh
fission package create --name tamano-pkg --env python \
--sourcearchive tamano.zip --buildcmd "./build.sh"
La compilación tarda unos segundos. Comprueba su estado:
fission package info --name tamano-pkg
Name: tamano-pkg
Environment: python
Status: succeeded
Build Logs:
Collecting humanize
...
Successfully installed humanize-4.12.3
Cuando el estado sea succeeded, crea la función indicando el punto de entrada con el formato módulo.función, y su ruta:
fission function create --name tamano --pkg tamano-pkg --entrypoint "main.main"
fission route create --name tamano --method GET --url /tamano --function tamano
curl "http://${FISSION_ROUTER}/tamano?bytes=3500000"
3500000 bytes son 3.5 MB
Si cambias el código, vuelve a generar el zip y actualiza el paquete con fission package update --name tamano-pkg --sourcearchive tamano.zip; Fission lo recompila y la función usa la versión nueva.
Paso 7: Añadir una función en Node.js
Cada lenguaje necesita su entorno. Crea el de Node.js:
fission env create --name nodejs --image ghcr.io/fission/node-env --poolsize 2
En este entorno la función exporta un manejador asíncrono que recibe context, donde context.request es la petición de Express:
cd ~/fission
nano hora.js
module.exports = async function (context) {
const zona = context.request.query.zona || 'Europe/Madrid';
try {
const hora = new Date().toLocaleTimeString('es-ES', { timeZone: zona });
return { status: 200, body: `Son las ${hora} en ${zona}\n` };
} catch {
return { status: 400, body: `Zona horaria no válida: ${zona}\n` };
}
};
Crea la función y su ruta, y pruébala:
fission function create --name hora --env nodejs --code hora.js
fission route create --name hora --method GET --url /hora --function hora
curl "http://${FISSION_ROUTER}/hora?zona=America/Mexico_City"
Son las 10:42:17 en America/Mexico_City
Paso 8: Programar funciones con triggers de tiempo
Un trigger de tiempo invoca una función según una expresión cron, sin necesidad de un CronJob de Kubernetes. Crea una función de tarea periódica:
nano tarea.py
import datetime
def main():
ahora = datetime.datetime.now(datetime.timezone.utc).isoformat()
print(f"Tarea programada ejecutada a las {ahora}", flush=True)
return "ok\n"
Regístrala y prográmala cada cinco minutos:
fission function create --name tarea --env python --code tarea.py
fission timer create --name cada-5-min --function tarea --cron "*/5 * * * *"
fission timer list
El componente timer interpreta la expresión en UTC. Pasados unos minutos, comprueba las ejecuciones en los logs de la función:
fission function log --name tarea
Tarea programada ejecutada a las 2026-09-25T10:45:00.012345+00:00
Tarea programada ejecutada a las 2026-09-25T10:50:00.009876+00:00
Paso 9: Ajustar el escalado y el arranque en frío
Fission tiene dos modos de ejecución (executors) y cada función usa uno:
| Executor | Cómo funciona | Arranque en frío | Úsalo para |
|---|---|---|---|
poolmgr (por defecto) | Carga la función en un pod precalentado del pool del entorno | Muy bajo | Funciones con tráfico irregular o bajo |
newdeploy | Crea un Deployment propio con autoescalado horizontal (HPA) | Alto si escala desde cero | Funciones con tráfico sostenido que necesitan varias réplicas |
Para el executor poolmgr, el parámetro importante es el tamaño del pool del entorno. Auméntalo si tienes muchas funciones distintas del mismo lenguaje:
fission env update --name python --poolsize 5
Para una función con carga constante, cámbiala a newdeploy con un mínimo de réplicas para evitar arranques en frío, un máximo, y los recursos que puede usar (CPU en milicores, memoria en MiB):
fission function update --name tamano \
--executortype newdeploy \
--minscale 1 --maxscale 5 \
--mincpu 100 --maxcpu 500 \
--minmemory 64 --maxmemory 256
Comprueba los pods de la función:
kubectl get pods -A -l functionName=tamano
Con --minscale 1 siempre hay al menos una réplica lista; con --minscale 0 la función escala a cero cuando no recibe tráfico y la primera petición espera a que arranque el pod.
Solución de problemas
fission function test devuelve un error 500. El código ha lanzado una excepción. Revisa fission function log --name <función>: allí aparece la traza de Python o Node.js. Un error habitual es que el archivo no defina main() en Python o que el --entrypoint no coincida con módulo.función.
El paquete se queda en failed. fission package info --name <paquete> muestra el log de compilación. Suele deberse a que build.sh no es ejecutable o no está en la raíz del zip (usa zip -j), o a un nombre de dependencia incorrecto en requirements.txt.
curl al router devuelve 404. La ruta no existe o no coincide el método. Compruébalo con fission route list. Si el error es de conexión, el port-forward se ha cerrado: vuelve a lanzarlo.
Los pods del entorno se quedan en ImagePullBackOff. El nodo no puede descargar la imagen desde ghcr.io. Revisa el nombre de la imagen con fission env list y la conectividad del nodo con kubectl describe pod <pod> en el namespace donde se ejecuta.
Conclusión
Has instalado Fission en Kubernetes, creado entornos de Python y Node.js, desplegado funciones sencillas y con dependencias, expuesto rutas HTTP, programado una tarea con un trigger de tiempo y ajustado el escalado según el tipo de carga. Como siguientes pasos, guarda la definición de entornos, funciones y triggers en archivos con fission spec init y fission spec apply para versionarla en Git, publica el router con un Ingress y HTTPS, y explora los triggers de colas de mensajes basados en KEDA para procesar eventos de Kafka o RabbitMQ.
