====== 08 - Arquitectura de aplicación ====== Hasta aquí, cada servidor se ha arrancado por su lado: un Tomcat, un MinIO, una base de datos. Una aplicación real es un **sistema** de varios servidores que colaboran. **Docker Compose** (tema 02) permite describir ese sistema completo en un ''compose.yaml'' y arrancarlo de una vez. ===== 1. El sistema ===== La arquitectura de referencia de una aplicación web clásica: @startuml actor "Navegador" as Browser node "nginx\npuerto 80" as Nginx node "App\nTomcat :8080" as App database "MariaDB\n:3306" as Db node "MinIO\n:9000" as Minio Browser --> Nginx : HTTP (único puerto publicado) Nginx --> Browser : frontend estático Nginx --> App : /api/** (reverse proxy) App --> Db : JDBC (red interna) App --> Minio : API S3 (red interna) @enduml * **nginx** es el punto de entrada único: sirve el **frontend** estático (HTML, CSS, JS) y actúa de **reverse proxy**: reenvía las rutas de la API a la aplicación. * **App** (Tomcat): la **API REST** en Java; no publica puerto propio, solo responde al proxy. * **MariaDB**: la persistencia relacional. * **MinIO**: el **almacenamiento de objetos** para los ficheros. ===== 2. La descripción: compose.yaml ===== services: nginx: image: nginx:alpine ports: - "80:80" volumes: - ./nginx.conf:/etc/nginx/conf.d/default.conf:ro - ./frontend:/usr/share/nginx/html:ro depends_on: - app app: build: ./app environment: DB_URL: jdbc:mariadb://db:3306/miapp S3_ENDPOINT: http://minio:9000 depends_on: - db - minio db: image: mariadb:11 environment: MARIADB_ROOT_PASSWORD: secreto MARIADB_DATABASE: miapp volumes: - db-data:/var/lib/mysql minio: image: elestio/minio command: server /data --console-address ":9001" environment: MINIO_ROOT_USER: admin MINIO_ROOT_PASSWORD: secreto123 volumes: - minio-data:/data volumes: db-data: minio-data: $ docker compose up -d # los cuatro servicios, juntos $ docker compose down ===== 3. Red interna y nombres ===== Compose crea una **red propia** donde cada servicio es alcanzable por su **nombre**: Docker resuelve ''db'' y ''minio'' a la IP de esos contenedores (DNS interno). * En ''DB_URL'' la base de datos es ''db:3306'', no ''localhost'': el contenedor de la app no es el mismo que el de la BBDD. * Lo mismo con ''S3_ENDPOINT: http://minio:9000''. * Solo **nginx** publica puerto al exterior (''80:80''): la app, la BBDD y MinIO viven en la red interna y no son accesibles desde el host. La superficie de exposición es mínima y coincide con la de un despliegue real. ''depends_on'' ordena el arranque de los servicios. ===== 4. La configuración de nginx ===== server { listen 80; location /api/ { proxy_pass http://app:8080; } location / { root /usr/share/nginx/html; } } Para el navegador todo sale del mismo servidor: el frontend en ''/'' y la API en ''/api/''. El proxy usa el nombre ''app'' de la red interna; si la app cambia de nombre o de puerto, solo toca este fichero. ===== 5. Lo que aporta ===== ^ Aporte ^ Cómo lo da Compose ^ | Reproducibilidad | Un ''compose.yaml'' describe el sistema completo: el mismo resultado en cualquier máquina | | Paralelismo con producción | La topología (proxy + app + BBDD + storage) es la de un despliegue real | | Aislamiento | Cada pieza en su contenedor, con su versión exacta | | Exposición mínima | Solo nginx publica un puerto; el resto vive en la red interna | La arquitectura del ejemplo es la clásica de tres niveles: presentación (nginx), aplicación (Tomcat) y datos (MariaDB, MinIO). Sustituir una pieza —otra base de datos, **S3** real en producción— toca la configuración del servicio, no la estructura del sistema. Y si la aplicación necesita más capacidad, se escala horizontalmente añadiendo réplicas detrás del proxy.