Instalación de Fn Project: Plataforma Serverless con Contenedores
Fn Project es una plataforma serverless nativa de contenedores, desarrollada originalmente por Oracle, que ejecuta cada función como un contenedor Docker independiente. Su diseño permite desplegar funciones en cualquier infraestructura Linux sin ataduras a proveedores cloud, con soporte para hot containers que reducen drásticamente la latencia de arranque en frío.
Requisitos Previos
- Ubuntu 20.04/22.04 o CentOS/Rocky Linux 8+
- Docker Engine 20.10+ con acceso sin sudo
- Al menos 2 GB de RAM (4 GB recomendado)
- Go 1.16+ (opcional, para funciones en Go)
- Acceso a internet para descargar imágenes base
- Acceso root o usuario con privilegios sudo
Instalación del Servidor Fn
El servidor Fn se ejecuta como un contenedor Docker:
# Instalar Docker si no está disponible
sudo apt-get update
sudo apt-get install -y docker.io curl
sudo systemctl enable docker
sudo systemctl start docker
sudo usermod -aG docker $USER
newgrp docker
# Iniciar el servidor Fn (descarga y arranca automáticamente)
curl -LSs https://raw.githubusercontent.com/fnproject/cli/master/install | sh
# Iniciar el servidor en segundo plano
fn start --detach
# Verificar que el servidor está corriendo
fn version
curl http://localhost:8080/version
Para control manual del servidor:
# Iniciar el servidor con logs detallados
fn start --log-level debug
# Verificar el estado del contenedor
docker ps | grep fnserver
# Ver logs del servidor
docker logs fnserver
# Detener el servidor
fn stop
Instalación de la CLI de Fn
Si la instalación anterior no incluyó la CLI:
# Descargar e instalar la CLI directamente
curl -LSs https://raw.githubusercontent.com/fnproject/cli/master/install | sh
# Verificar la versión instalada
fn version
# Configurar el contexto (servidor local por defecto)
fn list context
fn use context default
# Crear un contexto personalizado para servidor remoto
fn create context mi-servidor \
--provider default \
--api-url http://mi-servidor.ejemplo.com:8080 \
--registry mi-usuario-docker
fn use context mi-servidor
Desarrollo de Funciones
Crear la primera función
# Inicializar una nueva aplicación Fn
mkdir mis-funciones && cd mis-funciones
# Crear una función en Node.js
fn init --runtime node mi-saludo
cd mi-saludo
# Ver la estructura generada
ls -la
# func.js - código de la función
# func.yaml - metadatos
# package.json - dependencias
# Contenido del archivo func.js generado
cat func.js
Modificar la función con lógica personalizada:
# Reemplazar el contenido de func.js
cat > func.js << 'EOF'
// Función de procesamiento de pedidos
const fdk = require('@fnproject/fdk');
fdk.handle(async function(input) {
// Validar entrada
if (!input || !input.producto) {
return { error: "Se requiere el campo 'producto'" };
}
const precio = calcularPrecio(input.producto, input.cantidad || 1);
return {
producto: input.producto,
cantidad: input.cantidad || 1,
precio_total: precio,
timestamp: new Date().toISOString()
};
});
// Función auxiliar de cálculo
function calcularPrecio(producto, cantidad) {
const precios = { "servidor": 99.99, "vps": 19.99, "baremetal": 199.99 };
return (precios[producto] || 0) * cantidad;
}
EOF
# Crear aplicación en el servidor
fn create app mis-funciones
# Desplegar la función
fn --verbose deploy --app mis-funciones
Funciones en Python
# Crear función Python
fn init --runtime python3.9 analizador
cd analizador
cat > func.py << 'EOF'
import io
import json
import sys
# Leer datos de stdin (protocolo Fn por defecto)
def main():
datos = json.loads(sys.stdin.read() or '{}')
numeros = datos.get("numeros", [])
if not numeros:
print(json.dumps({"error": "Lista vacía"}))
return
resultado = {
"minimo": min(numeros),
"maximo": max(numeros),
"promedio": sum(numeros) / len(numeros),
"total": sum(numeros)
}
print(json.dumps(resultado))
if __name__ == "__main__":
main()
EOF
fn --verbose deploy --app mis-funciones
Invocar funciones
# Invocar función con datos de entrada
echo '{"producto": "vps", "cantidad": 3}' | fn invoke mis-funciones mi-saludo
# Invocar de forma síncrona y ver resultado
fn invoke mis-funciones analizador <<< '{"numeros": [1, 5, 3, 9, 7]}'
# Ver el log de la invocación
fn get logs mis-funciones mi-saludo <ID_LLAMADA>
# Listar funciones de la aplicación
fn list functions mis-funciones
Hot Containers y Rendimiento
Los hot containers mantienen el runtime activo entre invocaciones:
# Configurar idle timeout en func.yaml
cat > func.yaml << 'EOF'
# Configuración de la función con hot containers
schema_version: 20180708
name: mi-saludo
version: 0.0.2
runtime: node
entrypoint: node func.js
# Tiempo máximo de ejecución (segundos)
timeout: 30
# Tiempo que el contenedor permanece activo entre llamadas
idle_timeout: 30
# Recursos asignados
memory: 128
EOF
# Desplegar con configuración actualizada
fn deploy --app mis-funciones
# Verificar métricas de rendimiento
fn stats mis-funciones mi-saludo
Configuración de concurrencia para alta carga:
# Configurar anotaciones de concurrencia via API
curl -X PATCH http://localhost:8080/v2/fns/<ID_FUNCION> \
-H "Content-Type: application/json" \
-d '{"annotations": {"fnproject.io/fn/maxpending": 1000}}'
Triggers y Endpoints HTTP
Exponer funciones como endpoints HTTP:
# Crear un trigger HTTP para la función
fn create trigger mis-funciones mi-saludo mi-trigger \
--type http \
--source /pedidos
# Listar triggers configurados
fn list triggers mis-funciones
# Probar el endpoint HTTP directamente
curl -X POST http://localhost:8080/t/mis-funciones/pedidos \
-H "Content-Type: application/json" \
-d '{"producto": "baremetal", "cantidad": 1}'
# Crear trigger con método específico
fn create trigger mis-funciones analizador trigger-get \
--type http \
--source /analizar
Fn Flow para Orquestación
Fn Flow permite encadenar funciones en workflows complejos:
# Iniciar el servidor de Fn Flow
docker run --rm -d \
--name flowserver \
-p 8081:8081 \
-e no_proxy=fnserver \
--link fnserver \
fnproject/flow:latest
# Crear función que usa Flow (en Java/Maven)
fn init --runtime java flow-orchestrator
cd flow-orchestrator
# Configurar el servidor de Flow
fn config app mis-funciones COMPLETER_BASE_URL http://localhost:8081
Ejemplo de flujo básico en código Java:
# Verificar que el servidor de Flow responde
curl http://localhost:8081/ping
# Ver flujos activos
curl http://localhost:8081/graph
Despliegue en Producción
Configuración para entornos de producción:
# Crear archivo de configuración del servidor
cat > fn-config.yaml << 'EOF'
# Configuración del servidor Fn para producción
log_level: info
log_format: json
db_url: mysql://fn_user:password@db-host:3306/fn_db
mq_url: redis://redis-host:6379/
EOF
# Iniciar servidor con configuración de base de datos
docker run -d \
--name fnserver \
-p 8080:8080 \
-v /var/run/docker.sock:/var/run/docker.sock \
-e FN_DB_URL="mysql://fn_user:pass@mysql:3306/fn_db" \
-e FN_MQ_URL="redis://redis:6379/" \
-e FN_LOG_LEVEL="info" \
--restart unless-stopped \
fnproject/fnserver:latest
# Configurar Nginx como proxy inverso
sudo cat > /etc/nginx/sites-available/fn << 'EOF'
# Proxy para el servidor Fn
upstream fn_backend {
server 127.0.0.1:8080;
}
server {
listen 443 ssl;
server_name fn.mi-dominio.com;
location / {
proxy_pass http://fn_backend;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_read_timeout 300s;
}
}
EOF
sudo ln -s /etc/nginx/sites-available/fn /etc/nginx/sites-enabled/
sudo nginx -t && sudo systemctl reload nginx
Solución de Problemas
El servidor Fn no arranca:
# Verificar que Docker está corriendo
sudo systemctl status docker
# Revisar si el puerto 8080 está ocupado
ss -tlnp | grep 8080
# Ver logs del contenedor del servidor
docker logs fnserver --tail=50
Error al desplegar función (imagen no encontrada):
# Asegurarse de que Docker Hub está accesible
docker pull fnproject/node:jre11-latest
# Construir imagen localmente antes de desplegar
fn build
# Ver imágenes disponibles localmente
docker images | grep fnproject
Timeout en funciones:
# Aumentar el timeout en func.yaml
# timeout: 120 (segundos)
# Verificar recursos disponibles
docker stats fnserver --no-stream
free -h
Error de conexión a la base de datos:
# Probar conexión a MySQL
mysql -h db-host -u fn_user -p fn_db -e "SELECT 1"
# Revisar variables de entorno del contenedor
docker inspect fnserver | grep -A 20 "Env"
Conclusión
Fn Project ofrece una plataforma serverless completamente autoalojada con una arquitectura container-native que proporciona aislamiento perfecto entre funciones y soporte para cualquier lenguaje mediante imágenes Docker personalizadas. Los hot containers reducen significativamente la latencia de arranque en frío, haciendo de Fn una opción competitiva para aplicaciones que requieren baja latencia. La integración con Fn Flow permite construir workflows complejos encadenando múltiples funciones de manera declarativa.


