Ultima verificacion: Octubre 2025 | Docker: 24.x | Flask: 3.0.0 | PostgreSQL: 15 | Python: 3.11
El despliegue es frustrante. Logras que tu app Flask funcione perfectamente en tu maquina, luego pasas horas peleando con la configuracion del servidor, versiones de Python y dependencias faltantes cuando intentas desplegarla. Docker arregla esto empaquetando todo lo que tu app necesita en un contenedor que corre igual en todos lados.
Esta guia te muestra como containerizar un blog Flask y desplegarlo en Fly.io. Todo el proceso toma aproximadamente 15 minutos una vez que sabes lo que estas haciendo. Sin configuracion de servidor, sin infierno de dependencias, solo tu app corriendo en produccion.
Para Quien Es Esta Guia
Si tienes una app Flask que funciona localmente y quieres desplegarla sin los dolores de cabeza usuales, esto es para ti. Quizas estas cansado de debuggear por que algo funciona en tu laptop pero se rompe en produccion. Quizas quieres usar practicas modernas de despliegue sin pasar semanas aprendiendo DevOps.
Necesitaras conocimiento basico de Python y Flask. Si has construido una app Flask antes, estas listo. Deberias estar comodo con la linea de comandos, y necesitaras Docker Desktop instalado. Eso es todo.
Al final, tendras desarrollo local que coincide con produccion exactamente, despliegues que toman minutos en lugar de horas, y no mas conflictos de version de Python.
Por Que Docker Ayuda
Docker tiene mala fama por ser complejo, pero la idea central es simple: es una caja para tu codigo. Tu app va en la caja con todo lo que necesita para correr. Esa caja corre igual en tu laptop, en servidores CI, y en produccion.
Esta consistencia elimina categorias enteras de bugs. No mas discusiones de "pero funciona en mi maquina". No mas descubrir que produccion tiene Python 3.8 cuando desarrollaste en 3.11. No mas librerias de sistema faltantes que olvidaste documentar.
La verdadera victoria es la velocidad de despliegue. Una vez que tienes una configuracion Docker funcionando, desplegar se vuelve trivial. Sube tu codigo, construye la imagen, despliega. Los rollbacks son igual de faciles: redespliega la imagen anterior y vuelves a funcionar en segundos.
Que Estamos Construyendo
Vamos a tomar tu blog Flask existente y containerizarlo correctamente. Tendras desarrollo local con hot reloading para que puedas ver cambios instantaneamente. Usaremos PostgreSQL porque SQLite no esta hecho para produccion, sin importar lo que alguien te diga. Luego desplegaremos todo a Fly.io porque tienen un nivel gratuito generoso y corren tus contenedores Docker tal cual.
Preparando Tu App Flask
Primero, arreglemos tu requirements.txt. Si el tuyo solo dice "Flask" sin numero de version, estas buscando problemas. Esto es lo que necesitas para produccion:
Flask==3.0.0
Flask-SQLAlchemy==3.1.1
Flask-Migrate==4.0.5
psycopg2-binary==2.9.9
python-dotenv==1.0.0
gunicorn==21.2.0El servidor integrado de Flask es solo para desarrollo. Gunicorn es un servidor WSGI listo para produccion que puede manejar trafico real. El paquete psycopg2-binary te permite hablar con PostgreSQL. Todo tiene numeros de version porque "Flask" sin version significa que podrias obtener diferentes versiones en diferentes entornos, lo cual derrota todo el proposito.
Crea un archivo wsgi.py como punto de entrada de tu aplicacion:
from app import create_app
import os
app = create_app()
if __name__ == "__main__":
app.run(
host="0.0.0.0",
port=int(os.environ.get("PORT", 8080))
)Ese host="0.0.0.0" es importante. Significa "escuchar en todas las interfaces de red." El 127.0.0.1 por defecto solo escucha localmente, lo cual no funciona dentro de un contenedor. Este pequeno detalle ha causado horas de debugging para muchos desarrolladores.
Tu config.py deberia usar variables de entorno para cualquier cosa sensible:
import os
from dotenv import load_dotenv
basedir = os.path.abspath(os.path.dirname(__file__))
load_dotenv(os.path.join(basedir, '.env'))
class Config:
SECRET_KEY = os.environ.get('SECRET_KEY') or 'dev-secret-key-change-in-production'
SQLALCHEMY_DATABASE_URI = os.environ.get('DATABASE_URL') or \
f'sqlite:///{os.path.join(basedir, "app.db")}'
SQLALCHEMY_TRACK_MODIFICATIONS = False
# Algunos servicios usan postgres:// pero SQLAlchemy necesita postgresql://
if SQLALCHEMY_DATABASE_URI.startswith("postgres://"):
SQLALCHEMY_DATABASE_URI = SQLALCHEMY_DATABASE_URI.replace(
"postgres://", "postgresql://", 1
)Nunca hardcodees secretos. Usa variables de entorno. Tu yo futuro te lo agradecera cuando no subas accidentalmente tu contrasena de base de datos de produccion a GitHub.
Escribiendo un Dockerfile Que Funciona
Aqui hay un Dockerfile que funciona en produccion:
FROM python:3.11-slim as base
# El buffering de Python puede causar problemas en contenedores
ENV PYTHONUNBUFFERED=1 \
PYTHONDONTWRITEBYTECODE=1 \
PIP_NO_CACHE_DIR=1 \
PIP_DISABLE_PIP_VERSION_CHECK=1
WORKDIR /app
# Instalar dependencias del sistema
RUN apt-get update && apt-get install -y \
gcc \
postgresql-client \
&& rm -rf /var/lib/apt/lists/*
# Copiar requirements primero para mejor caching
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY . .
# Crear usuario no-root por seguridad
RUN useradd -m -u 1000 flaskuser && \
chown -R flaskuser:flaskuser /app
USER flaskuser
EXPOSE 8080
CMD ["gunicorn", "--bind", "0.0.0.0:8080", "--workers", "2", "wsgi:app"]El orden importa aqui. Copiar requirements.txt antes de copiar tu codigo significa que Docker puede cachear la capa de pip install. Cuando cambias tu codigo pero no tus dependencias, Docker reutiliza la capa cacheada con todos tus paquetes ya instalados. Esto convierte una reconstruccion de 5 minutos en una de 10 segundos.
Correr como usuario no-root es una mejor practica de seguridad. Si alguien compromete tu app, no tendran acceso root al contenedor.
Docker Compose para Desarrollo Local
Docker Compose te permite correr multiples contenedores juntos. Aqui hay un docker-compose.yml que configura tu app Flask con PostgreSQL:
version: '3.8'
services:
web:
build: .
ports:
- "8080:8080"
environment:
- DATABASE_URL=postgresql://postgres:postgres@db:5432/flask_blog
- SECRET_KEY=dev-secret-key
- FLASK_ENV=development
volumes:
- .:/app # Monta tu codigo para hot reloading
depends_on:
- db
command: flask run --host=0.0.0.0 --port=8080 --reload
db:
image: postgres:15-alpine
environment:
- POSTGRES_USER=postgres
- POSTGRES_PASSWORD=postgres
- POSTGRES_DB=flask_blog
ports:
- "5432:5432"
volumes:
- postgres_data:/var/lib/postgresql/data
volumes:
postgres_data:El mount de volumen (.:/app) significa que los cambios a tu codigo se reflejan inmediatamente sin reconstruir el contenedor. El volumen postgres_data asegura que tu base de datos persista incluso cuando detienes los contenedores.
Ese depends_on solo controla el orden de inicio. No espera a que PostgreSQL este listo, asi que tu app Flask podria crashear en el primer inicio. Solo reiniciala; esto es normal y solo pasa una vez.
Corriendo Todo
Construye tu imagen primero:
docker-compose buildLa primera construccion toma un rato mientras descarga imagenes base e instala paquetes. Las construcciones subsecuentes son mucho mas rapidas gracias al caching de capas de Docker.
Inicia la base de datos:
docker-compose up -d dbInicializa tus migraciones de base de datos si no lo has hecho ya:
docker-compose run --rm web flask db init
docker-compose run --rm web flask db migrate -m "Initial migration"
docker-compose run --rm web flask db upgradeAhora inicia todo:
docker-compose upVisita localhost:8080 y tu blog deberia estar corriendo. Si algo esta mal, los logs te diran exactamente que. Docker te muestra todo, lo cual es mucho mejor que fallas misteriosas de produccion sin mensajes de error.
Para ver solo los logs de tu app sin el ruido de PostgreSQL, usa docker-compose logs -f web.
Desplegando en Fly.io
Fly.io corre tu contenedor Docker real, no alguna version interpretada de el. Tienen un nivel gratuito que no requiere tarjeta de credito, lo cual es refrescante en 2025. Para una mirada mas profunda a las capacidades y limitaciones del nivel gratuito de Fly.io, incluyendo comparaciones de rendimiento y estrategias de escalado, revisa nuestra guia completa.
Instala su CLI primero.
En Mac:
brew install flyctlEn Windows, descarga el instalador de su sitio web o usa PowerShell:
pwsh -Command "iwr https://fly.io/install.ps1 -useb | iex"En Linux:
curl -L https://fly.io/install.sh | shPodrias necesitar agregar flyctl a tu PATH. El instalador te dira si esto es necesario y te mostrara el comando exacto a ejecutar.
Lanza tu app con flyctl launch. Cuando pregunte, dale a tu app un nombre (o deja que genere uno), elige una region cercana a ti o tus usuarios, di si a PostgreSQL (elige development para nivel gratuito), y di no a desplegar inmediatamente porque necesitamos configurar secretos primero.
Esto crea un archivo fly.toml que configura tu despliegue:
app = "your-app-name"
primary_region = "iad"
[build]
[env]
PORT = "8080"
[http_service]
internal_port = 8080
force_https = true
auto_stop_machines = true
auto_start_machines = true
min_machines_running = 0
[[vm]]
cpu_kind = "shared"
cpus = 1
memory_mb = 256La configuracion auto_stop_machines detiene tu app cuando nadie la esta usando, lo cual te ayuda a mantenerte dentro de los limites del nivel gratuito. Se inicia de nuevo automaticamente cuando alguien visita.
Configura tu clave secreta:
flyctl secrets set SECRET_KEY=$(openssl rand -hex 32)Despliega tu app:
flyctl deployEsto construye tu imagen Docker y la despliega. Toma aproximadamente 2 minutos. Cuando termine, ejecuta tus migraciones de base de datos:
flyctl ssh console -C "flask db upgrade"Abre tu app desplegada con flyctl open. Ahora tienes una app Flask en produccion con HTTPS, reinicios automaticos y respaldos de base de datos. Sin configuracion de servidor necesaria.
Problemas Comunes y Soluciones
Cuando ves "Port already in use", probablemente tienes otro contenedor corriendo. Ejecuta docker-compose down para detener todo, o simplemente cambia el puerto. A veces Docker Desktop se confunde y reiniciarlo lo arregla.
Los errores de conexion de base de datos al iniciar usualmente significan que Flask esta intentando conectarse antes de que PostgreSQL este listo. Solo reinicia el contenedor Flask. Podrias agregar logica de reintento a tu codigo de conexion de base de datos, pero para desarrollo local, un simple reinicio funciona bien.
Si Docker Desktop dice que no puede conectarse al daemon de Docker, reinicia Docker Desktop. Si eso no funciona, reinicia tu computadora. Docker Desktop tiene sus peculiaridades.
El nivel gratuito de Fly.io te da 256MB de RAM. Si tu app necesita mas, ejecuta flyctl scale memory 512. O optimiza tu app; probablemente no necesitas cargar todo en memoria de una vez.
Cuando los cambios no aparecen localmente, revisa ese mount de volumen en docker-compose.yml. En produccion, necesitas reconstruir y desplegar con flyctl deploy. Docker no detecta automaticamente cambios de codigo en produccion.
Consejos Que Ahorran Tiempo
Las imagenes Docker pueden volverse enormes. Usa imagenes base slim y agrega un archivo .dockerignore:
__pycache__
*.pyc
.git
.env
venv/
node_modules/
*.db
.DS_StoreAgrega logging apropiado a tu app. Cuando algo se rompe en produccion, los logs son tu unica ventana a lo que paso:
import logging
logging.basicConfig(level=logging.INFO)
app.logger.info('App starting up')La configuracion de Docker que acabas de crear es la misma que muchas empresas usan en produccion. Esta no es una configuracion de juguete; es despliegue de grado profesional que resulta ser gratis.
Lo Lograste
Has containerizado exitosamente una aplicacion Flask con una base de datos de produccion, hot reloading local y despliegue de un comando. Tu entorno de desarrollo ahora coincide con produccion exactamente, eliminando una clase entera de bugs de despliegue.
Este es el mismo flujo de trabajo que usan los equipos profesionales. El mismo Docker, el mismo proceso de despliegue, el mismo todo. La brecha entre proyectos hobby y aplicaciones de produccion es mas pequena de lo que la mayoria piensa. Es principalmente solo conocer las herramientas correctas.
Construye Tu Aplicacion Flask Primero
No tienes un blog Flask para dockerizar aun? Empieza aqui:
- Construye un Blog con Flask - Crea un blog Flask completo desde cero con PostgreSQL y autenticacion
- Construye un Portafolio con Flask - Aprende fundamentos de Flask con un sitio de portafolio profesional
- Construye E-Commerce con Flask - Domina Flask con un carrito de compras completo e integracion de pagos
Cada tutorial incluye prompts de IA paso a paso para guiarte en la construccion de aplicaciones Flask listas para produccion. Una vez que hayas construido tu app, regresa a esta guia para dockerizarla y desplegarla.
Ahora ve a construir algo genial.
Fred
AUTHORFull-stack developer with 10+ years building production applications. I've containerized dozens of production applications and learned these lessons the hard way.
Need a developer who gets it?
POC builds, vibe-coded fixes, and real engineering. Let's talk.
Hire Me →
