Ejemplo 2: Implementación de servidor con Nginx, Flask y mySQL
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 endpoint 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
:
<!DOCTYPE html>
<html lang="es">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Formulario de Usuario</title>
</head>
<body>
<h2>Ingresar datos</h2>
<form method="POST">
<label for="name">Nombre:</label>
<input type="text" id="name" name="name" required><br><br>
<label for="email">Correo:</label>
<input type="email" id="email" name="email" required><br><br>
<button type="submit">Enviar</button>
</form>
{% if data %}
<h2>Datos enviados</h2>
<table border="1">
<tr>
<th>ID</th>
<th>Nombre</th>
<th>Email</th>
</tr>
{% for row in data %}
<tr>
<td>{{ row[0] }}</td>
<td>{{ row[1] }}</td>
<td>{{ row[2] }}</td>
</tr>
{% endfor %}
</table>
{% endif %}
</body>
</html>
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:
server { listen 80; location / { proxy_pass http://flask-app:5000; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; } }
Creamos ahora un
Dockerfile
para Nginx: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:
MYSQL_ROOT_PASSWORD=1234
MYSQL_DATABASE=fskalex
MYSQL_USER=alex
MYSQL_PASSWORD=P@ssw0rd
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');
Esto veremos que lo añadiremos a la carpeta de iniciación del contenedor (/docker-entrypoint-initdb.d
), más info: https://tecadmin.net/using-mysql-with-docker-compose/
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.
Última actualización