El objetivo de esta práctica es configurar y desplegar una aplicación web basada en una pila Nginx + Flask + MySQL utilizando Docker.
Nuestra práctica tendrá la siguiente estructura de carpetas:
docker-compose.yaml
/python
app.py
requirements.txt
Dockerfile
/templates
form.html
/nginx
nginx.conf
Dockerfile
/initdb
script.sql
1. Creamos un servidor web con Flask
Realizaremos esta práctica con una pequeña aplicación web en Flask que tenga un básico de flask (/) que muestre un formulario de HTML donde te pida nombre y email y al pulsar "enviar" te muestre todos los resultados de la base de datos.
El código podría ser para app.py:
from flask import Flask, render_template, request
import mysql.connector
app = Flask(__name__)
# Ruta para mostrar el formulario y los datos enviados
@app.route('/', methods=['GET', 'POST'])
def form():
if request.method == 'POST':
name = request.form['name']
email = request.form['email']
try:
# Conectar a la base de datos
conn = mysql.connector.connect(
host="db",
user="alex",
password="P@ssw0rd",
database="fskalex"
)
cursor = conn.cursor()
cursor.execute("INSERT INTO basic_table (name, email) VALUES (%s, %s)", (name, email))
conn.commit()
# Recuperar los datos recién enviados
cursor.execute("SELECT * FROM basic_table ORDER BY id DESC LIMIT 5") # Muestra los últimos 5 registros
data = cursor.fetchall()
conn.close()
return render_template('form.html', data=data)
except Exception as e:
return str(e), 500
return render_template('form.html', data=[])
# Ejecuta la app en localhost puerto 5000
if __name__ == "__main__":
app.run(host="0.0.0.0", port=5000, debug=True)
Y el documento siguiente de html guárdalo como form.html en una carpeta /templates :
Ahora crea un archivo requirements.txt con el siguiente contenido:
flask
mysql-connector-python
2. Creamos una imagen de docker personalizada de Flask
Escribe un Dockerfile para el servidor Flask:
#Exportamos la imagen estable mas reciente
FROM python:latest
# Copiamos los archivos de la aplicación (fijate en las rutas)
WORKDIR /app
COPY . /app
# Instala dependencias a partir del txt de antes
RUN pip install --no-cache-dir -r requirements.txt
# O bien puedes usar la siguiente sentencia que hace lo mismo:
# RUN pip install --no-cache-dir flask mysql-connector-python
# Exponemos el puerto de Flask
EXPOSE 5000
# Comando para iniciar la aplicación
CMD ["python", "app.py"]
Y construye la imagen de Flask ejecutando el comando:
docker build -t flask-app .
3. Configurar un proxy inverso con Nginx
Para ello primero debemos configurar un archivo nginx.conf:
Este archivo manejará las solicitudes entrantes y las redirigirá al servidor Flask:
FROM nginx:latest
# Copiar la configuración personalizada de Nginx
COPY nginx.conf /etc/nginx/conf.d/default.conf
Construir la imagen de Nginx:
docker build -t nginx-proxy .
4. Preparación del contenedor de mysql
Para el contenedor de MySQL utilizaremos la imagen oficial de MySQL configurando las variables de entorno (ten en cuenta que esto es un comando entero y que deberá ser lo mismo que en la app de python) y añadiendo un script de iniciación de la base de datos.
Recuerda que nuestra bariables de entorno para el docker-compose serán las siguientes:
Creamos una carpeta ./initdb en la carpeta de docker-compose con el siguiente script script.sql para crear una tabla, dar privilegios y agregar unos datos simples:
CREATE DATABASE IF NOT EXISTS fskalex;
CREATE USER IF NOT EXISTS 'alex'@'%' IDENTIFIED BY 'P@ssw0rd';
GRANT ALL PRIVILEGES ON fskalex.* TO 'alex'@'%';
FLUSH PRIVILEGES;
USE fskalex;
CREATE TABLE IF NOT EXISTS basic_table (
id INT AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(255) NOT NULL,
email VARCHAR(255) NOT NULL
);
INSERT INTO basic_table (name, email) VALUES ('Rosa Melano', 'bienrosita@yahoo.es'), ('Armando Jaleo', 'jaleito@copy.org');
Recuerda que puedes acceder a tu contenedor mysql en cualquier momento haciendo uso del siguiente comando con el password 1234:
docker exec -it mysql-db mysql -u root -p
5. Orquestar los contenedores con Docker Compose
El último paso es ya crear el archivo de docker compose agregando todas las imágenes creadas. Para ello creamos un archivo docker-compose.yml:
version: '3.8'
services:
db:
image: mysql:latest
container_name: mysql-db
environment:
MYSQL_ROOT_PASSWORD: 1234
MYSQL_DATABASE: fskalex
MYSQL_USER: alex
MYSQL_PASSWORD: P@ssw0rd
volumes:
- mysql_data:/var/lib/mysql # Volumen persistente para los datos de la DB
- ./initdb:/docker-entrypoint-initdb.d # Montamos el script de inicialización
networks:
- webnet
flask-app:
image: flask-app:latest
container_name: flask-app
depends_on:
- db
networks:
- webnet
ports:
- "5000:5000"
restart: always # Asegura que reinicie si falla por la DB no estar lista
nginx:
image: nginx-proxy
container_name: nginx-proxy
depends_on:
- flask-app
networks:
- webnet
ports:
- "80:80"
volumes:
mysql_data:
networks:
webnet:
Vamos ahora a iniciar todos los servicios:
docker-compose up --build
#o bien para enviarlo a segundo plano:
docker-compose up -d --build
Probemos ahora la aplicación abriendo un navegador y accediendo a:
http://localhost/ → Deberías ver el formulario HTML.
Mas ideas para añadir/modificar:
Añade persistencia de datos configurando volúmenes para Nginx y MySQL.
Integra una herramienta de monitoreo como Prometheus o Grafana.
Implementa SSL en el proxy Nginx con Let's Encrypt.
Esto veremos que lo añadiremos a la carpeta de iniciación del contenedor (/docker-entrypoint-initdb.d), más info: