Python
Kubiy ejecuta aplicaciones Python dentro de un virtualenv persistente gestionado por systemd. El virtualenv se crea en el servidor y se reutiliza entre deploys, lo que hace que los deploys subsecuentes sean más rápidos.
Presets disponibles
python [archivo]
Ejecuta un archivo Python directamente. Útil para aplicaciones simples o scripts que incluyen su propio servidor HTTP (por ejemplo, con http.server o frameworks que usan app.run()).
| Parámetro | Valor |
|---|---|
startMode | python |
| Target por defecto | main.py |
| Build por defecto | pip install -r requirements.txt |
Ejemplo de configuración:
Preset: python [archivo]
Archivo: app.py
El proceso arranca como: python app.py
Ejemplo de app Flask con este modo:
import os
from flask import Flask
app = Flask(__name__)
@app.route('/health')
def health():
return {'status': 'ok'}
if __name__ == '__main__':
port = int(os.environ.get('PORT', 8000))
app.run(host='0.0.0.0', port=port)
Este modo no es recomendable para producción con tráfico real. El servidor de desarrollo de Flask o Django no está diseñado para manejar concurrencia. Usa gunicorn o uvicorn en producción.
gunicorn
Ejecuta la app con Gunicorn, el servidor WSGI de referencia para Python. Ideal para aplicaciones Django, Flask o cualquier app compatible con WSGI.
| Parámetro | Valor |
|---|---|
startMode | gunicorn |
| Target por defecto | app:app |
| Build por defecto | pip install -r requirements.txt |
Formato del target: modulo:variable_de_la_app
| Ejemplo | Significado |
|---|---|
app:app | En app.py, la variable app |
myproject.wsgi:application | Django standard |
src.main:create_app() | App factory pattern |
Ejemplo de configuración para Django:
Preset: gunicorn
Target: myproject.wsgi:application
Ejemplo de configuración para Flask:
Preset: gunicorn
Target: app:app
Kubiy ejecuta gunicorn con: gunicorn --bind 0.0.0.0:$PORT <target>
Gunicorn se instala automáticamente en el virtualenv de tu app, aunque no esté en tu requirements.txt. No necesitas agregarlo.
uvicorn
Ejecuta la app con Uvicorn, el servidor ASGI de alto rendimiento. Ideal para FastAPI, Starlette y cualquier app compatible con ASGI.
| Parámetro | Valor |
|---|---|
startMode | uvicorn |
| Target por defecto | main:app |
| Build por defecto | pip install -r requirements.txt |
Formato del target: modulo:variable_de_la_app
| Ejemplo | Significado |
|---|---|
main:app | En main.py, la variable app |
src.api.main:app | Estructura de paquetes |
Ejemplo de configuración para FastAPI:
Preset: uvicorn
Target: main:app
Kubiy ejecuta uvicorn con: uvicorn --host 0.0.0.0 --port $PORT <target>
Uvicorn se instala automáticamente en el virtualenv de tu app, aunque no esté en tu requirements.txt. No necesitas agregarlo.
Puerto
El puerto se pasa automáticamente a gunicorn y uvicorn. Para el modo python, debes leerlo desde la variable de entorno:
port = int(os.environ.get('PORT', 8000))
El puerto por defecto es 8000.
Virtualenv
Kubiy crea un virtualenv en el servidor la primera vez que haces deploy. Las instalaciones con pip van a ese virtualenv. En deploys subsecuentes, el virtualenv se reutiliza, por lo que solo se instalan las dependencias nuevas.
Si cambias la versión de Python o quieres un virtualenv limpio, contacta a soporte o reconecta la app (lo que recrea el entorno desde cero).
Requirements
El archivo requirements.txt debe estar en la raíz del proyecto (o en el subdirectorio configurado). El formato estándar funciona correctamente:
flask==3.0.0
sqlalchemy==2.0.23
psycopg2-binary==2.9.9
También puedes usar requirements-prod.txt u otro archivo cambiando el Build Command:
pip install -r requirements-prod.txt
Build Command
Si dejas el campo vacío, Kubiy ejecuta:
pip install -r requirements.txt
Si especificas un Build Command, ese comando reemplaza la instalación automática. Sin embargo, gunicorn y uvicorn siempre se instalan automáticamente en el virtualenv, independientemente del Build Command.
Ejemplos comunes:
# Instalar desde un archivo alternativo
pip install -r requirements/prod.txt
# Con upgrade de pip primero
pip install --upgrade pip && pip install -r requirements.txt
# Múltiples archivos de requirements
pip install -r requirements.txt -r requirements-extras.txt
Ver la referencia completa de Build Command.
Casos de uso comunes
FastAPI
# main.py
from fastapi import FastAPI
import os
app = FastAPI()
@app.get("/health")
def health():
return {"status": "ok"}
# requirements.txt
fastapi==0.104.0
Configuración en Kubiy:
Preset: uvicorn
Target: main:app
Health: /health
Uvicorn se instala automáticamente; no necesitas incluirlo en requirements.txt.
Django
# myproject/settings.py
ALLOWED_HOSTS = ['*'] # o configura el dominio específico
Configuración en Kubiy:
Preset: gunicorn
Target: myproject.wsgi:application
Build Command: pip install -r requirements.txt && python manage.py collectstatic --noinput
ALLOWED_HOSTS debe incluir el dominio de Kubiy o * para que Django no rechace las peticiones.
Flask con app factory
# app/__init__.py
from flask import Flask
def create_app():
app = Flask(__name__)
# configuración...
return app
Preset: gunicorn
Target: app:create_app()
Aplicación en subdirectorio
Si tu app está en backend/:
Subdirectorio: backend
Preset: uvicorn
Target: main:app
Variables de entorno disponibles
| Variable | Descripción |
|---|---|
PORT | Puerto asignado (default 8000) |
APP_PORT | Alias de PORT |
KUBIY_DEPLOY_ID | ID del deploy actual |
KUBIY_APP_ID | ID de la aplicación |
Para leer variables en tu app:
import os
database_url = os.environ['DATABASE_URL']
secret_key = os.environ.get('SECRET_KEY', 'dev-key-insegura')
Health Check recomendado
# FastAPI
@app.get("/health")
def health():
return {"status": "ok"}
# Flask
@app.route("/health")
def health():
return {"status": "ok"}, 200
# Django (en urls.py)
from django.http import JsonResponse
def health(request):
return JsonResponse({"status": "ok"})
Troubleshooting
ModuleNotFoundError al iniciar
El módulo no se instaló. Causas comunes:
- No tienes
requirements.txt— Kubiy busca este archivo por defecto. - Error en
requirements.txt— Un paquete mal especificado puede hacer quepip installfalle silenciosamente para ese paquete. - Subdirectorio mal configurado — Kubiy busca
requirements.txten el subdirectorio configurado.
Gunicorn/uvicorn: "No module named X"
Aunque gunicorn y uvicorn se instalan automáticamente, sus dependencias opcionales no lo hacen. Si uvicorn necesita uvloop o httptools, agrégalos a requirements.txt:
uvicorn[standard]==0.24.0
Django: "DisallowedHost"
Agrega el dominio de Kubiy a ALLOWED_HOSTS en settings.py, o usa la variable de entorno para configurarlo:
import os
ALLOWED_HOSTS = os.environ.get('ALLOWED_HOSTS', '').split(',') + ['localhost']
Luego configura en Kubiy: ALLOWED_HOSTS=tu-app.kubiy.site
El virtualenv tiene versiones antiguas de paquetes
Si hiciste deploy antes y las versiones han cambiado en requirements.txt, puede que pip no actualice automáticamente. Usa el Build Command para forzar la actualización:
pip install --upgrade -r requirements.txt
Gunicorn timeout
Si tu app tarda en procesar requests, puedes configurar el timeout de gunicorn con el Build Command para variables de entorno, o usando un gunicorn.conf.py:
# gunicorn.conf.py
timeout = 120
workers = 2
Y en el Build Command agrega la configuración como env var o usa el archivo de configuración:
Preset: gunicorn
Target: app:app --config gunicorn.conf.py
Kubiy pasa el target directamente a gunicorn. Puedes agregar flags adicionales en el campo Target después del módulo WSGI, separados por espacios.
Puerto incorrecto en modo python
Si usas el preset python [archivo] y tu app no escucha en el puerto correcto, verifica que lees os.environ.get('PORT', 8000) y no un puerto hardcodeado.