Tutorial Dockerizando una aplicación
Contenido
- 1 Prerrequisitos
- 2 Dockerizando una Aplicación Flask
- 3 Dockerizando una Aplicación Flask con Base de Datos usando Docker Compose
Prerrequisitos
Instalar Docker Compose
El primer paso es descargar la última versión de Docker Compose. Puedes descargar Docker Compose usando el siguiente comando, pero asegúrate de verificar la última versión en la página de lanzamientos de Docker Compose:
sudo curl -L "https://github.com/docker/compose/releases/download/2.20.2/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
Aplicar Permisos Ejecutables: asegúrate de que el archivo de Docker Compose tenga permisos ejecutables:
sudo chmod +x /usr/local/bin/docker-compose
Verificar la instalación de Docker Compose: para confirmar que Docker Compose se ha instalado correctamente, ejecuta:
docker-compose --version
Dockerizando una Aplicación Flask
En este tutorial, aprenderemos a dockerizar la aplicación Flask `flask_testing_project` que creamos en la práctica anterior. Con esta dockerización, podrás ejecutar tu aplicación Flask en un contenedor Docker, lo que facilita la portabilidad y la ejecución en diferentes entornos.
Para lograr esto, utilizaremos un archivo `Dockerfile` y un archivo de dependencias `requirements.txt` que especificarán cómo construir la imagen Docker y qué paquetes necesita la aplicación.
Estructura del Proyecto
La estructura inicial del proyecto `flask_testing_project` es la siguiente:
flask_testing_project/
│
├── app.py # Archivo principal de la aplicación Flask
├── templates/ # Directorio que contiene la plantilla HTML
│ └── tasks.html # Plantilla para mostrar y agregar tareas
├── tests/
│ ├── test_app.py # Pruebas unitarias usando pytest
│ └── test_interfaz.py # Pruebas de interfaz con Selenium
└── locustfile.py # Archivo para pruebas de carga con Locust
Para dockerizar la aplicación, añadiremos dos nuevos archivos:
- Dockerfile: Define las instrucciones para construir la imagen de Docker.
- requirements.txt: Contiene las dependencias de Python necesarias para ejecutar la aplicación.
La estructura de directorios después de añadir estos archivos será:
flask_testing_project/
│
├── app.py # Archivo principal de la aplicación Flask
├── templates/ # Directorio que contiene la plantilla HTML
│ └── tasks.html # Plantilla para mostrar y agregar tareas
├── tests/
│ ├── test_app.py # Pruebas unitarias usando pytest
│ └── test_interfaz.py # Pruebas de interfaz con Selenium
├── locustfile.py # Archivo para pruebas de carga con Locust
├── Dockerfile # Archivo para construir la imagen Docker de la aplicación
└── requirements.txt # Dependencias de Python necesarias para la aplicación
Paso 1: Crear el archivo requirements.txt
El archivo `requirements.txt` lista todas las dependencias de la aplicación. Es crucial para Docker porque le indica qué librerías de Python instalar.
Dentro de `flask_testing_project`, crea un archivo llamado `requirements.txt` y copia el siguiente contenido en él:
attrs==24.2.0
blinker==1.8.2
Brotli==1.1.0
certifi==2024.8.30
charset-normalizer==3.4.0
click==8.1.7
ConfigArgParse==1.7
coverage==7.6.4
Flask==3.0.3
Flask-Cors==5.0.0
Flask-Login==0.6.3
Flask-SQLAlchemy==3.1.1
gevent==24.10.3
geventhttpclient==2.3.1
greenlet==3.1.1
h11==0.14.0
idna==3.10
iniconfig==2.0.0
itsdangerous==2.2.0
Jinja2==3.1.4
locust==2.32.0
MarkupSafe==3.0.2
msgpack==1.1.0
outcome==1.3.0.post0
packaging==24.1
pluggy==1.5.0
psutil==6.1.0
PyMySQL==1.1.1
PySocks==1.7.1
pytest==8.3.3
pytest-cov==5.0.0
python-dotenv==1.0.1
pyzmq==26.2.0
requests==2.32.3
selenium==4.25.0
setuptools==75.2.0
sniffio==1.3.1
sortedcontainers==2.4.0
SQLAlchemy==2.0.36
trio==0.27.0
trio-websocket==0.11.1
typing_extensions==4.12.2
urllib3==2.2.3
webdriver-manager==4.0.2
websocket-client==1.8.0
Werkzeug==3.0.4
wsproto==1.2.0
zope.event==5.0
zope.interface==7.1.1
¿Recuerdas como instalar estas dependencias en un único paso?
Paso 2: Crear el archivo Dockerfile
El `Dockerfile` es el núcleo de la dockerización, ya que define las instrucciones paso a paso para crear una imagen de Docker que ejecutará nuestra aplicación Flask.
Dentro de `flask_testing_project`, crea un archivo llamado `Dockerfile` con el siguiente contenido:
# Usar una imagen base de Python
FROM python:3.12-slim
# Establecer el directorio de trabajo dentro del contenedor
WORKDIR /app
# Copiar el archivo de requisitos al directorio de trabajo del contenedor
COPY requirements.txt .
# Instalar las dependencias desde requirements.txt
RUN pip install --no-cache-dir -r requirements.txt
# Copiar el contenido de tu aplicación al directorio de trabajo del contenedor
COPY . .
# Exponer el puerto que usa Flask
EXPOSE 5000
# Comando para ejecutar la aplicación Flask
CMD ["python", "app.py"]
Explicación línea a línea del Dockerfile
- `FROM python:3.12-slim`: Utiliza una imagen base de Python ligera (versión 3.12) para optimizar el espacio que ocupa la imagen.
- `WORKDIR /app`: Crea y define `/app` como el directorio de trabajo donde se copiarán los archivos de la aplicación.
- `COPY requirements.txt .`: Copia el archivo `requirements.txt` desde el sistema de archivos local al directorio actual del contenedor (`/app`). Esto asegura que el contenedor tenga acceso a las dependencias de la aplicación.
- `RUN pip install --no-cache-dir -r requirements.txt`: Instala las dependencias especificadas en `requirements.txt` sin cachear archivos temporales, reduciendo el tamaño final de la imagen.
- `COPY . .`: Copia todos los archivos y carpetas desde el sistema local al directorio `/app` del contenedor, incluyendo `app.py` y otras carpetas de proyecto.
- `EXPOSE 5000`: Indica que el contenedor usará el puerto 5000, donde Flask ejecutará la aplicación.
- `CMD ["python", "app.py"]`: Define el comando que se ejecutará cuando el contenedor inicie, en este caso, lanzando la aplicación Flask en `app.py`.
Paso 3: Modificar app.py para Ejecutar en Docker
Flask, por defecto, ejecuta su servidor solo en `localhost`, lo que hace que el contenedor no sea accesible desde fuera. Para resolver esto, edita `app.py` y asegúrate de que contenga el siguiente código al final del archivo:
if __name__ == '__main__':
app.run(host='0.0.0.0', port=5000, debug=True)
Al añadir `host='0.0.0.0'`, permitimos que Flask acepte conexiones desde cualquier IP externa, asegurando que podamos acceder a la aplicación desde fuera del contenedor Docker.
Paso 4: Construir y Ejecutar la Imagen Docker
Con los archivos `Dockerfile`, `requirements.txt` y `app.py` preparados, estamos listos para construir la imagen Docker y ejecutar un contenedor con la aplicación.
En la terminal, navega al directorio `flask_testing_project` y ejecuta los siguientes comandos:
# Construir la imagen Docker y asignarle el nombre 'flask-testing_project'
docker build -t flask-testing_project .
# Ejecutar el contenedor desde la imagen, mapeando el puerto 5000 al mismo puerto en el host
docker run -p 5000:5000 flask-testing_project
- `docker build -t flask-testing_project .`: Construye una imagen Docker basada en el `Dockerfile` del directorio actual. El argumento `-t flask-testing_project` asigna un nombre a la imagen creada.
- `docker run -p 5000:5000 flask-testing_project`: Ejecuta la imagen en un contenedor, mapeando el puerto 5000 del contenedor al puerto 5000 de la máquina local. De esta forma, la aplicación Flask es accesible desde el navegador en `localhost:5000`.
Una vez que el contenedor esté en ejecución, abre tu navegador y accede a [1](http://localhost:5000). Si ves la aplicación funcionando, ¡felicidades! Has dockerizado exitosamente la aplicación Flask.
Resumen
Este tutorial te ha guiado a través del proceso completo de dockerización de una aplicación Flask:
- Creamos el archivo `requirements.txt` para listar las dependencias de la aplicación.
- Construimos un `Dockerfile` detallado para definir los pasos de construcción de la imagen.
- Modificamos `app.py` para hacer la aplicación accesible externamente.
- Construimos la imagen y ejecutamos el contenedor, logrando que la aplicación esté disponible en el navegador.
Al seguir estos pasos, has asegurado que la aplicación Flask pueda ejecutarse en cualquier entorno compatible con Docker, simplificando la portabilidad y la escalabilidad del proyecto.
Dockerizando una Aplicación Flask con Base de Datos usando Docker Compose
En este tutorial, aprenderemos a dockerizar la aplicación Flask `flask_testing_project` que creamos en la práctica anterior y añadiremos una base de datos externa. Esto nos permitirá ejecutar la aplicación en contenedores separados para la aplicación Flask y la base de datos, facilitando la escalabilidad y el mantenimiento.
Para lograr esto, usaremos Docker Compose y ajustaremos nuestra aplicación para que utilice una base de datos MariaDB.
Estructura del Proyecto
La estructura inicial de `flask_testing_project` es la siguiente:
flask_testing_project/
│
├── app.py # Archivo principal de la aplicación Flask
├── templates/ # Directorio con la plantilla HTML
│ └── tasks.html # Plantilla para mostrar y agregar tareas
├── tests/ # Directorio con pruebas unitarias y de interfaz
│ ├── test_app.py
│ └── test_interfaz.py
├── locustfile.py # Archivo para pruebas de carga con Locust
├── Dockerfile # Archivo para construir la imagen Docker de la aplicación
└── requirements.txt # Dependencias de Python necesarias para la aplicación
Para agregar Docker Compose, crearemos un nuevo archivo `docker-compose.yml`, y realizaremos algunos cambios en `app.py` para que la aplicación se conecte a MariaDB.
La estructura final del proyecto será:
flask_testing_project/
│
├── app.py # Archivo principal de la aplicación Flask
├── templates/ # Directorio con la plantilla HTML
│ └── tasks.html # Plantilla para mostrar y agregar tareas
├── tests/
│ ├── test_app.py
│ └── test_interfaz.py
├── locustfile.py # Archivo para pruebas de carga con Locust
├── Dockerfile # Archivo para construir la imagen Docker de la aplicación
├── requirements.txt # Dependencias de Python necesarias para la aplicación
└── docker-compose.yml # Archivo de configuración de Docker Compose
Paso 1: Crear el archivo docker-compose.yml
Docker Compose permite definir y gestionar múltiples contenedores en un solo archivo de configuración. En este archivo, definiremos dos servicios: uno para la aplicación Flask (`web`) y otro para la base de datos MariaDB (`db`).
Dentro de `flask_testing_project`, crea un archivo llamado `docker-compose.yml` y copia el siguiente contenido:
version: '3'
services:
web:
build: .
ports:
- "5000:5000"
environment:
- FLASK_ENV=development
- DATABASE_HOST=db
- DATABASE_USER=root
- DATABASE_PASSWORD=my-secret-pw
- DATABASE_DB=flaskdb
depends_on:
- db
db:
image: mariadb:10.5
restart: always
environment:
MYSQL_ROOT_PASSWORD: my-secret-pw
MYSQL_DATABASE: flaskdb
volumes:
- db_data:/var/lib/mysql
volumes:
db_data:
Explicación línea a línea del docker-compose.yml
- `version: '3'`: Especifica la versión de Docker Compose.
- `services`: Define los servicios que Docker Compose manejará, en este caso `web` y `db`.
- `web`: Servicio para la aplicación Flask.
- `build: .`: Indica que el servicio usará el Dockerfile en el directorio actual.
- `ports`: Mapea el puerto 5000 del contenedor al puerto 5000 de la máquina local.
- `environment`: Define variables de entorno para configurar la conexión a la base de datos.
- `FLASK_ENV=development`: Ejecuta Flask en modo de desarrollo.
- `DATABASE_HOST=db`: Dirección del contenedor `db` para la base de datos.
- `DATABASE_USER=root`, `DATABASE_PASSWORD=my-secret-pw`, `DATABASE_DB=flaskdb`: Credenciales y base de datos que usará Flask.
- `depends_on`: Asegura que el contenedor `db` esté ejecutándose antes de iniciar `web`.
- `db`: Servicio para la base de datos MariaDB.
- `image: mariadb:10.5`: Usa la imagen de MariaDB versión 10.5.
- `restart: always`: Reinicia el contenedor automáticamente en caso de errores.
- `environment`: Define las credenciales y la base de datos por defecto.
- `volumes`: Almacena los datos en un volumen persistente `db_data`.
- `volumes`: Define `db_data` para que los datos de la base de datos persistan en el sistema anfitrión.
Paso 2: Modificar app.py para Conectarse a MariaDB
Actualizaremos `app.py` para usar SQLAlchemy y conectarse a MariaDB mediante las variables de entorno definidas en Docker Compose.
Reemplaza el contenido de `app.py` por el siguiente:
from flask import Flask, jsonify, request, render_template, redirect, url_for
from flask_sqlalchemy import SQLAlchemy
import os
app = Flask(__name__)
# Configuración de la base de datos MariaDB
app.config['SQLALCHEMY_DATABASE_URI'] = f"mysql+pymysql://{os.getenv('DATABASE_USER')}:{os.getenv('DATABASE_PASSWORD')}@{os.getenv('DATABASE_HOST')}/{os.getenv('DATABASE_DB')}"
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
db = SQLAlchemy(app)
# Definición del modelo de Tarea
class Task(db.Model):
id = db.Column(db.Integer, primary_key=True)
title = db.Column(db.String(100), nullable=False)
done = db.Column(db.Boolean, default=False)
def to_dict(self):
return {
'id': self.id,
'title': self.title,
'done': self.done
}
# Ruta para obtener la lista de tareas (versión HTML)
@app.route('/')
def task_list():
tasks = Task.query.all()
return render_template('tasks.html', tasks=tasks)
# Ruta para obtener la lista de tareas en JSON (API)
@app.route('/tasks', methods=['GET'])
def get_tasks():
tasks = Task.query.all()
return jsonify({'tasks': [task.to_dict() for task in tasks]})
# Ruta para crear una nueva tarea desde un formulario HTML
@app.route('/add_task', methods=['POST'])
def add_task_html():
title = request.form.get('title')
if not title:
return "El título es necesario", 400
new_task = Task(title=title, done=False)
db.session.add(new_task)
db.session.commit()
return redirect(url_for('task_list'))
# Ruta para crear una nueva tarea (API JSON)
@app.route('/tasks', methods=['POST'])
def create_task():
if not request.json or 'title' not in request.json:
return jsonify({'error': 'El título es necesario'}), 400
new_task = Task(title=request.json['title'], done=False)
db.session.add(new_task)
db.session.commit()
return jsonify(new_task.to_dict()), 201
if __name__ == '__main__':
# Crear las tablas en la base de datos si no existen
with app.app_context():
db.create_all()
app.run(host='0.0.0.0', port=5000, debug=True)
Paso 3: Construir y Ejecutar los Contenedores con Docker Compose
Ahora que `docker-compose.yml` y `app.py` están configurados, estamos listos para construir y ejecutar la aplicación con Docker Compose.
En la terminal, navega al directorio `flask_testing_project` y ejecuta los siguientes comandos:
# Construir y ejecutar los contenedores
docker compose up
- `docker compose up`: Construye y ejecuta los contenedores en segundo plano. Si la imagen no existe, la creará usando el Dockerfile y las configuraciones de Docker Compose.
Para detener los contenedores y eliminar el entorno, ejecuta:
# Parar y remover los contenedores
docker compose down
- `docker compose down`: Detiene todos los contenedores y elimina el entorno definido en `docker-compose.yml`, sin eliminar los volúmenes de datos.
Una vez que los contenedores estén en ejecución, abre tu navegador y accede a [2](http://localhost:5000). Si ves la aplicación funcionando y puedes agregar tareas, ¡felicidades! Has dockerizado exitosamente la aplicación Flask con una base de datos MariaDB.
Resumen
En este tutorial:
- Creamos un archivo `docker-compose.yml` para gestionar múltiples contenedores.
- Modificamos `app.py` para usar SQLAlchemy y conectar la aplicación Flask a una base de datos MariaDB.
- Ejecutamos y verificamos la aplicación con Docker Compose.
Ahora tienes una aplicación Flask lista para desarrollarse y desplegarse fácilmente en cualquier entorno.