Categoría: Sistemas

  • Despliegue JEE (Servlet + HTML/JS) + MySQL en Docker

    Despliegue JEE (Servlet + HTML/JS) + MySQL en Docker

    Levantar una aplicación Java (Servlet) desplegada en Tomcat y conectada a MySQL, todo en contenedores Docker, sin frameworks y sin docker-compose.

    Requisitos

    • Docker instalado y funcionando.
    • Tu aplicación empaquetada como WAR (ej: miapp.war).
    • Una carpeta de proyecto en tu PC (host).

    Estructura del proyecto (en el host)

    Crea una carpeta de trabajo, por ejemplo:

    mkdir -p ~/proyecto-jee-docker
    cd ~/proyecto-jee-docker
    mkdir -p deploy

    Copia tu WAR dentro de deploy/:

    cp /RUTA/AL/WAR/miapp.war ./deploy/

    Crear una red Docker para que se vean por nombre

    Esto permite que Tomcat encuentre MySQL usando el nombre del contenedor.

    docker network create red-jee

    Levantar MySQL con volumen (persistencia)

    2.1 Crear volumen para MySQL

    docker volume create mysql_data

    2.2 Lanzar el contenedor MySQL

    ⚠️ Cambia passwords y nombre de BD si quieres, pero respeta la idea.

    docker run -d \
      --name mysql-jee \
      --network red-jee \
      -e MYSQL_ROOT_PASSWORD=root1234 \
      -e MYSQL_DATABASE=appdb \
      -e MYSQL_USER=appuser \
      -e MYSQL_PASSWORD=app1234 \
      -v mysql_data:/var/lib/mysql \
      -p 3307:3306 \
      mysql:8.0

    Qué hace esto:

    • --network red-jee → MySQL estará accesible desde Tomcat por hostname mysql-jee
    • -v mysql_data:/var/lib/mysql → los datos sobreviven aunque borres el contenedor
    • -p 3307:3306 → MySQL será accesible desde tu PC en localhost:3307 (evita conflictos si tu 3306 está ocupado)

    2.3 Comprobar que MySQL está arriba

    docker psdocker logs mysql-jee --tail30

    Crear tablas y datos de prueba (dentro del contenedor)

    Entra a MySQL dentro del contenedor:

    docker exec -it mysql-jee mysql -u root -p

    Escribe la contraseña root1234.

    Luego (ejemplo genérico), crea una tabla y mete algo.


    Preparar el contenedor Tomcat y desplegar el WAR

    Ejecutar Tomcat y montar tu WAR (sin construir imagen propia)

    Opción simple: montas la carpeta deploy en webapps.

    docker run -d \
      --name tomcat-jee \
      --network red-jee \
      -p 8080:8080 \
      -v "$PWD/deploy:/usr/local/tomcat/webapps" \
      tomcat:10.1-jdk17

    Qué hace esto:

    • -p 8080:8080 → accedes en http://localhost:8080
    • -v .../webapps → Tomcat “ve” tu WAR y lo despliega al arrancar

    4.2 Ver logs de Tomcat (muy importante)

    docker logs -f tomcat-jee

    Busca líneas tipo “Deploying web application archive … miapp.war”.


    5) Configurar la conexión a MySQL en tu Java (punto clave)

    Dentro de Docker, NO uses localhost para MySQL desde Tomcat.
    Debes usar el nombre del contenedor:

    • Host: mysql-jee
    • Puerto interno: 3306
    • BD: appdb
    • User: appuser
    • Pass: app1234

    Ejemplo de URL JDBC:

    jdbc:mysql://mysql-jee:3306/appdb?useSSL=false&allowPublicKeyRetrieval=true&serverTimezone=UTC

    ✅ Si tu app usa un fichero de configuración (properties), ajusta eso.

    Ejemplo (si usas Properties):

    db.url=jdbc:mysql://mysql-jee:3306/appdb?useSSL=false&allowPublicKeyRetrieval=true&serverTimezone=UTC
    db.user=appuser
    db.pass=app1234

    Nota: si tu WAR ya estaba compilado con localhost, toca recompilar con mysql-jee.


    6) Probar la aplicación desde el navegador

    1. Entra a tu app (depende del nombre del WAR):
    • Si el WAR se llama miapp.war, normalmente será:
      • http://localhost:8080/miapp/
    1. Prueba el endpoint del servlet que devuelve JSON:
    • Ejemplo:
      • http://localhost:8080/miapp/api/items

    7) Verificar el fetch() y el DOM (JS)

    Tu JavaScript hará algo así:

    fetch('/miapp/api/items')
      .then(r => r.json())
      .then(data => {
        // pintar DOM
      });

    Errores típicos

    • 404 en fetch → la ruta no coincide con el url-pattern del servlet.
    • El fetch devuelve HTML en vez de JSON → estás pegando a una ruta que devuelve una página, no el endpoint.
    • CORS: si sirves el HTML desde Tomcat y llamas al servlet en el mismo host/puerto, normalmente no hay CORS.
      CORS aparece si llamas a otro host/puerto distinto.

    8) Comandos útiles de operación (vida real)

    Ver contenedores

    docker ps
    docker ps-a

    Parar / arrancar

    docker stop tomcat-jee mysql-jee
    docker start mysql-jee
    docker start tomcat-jee

    Entrar a un contenedor

    docker exec -it tomcat-jee bash
    docker exec -it mysql-jee bash

    Ver redes y comprobar nombres

    docker network ls
    docker network inspect red-jee

    9) Reinicio limpio (sin perder datos)

    Si quieres borrar Tomcat y recrearlo (sin perder DB):

    docker rm -f tomcat-jee
    docker run -d \
      --name tomcat-jee \
      --network red-jee \
      -p 8080:8080 \
      -v "$PWD/deploy:/usr/local/tomcat/webapps" \
      tomcat:10.1-jdk17

    La BD se conserva porque está en el volumen mysql_data.

    Resumen de pasos a realizar:

    • He creado red-jee
    • He creado el volumen mysql_data
    • He levantado mysql-jee y responde
    • He creado tablas y datos en appdb
    • He levantado tomcat-jee con el WAR montado
    • La app carga en http://localhost:8080/...
    • El servlet devuelve JSON válido
    • El fetch() recibe JSON y pinta en el DOM
  • Práctica – Juego de retos de Docker

    Práctica – Juego de retos de Docker

    Reto1

    – Crear un contenedor docker de ubuntu.
    – Instalar python, la libreria request y de mysql
    – Crear una imgane personalizada con el contenedor

    Reto 2

    • Crear un contenedor nuevo con la imagen personalizada  de docker
    • Este contenedor tendra un volumen con una ruta en el disco del anfitrión (Bind)

    Reto 3

    • Crear un repositorio git en la carpeta del anfitrión y unirlo con un repositorio en Github

    Reto 4

    • Crear un contenedor mysql.
    • Crear una base de datos, para almacenar Coches. Los campos seran id, marca, modelo, color, km y precio
    • añadir almenos 10 coches a modo de contenido de muestra.

    Reto 5 

    • Crear en el repositorio Local un programa en python que se conecte a la base de datos y obtenga los registros de la mase de datos.
      – El programa debe listar los datos de los coches guardados en la base de datos de forma estetica.

    ID    MARCA          MODELO         COLOR     KM        PRECIO    
    ————————————————————————
    1     Toyota             Corolla              Blanco    20000     15000     
    2     Honda              Civic                Rojo        30000     17000     
    3     Ford                  Focus               Azul       25000     16000     

    Reto 6

    • Almacenar los datos de conexion a la base de datos en un archivo JSON y que el programa Python los lea de dicho archivo. 
      * crear un nuevo archivo para la modificación.
      * Realiza un commit en cada paso
    • crear el .gitignore para que no suba el archivo con los datos de conexión.

    Reto 7

    Formatear la tabla para que quede mas estetica con la libreria 

    +—-+——–+———+——-+————-+——–+
    | ID | Marca  | Modelo  | Color | Kilometraje  | Precio |
    +—-+——–+———+——-+————-+——–+
    | 1  | Toyota | Corolla | Rojo  | 25000        | 15000  |
    | 2  | Honda  | Civic   | Azul  | 30000        | 18000  |
    | 3  | Ford   | Focus   | Blanco| 40000        | 17000  |
    +—-+——–+———+——-+————-+——–+

    Reto 8

    Crear un conetenedor Mongo y conectarse desde la terminal y utilizando MongoDB
    Crea la una bd e inserta en una colecci’on coches con el criterio de de campos del reto anterior
    Crear un Script de Python  para leer los datos de colecciones de MongoDB y los imprima en una tabla.

    Reto 9

    Subir una imagen personaliza de nuestro contenedor mongodb al  hub de Docker.
    En el Linux Parrot montar un contenedor con la imagen subida al hub.

    Documento de ayuda y pistas para los retos


    🚀 RETO 1 — Tu primer contenedor personalizado

    Objetivo

    Crear un contenedor Ubuntu con Python y librerías necesarias, y convertirlo en una imagen reutilizable.

    Pistas

    Según la guía visual del PDF (pág. 1), debes:

    • Ejecutar un contenedor Ubuntu
    • Instalar:
      • python3
      • pip
      • requests
      • cliente MySQL

    Después crea una imagen personalizada con:

    docker commit <contenedor> mi-imagen-personalizada
    

    ✅ Checkpoint

    Debes poder ver tu imagen con:

    docker images
    

    🚀 RETO 2 — Persistencia con Bind Mount

    Objetivo

    Crear un nuevo contenedor usando la imagen anterior y asociarlo a una carpeta del host.

    📌 En la página 2 del PDF se muestra cómo activar modo interactivo y configurar el volumen.

    Ejemplo conceptual:

    docker run -it -v /ruta/host:/ruta/contenedor mi-imagen
    

    ¿Por qué es importante?

    Si borras el contenedor, los datos seguirán vivos.

    Bienvenido al mundo real.

    ✅ Checkpoint

    Crea un archivo dentro del contenedor y verifica que aparece en el host.


    🚀 RETO 3 — Control de versiones

    Objetivo

    Versionar tu carpeta de trabajo y conectarla a GitHub.

    Tal como aparece en la página 3 del PDF:

    1️⃣ Inicializa Git
    2️⃣ Crea un repositorio en GitHub
    3️⃣ Ejecuta:

    git add .
    git commit -m "Inicio del laboratorio"
    git remote add origin <repo>
    git push -u origin main
    

    ✅ Checkpoint

    Tu repositorio debe contener al menos:

    • scripts
    • documentación
    • archivos de configuración

    🚀 RETO 4 — MySQL en contenedor

    Objetivo

    Levantar un contenedor MySQL y crear una base de datos de coches.

    Campos:

    • id
    • marca
    • modelo
    • color
    • km
    • precio

    Inserta mínimo 10 registros.

    📌 La página 4 del PDF muestra la configuración del contenedor.

    ✅ Checkpoint

    Debe funcionar:

    SELECT * FROM coches;
    

    🚀 RETO 5 — Python contra la base de datos

    Objetivo

    Crear un script que lea los coches desde MySQL.

    Las páginas 5–7 del PDF enseñan:

    • conexión con mysql.connector
    • uso de cursor
    • fetchall()

    Ejemplo conceptual:

    cursor.execute("SELECT * FROM coches")
    for coche in cursor.fetchall():
        print(coche)
    

    ⚠️ Problema común

    En la página 9 se menciona un conflicto con el conector de MySQL en Ubuntu.

    Solución alternativa:

    pip install mysql-connector-python --break-system-packages
    

    ✅ Checkpoint

    El script debe mostrar registros sin errores.


    🚀 RETO 6 — Seguridad básica

    Objetivo

    Separar credenciales en un archivo JSON.

    Después:

    ✔ Leer ese archivo desde Python
    ✔ Crear .gitignore
    ✔ Evitar subir credenciales

    ✅ Checkpoint

    Tu repo NO debe contener:

    config.json
    .env
    credenciales
    

    🚀 RETO 7 — Salida profesional

    Objetivo

    Mostrar los datos en formato tabla.

    En la página 10 se recomienda usar:

    apt install python3-prettytable
    

    Ejemplo:

    from prettytable import PrettyTable
    

    ✅ Checkpoint

    La salida debe parecer una tabla real, no texto desordenado.


    🚀 RETO 8 — MongoDB entra en escena

    Ahora pasamos a bases de datos NoSQL.

    Según las páginas 12–16:

    Debes:

    • Crear contenedor Mongo
    • Definir usuario y contraseña
    • Crear BD
    • Insertar coches
    • Consultar datos

    Acceso desde terminal:

    docker exec -it <contenedor> bash
    mongosh -u usuario -p password --authenticationDatabase admin
    

    ✅ Checkpoint

    Debe funcionar:

    db.coches.find().pretty()
    

    🚀 RETO 9 — Python + MongoDB

    Instala pymongo (pág. 18):

    apt install python3-pymongo
    

    Conecta y recorre la colección.

    Después muestra los datos en tabla (pág. 20).

    ✅ Checkpoint

    Debes tener:

    • script funcional
    • salida formateada
    • conexión estable

    🚀 RETO FINAL — Publica tu imagen

    Sube tu imagen de Mongo personalizada a Docker Hub.

    Después:

    👉 descárgala desde otra máquina (por ejemplo Parrot)
    👉 levanta el contenedor

    Si funciona…

    Acabas de reproducir un flujo profesional real.

  • MySQL + phpMyAdmin con Docker Compose

    MySQL + phpMyAdmin con Docker Compose

    • Desplegar MySQL y phpMyAdmin con docker compose
    • Usar volumen para persistencia
    • Verificar conexión y datos
    • Practicar variables de entorno, puertos y reinicios

    1) Estructura del proyecto

    Crea una carpeta de práctica:

    mkdir mysql-pma-compose
    cd mysql-pma-compose
    

    2) Crear el archivo docker-compose.yml

    Crea el fichero:

    
    # Define los servicios (contenedores) que vamos a ejecutar
    services:
    
      # ----- SERVICIO MYSQL -----
      mysql:
        image: mysql:8.0              # Imagen oficial que se descargará de Docker Hub
        container_name: mysql1        # Nombre fijo del contenedor (opcional, pero útil)
        restart: unless-stopped       # Reinicia el contenedor automáticamente salvo que lo pares tú
    
        # Variables de entorno que usa la imagen de MySQL en su primer arranque
        environment:
          MYSQL_ROOT_PASSWORD: "RootPass_123!"   # Contraseña del usuario root
          MYSQL_DATABASE: "academia"             # Base de datos que se crea automáticamente
          MYSQL_USER: "alumno"                   # Usuario adicional que se creará
          MYSQL_PASSWORD: "AlumnoPass_123!"      # Contraseña del usuario alumno
    
        # Volúmenes → permiten persistencia (los datos sobreviven aunque borres el contenedor)
        volumes:
          - mysql_data:/var/lib/mysql   # Guarda los datos reales de MySQL fuera del contenedor
    
        # Conecta el contenedor a una red Docker interna
        networks:
          - red-bbdd
    
    
      # ----- SERVICIO PHPMYADMIN -----
      phpmyadmin:
        image: phpmyadmin:latest        # Imagen oficial de phpMyAdmin
        container_name: pma1
        restart: unless-stopped
    
        # Indica que MySQL debe arrancar antes (solo orden, no espera a que esté listo)
        depends_on:
          - mysql
    
        # Variables que indican a phpMyAdmin a qué servidor MySQL conectarse
        environment:
          PMA_HOST: "mysql"   # Nombre del servicio MySQL dentro de la red Docker
          PMA_PORT: 3306      # Puerto interno de MySQL
    
        # Publica puertos → expone el servicio al exterior
        ports:
          - "8080:80"         # Puerto HOST:PUERTO_CONTENEDOR → http://localhost:8080
    
        # Conecta phpMyAdmin a la misma red que MySQL para que puedan verse
        networks:
          - red-bbdd
    
    
    # ----- DEFINICIÓN DE VOLÚMENES -----
    volumes:
      mysql_data:   # Volumen gestionado por Docker (no es carpeta local visible normalmente)
    
    
    # ----- DEFINICIÓN DE REDES -----
    networks:
      red-bbdd:     # Red interna donde los contenedores se comunican por nombre (DNS interno)
    

    Qué está pasando aquí (muy importante)

    • services: dos contenedores, uno para MySQL y otro para phpMyAdmin.
    • volumes: mysql_data guarda la base de datos fuera del contenedor (persistencia).
    • networks: red privada para que phpmyadmin pueda acceder a mysql por nombre.
    • depends_on: arranca primero MySQL (ojo: no garantiza “ready”, solo orden de arranque).

    3) Levantar los contenedores

    docker compose up -d
    

    Verifica:

    docker compose ps
    docker compose logs mysql --tail 30
    docker compose logs phpmyadmin --tail 30
    

    4) Acceder a phpMyAdmin

    Abre en el navegador:

    • http://localhost:8080

    Credenciales:

    • Usuario: root (o alumno)
    • Password: RootPass_123! (o AlumnoPass_123!)

    Comprueba:

    • Existe la BD academia

    5) Crear tabla de prueba (verificación)

    Opción A: desde phpMyAdmin (SQL)
    Ejecuta:

    USE academia;
    CREATE TABLE prueba (
      id INT PRIMARY KEY AUTO_INCREMENT,
      texto VARCHAR(50)
    );
    INSERT INTO prueba (texto) VALUES ("hola compose");
    SELECT * FROM prueba;
    

    Opción B: desde terminal (dentro del contenedor)

    docker compose exec mysql mysql -u root -p
    



    Comandos útiles para alumnos

    docker compose ps
    docker compose logs -f
    docker compose exec mysql bash
    docker compose exec phpmyadmin bash
    docker compose down
    docker compose down -v
    

  • [Reto] – Despliegue de servicios con Docker y Docker Compose

    [Reto] – Despliegue de servicios con Docker y Docker Compose

    1. Contexto de la práctica

    En esta práctica vas a desplegar una pequeña infraestructura de servicios utilizando Docker y Docker Compose.

    El objetivo no es únicamente “levantar contenedores”, sino comprender cómo se organizan los servicios, cómo se comunican entre ellos, cómo se almacenan los datos, cómo se exponen puertos al exterior y cómo se puede documentar y justificar una instalación técnica.

    Durante la práctica se trabajará con servicios similares a los vistos en clase:

    • Servidor web HTTP con Apache.
    • PHP para ejecutar código dinámico.
    • MySQL como base de datos relacional.
    • phpMyAdmin como herramienta de administración.
    • MongoDB como base de datos NoSQL.
    • Mongo Express como herramienta de administración.
    • Redes Docker.
    • Volúmenes persistentes.
    • Variables de entorno.
    • Logs y comprobaciones.
    • Copias de seguridad básicas.
    • Documentación técnica.

    2. Objetivos de aprendizaje

    Al finalizar la práctica, el alumno deberá ser capaz de:

    1. Explicar qué es Docker y para qué se utiliza.
    2. Diferenciar una imagen de un contenedor.
    3. Crear y ejecutar contenedores mediante Docker Compose.
    4. Configurar servicios conectados entre sí.
    5. Usar volúmenes para conservar datos.
    6. Usar redes Docker para aislar servicios.
    7. Configurar variables de entorno.
    8. Desplegar una aplicación PHP conectada a MySQL.
    9. Desplegar y consultar una base de datos MongoDB.
    10. Comprobar el estado de los servicios mediante comandos.
    11. Interpretar errores básicos mediante logs.
    12. Documentar una instalación técnica de forma clara.
    13. Defender oralmente el trabajo realizado.

    3. Resultado final esperado

    Al terminar la práctica deberás tener funcionando una infraestructura compuesta por varios contenedores:

    ServicioTecnologíaPuerto externo sugeridoFunción
    Web PHPApache + PHP8080Servidor web principal
    MySQLMySQL3306 o solo internoBase de datos relacional
    phpMyAdminphpMyAdmin8081Administración de MySQL
    MongoDBMongoDB27017 o solo internoBase de datos NoSQL
    Mongo ExpressMongo Express8082Administración de MongoDB

    La aplicación PHP deberá mostrar una página web con información del alumno, conexión a MySQL y, opcionalmente, conexión a MongoDB.


    4. Normas de entrega

    El alumno deberá entregar:

    1. Carpeta completa del proyecto.
    2. Archivo docker-compose.yml.
    3. Archivo .env.
    4. Código fuente de la aplicación PHP.
    5. Capturas de pantalla.
    6. Documento de memoria en PDF.
    7. Comandos utilizados.
    8. Respuestas a las preguntas de reflexión.
    9. Evidencias de funcionamiento.
    10. Breve vídeo opcional de demostración.

    5. Estructura recomendada del proyecto

    Crea una carpeta llamada:

    practica-docker-servicios-nombre-apellido

    Dentro de ella deberás crear una estructura similar a esta:

    practica-docker-servicios-nombre-apellido/

    ├── docker-compose.yml
    ├── .env
    ├── README.md

    ├── web/
    │ ├── index.php
    │ ├── conexion_mysql.php
    │ ├── insertar.php
    │ ├── listar.php
    │ └── estilos.css

    ├── mysql/
    │ └── init.sql

    ├── evidencias/
    │ ├── captura_01_docker_version.png
    │ ├── captura_02_contenedores.png
    │ ├── captura_03_web_funcionando.png
    │ ├── captura_04_phpmyadmin.png
    │ ├── captura_05_mongo_express.png
    │ └── captura_06_logs.png

    └── memoria/
    └── memoria_practica.pdf

    6. Fase 1 — Preparación del entorno

    6.1. Comprobar Docker

    Ejecuta los siguientes comandos:

    docker --version
    docker compose version

    Guarda una captura de pantalla donde se vea el resultado.

    Preguntas de reflexión

    Responde en tu memoria:

    1. ¿Qué diferencia hay entre Docker y Docker Compose?
    2. ¿Qué problema soluciona Docker cuando trabajamos con varios servicios?
    3. ¿Por qué puede ser útil usar Docker en un entorno educativo o de laboratorio?

    6.2. Comprobar que Docker funciona

    Ejecuta:

    docker run hello-world

    Evidencia obligatoria

    Incluye una captura del resultado del comando.

    Pregunta de reflexión

    Explica con tus palabras qué ha ocurrido al ejecutar hello-world.

    Debes mencionar:

    • Si Docker ha usado una imagen local o la ha descargado.
    • Qué es un contenedor.
    • Por qué el contenedor termina después de ejecutarse.

    7. Fase 2 — Primer diseño de la infraestructura

    Antes de escribir el docker-compose.yml, realiza un pequeño esquema de la infraestructura.

    Puedes hacerlo con una tabla, un dibujo o un diagrama sencillo.

    Debe aparecer:

    • Servicio web.
    • Base de datos MySQL.
    • phpMyAdmin.
    • MongoDB.
    • Mongo Express.
    • Red interna.
    • Volúmenes de datos.
    • Puertos publicados.

    Ejemplo conceptual:

    Navegador
    |
    | puerto 8080
    v
    Apache + PHP
    |
    | red interna docker
    v
    MySQL

    Navegador
    |
    | puerto 8081
    v
    phpMyAdmin
    |
    v
    MySQL

    Navegador
    |
    | puerto 8082
    v
    Mongo Express
    |
    v
    MongoDB

    Preguntas de reflexión

    1. ¿Por qué no es recomendable instalar todos los servicios dentro del mismo contenedor?
    2. ¿Qué ventajas tiene separar web, base de datos y herramientas de administración?
    3. ¿Qué servicios deberían ser accesibles desde el navegador y cuáles deberían quedar solo dentro de la red Docker?

    8. Fase 3 — Creación del archivo .env

    Crea un archivo llamado .env en la raíz del proyecto.

    Ejemplo:

    MYSQL_ROOT_PASSWORD=rootpassword
    MYSQL_DATABASE=asir_db
    MYSQL_USER=asir_user
    MYSQL_PASSWORD=asir_password

    MONGO_INITDB_ROOT_USERNAME=admin
    MONGO_INITDB_ROOT_PASSWORD=adminpassword
    MONGO_DATABASE=asir_mongo

    WEB_PORT=8080
    PHPMYADMIN_PORT=8081
    MONGO_EXPRESS_PORT=8082

    Importante

    El archivo .env permite separar configuración del archivo docker-compose.yml.

    No deberías escribir directamente las contraseñas dentro del docker-compose.yml si puedes evitarlo.

    Preguntas de reflexión

    1. ¿Qué ventaja tiene usar variables de entorno?
    2. ¿Por qué puede ser peligroso subir un archivo .env real a un repositorio público?
    3. ¿Qué información sensible contiene este archivo?

    9. Fase 4 — Creación del docker-compose.yml

    Crea el archivo docker-compose.yml.

    Propuesta base:

    services:

    web:
    image: php:8.2-apache
    container_name: asir_web_php
    ports:
    - "${WEB_PORT}:80"
    volumes:
    - ./web:/var/www/html
    depends_on:
    - mysql
    - mongodb
    networks:
    - red_asir

    mysql:
    image: mysql:8.0
    container_name: asir_mysql
    restart: always
    environment:
    MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD}
    MYSQL_DATABASE: ${MYSQL_DATABASE}
    MYSQL_USER: ${MYSQL_USER}
    MYSQL_PASSWORD: ${MYSQL_PASSWORD}
    volumes:
    - mysql_data:/var/lib/mysql
    - ./mysql/init.sql:/docker-entrypoint-initdb.d/init.sql
    networks:
    - red_asir

    phpmyadmin:
    image: phpmyadmin:latest
    container_name: asir_phpmyadmin
    restart: always
    ports:
    - "${PHPMYADMIN_PORT}:80"
    environment:
    PMA_HOST: mysql
    PMA_PORT: 3306
    depends_on:
    - mysql
    networks:
    - red_asir

    mongodb:
    image: mongo:latest
    container_name: asir_mongodb
    restart: always
    environment:
    MONGO_INITDB_ROOT_USERNAME: ${MONGO_INITDB_ROOT_USERNAME}
    MONGO_INITDB_ROOT_PASSWORD: ${MONGO_INITDB_ROOT_PASSWORD}
    volumes:
    - mongo_data:/data/db
    networks:
    - red_asir

    mongo-express:
    image: mongo-express:latest
    container_name: asir_mongo_express
    restart: always
    ports:
    - "${MONGO_EXPRESS_PORT}:8081"
    environment:
    ME_CONFIG_MONGODB_ADMINUSERNAME: ${MONGO_INITDB_ROOT_USERNAME}
    ME_CONFIG_MONGODB_ADMINPASSWORD: ${MONGO_INITDB_ROOT_PASSWORD}
    ME_CONFIG_MONGODB_SERVER: mongodb
    depends_on:
    - mongodb
    networks:
    - red_asir

    volumes:
    mysql_data:
    mongo_data:

    networks:
    red_asir:
    driver: bridge

    9.1. Preguntas sobre el docker-compose.yml

    Responde en tu memoria:

    1. ¿Qué significa services?
    2. ¿Qué diferencia hay entre image y container_name?
    3. ¿Para qué sirve ports?
    4. ¿Qué diferencia hay entre el puerto de la izquierda y el de la derecha en esta línea?
    - "8080:80"
    1. ¿Para qué sirve volumes?
    2. ¿Qué pasaría con los datos de MySQL si no usásemos un volumen?
    3. ¿Qué hace depends_on?
    4. ¿Qué limitación tiene depends_on?
    5. ¿Para qué sirve definir una red propia llamada red_asir?
    6. ¿Por qué el servicio web puede conectarse a MySQL usando el nombre mysql?

    10. Fase 5 — Script inicial de MySQL

    Dentro de la carpeta mysql, crea el archivo init.sql.

    Ejemplo:

    CREATE TABLE IF NOT EXISTS alumnos (
    id INT AUTO_INCREMENT PRIMARY KEY,
    nombre VARCHAR(100) NOT NULL,
    apellido VARCHAR(100) NOT NULL,
    curso VARCHAR(100) NOT NULL,
    fecha_registro TIMESTAMP DEFAULT CURRENT_TIMESTAMP
    );

    INSERT INTO alumnos (nombre, apellido, curso)
    VALUES
    ('Alumno', 'Ejemplo', 'ASIR'),
    ('Docker', 'Compose', 'Servicios');

    Este script se ejecutará automáticamente cuando se cree por primera vez el contenedor de MySQL y el volumen esté vacío.

    Preguntas de reflexión

    1. ¿Cuándo se ejecutan los scripts dentro de /docker-entrypoint-initdb.d/?
    2. Si modificas init.sql después de haber creado el volumen, ¿se vuelve a ejecutar automáticamente?
    3. ¿Qué tendrías que hacer para reiniciar completamente la base de datos desde cero?
    4. ¿Por qué hay que tener cuidado al borrar volúmenes?

    11. Fase 6 — Crear la aplicación PHP

    Dentro de la carpeta web, crea el archivo index.php.

    Ejemplo:

    <?php
    $host = 'mysql';
    $db = 'asir_db';
    $user = 'asir_user';
    $password = 'asir_password';

    $conexionCorrecta = false;
    $error = '';

    try {
    $pdo = new PDO("mysql:host=$host;dbname=$db;charset=utf8", $user, $password);
    $conexionCorrecta = true;
    } catch (PDOException $e) {
    $error = $e->getMessage();
    }
    ?>

    <!DOCTYPE html>
    <html lang="es">
    <head>
    <meta charset="UTF-8">
    <title>Práctica Docker ASIR</title>
    <link rel="stylesheet" href="estilos.css">
    </head>
    <body>

    <main>
    <h1>Práctica Docker, Docker Compose y Servicios</h1>

    <section>
    <h2>Datos del alumno</h2>
    <p><strong>Nombre:</strong> Escribe aquí tu nombre</p>
    <p><strong>Curso:</strong> ASIR</p>
    <p><strong>Módulo:</strong> Implantación de aplicaciones / Servicios / Sistemas</p>
    </section>

    <section>
    <h2>Estado de la conexión con MySQL</h2>

    <?php if ($conexionCorrecta): ?>
    <p class="ok">Conexión correcta con MySQL.</p>
    <?php else: ?>
    <p class="error">Error de conexión con MySQL.</p>
    <pre><?php echo $error; ?></pre>
    <?php endif; ?>
    </section>

    <section>
    <h2>Listado de alumnos desde MySQL</h2>

    <?php
    if ($conexionCorrecta) {
    $consulta = $pdo->query("SELECT * FROM alumnos");

    echo "<table>";
    echo "<tr><th>ID</th><th>Nombre</th><th>Apellido</th><th>Curso</th><th>Fecha</th></tr>";

    while ($fila = $consulta->fetch(PDO::FETCH_ASSOC)) {
    echo "<tr>";
    echo "<td>" . htmlspecialchars($fila['id']) . "</td>";
    echo "<td>" . htmlspecialchars($fila['nombre']) . "</td>";
    echo "<td>" . htmlspecialchars($fila['apellido']) . "</td>";
    echo "<td>" . htmlspecialchars($fila['curso']) . "</td>";
    echo "<td>" . htmlspecialchars($fila['fecha_registro']) . "</td>";
    echo "</tr>";
    }

    echo "</table>";
    }
    ?>
    </section>
    </main>

    </body>
    </html>

    11.1. Archivo CSS

    Crea estilos.css:

    body {
    font-family: Arial, sans-serif;
    background-color: #f4f4f4;
    margin: 0;
    padding: 0;
    }

    main {
    width: 80%;
    margin: 40px auto;
    background-color: white;
    padding: 30px;
    border-radius: 10px;
    }

    h1 {
    color: #333;
    }

    section {
    margin-bottom: 30px;
    }

    .ok {
    color: green;
    font-weight: bold;
    }

    .error {
    color: red;
    font-weight: bold;
    }

    table {
    width: 100%;
    border-collapse: collapse;
    }

    th {
    background-color: #333;
    color: white;
    }

    td, th {
    padding: 10px;
    border: 1px solid #ccc;
    }

    11.2. Problema intencionado

    Con la imagen oficial php:8.2-apache, puede ocurrir que PHP no tenga activada la extensión necesaria para conectarse a MySQL mediante PDO.

    Si al abrir la web aparece un error relacionado con MySQL o PDO, deberás investigarlo y solucionarlo.

    Pista

    Puede ser necesario crear un Dockerfile personalizado para el servicio web.


    12. Fase 7 — Crear una imagen personalizada para PHP

    Crea un archivo llamado Dockerfile dentro de la carpeta web.

    FROM php:8.2-apache

    RUN docker-php-ext-install pdo pdo_mysql mysqli

    Ahora modifica el servicio web en el docker-compose.yml.

    Antes:

    web:
    image: php:8.2-apache

    Después:

    web:
    build: ./web

    El servicio completo quedaría así:

    web:
    build: ./web
    container_name: asir_web_php
    ports:
    - "${WEB_PORT}:80"
    volumes:
    - ./web:/var/www/html
    depends_on:
    - mysql
    - mongodb
    networks:
    - red_asir

    Preguntas de reflexión

    1. ¿Qué diferencia hay entre usar image y usar build?
    2. ¿Para qué sirve un Dockerfile?
    3. ¿Qué hace esta línea?
    RUN docker-php-ext-install pdo pdo_mysql mysqli
    1. ¿Por qué necesitamos instalar extensiones de PHP?
    2. ¿Qué ventaja tiene crear nuestra propia imagen personalizada?

    13. Fase 8 — Levantar los servicios

    Ejecuta:

    docker compose up -d

    Después comprueba:

    docker compose ps

    También puedes usar:

    docker ps

    Evidencias obligatorias

    Incluye capturas donde se vea:

    • Los contenedores levantados.
    • Los puertos publicados.
    • El estado de cada contenedor.

    Preguntas de reflexión

    1. ¿Qué significa ejecutar Docker Compose con -d?
    2. ¿Qué diferencia hay entre docker compose ps y docker ps?
    3. ¿Qué significa que un contenedor esté en estado Up?
    4. ¿Qué harías si un contenedor aparece como Restarting?

    14. Fase 9 — Comprobación de servicios en navegador

    Accede desde el navegador a:

    http://localhost:8080

    Deberías ver la aplicación PHP.

    Accede también a:

    http://localhost:8081

    Deberías ver phpMyAdmin.

    Accede a:

    http://localhost:8082

    Deberías ver Mongo Express.

    Evidencias obligatorias

    Incluye capturas de:

    1. Página PHP funcionando.
    2. phpMyAdmin mostrando la base de datos.
    3. Tabla alumnos dentro de MySQL.
    4. Mongo Express funcionando.

    Preguntas de reflexión

    1. ¿Por qué accedemos a la web usando localhost:8080 y no localhost:80?
    2. ¿Qué usuario y contraseña has utilizado para entrar en phpMyAdmin?
    3. ¿Qué base de datos aparece creada automáticamente?
    4. ¿Qué diferencia hay entre administrar MySQL desde línea de comandos y hacerlo desde phpMyAdmin?
    5. ¿Qué riesgos tendría dejar phpMyAdmin abierto en un servidor real?

    15. Fase 10 — Insertar datos desde PHP

    Crea un archivo llamado insertar.php.

    <?php
    $host = 'mysql';
    $db = 'asir_db';
    $user = 'asir_user';
    $password = 'asir_password';

    try {
    $pdo = new PDO("mysql:host=$host;dbname=$db;charset=utf8", $user, $password);

    $sql = "INSERT INTO alumnos (nombre, apellido, curso) VALUES (:nombre, :apellido, :curso)";
    $stmt = $pdo->prepare($sql);

    $stmt->execute([
    ':nombre' => 'NombreAlumno',
    ':apellido' => 'ApellidoAlumno',
    ':curso' => 'ASIR'
    ]);

    echo "Registro insertado correctamente.";
    } catch (PDOException $e) {
    echo "Error: " . $e->getMessage();
    }

    Accede a:

    http://localhost:8080/insertar.php

    Después vuelve a:

    http://localhost:8080/index.php

    Comprueba que el nuevo registro aparece en la tabla.

    Trabajo obligatorio

    Modifica el archivo para que inserte tus propios datos.

    Preguntas de reflexión

    1. ¿Qué ocurre cada vez que recargas insertar.php?
    2. ¿Por qué puede ser peligroso insertar datos directamente sin un formulario controlado?
    3. ¿Qué diferencia hay entre una consulta normal y una consulta preparada?
    4. ¿Qué problema de seguridad ayudan a evitar las consultas preparadas?

    16. Fase 11 — Crear formulario de inserción

    Crea una página formulario.php.

    <!DOCTYPE html>
    <html lang="es">
    <head>
    <meta charset="UTF-8">
    <title>Formulario de alumnos</title>
    <link rel="stylesheet" href="estilos.css">
    </head>
    <body>

    <main>
    <h1>Insertar alumno</h1>

    <form action="guardar.php" method="post">
    <label>Nombre:</label><br>
    <input type="text" name="nombre" required><br><br>

    <label>Apellido:</label><br>
    <input type="text" name="apellido" required><br><br>

    <label>Curso:</label><br>
    <input type="text" name="curso" required><br><br>

    <button type="submit">Guardar</button>
    </form>
    </main>

    </body>
    </html>

    Crea ahora guardar.php.

    <?php
    $host = 'mysql';
    $db = 'asir_db';
    $user = 'asir_user';
    $password = 'asir_password';

    if ($_SERVER['REQUEST_METHOD'] === 'POST') {
    $nombre = $_POST['nombre'] ?? '';
    $apellido = $_POST['apellido'] ?? '';
    $curso = $_POST['curso'] ?? '';

    try {
    $pdo = new PDO("mysql:host=$host;dbname=$db;charset=utf8", $user, $password);

    $sql = "INSERT INTO alumnos (nombre, apellido, curso) VALUES (:nombre, :apellido, :curso)";
    $stmt = $pdo->prepare($sql);

    $stmt->execute([
    ':nombre' => $nombre,
    ':apellido' => $apellido,
    ':curso' => $curso
    ]);

    echo "Alumno guardado correctamente.";
    echo "<br><a href='index.php'>Volver al listado</a>";

    } catch (PDOException $e) {
    echo "Error: " . $e->getMessage();
    }
    }

    Evidencia obligatoria

    Incluye captura del formulario y del registro insertado.

    Preguntas de reflexión

    1. ¿Qué método HTTP utiliza el formulario?
    2. ¿Qué diferencia hay entre GET y POST?
    3. ¿Dónde llegan los datos enviados por el formulario?
    4. ¿Qué validaciones mínimas debería tener este formulario?
    5. ¿Por qué no deberíamos confiar nunca únicamente en la validación del navegador?

    17. Fase 12 — Trabajo con MongoDB

    MongoDB es una base de datos NoSQL. En lugar de trabajar con tablas y filas, trabaja con bases de datos, colecciones y documentos.

    Accede a Mongo Express:

    http://localhost:8082

    Crea una base de datos llamada:

    asir_mongo

    Crea una colección llamada:

    inventario

    Inserta al menos tres documentos similares a estos:

    {
    "nombre": "Servidor web",
    "tipo": "contenedor",
    "servicio": "Apache PHP",
    "puerto": 8080
    }
    {
    "nombre": "Base de datos relacional",
    "tipo": "contenedor",
    "servicio": "MySQL",
    "puerto": 3306
    }
    {
    "nombre": "Base de datos NoSQL",
    "tipo": "contenedor",
    "servicio": "MongoDB",
    "puerto": 27017
    }

    Evidencias obligatorias

    Incluye capturas de:

    • Base de datos creada.
    • Colección creada.
    • Documentos insertados.

    Preguntas de reflexión

    1. ¿Qué diferencia hay entre una tabla de MySQL y una colección de MongoDB?
    2. ¿Qué diferencia hay entre una fila y un documento?
    3. ¿Qué ventajas puede tener MongoDB frente a MySQL?
    4. ¿Qué ventajas puede tener MySQL frente a MongoDB?
    5. ¿En qué tipo de proyecto usarías cada uno?

    18. Fase 13 — Comandos de administración

    Ejecuta y documenta los siguientes comandos.

    Ver contenedores activos

    docker ps

    Ver todos los contenedores

    docker ps -a

    Ver imágenes

    docker images

    Ver redes

    docker network ls

    Ver volúmenes

    docker volume ls

    Ver logs del servicio web

    docker compose logs web

    Ver logs de MySQL

    docker compose logs mysql

    Entrar dentro del contenedor web

    docker exec -it asir_web_php bash

    Dentro del contenedor, ejecuta:

    ls -la /var/www/html

    Después sal:

    exit

    Evidencias obligatorias

    Incluye capturas de al menos cinco comandos anteriores.

    Preguntas de reflexión

    1. ¿Para qué sirve docker ps?
    2. ¿Qué información muestra docker images?
    3. ¿Qué diferencia hay entre una imagen y un contenedor?
    4. ¿Qué utilidad tienen los logs?
    5. ¿Para qué puede servir entrar dentro de un contenedor?
    6. ¿Por qué no deberíamos modificar manualmente demasiadas cosas dentro de un contenedor en producción?

    19. Fase 14 — Persistencia de datos

    Vas a comprobar que los datos sobreviven aunque los contenedores se detengan.

    Ejecuta:

    docker compose down

    Después vuelve a levantar:

    docker compose up -d

    Comprueba:

    • Que la web sigue funcionando.
    • Que los datos de MySQL siguen estando.
    • Que los documentos de MongoDB siguen estando.

    Ahora ejecuta:

    docker compose down -v

    Vuelve a levantar:

    docker compose up -d

    Comprueba qué ha ocurrido con los datos.

    Mucho cuidado

    El parámetro -v elimina los volúmenes asociados al proyecto.

    Preguntas de reflexión

    1. ¿Qué diferencia hay entre docker compose down y docker compose down -v?
    2. ¿Por qué se han conservado los datos en el primer caso?
    3. ¿Por qué se han perdido los datos en el segundo caso?
    4. ¿Qué papel tienen los volúmenes en Docker?
    5. ¿Por qué la persistencia es fundamental en bases de datos?

    20. Fase 15 — Copia de seguridad de MySQL

    Realiza una copia de seguridad de la base de datos MySQL.

    Ejemplo:

    docker exec asir_mysql mysqldump -u root -p asir_db > backup_asir_db.sql

    El sistema pedirá la contraseña de root.

    Después comprueba que se ha creado el archivo:

    ls -lh backup_asir_db.sql

    Evidencia obligatoria

    Incluye captura del archivo generado.

    Preguntas de reflexión

    1. ¿Qué es mysqldump?
    2. ¿Por qué es importante hacer copias de seguridad?
    3. ¿Dónde se ha guardado el archivo SQL?
    4. ¿Qué información contiene ese archivo?
    5. ¿Sería suficiente esta copia de seguridad en un entorno real? Justifica la respuesta.

    21. Fase 16 — Restauración básica de MySQL

    Para comprobar la restauración, puedes crear una nueva base de datos desde phpMyAdmin o desde consola e importar el archivo.

    Ejemplo orientativo:

    docker exec -i asir_mysql mysql -u root -p asir_db < backup_asir_db.sql

    Preguntas de reflexión

    1. ¿Qué diferencia hay entre exportar e importar una base de datos?
    2. ¿Qué riesgos existen al restaurar una copia sobre una base de datos que ya contiene información?
    3. ¿Qué medidas tomarías antes de restaurar una copia en producción?

    22. Fase 17 — Comprobación de red entre contenedores

    Entra en el contenedor web:

    docker exec -it asir_web_php bash

    Instala herramientas de red si fuera necesario:

    apt update
    apt install -y iputils-ping

    Prueba conectividad:

    ping mysql
    ping mongodb

    Sal del contenedor:

    exit

    Preguntas de reflexión

    1. ¿Por qué podemos hacer ping mysql y no necesitamos conocer la IP del contenedor?
    2. ¿Qué papel hace el DNS interno de Docker?
    3. ¿Cambiaría la IP del contenedor si lo eliminamos y lo volvemos a crear?
    4. ¿Por qué es mejor usar nombres de servicio que direcciones IP?

    23. Fase 18 — Seguridad básica

    Analiza la configuración actual.

    Responde:

    1. ¿Qué puertos están expuestos al equipo anfitrión?
    2. ¿Qué servicios son accesibles desde el navegador?
    3. ¿Tiene sentido exponer MySQL directamente al exterior?
    4. ¿Tiene sentido exponer MongoDB directamente al exterior?
    5. ¿Qué contraseñas son débiles?
    6. ¿Qué cambiarías si esto fuese un servidor real?
    7. ¿Qué riesgos tiene usar root para administrar la base de datos?
    8. ¿Qué riesgos tiene dejar herramientas como phpMyAdmin o Mongo Express accesibles públicamente?

    Mejora obligatoria

    Modifica el docker-compose.yml para que MySQL y MongoDB no publiquen puertos hacia el exterior.

    Es decir, evita configuraciones como:

    ports:
    - "3306:3306"

    o:

    ports:
    - "27017:27017"

    Los servicios internos deben comunicarse por la red Docker, no necesariamente por puertos públicos.

    Pregunta de reflexión

    Si MySQL no tiene puerto publicado, ¿por qué phpMyAdmin puede seguir conectando con él?


    24. Fase 19 — Personalización del proyecto

    El alumno deberá personalizar la práctica.

    Como mínimo deberá:

    1. Cambiar el nombre de los contenedores.
    2. Cambiar el nombre de la base de datos.
    3. Cambiar usuario y contraseña.
    4. Personalizar la página principal.
    5. Insertar datos propios.
    6. Añadir una nueva tabla en MySQL.
    7. Añadir una nueva colección en MongoDB.
    8. Documentar los cambios realizados.

    Nueva tabla obligatoria

    Crea una tabla llamada servicios.

    Ejemplo:

    CREATE TABLE IF NOT EXISTS servicios (
    id INT AUTO_INCREMENT PRIMARY KEY,
    nombre VARCHAR(100) NOT NULL,
    imagen VARCHAR(100) NOT NULL,
    puerto VARCHAR(20),
    descripcion TEXT
    );

    Inserta al menos cinco servicios:

    • Apache/PHP.
    • MySQL.
    • phpMyAdmin.
    • MongoDB.
    • Mongo Express.

    Preguntas de reflexión

    1. ¿Qué campos has elegido para la tabla servicios?
    2. ¿Por qué has elegido esos campos?
    3. ¿Qué relación existe entre esta tabla y la infraestructura desplegada?
    4. ¿Cómo podrías mostrar esta tabla desde PHP?

    25. Fase 20 — Ampliación opcional

    Para subir nota, puedes realizar una o varias de estas mejoras.

    Opción A — Añadir Nginx como proxy inverso

    Añade un contenedor Nginx que actúe como punto de entrada.

    Debe permitir acceder a la aplicación PHP desde otro puerto o ruta.

    Opción B — Añadir Adminer

    Añade Adminer como alternativa a phpMyAdmin.

    Opción C — Añadir Redis

    Añade Redis como servicio adicional y explica para qué se utiliza.

    Opción D — Crear una aplicación PHP más completa

    La aplicación deberá permitir:

    • Insertar alumnos.
    • Listar alumnos.
    • Borrar alumnos.
    • Editar alumnos.

  • 1. Moltbot: El Asistente con Garras que Nunca se Olvida del Token

    1. Moltbot: El Asistente con Garras que Nunca se Olvida del Token

    INSTALACIÓN DE CLAWDBOT EN UBUNTU

    Objetivo:
    • Dejar Clawdbot instalado y funcional en Ubuntu.
    • Elegir entre dos modos de operación:
    1) IA externa mediante API.
    2) IA local mediante Ollama (ya presente en el sistema).

    Nivel de privilegio necesario: usuario normal con terminal y sudo.

    1. ACTUALIZAR EL SISTEMA

    Primera regla de supervivencia Linux: actualizar repos.

    Abre terminal y ejecuta:

    sudo apt update && sudo apt upgrade -y
    

    Esto asegura que tu zoológico de paquetes no tenga criaturas desactualizadas.

    2. INSTALAR NODE.JS 22 CON NVM

    Aquí usamos NVM (Node Version Manager), porque permite instalar versiones específicas sin contaminar el sistema.

    Instalación de NVM:

    curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.7/install.sh | bash
    

    Cierra terminal y ábrela de nuevo (o source ~/.bashrc si quieres ahorrar clicks mentales).

    Instala Node.js 22:

    nvm install 22
    nvm use 22
    

    Comprueba versión:

    node -v
    

    Si ves v22.x.x, perfecto.

    3. INSTALAR CLAWDBOT EN UBUNTU

    Clawdbot ofrece dos caminos: script o npm. Ambos llevan al mismo sitio.

    Opción A — Instalar con script oficial:

    curl -fsSL https://clawd.bot/install.sh | bash
    

    Opción B — Instalar vía npm:

    npm install -g clawdbot@latest
    

    Verificar que existe:

    clawdbot --version
    

    Si devuelve una versión, el bot ya está en casa.

    4. CONFIGURAR CLAWDBOT (ONBOARD)

    El programa tiene un asistente interactivo para dejarlo listo.

    Lánzalo:

    clawdbot onboard --install-daemon
    

    Durante este paso te preguntará por:

    • Método de IA
    • Tokens o claves (si usas proveedores externos)
    • Integración con mensajería (opcional)
    • Arranque como daemon (servicio en segundo plano)

    Aquí se bifurcan nuestros caminos.


    5. ESCENARIO A: USANDO IA EXTERNA

    En este modo Clawdbot actuaría como un cerebro sin neuronas propias, pidiendo a proveedores externos que piensen por él.

    Requisitos previos:

    • Haber generado tokens API en servicios como OpenAI, Anthropic, etc.
    • Tener anotada la clave (no la pierdas, equivale a la llave del laboratorio).

    Durante el onboard, escoge:

    → “Proveedor externo”
    → Introduce el endpoint si lo pide
    → Introduce tu token API

    Ejemplo típico con OpenAI (pseudointerfaz del asistente):

    Select AI Provider:
    1 - OpenAI
    2 - Anthropic
    3 - Others
    Choice: 1
    
    Enter API key: sk-********************************
    

    (Ve al final del documento para ver el proceso paso a paso)

    Una vez completado, Clawdbot usará internet para obtener las respuestas.

    Prueba de funcionamiento:

    clawdbot start
    

    Si has integrado Telegram/Discord/CLI, deberías ver respuestas.


    6. ESCENARIO B: USANDO OLLAMA LOCAL

    En este modo Clawdbot usa el cerebro que ya existe en tu máquina, sin enviar nada fuera. Captura la idea de “computación autónoma”. Muy útil en ciberseguridad o en entornos sin internet.

    Requisitos previos:

    • Ollama ya instalado y funcionando.
    • Un modelo instalado (ej: llama3).
    • Servicio de Ollama escuchando en http://localhost:11434.

    No explicamos cómo instalar Ollama porque ya está presente — solo necesitamos conectarlo.

    Durante el onboard, selecciona:

    → “Ollama (local)”

    El asistente preguntará por:

    • URL del servidor (usar http://localhost:11434)
    • Nombre del modelo (ej: llama3, mistral, etc.)

    Ejemplo textual:

    Select AI Provider:
    1 - OpenAI
    2 - Anthropic
    3 - Ollama (local)
    Choice: 3
    
    Enter Ollama Endpoint [http://localhost:11434]: 
    → (dejar en blanco para usar el valor por defecto)
    
    Enter Model Name: llama3
    

    Tras eso, Clawdbot sabrá pedirle respuestas al servicio local de Ollama.

    Prueba de funcionamiento:

    clawdbot start
    

    Si todo está en orden, al enviar una pregunta Clawdbot se la envía a Ollama y devuelve el resultado.


    7. COMPROBACIONES ÚTILES

    Ver si Clawdbot está funcionando como daemon:

    systemctl --user status clawdbot
    

    Ver logs para diagnosticar:

    clawdbot logs
    

    Ver si Ollama responde (solo en escenario B):

    curl http://localhost:11434
    

    Si responde JSON, Ollama está despierto.


    8. USO COMPLEMENTARIO

    Para integraciones con mensajería (Telegram, Discord, etc.) el asistente de onboard sirve de guía. Estas integraciones no influyen en si usas IA externa o IA local; son capas independientes del cerebro del bot.

    INSTALACIÓN DE CLAWDBOT EN WINDOWS MEDIANTE WSL

    Objetivo:
    • Iniciar un entorno Linux dentro de Windows
    • Instalar Node.js 22
    • Instalar Clawdbot
    • Configurar IA externa u Ollama

    1. HABILITAR WSL2

    Abrir PowerShell como Administrador y ejecutar:

    wsl --install
    

    Esto habilita los componentes necesarios (Subsistema Linux + máquina virtual liviana). Después quizá te pida reiniciar.

    Tras el reinicio, aparecerá Ubuntu en tu lista de aplicaciones o se te mostrará un prompt para configurar usuario y contraseña.

    2. ACTUALIZAR UBUNTU

    Abrir Ubuntu desde el menú de Windows y ejecutar:

    sudo apt update && sudo apt upgrade -y
    

    Esto pone al día los paquetes internos del nuevo Linux doméstico.

    3. INSTALAR NVM + NODE.JS 22

    NVM es el truco para tener la versión exacta de Node.js sin ensuciar el sistema.

    Instalar NVM:

    sudo apt install curl -y
    curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.7/install.sh | bash
    

    Cerrar terminal y abrirla de nuevo (o source ~/.bashrc si tienes prisa).

    Instalar Node.js 22:

    nvm install 22
    nvm use 22
    

    Verificar con:

    node -v
    

    Si devuelve v22.x.x, vas bien.

    4. INSTALAR CLAWDBOT

    Aquí dos opciones, igual que en Linux nativo:

    Opción A: Script oficial

    curl -fsSL https://clawd.bot/install.sh | bash
    

    Opción B: npm global

    npm install -g clawdbot@latest
    

    Verificar:

    clawdbot --version
    

    Si responde una versión, ya está dentro del laboratorio.

    5. CONFIGURACIÓN INICIAL

    Activar asistente interactivo:

    clawdbot onboard --install-daemon
    

    Este asistente pregunta por:
    • proveedor de IA
    • claves API para IA externa (si aplica)
    • integraciones con mensajería
    • arranque como daemon

    (Ve al final del documento para ver el proceso paso a paso)


    6. ESCENARIO A: USAR IA EXTERNA DESDE WSL

    Este es el más sencillo. Sirve para OpenAI, Anthropic, etc.

    Durante el onboard elegimos proveedor externo, metemos clave y listo. Después WSL puede salir a Internet sin problemas, así que Clawdbot obtiene las respuestas y las devuelve sin drama.

    Prueba:

    clawdbot start
    


    7. ESCENARIO B: USAR OLLAMA DESDE WSL

    Aquí hay un detalle curioso: Ollama debe correr en Windows nativo, no dentro de WSL, porque Ollama usa GPU y servicios del host. Actualmente Ollama no funciona bien dentro de WSL.

    Por tanto, el flujo es:

    1. Instalar Ollama en Windows
    2. Lanzarlo (Windows abre un servicio en localhost:11434)
    3. Desde WSL, Clawdbot le habla como si estuviera en la misma red

    Comprobación desde WSL:

    curl http://localhost:11434
    

    Si devuelve JSON, la frontera entre Windows y Linux es porosa y amigable.

    Durante el onboard, seleccionar:
    → “Ollama (local)”
    → Endpoint: http://localhost:11434
    → Modelo: por ejemplo llama3

    Después:

    clawdbot start
    

    Clawdbot enviará las preguntas desde WSL al servicio de Ollama en Windows, y te contestará sin salir jamás a la nube.

    8. DIAGNÓSTICO Y LOGS

    Estado del daemon:

    systemctl --user status clawdbot
    

    Logs:

    clawdbot logs
    

    9. NOTA

    Usar WSL es cómodo para desarrollo o pruebas, pero no siempre ideal para producción: si cierras la terminal o el portátil duerme, los servicios mueren. Para sistemas siempre despiertos, vale más montar esto en una máquina Linux real, un NAS, o un pequeño Proxmox.

    10. RESUMEN

    Para que quede en un tiro limpio:

    1. wsl --install
    2. Abrir Ubuntu
    3. sudo apt update && sudo apt upgrade -y
    4. Instalar NVM + Node.js 22
    5. Instalar Clawdbot
    6. clawdbot onboard --install-daemon
    7. Elegir IA externa o conectarlo a Ollama de Windows

    Esto deja un entorno funcional donde Clawdbot vive en WSL y la IA puede vivir en la nube o en Windows según filosofía del usuario.


    INSTALACIÓN DE CLAWDBOT EN macOS

    Objetivo:
    • Instalar Clawdbot en macOS usando Terminal
    • Permitir funcionamiento con:
    (A) IA externa o
    (B) Ollama local previamente instalado

    1. PREPARAR EL ENTORNO

    Aunque no es estrictamente obligatorio, tener Homebrew facilita la vida. Homebrew es un gestor de paquetes que convierte el Mac en una especie de «Linux con diseño bonito».

    Comprobar si está instalado:

    brew -v
    

    Si no responde con una versión, instalarlo con:

    /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
    

    Una vez instalado, cerrar y abrir Terminal.

    2. INSTALAR NODE.JS 22

    Puedes hacerlo de dos formas: Homebrew o NVM. La más limpia para versiones específicas es NVM, así que lo haremos con él.

    Instalar NVM vía Homebrew:

    brew install nvm
    

    Crear directorio para NVM:

    mkdir -p ~/.nvm
    

    Añadir a tu ~/.zshrc (o ~/.bashrc, según shell) lo siguiente:

    export NVM_DIR="$HOME/.nvm"
    source "$(brew --prefix nvm)/nvm.sh"
    

    Después recargar la shell:

    source ~/.zshrc
    

    Instalar Node.js 22:

    nvm install 22
    nvm use 22
    

    Comprobar versión:

    node -v
    

    Si ves v22.x.x, ya tienes el cerebro JavaScript funcional.

    3. INSTALAR CLAWDBOT

    Dos caminos disponibles:

    Opción A — Script oficial:

    curl -fsSL https://clawd.bot/install.sh | bash
    

    Opción B — NPM global:

    npm install -g clawdbot@latest
    

    Verificar instalación:

    clawdbot --version
    

    Si devuelve una versión, Clawdbot ya vive en tu Mac.

    4. CONFIGURACIÓN INICIAL

    Iniciar asistente interactivo:

    clawdbot onboard --install-daemon
    

    Este asistente te pedirá tres tipos de decisiones:

    1. Qué IA usar
    2. Integraciones con mensajería (opcional)
    3. Si deseas ejecutar como daemon (servicio)

    (Ve al final del documento para ver el proceso paso a paso)


    5. ESCENARIO A: IA EXTERNA EN macOS

    Este modo envía las peticiones a un proveedor externo como OpenAI o Anthropic. Es útil si quieres modelos grandes sin instalarlos localmente.

    Requisitos: token API del proveedor.

    Durante onboarding, elegir:

    AI Provider: OpenAI / Anthropic / Otros
    

    Introducir tu clave API cuando te la pida.

    Probar funcionamiento:

    clawdbot start
    

    Si has configurado una integración (Telegram, Discord, etc.) deberías recibir respuestas desde esas plataformas.


    6. ESCENARIO B: OLLAMA EN macOS

    Aquí no explicamos la instalación de Ollama porque ya está instalada según tu petición. Solo nos interesa cómo conectar.

    Comprobación rápida de que Ollama está vivo:

    curl http://localhost:11434
    

    Si devuelve JSON, el servidor está en pie.

    Durante el onboard, seleccionar:

    AI Provider: Ollama (local)
    Endpoint: http://localhost:11434
    Model Name: llama3
    

    Puedes usar cualquier modelo que tengas descargado (alto secreto: macOS tira especialmente bien con Mistral y Llama3 por tema de optimización ARM).

    Probar Clawdbot:

    clawdbot start
    

    Cuando envíes mensajes verás que Clawdbot se convierte en una especie de diplomático entre tu terminal y el modelo local.

    7. VERIFICACIÓN Y LOGS

    Comprobar si corre como daemon (usuario):

    launchctl list | grep clawdbot
    

    Observar logs de Clawdbot:

    clawdbot logs
    

    Ver si Ollama responde (solo escenario B):

    curl http://localhost:11434
    

    8. NOTAS OPERATIVAS MAC

    – macOS es actualmente uno de los mejores sistemas para IA local gracias al hardware ARM.
    – Clawdbot no requiere privilegios elevados para funcionar, solo permisos de usuario.
    – Si quieres integraciones persistentes (Telegram, Discord) conviene activar el modo daemon en el onboard.

    9. RESUMEN

    El procedimiento queda así:

    1. Instalar Homebrew (opcional pero útil)
    2. Instalar NVM
    3. Instalar Node.js 22
    4. Instalar Clawdbot
    5. Ejecutar clawdbot onboard --install-daemon
    6. Elegir IA externa u Ollama
    7. Verificar con clawdbot start

    Esta combinación te da un asistente local que piensa con modelos externos (si quieres potencia cloud) o con cerebros locales (si quieres privacidad y autonomía).

    PROCESO DE INSTALACIÓN CLOAWBOT

    ────────────────────────────────────────────
    📷 Imagen: Inicio del onboarding de Clawdbot (modo QuickStart)
    ────────────────────────────────────────────

    Descripción:
    Se muestra el asistente de configuración inicial (onboard) en la terminal. La primera pregunta confirma que el usuario entiende la naturaleza del software (agente automatizado) y se le pide confirmar con Yes.

    Elementos relevantes:

    • Onboarding mode: QuickStart
    • Configuración predeterminada del Gateway: Gateway port: 18789 Gateway bind: Loopback (127.0.0.1) Gateway auth: Token (default) Tailscale exposure: Off Direct to chat channels.

    Significado operativo:
    En este modo, Clawdbot se ejecuta de forma local, no expone el servicio en la red, y autentica mediante token. Es ideal para principiantes o entornos personales.

    Acciones recomendadas para el usuario:

    • Confirmar QuickStart en este punto si no requiere exposición de red.
    • Solo usuarios avanzados deben usar otros modos de gateway.

    ────────────────────────────────────────────
    📷 Imagen: Selección del proveedor de IA (Model/auth provider)
    ────────────────────────────────────────────

    Descripción:
    Aquí el asistente solicita elegir qué proveedor dará servicio de inferencia al bot. Esta es la decisión clave entre IA externa (nube) o IA local.

    Opciones visibles en la captura:

    • OpenAI
    • Anthropic
    • MiniMax
    • Qwen
    • Synthetic
    • Venice AI
    • Google
    • Copilot
    • OpenRouter
    • Vercel AI Gateway
    • Moonshot AI
    • Z.AI
    • OpenCode Zen
    • Skip for now

    Significado operativo:
    Esto determina de dónde obtendrá Clawdbot sus respuestas. Si el usuario planea usar Ollama más adelante, puede elegir Skip for now y configurarlo posteriormente.

    Acciones recomendadas para alumnos según escenario:

    • IA externa: seleccionar OpenAI o similar e introducir clave.
    • IA local con Ollama: seleccionar Skip for now y configurarlo después.
    • Entornos de prueba: también Skip for now si solo se quiere ver el panel.

    ────────────────────────────────────────────
    📷 Imagen: Selección del canal de comunicación (QuickStart)
    ────────────────────────────────────────────

    Descripción:
    El asistente ahora pide elegir a través de qué canal responderá el bot. Aparecen múltiples integraciones, algunas por API y otras por aplicaciones intermedias.

    Opciones visibles en la captura:

    • Telegram
    • WhatsApp
    • Discord
    • Google Chat
    • Slack
    • Signal
    • iMessage
    • Microsoft Teams
    • Nextcloud Talk
    • Matrix
    • BlueBubbles
    • LINE
    • Zalo
    • TLon (Urbit)
    • Skip for now

    Significado operativo:
    Cada integración requiere pasos adicionales (tokens, claves, o conectores). Para configurar primero el backend del bot, se puede usar Skip for now.

    Acción recomendada para alumnos en laboratorio:

    • Seleccionar Skip for now la primera vez.
    • Más adelante añadir canales con: clawdbot channels add

    ────────────────────────────────────────────
    📷 Imagen: Estado de habilidades (Skills Status) + Hooks
    ────────────────────────────────────────────

    Descripción:
    Aquí se muestra la comprobación de habilidades del agente y la posibilidad de configurar Hooks.

    Contenido clave:

    • Skills status:
      • Eligible: 7
      • Missing requirements: 42
      • Blocked by allowlist: 0
    • Configure skills now?No
    • Hooks explicados con descripción funcional.

    Significado operativo:
    Las habilidades son módulos que permiten a Clawdbot ejecutar acciones: leer archivos, ejecutar comandos, manipular memoria del agente, etc. Los Hooks permiten automatizar acciones en eventos internos.

    Acciones recomendadas:

    • Para instalaciones iniciales:
      Configure skills now?No
      Enable hooks?Skip for now
    • Para uso avanzado, activar por ejemplo:
      • boot-md para ejecutar comandos al iniciar
      • command-logger para auditoría
      • session-memory para retención de contexto

    ────────────────────────────────────────────
    📷 Imagen: Panel web de Clawdbot (Gateway Dashboard)
    ────────────────────────────────────────────

    Descripción:
    Es la interfaz web del gateway de Clawdbot. Permite gestionar chat directo, sesiones, logs, habilidades, nodos y configuración del agente.

    Elementos visibles en la captura:

    • Sección izquierda de navegación:
      • Chat
      • Overview
      • Channels
      • Sessions
      • Cron Jobs
      • Skills
      • Nodes
      • Config
      • Debug
      • Logs
      • Docs
    • Área principal mostrando ejecución de comandos:
      • read ~/clawd/SOUL.md
      • read ~/clawd/USER.md
      • exec date
      • memory_search
      • etc.

    Significado operativo:
    El panel confirma que el gateway está funcional, el agente responde a comandos, y el estado del sistema es saludable (Health OK).

    Acciones recomendadas:

    • Usar esta interfaz para verificar que el bot está funcionando.
    • Confirmar que la IA está generando respuestas en el panel (Hey, I'm online.).
    • Configurar canales o IA desde sección Config si se omitió al inicio.

  • 1. Introducción a MongoDB

    1. Introducción a MongoDB

    1. ¿Qué es MongoDB?

    MongoDB es una base de datos NoSQL orientada a documentos.
    Características principales:

    • Guarda la información en documentos JSON (llamados BSON internamente).
    • No usa tablas ni filas como en SQL.
    • Es flexible: cada documento puede tener campos distintos.
    • Escalable y ampliamente usado en desarrollo web.

    Ejemplo de documento en MongoDB:

    {
      "nombre": "Pedro",
      "edad": 23,
      "ciudad": "Madrid"
    }
    

    2. Instalación en Ubuntu/Debian

    2.1. Actualizar el sistema

    sudo apt update && sudo apt upgrade -y
    

    2.2. Instalar MongoDB desde repositorios oficiales (recomendado)

    1. Importar la clave GPG:
    curl -fsSL https://pgp.mongodb.com/server-7.0.asc | \
    sudo gpg -o /usr/share/keyrings/mongodb-server-7.0.gpg --dearmor
    
    1. Añadir el repositorio:
    echo "deb [arch=amd64,arm64 signed-by=/usr/share/keyrings/mongodb-server-7.0.gpg] \
    https://repo.mongodb.org/apt/ubuntu jammy/mongodb-org/7.0 multiverse" | \
    sudo tee /etc/apt/sources.list.d/mongodb-org-7.0.list
    

    1. Instalar MongoDB:
    sudo apt update
    sudo apt install -y mongodb-org
    

    3. Iniciar, detener y habilitar el servicio

    MongoDB se gestiona con systemctl:

    • Iniciar:
    sudo systemctl start mongod
    
    • Detener:
    sudo systemctl stop mongod
    
    • Reiniciar:
    sudo systemctl restart mongod
    
    • Ver estado:
    sudo systemctl status mongod
    
    • Habilitar al arranque:
    sudo systemctl enable mongod
    

    Comprobar que funciona:

    mongosh
    

    Si aparece el prompt test>, está funcionando correctamente.


    4. Acceso a la Consola de MongoDB (mongosh)

    La herramienta principal para trabajar con MongoDB por consola es:

    mongosh
    

    Al entrar, verás un prompt similar a:

    test>
    

    test es la base de datos por defecto.


    5. Comandos básicos

    5.1. Mostrar bases de datos

    show dbs
    

    5.2. Cambiar o crear una base de datos

    use tienda
    

    Si no existe, MongoDB la creará al guardar datos.

    5.3. Ver colecciones

    Una colección es equivalente a una tabla en SQL.

    show collections
    

    5.4. Insertar documentos

    Ejemplo:

    db.clientes.insertOne({ nombre: "Ana", edad: 25, ciudad: "Sevilla" })
    

    o varios a la vez:

    db.clientes.insertMany([
      { nombre: "Luis", edad: 30 },
      { nombre: "María", edad: 27 }
    ])
    

    5.5. Consultas (búsquedas)

    Mostrar todos:

    db.clientes.find()
    

    Filtrar:

    db.clientes.find({ edad: { $gt: 25 } })
    

    5.6. Actualizar documentos

    Modificar un campo:

    db.clientes.updateOne(
      { nombre: "Ana" },
      { $set: { ciudad: "Granada" } }
    )
    

    5.7. Borrar documentos

    Borrar uno:

    db.clientes.deleteOne({ nombre: "Luis" })
    

    Borrar varios:

    db.clientes.deleteMany({ edad: { $lt: 28 } })
    

    5.8. Borrar una colección entera

    db.clientes.drop()
    

    5.9. Borrar una base de datos

    Primero entrar en ella:

    use tienda
    

    Luego eliminarla:

    db.dropDatabase()
    

    6. Estructura conceptual

    En MongoDB la jerarquía es:

    Servidor → Bases de datos → Colecciones → Documentos → Campos
    

    Ejemplo:

    • Base de datos: tienda
    • Colección: productos
    • Documento:
    {
      "nombre": "Galletas",
      "precio": 1.20,
      "stock": 50
    }
    

    7. Exportación e Importación (extra)

    Exportar una colección:

    mongoexport --db tienda --collection clientes --out clientes.json
    

    Importar:

    mongoimport --db tienda --collection clientes --file clientes.json
    

    8. Detener el servicio y desinstalar (opcional)

    Detener:

    sudo systemctl stop mongod
    

    Desinstalar:

    sudo apt purge mongodb-org -y
    sudo rm -r /var/log/mongodb
    sudo rm -r /var/lib/mongodb
    

    Práctica Guiada: “MongoDB en la USS Horizon”

    La USS Horizon ha sido enviada a explorar un cúmulo estelar cercano a Andoria. La tripulación científica necesita un sistema de gestión para almacenar informes, muestras biológicas, registros de comunicaciones y perfiles de planetas. Como Oficial de Ingeniería Informática, tu misión es instalar un sistema MongoDB en el núcleo de datos del servidor de la nave, aprender a administrarlo por consola y cargar registros básicos.


    FASE 1 — Instalación del Servidor MongoDB

    Instalar MongoDB en el servidor Linux de la USS Horizon.

    Procedimiento

    1. Accede al servidor (terminal local o SSH).
    2. Actualiza los paquetes del sistema:
    sudo apt update && sudo apt upgrade -y
    
    1. Añade la llave GPG del “repositorio de la Federación”:
    curl -fsSL https://pgp.mongodb.com/server-7.0.asc | \
    sudo gpg -o /usr/share/keyrings/mongodb-server-7.0.gpg --dearmor
    
    1. Activa el repositorio estable:
    echo "deb [arch=amd64,arm64 signed-by=/usr/share/keyrings/mongodb-server-7.0.gpg] \
    https://repo.mongodb.org/apt/ubuntu jammy/mongodb-org/7.0 multiverse" | \
    sudo tee /etc/apt/sources.list.d/mongodb-org-7.0.list
    
    1. Instala MongoDB:
    sudo apt update
    sudo apt install -y mongodb-org
    

    Validación

    Si no ha habido errores, MongoDB está instalado en el servidor auxiliar del núcleo de datos.


    FASE 2 — Arranque del Núcleo de Datos MongoDB

    Objetivo

    Levantar el servicio mongod y verificar su estado.

    Procedimiento

    1. Inicia el servicio:
    sudo systemctl start mongod
    
    1. Comprueba su estado operativo:
    sudo systemctl status mongod
    
    1. Actívalo para que arranque con el sistema de la nave:
    sudo systemctl enable mongod
    

    Validación

    Si el servicio está activo, el núcleo de datos está disponible.


    FASE 3 — Acceso al Observador de Datos (mongosh)

    Objetivo

    Acceder a la consola interactiva de MongoDB.

    Procedimiento

    Entrada al núcleo:

    mongosh
    

    Resultado esperado:

    test>
    

    Ese prompt indica que estás dentro del sistema base.


    FASE 4 — Organización del Archivo Estelar

    En la Flota Estelar, los registros se organizan por sectores. En MongoDB será así:

    Servidor → Bases de datos → Colecciones → Documentos → Campos
    

    FASE 5 — Creación de Base de Datos y Colecciones

    Objetivo

    Crear una base de datos para almacenar datos del Sector Andoria.

    Procedimiento

    1. Cambia a la base de datos andoria_sector:
    use andoria_sector
    

    Ahora crearás una colección llamada planetas.

    1. Inserta un documento básico:
    db.planetas.insertOne({
      nombre: "Andoria",
      especie_principal: "Andoriano",
      clima: "Frío",
      alineacion: "Federación",
      tecnologia: "Warp"
    })
    
    1. Comprueba el contenido:
    db.planetas.find()
    

    FASE 6 — Manejo de Registros Científicos

    Objetivo

    Insertar, buscar, actualizar y eliminar registros.

    A) Inserciones múltiples

    Añade varios planetas explorados:

    db.planetas.insertMany([
      { nombre: "Vulcano", especie_principal: "Vulcano", alineacion: "Federación", tecnologia: "Warp" },
      { nombre: "Qo'noS", especie_principal: "Klingon", alineacion: "Imperio Klingon", tecnologia: "Warp" },
      { nombre: "Romulus", especie_principal: "Romulano", alineacion: "Imperio Estelar", tecnologia: "Warp" }
    ])
    

    B) Consultas

    Lista los planetas:

    db.planetas.find()
    

    Filtra por alineación:

    db.planetas.find({ alineacion: "Federación" })
    

    C) Actualizaciones

    El Consejo Andoriano ha cambiado la clasificación de Andoria:

    db.planetas.updateOne(
      { nombre: "Andoria" },
      { $set: { clima: "Ártico" } }
    )
    

    D) Eliminaciones

    Tras un incidente diplomático, se decide borrar temporalmente un registro:

    db.planetas.deleteOne({ nombre: "Romulus" })
    

    Comprueba que desapareció:

    db.planetas.find()
    

    FASE 7 — Gestión de Colecciones y Base de Datos

    Ver colecciones existentes

    show collections
    

    Eliminar una colección entera

    Ejemplo:

    db.planetas.drop()
    

    Eliminar una base de datos

    Primero asegúrate de estar en ella:

    use andoria_sector
    

    Luego:

    db.dropDatabase()
    

    FASE 8 — Exportación e Importación (Bitácora Estelar)

    Para generar bitácoras externas:

    Exportar colección:

    mongoexport --db andoria_sector --collection planetas --out planetas.json
    

    Importar colección:

    mongoimport --db andoria_sector --collection planetas --file planetas.json
    

    FASE 9 — Cierre del Núcleo

    Puedes detener el servicio si la nave entra en modo de sigilo:

    sudo systemctl stop mongod
    

  • 2. MongoDB Compass

    2. MongoDB Compass

    Compass es un entorno gráfico oficial para MongoDB. Permite:

    • Conectarse a una base de datos local o remota
    • Ver bases de datos y colecciones
    • Visualizar documentos
    • Crear, editar y borrar documentos
    • Crear índices
    • Lanzar agregaciones con interfaz visual
    • Ver estadísticas de la colección (distribuciones, tamaños, etc.)

    En esencia, Compass cumple el mismo papel que “phpMyAdmin” en MySQL, pero para MongoDB.


    Instalación de MongoDB Compass (Linux/Windows/macOS)

    Para clase normalmente recomiendo:

    • Que los alumnos lo instalen en su portátil si lo tienen
    • Si no, instalarlo en el servidor Linux con GUI (si existe) o usar su PC personal

    Descarga oficial

    https://www.mongodb.com/try/download/compass

    Ir a:

    Seleccionar:

    • Versión estable
    • Sistema operativo correspondiente

    Instalar siguiendo el asistente.


    Configuración inicial en clase

    Antes de abrir Compass, asegúrate de que el servidor MongoDB ya está corriendo en Linux:

    sudo systemctl status mongod
    

    Y que el puerto por defecto (27017) está accesible en la red del aula.

    Si usan Compass desde sus ordenadores:

    • Conexión dentro de la misma LAN del aula → bien
    • Si hay cortafuegos, abrir el puerto 27017
    • Si es SSH, configurar túnel (lo explico más abajo opcionalmente)

    Conexión desde Compass (práctica guiada sencilla)

    Abrir Compass → aparecerá pantalla con Connection String.

    Por defecto la cadena es:

    mongodb://localhost:27017
    

    Casos:

    Caso A: Compass instalado en el servidor

    Usar:

    mongodb://localhost:27017
    

    Clic Connect.

    Caso B: Compass desde portátil del alumno

    Si conocen la IP del servidor:

    mongodb://IP_DEL_SERVIDOR:27017
    

    Ejemplo:

    mongodb://192.168.0.50:27017
    

    Para realizar conexiones remotas debemos cambiar la configuración del archivo mongod.conf

    sudo nano /etc/mongod.conf

    y cambiar el 127.0.0.1 por 0.0.0.

    Clic Connect.

    Si la conexión funciona, aparecen las bases de datos.


    Exploración visual de datos (lo que deben observar)

    Una vez dentro:

    1. Sección izquierda: lista de bases de datos
    2. Seleccionar andoria_sector (o la que crearon antes)
    3. Seleccionar colección planetas

    Ahora verán documentos tipo:

    {
      "_id": ObjectId("..."),
      "nombre": "Andoria",
      "especie_principal": "Andoriano",
      ...
    }
    

    Aquí ya puedes hacer mini demostración:

    • Ordenar por campo
    • Editar un documento (botón Edit Document)
    • Añadir nuevos campos manualmente
    • Borrar un documento desde la interfaz

    Esto consolida el concepto “un documento no necesita la misma estructura en todos los registros”.


    Agregaciones visuales (el jugo interesante)

    Compass tiene una sección llamada Aggregations:

    • Clic en Aggregations
    • Crear un pipeline con $match
    • Ejemplo:
    { "$match": { "alineacion": "Federación" } }
    

    Esto muestra solo planetas federados.

    Si quieres mostrarles algo más vistoso:

    • $group por alineacion
    • $sort descendente por conteo

    El pipeline sería:

    [
      { "$group": { "_id": "$alineacion", "total": { "$sum": 1 } } },
      { "$sort": { "total": -1 } }
    ]
    

    Esto es excelente para enseñar que MongoDB es más “analítico” que un simple CRUD.


    Índices

    Compass → pestaña Indexes

    Allí puedes:

    • Ver índices existentes
    • Crear uno nuevo desde GUI

    Por ejemplo, crear índice en nombre:

    • Clic Create Index
    • Campo: nombre
    • Orden: Ascending
    • Crear

    Esto deja caer la idea de rendimiento sin entrar en ingeniería pesada.


    Estadísticas de colección

    Compass tiene una pestaña Schema que permite:

    • Inferir estructura de documentos
    • Detectar tipos
    • Ver distribuciones

    Ejemplo: podrían ver que clima es “Frío”, “Ártico”, etc.
    Visualmente ayuda a entender diversidad de documentos.


    Práctica Guiada: “Exploración Visual de Datos con MongoDB Compass”

    La USS Horizon ha completado su instalación del núcleo MongoDB en la sala de máquinas. Ahora la Sección de Ciencia quiere que los oficiales accedan a los registros desde una interfaz visual que permita agrupar, filtrar y entender datos sin necesidad de abrir un terminal. Te han asignado la operación.


    FASE 1 — Preparar la Conexión desde Compass

    Tu estación de trabajo local será el cliente de monitorización. Antes de iniciar la misión:

    1. Asegúrate de que MongoDB está activo en el servidor de la nave:
    sudo systemctl status mongod
    
    1. Si estás en el mismo equipo donde instalaste MongoDB, podrás conectarte con localhost.
    2. Si estás desde otro equipo del aula, necesitas la IP del servidor de la nave (por ejemplo 192.168.0.50).

    Abre MongoDB Compass y en el campo de conexión escribe:

    Para conexión local:

    mongodb://localhost:27017
    

    Para conexión remota en la red de aula:

    mongodb://IP_DEL_SERVIDOR:27017
    

    Pulsa Connect. Si todo va bien, deberías ver una lista de bases de datos en la barra lateral izquierda. Bienvenido al puente de mando.


    FASE 2 — Exploración de la Biblioteca de Datos

    Al conectarte, Compass mostrará un conjunto de bases predeterminadas del sistema.

    Tu tarea inicial consiste en crear una estructura nueva que represente planetas registrados por la Federación.

    1. Dirígete al botón de Create database
    2. Nombre de la base de datos: fed_records
    3. Nombre de la colección inicial: planets
    4. Clic en Create

    Acabas de crear un archivo científico dentro de la Biblioteca Estelar.


    FASE 3 — Inserción de Datos Científicos

    Ahora toca poblar la colección con datos reales que los sensores ya capturaron.
    Compass permite insertar datos con un editor visual.

    Abre la colección planets y pulsa Insert Document.

    Aparece un editor con un documento JSON. Rellénalo con:

    {
      "name": "Vulcan",
      "species": "Vulcans",
      "affiliation": "Federation",
      "warp_capable": true
    }
    

    Pulsa Insert para guardar.

    Agrega un segundo documento pero esta vez usando Insert Document y cambia el contenido:

    {
      "name": "Qo'noS",
      "species": "Klingons",
      "affiliation": "Klingon Empire",
      "warp_capable": true
    }
    

    Inserta un tercero:

    {
      "name": "Ferenginar",
      "species": "Ferengi",
      "affiliation": "Ferengi Alliance",
      "warp_capable": true
    }
    

    Fíjate en un detalle interesante: no hay esquema rígido. MongoDB no te obliga a declarar columnas antes. Es como una biblioteca que acepta libros sin exigir número exacto de capítulos.


    FASE 4 — Visualización y Edición de Documentos

    Observa cómo Compass representa cada documento con su _id. Esa key es asignada automáticamente y sirve como identificador universal.

    Ahora haz dos pruebas:

    1. Edita un documento desde el icono Edit Document
      Cambia warp_capable de true a false en algún planeta no confirmado. Guarda y comprueba que Compass valida el JSON.
    2. Elimina un planeta usando el botón Delete para simular que los registros debieron ser clasificadas tras un fallo diplomático.

    Nadie en la Flota se escapa del poder del botón Delete.


    FASE 5 — Consultas Visuales con Filtros

    La Sección de Ciencia quiere consultar todos los planetas bajo Federation.
    Compass lo hace sin comandos: usa el buscador superior.

    Pulsa el filtro visual y escribe:

    { "affiliation": "Federation" }
    

    Pulsa Apply.

    Si el universo está en orden, solo aparecerán planetas pertenecientes a la Federación.


    FASE 6 — Agregaciones en la Sala de Análisis

    Compass dispone de un módulo llamado Aggregations que permite crear pipelines de análisis (equivalente a map–reduce ligero).

    Entra en Aggregations y añade una etapa $group:

    {
      "$group": {
        "_id": "$affiliation",
        "total": { "$sum": 1 }
      }
    }
    

    Pulsa Run.

    Compass mostrará un resultado parecido a una estadística diplomática:

    Federation: 1
    Klingon Empire: 1
    Ferengi Alliance: 1
    

    Este tipo de vista enseña que MongoDB no solo guarda datos, también los procesa de forma analítica.


    FASE 7 — Inferir Esquemas

    Entra en la pestaña Schema dentro de la colección.

    Compass examinará los documentos e inferirá:

    • Tipos de campos
    • Frecuencia de aparición
    • Valores más comunes

    Esto simula cómo la Sección de Xenobiología analiza patrones entre especies sin necesidad de preguntar “¿cuál es la estructura del registro?”.


    FASE 8 — Crear Índices

    Ahora ve a la pestaña Indexes para crear un índice sobre el campo name.

    Pulsa Create Index y configura:

    • Field: name
    • Sort: Ascending

    Clic en Create.

    MongoDB construirá el índice internamente. Tu planeta ahora se encuentra más rápido cuando alguien lo necesita. Rendimiento y diplomacia se dan la mano.


    FASE 9 — Desconexión y Cierre de Misión

    Cierra Compass.
    Detén el servicio MongoDB solo si el servidor necesita entrar en modo sigilo:

    sudo systemctl stop mongod
    

    La misión Compass se considera cumplida si has conseguido:

    • Conectarse a una instancia MongoDB
    • Crear bases de datos y colecciones desde GUI
    • Insertar y editar documentos
    • Filtrar visualmente

  • 3. MongoDB desde PHP y Python

    3. MongoDB desde PHP y Python

    Partimos de:

    • Servidor MongoDB: ya instalado y corriendo en Linux (mongod).
    • Base de datos de ejemplo: fed_records
    • Colección de ejemplo: planets
    • Conexión por defecto: mongodb://localhost:27017
      (si el servidor está en otra máquina: mongodb://IP_DEL_SERVIDOR:27017)

    En ambos lenguajes usaremos:

    • Crear conexión
    • Elegir base de datos y colección
    • CRUD básico: insertar, listar, buscar, actualizar, borrar

    Uso de MongoDB desde PHP

    Instalar el driver de MongoDB para PHP

    En un entorno típico (Linux con PHP y Apache):

    1. Instalar la extensión de MongoDB:
    sudo pecl install mongodb
    

    Puede ser que no tengas instaladas las herramientas deb, para hacerlo en ubuntu:

    sudo apt update
    sudo apt install php-pear php-dev build-essential

    Tambien debemos instalar el conector de mongo con PHP

    sudo apt install php-mongodb

    1. Activar la extensión en PHP (por ejemplo en /etc/php/8.3/apache2/php.ini o similar):

    Añadir esta línea:

    extension=mongodb.so
    
    1. Reiniciar Apache:
    sudo systemctl restart apache2
    
    1. Instalar el paquete Composer del driver oficial:

    En el directorio del proyecto PHP:

    composer require mongodb/mongodb
    

    Si no usan Composer todavía, esta es buena ocasión para introducirlo.

    Si no tienes instalada la herramienta composer de php:

    sudo apt install composer

    Recuerda que siempre es util pedir al servidor que muestre los errores de código.

    ini_set(‘display_errors’, 1);

    ini_set(‘display_startup_errors’, 1);

    error_reporting(E_ALL);

    Estructura de conexión en PHP

    Archivo de ejemplo: mongo_test.php

    <?php
    require 'vendor/autoload.php'; // Carga automática de Composer
    
    use MongoDB\Client;
    
    // 1. Crear cliente (conexión)
    $client = new Client("mongodb://localhost:27017");
    
    // 2. Seleccionar base de datos y colección
    $database = $client->fed_records;
    $collection = $database->planets;
    
    // 3. Insertar un documento
    $insertResult = $collection->insertOne([
        'name' => 'Vulcan',
        'species' => 'Vulcans',
        'affiliation' => 'Federation',
        'warp_capable' => true
    ]);
    
    echo "Insertado con ID: " . $insertResult->getInsertedId() . "<br>";
    
    // 4. Buscar todos los documentos
    echo "<h2>Lista de planetas:</h2>";
    
    $cursor = $collection->find();
    
    foreach ($cursor as $planet) {
        echo "Nombre: " . $planet['name'] . " - Alineación: " . $planet['affiliation'] . "<br>";
    }
    
    // 5. Búsqueda filtrada
    echo "<h2>Planetas de la Federación:</h2>";
    
    $cursor = $collection->find(['affiliation' => 'Federation']);
    
    foreach ($cursor as $planet) {
        echo "Nombre: " . $planet['name'] . "<br>";
    }
    

    Abrir en el navegador (por ejemplo):
    http://localhost/mongo_test.php


    Operaciones CRUD básicas en PHP

    Insertar varios documentos

    $collection->insertMany([
        [
            'name' => 'Qo\'noS',
            'species' => 'Klingons',
            'affiliation' => 'Klingon Empire',
            'warp_capable' => true
        ],
        [
            'name' => 'Ferenginar',
            'species' => 'Ferengi',
            'affiliation' => 'Ferengi Alliance',
            'warp_capable' => true
        ]
    ]);
    

    Buscar un solo documento

    $planet = $collection->findOne(['name' => 'Vulcan']);
    
    if ($planet) {
        echo "Encontrado: " . $planet['name'] . " (" . $planet['species'] . ")";
    }
    

    Actualizar

    $updateResult = $collection->updateOne(
        ['name' => 'Vulcan'],
        ['$set' => ['warp_capable' => false]]
    );
    
    echo "Documentos modificados: " . $updateResult->getModifiedCount();
    

    Borrar

    $deleteResult = $collection->deleteOne(['name' => 'Ferenginar']);
    
    echo "Documentos eliminados: " . $deleteResult->getDeletedCount();
    

    Con esto ya pueden hacer una pequeña “mini-API” o scripts de administración en PHP.


    Uso de MongoDB desde Python

    Instalar el driver de MongoDB para Python

    Usaremos el driver oficial pymongo.

    Pymongo vive fuera del zoológico de paquetes de Ubuntu, así que el mensaje de PEP 668 que viste antes aplica aquí. La forma elegante es montar un entorno virtual y meter ahí el driver.

    Pasos rápidos:

    Instala las herramientas para crear entornos:

    sudo apt install python3-venv python3-full
    

    Crea un entorno para tu proyecto Mongo:

    python3 -m venv ~/.venvs/mongo
    

    Actívalo:

    source ~/.venvs/mongo/bin/activate
    

    Ahora el pip dentro de ese entorno puede instalar lo que sea sin que Ubuntu proteste:

    pip install pymongo
    

    Comprueba que funciona desde Python:

    python3 - << 'EOF'
    import pymongo
    print("Pymongo ok, versión:", pymongo.__version__)
    EOF


    Conexión y CRUD básico en Python

    Archivo de ejemplo: mongo_test.py

    from pymongo import MongoClient
    
    # 1. Crear cliente (conexión)
    client = MongoClient("mongodb://localhost:27017")
    
    # 2. Seleccionar base de datos y colección
    db = client["fed_records"]
    planets = db["planets"]
    
    # 3. Insertar un documento
    result = planets.insert_one({
        "name": "Vulcan",
        "species": "Vulcans",
        "affiliation": "Federation",
        "warp_capable": True
    })
    
    print("Insertado con ID:", result.inserted_id)
    
    # 4. Obtener todos los documentos
    print("\nLista de planetas:")
    for planet in planets.find():
        print(f"- {planet['name']} ({planet['affiliation']})")
    
    # 5. Búsqueda filtrada
    print("\nPlanetas de la Federación:")
    for planet in planets.find({"affiliation": "Federation"}):
        print(f"- {planet['name']}")
    

    Ejecutar:

    python3 mongo_test.py
    

    Operaciones CRUD más completas en Python

    planets.insert_many([
        {
            "name": "Qo'noS",
            "species": "Klingons",
            "affiliation": "Klingon Empire",
            "warp_capable": True
        },
        {
            "name": "Ferenginar",
            "species": "Ferengi",
            "affiliation": "Ferengi Alliance",
            "warp_capable": True
        }
    ])
    

    Buscar uno

    Insertar varios

    vulcan = planets.find_one({"name": "Vulcan"})
    if vulcan:
        print("Encontrado:", vulcan["name"], "-", vulcan["species"])
    

    Actualizar

    update_result = planets.update_one(
        {"name": "Vulcan"},
        {"$set": {"warp_capable": False}}
    )
    
    print("Documentos modificados:", update_result.modified_count)
    

    Borrar

    delete_result = planets.delete_one({"name": "Ferenginar"})
    print("Documentos eliminados:", delete_result.deleted_count)
    

    Ejemplo de pequeña “consulta analítica” (aggregations) en Python

    Simulando algo tipo “cuántos planetas hay por alineación”:

    pipeline = [
        {"$group": {"_id": "$affiliation", "total": {"$sum": 1}}},
        {"$sort": {"total": -1}}
    ]
    
    print("\nResumen por alineación:")
    for group in planets.aggregate(pipeline):
        print(f"{group['_id']}: {group['total']}")
    

    Este ejemplo encaja muy bien con lo que ya han visto en Compass (pestaña Aggregations).


    Práctica Guiada:

    “Un mismo universo de datos: PHP, Python y MongoDB Compass”

    Antes de empezar, debe estar listo:

    1. Servidor MongoDB instalado y funcionando en el servidor Linux: sudo systemctl status mongod
    2. PHP instalado (por ejemplo PHP 8.x) y un servidor web (Apache) o PHP CLI.
    3. Composer instalado: composer --version
    4. Python 3 instalado: python3 --version
    5. MongoDB Compass instalado en el equipo del alumno o en alguna máquina con entorno gráfico.

    PARTE 1 – PHP + MongoDB

    Fase 1.1 — Preparar el proyecto PHP

    1. Crea una carpeta para el proyecto, por ejemplo: mkdir ~/mongo_php_lab cd ~/mongo_php_lab
    2. Instala el driver oficial de MongoDB para PHP vía Composer: composer require mongodb/mongodb
    3. Asegúrate de tener instalada y activada la extensión nativa de MongoDB en PHP:
      • Instalar extensión (si no está): sudo pecl install mongodb
      • Añadir en el php.ini correspondiente (CLI o Apache): extension=mongodb.so
      • Reiniciar Apache si usas servidor web: sudo systemctl restart apache2
      • Comprobar desde CLI: php -m | grep mongodb
      Debe aparecer mongodb en la lista de módulos.

    Fase 1.2 — Crear el script PHP

    Crea el archivo mongo_php_lab.php dentro de ~/mongo_php_lab con este contenido:

    <?php
    require 'vendor/autoload.php';
    
    use MongoDB\Client;
    
    // 1. Conexión al servidor MongoDB
    $client = new Client("mongodb://localhost:27017");
    
    // 2. Selección de base de datos y colección
    $database = $client->fed_records;
    $collection = $database->planets;
    
    echo "<h1>PHP + MongoDB: Laboratorio de planetas</h1>";
    
    // 3. Insertar varios planetas (insertMany)
    echo "<h2>1. Insertando planetas...</h2>";
    
    $insertResult = $collection->insertMany([
        [
            'name' => 'Vulcan',
            'species' => 'Vulcans',
            'affiliation' => 'Federation',
            'warp_capable' => true
        ],
        [
            'name' => "Qo'noS",
            'species' => 'Klingons',
            'affiliation' => 'Klingon Empire',
            'warp_capable' => true
        ],
        [
            'name' => 'Ferenginar',
            'species' => 'Ferengi',
            'affiliation' => 'Ferengi Alliance',
            'warp_capable' => true
        ]
    ]);
    
    echo "Planetas insertados: " . $insertResult->getInsertedCount() . "<br>";
    
    // 4. Listar todos los planetas
    echo "<h2>2. Lista completa de planetas</h2>";
    
    $cursor = $collection->find();
    
    foreach ($cursor as $planet) {
        echo "Nombre: " . $planet['name'] .
             " | Especie: " . $planet['species'] .
             " | Alineación: " . $planet['affiliation'] .
             " | Warp: " . ($planet['warp_capable'] ? 'Sí' : 'No') .
             "<br>";
    }
    
    // 5. Mostrar solo los de la Federación
    echo "<h2>3. Planetas de la Federación</h2>";
    
    $cursorFed = $collection->find(['affiliation' => 'Federation']);
    
    foreach ($cursorFed as $planet) {
        echo "Nombre: " . $planet['name'] . "<br>";
    }
    
    // 6. Cambiar un campo (warp_capable) para Vulcan
    echo "<h2>4. Actualizando warp_capable de Vulcan a false</h2>";
    
    $updateResult = $collection->updateOne(
        ['name' => 'Vulcan'],
        ['$set' => ['warp_capable' => false]]
    );
    
    echo "Documentos modificados: " . $updateResult->getModifiedCount() . "<br>";
    
    // 7. Borrar un registro (Ferenginar)
    echo "<h2>5. Borrando el planeta Ferenginar</h2>";
    
    $deleteResult = $collection->deleteOne(['name' => 'Ferenginar']);
    
    echo "Documentos eliminados: " . $deleteResult->getDeletedCount() . "<br>";
    
    // 8. Lista final para comprobar cambios
    echo "<h2>6. Lista final de planetas tras cambios</h2>";
    
    $cursorFinal = $collection->find();
    
    foreach ($cursorFinal as $planet) {
        echo "Nombre: " . $planet['name'] .
             " | Alineación: " . $planet['affiliation'] .
             " | Warp: " . ($planet['warp_capable'] ? 'Sí' : 'No') .
             "<br>";
    }
    

    Fase 1.3 — Ejecutar el script PHP

    Opción A – Desde navegador (si usas Apache):

    1. Copia el proyecto a la carpeta del servidor, por ejemplo: sudo cp -r ~/mongo_php_lab /var/www/html/
    2. En el navegador, abre: http://IP_DEL_SERVIDOR/mongo_php_lab/mongo_php_lab.php

    Opción B – Desde línea de comandos (CLI):

    cd ~/mongo_php_lab
    php mongo_php_lab.php
    

    (La salida será texto plano, pero funcional para comprobar inserciones y cambios.)

    Cuando termine esta parte, en la colección fed_records.planets deberían existir al menos:

    • Vulcan (warp_capable = false tras el update)
    • Qo'noS
      Y no debería estar Ferenginar (borrado).

    PARTE 2 – Python + MongoDB

    Ahora toca hacer lo mismo, pero desde Python, y además añadir una agregación por affiliation.

    Fase 2.1 — Instalar pymongo

    En el servidor o equipo donde ejecutes Python:

    pip install pymongo
    

    (si usas pip3, cámbialo por pip3)


    Fase 2.2 — Crear el script Python

    En tu home (o donde quieras), crea para el lab:

    mkdir ~/mongo_python_lab
    cd ~/mongo_python_lab
    

    Crea el archivo mongo_python_lab.py con este contenido:

    from pymongo import MongoClient
    
    # 1. Conexión al servidor MongoDB
    client = MongoClient("mongodb://localhost:27017")
    
    # 2. Seleccionar base de datos y colección
    db = client["fed_records"]
    planets = db["planets"]
    
    print("PYTHON + MongoDB: Laboratorio de planetas\n")
    
    # 3. Insertar nuevos planetas
    print("1) Insertando nuevos planetas...\n")
    
    insert_result = planets.insert_many([
        {
            "name": "Andoria",
            "species": "Andorians",
            "affiliation": "Federation",
            "warp_capable": True
        },
        {
            "name": "Cardassia Prime",
            "species": "Cardassians",
            "affiliation": "Cardassian Union",
            "warp_capable": True
        }
    ])
    
    print("IDs insertados:", insert_result.inserted_ids, "\n")
    
    # 4. Listar todos los planetas
    print("2) Lista completa de planetas:")
    
    for planet in planets.find():
        print(f"- {planet['name']} ({planet['affiliation']}) | Warp: {planet.get('warp_capable', 'N/A')}")
    
    print()
    
    # 5. Filtrar solo la Federación
    print("3) Planetas de la Federación:")
    
    for planet in planets.find({"affiliation": "Federation"}):
        print(f"- {planet['name']}")
    
    print()
    
    # 6. Actualizar: poner warp_capable = True de nuevo en Vulcan (si existe)
    print("4) Actualizando warp_capable de Vulcan a True...\n")
    
    update_result = planets.update_one(
        {"name": "Vulcan"},
        {"$set": {"warp_capable": True}}
    )
    
    print("Documentos modificados:", update_result.modified_count, "\n")
    
    # 7. Borrar un planeta concreto: Cardassia Prime
    print("5) Borrando Cardassia Prime...\n")
    
    delete_result = planets.delete_one({"name": "Cardassia Prime"})
    print("Documentos eliminados:", delete_result.deleted_count, "\n")
    
    # 8. Agregación por affiliation
    print("6) Agregación: número de planetas por affiliation:\n")
    
    pipeline = [
        {"$group": {"_id": "$affiliation", "total": {"$sum": 1}}},
        {"$sort": {"total": -1}}
    ]
    
    for group in planets.aggregate(pipeline):
        print(f"{group['_id']}: {group['total']} planetas")
    

    Fase 2.3 — Ejecutar el script Python

    Desde la carpeta del proyecto:

    cd ~/mongo_python_lab
    python3 mongo_python_lab.py
    

    Observa:

    • Insertará Andoria y Cardassia Prime.
    • Luego listará todo lo que haya en fed_records.planets (incluyendo lo creado por PHP).
    • Volverá a poner Vulcan con warp_capable = True.
    • Borrará Cardassia Prime.
    • Mostrará la agregación por affiliation.

    Con esto ya habrán hecho la misma lógica (y algo más) que en PHP, pero desde Python.


    PARTE 3 – Verificación en MongoDB Compass

    (La parte chula para cerrar el círculo)

    Fase 3.1 — Conectarse con Compass

    1. Abre MongoDB Compass.
    2. En la pantalla inicial de conexión, usa:
      • Si Compass está en el mismo servidor que MongoDB:
        • mongodb://localhost:27017
      • Si Compass está en otro equipo de la red:
        • mongodb://IP_DEL_SERVIDOR:27017
    3. Pulsa Connect.

    Fase 3.2 — Explorar la base de datos fed_records

    1. En la barra lateral izquierda, localiza la base de datos fed_records.
    2. Entra en la colección planets.

    Ahí deberías ver documentos provenientes de:

    • Las inserciones del script PHP.
    • Las inserciones del script Python.

    Es decir, una mezcla de Vulcan, Qo’noS, Andoria, etc.


    Fase 3.3 — Comprobar coherencia de los cambios

    1. Verifica que:
      • Vulcan existe y tiene warp_capable = true (último cambio lo hizo Python).
      • Ferenginar no está (PHP lo borró).
      • Cardassia Prime no está (Python lo borró).
    2. Modifica un documento desde Compass, por ejemplo:
      • Edita Qo'noS y cambia affiliation a "Klingon Empire (Updated)".
      • Guarda los cambios.
    3. Vuelve a ejecutar el script Python: cd ~/mongo_python_lab python3 mongo_python_lab.py En la parte de “lista completa de planetas” verás la nueva affiliation de Qo'noS leída desde Python.
    4. Si vuelves a ejecutar el script PHP, también verá la misma realidad.

    Con esto se ve claramente que la fuente de verdad es MongoDB, y PHP / Python / Compass son solo distintas formas de mirar y manipular ese mismo universo de datos.


  • 1. Introducción al Shell y al Scripting

    1. Introducción al Shell y al Scripting

    1. ¿Qué es un Shell?

    Un shell es un programa que permite al usuario comunicarse con el sistema operativo. Interpreta los comandos que escribimos y envía instrucciones al sistema para que las ejecute.

    En sistemas GNU/Linux existen varios shells. Algunos de los más conocidos son:

    • Bash (Bourne Again SHell): el más utilizado en Linux, objetivo de este curso.
    • Zsh: muy usado en macOS y por usuarios que personalizan el terminal.
    • Fish: ofrece funcionalidades más modernas (autocompletado avanzado, etc.).
    • Dash: es un shell muy minimalista usado en muchos sistemas para scripts del sistema.

    En nuestro caso trabajaremos con Bash porque es el estándar en Ubuntu y muy común en servidores Linux.


    2. ¿Qué es Bash?

    Bash es tanto un intérprete de comandos como un lenguaje de scripting. Esto significa que:

    • Podemos usarlo interactivamente, escribiendo comandos en la terminal.
    • Podemos guardar comandos en un archivo para ejecutarlos como un programa.

    Gracias a esto, Bash es muy útil para:

    • Automatizar tareas repetitivas.
    • Administrar sistemas Linux.
    • Crear herramientas personalizadas.
    • Trabajar en entornos DevOps y ciberseguridad.

    3. ¿Qué es un Script?

    Un script es un archivo que contiene una secuencia de comandos. En lugar de escribirlos uno a uno en la terminal, los agrupamos para que se ejecuten automáticamente.

    Un ejemplo básico de script sería:

    
    
    
    
    
    echo "Hola, mundo!"
    echo "Este es mi primer script."
    

    Un script se ejecuta de principio a fin, permitiendo automatizar procesos como:

    • Copias de seguridad.
    • Instalación de software.
    • Monitorización del sistema.
    • Generación de informes.
    • Gestión de archivos.

    4. ¿Por qué aprender Bash?

    Dominar Bash abre la puerta a muchas áreas técnicas, como:

    • Administración de sistemas y servidores.
    • DevOps y automatización CI/CD.
    • Ciberseguridad (análisis, auditorías, automatización).
    • Ciencia de datos (procesamiento rápido de archivos).
    • Desarrollo backend y despliegues.

    Además:

    • Está disponible por defecto en la mayoría de sistemas Linux.
    • Funciona en entornos gráficos y no gráficos.
    • Requiere pocos recursos.
    • Es sencillo de empezar, pero muy potente en niveles avanzados.

    5. Rutas, Directorios y Comandos Básicos

    Para trabajar con Bash necesitamos movernos entre carpetas y ejecutar comandos.

    Algunos comandos básicos que ya deberías conocer o aprender ahora son:

    • pwd — muestra la ruta actual (“print working directory”)
    • ls — lista los archivos en el directorio
    • cd — cambia de directorio
    • mkdir — crea una carpeta
    • touch — crea un archivo vacío
    • cat — muestra el contenido de un archivo
    • rm, cp, mv — borrar, copiar y mover archivos
    • man comando — ver el manual de un comando

    Estos comandos se usan tanto en modo interactivo como dentro de scripts.


    6. Tipos de Rutas: Absolutas y Relativas

    En Linux todo comienza en /, llamado root del sistema.

    Existen dos tipos de rutas:

    Ruta absoluta: empieza desde la raíz del sistema.
    Ejemplos:

    
    
    
    
    
    /home/usuario/documentos
    /etc
    /var/log
    

    Ruta relativa: depende de la ruta en la que estés.
    Ejemplos:

    
    
    
    
    
    ./miarchivo
    ../otra_carpeta
    scripts/
    

    Conocer esto es importante para escribir scripts reproducibles.


    7. Primer Script: Hola Mundo

    Vamos a crear un script sencillo para entender el proceso.

    1. Crea un archivo:
    
    
    
    
    
    nano hola.sh
    
    1. Escribe dentro:
    
    
    
    
    
    #!/bin/bash
    echo "Hola mundo desde Bash"
    
    1. Guarda y sal del editor.
    2. Dale permisos de ejecución:
    
    
    
    
    
    chmod +x hola.sh
    
    1. Ejecútalo:
    
    
    
    
    
    ./hola.sh
    

    Si aparece el texto en pantalla, lo has hecho bien.


    8. ¿Qué es el Shebang?

    La primera línea del script se llama shebang, y sirve para indicar qué intérprete debe ejecutar el archivo.

    Ejemplos:

    • #!/bin/bash → interpreta el script con Bash
    • #!/usr/bin/python3 → interpreta con Python 3
    • #!/bin/sh → shell compatible POSIX

    Si no pones shebang, el sistema usará el intérprete por defecto, lo que puede causar comportamientos inesperados.


    9. Errores habituales del Principiante

    Es normal ver errores como:

    • permission denied → falta ejecutar chmod +x script.sh
    • command not found → se ejecuta con un shell distinto o está mal escrito
    • no such file or directory → falta ruta, archivo o extensión

    También es común olvidar que Linux diferencia mayúsculas y minúsculas:

    
    
    
    
    
    hola.sh ≠ Hola.sh ≠ HOLA.SH
    

    Ejercicios propuestos

    Ejercicio 1: Abrir la terminal y ejecutar los comandos:

    • pwd
    • ls
    • cd hacia diferentes carpetas
    • Crear y borrar archivos con touch y rm

    Ejercicio 2: Crear un script llamado presentacion.sh que muestre:

    • Tu nombre
    • El día actual
    • Tu directorio de trabajo

    Ejemplo de salida esperada:

    
    
    
    
    
    Mi nombre es Juan Pérez
    Hoy es 2026-01-10
    Estoy trabajando en /home/juan
    

    Ejercicio 3: Crear un script que liste los archivos del directorio /etc y guarde el resultado en etc-listado.txt.


    Soluciones

    Ejercicio 1 — Solución

    Enunciado:
    Abrir la terminal y ejecutar los comandos:

    • pwd
    • ls
    • cd hacia diferentes carpetas
    • Crear y borrar archivos con touch y rm

    📌 Solución / Resultado esperado:

    1. Mostrar la ruta actual:
    
    
    
    
    
    pwd
    

    Ejemplo de salida:

    
    
    
    
    
    /home/alumno
    
    1. Listar archivos del directorio actual:
    
    
    
    
    
    ls
    

    Salida posible:

    
    
    
    
    
    Documentos  Descargas  Imágenes
    
    1. Cambiar de directorio:
    
    
    
    
    
    cd Documentos
    pwd
    

    Ejemplo:

    
    
    
    
    
    /home/alumno/Documentos
    

    Luego volver al home:

    
    
    
    
    
    cd ~
    pwd
    
    1. Crear y borrar archivos:

    Crear un archivo vacío:

    
    
    
    
    
    touch prueba.txt
    

    Verificar:

    
    
    
    
    
    ls
    

    Debería aparecer prueba.txt.

    Borrar el archivo:

    
    
    
    
    
    rm prueba.txt
    

    Ejercicio 2 — Solución

    Enunciado:
    Crear un script presentacion.sh que muestre:

    • Tu nombre
    • El día actual
    • Tu directorio de trabajo

    Ejemplo de salida esperada:

    
    
    
    
    
    Mi nombre es Juan Pérez
    Hoy es 2026-01-10
    Estoy trabajando en /home/juan
    

    💡 Solución propuesta (presentacion.sh):

    
    
    
    
    
    #!/bin/bash
    
    echo "Mi nombre es Juan Pérez"
    echo "Hoy es $(date +%Y-%m-%d)"
    echo "Estoy trabajando en $(pwd)"
    

    📌 Instrucciones de ejecución:

    Dar permisos:

    
    
    
    
    
    chmod +x presentacion.sh
    

    Ejecutar:

    
    
    
    
    
    ./presentacion.sh
    

    Salida aproximada:

    
    
    
    
    
    Mi nombre es Juan Pérez
    Hoy es 2026-01-10
    Estoy trabajando en /home/juan
    

    Evidentemente, cada alumno pondrá su nombre.


    Ejercicio 3 — Solución

    Enunciado:
    Crear un script que liste los archivos del directorio /etc y guarde el resultado en etc-listado.txt.


    💡 Solución propuesta (listar_etc.sh):

    
    
    
    
    
    #!/bin/bash
    
    ls /etc > etc-listado.txt
    

    📌 Explicación:

    • ls /etc → lista el contenido del directorio /etc
    • > → redirecciona la salida estándar a un archivo

    📌 Instrucciones:

    1. Crear script:
    
    
    
    
    
    nano listar_etc.sh
    
    1. Pegar el contenido, guardar y salir.
    2. Dar permisos:
    
    
    
    
    
    chmod +x listar_etc.sh
    
    1. Ejecutar:
    
    
    
    
    
    ./listar_etc.sh
    
    1. Verificar el resultado:
    
    
    
    
    
    cat etc-listado.txt
    

    Ejemplo de contenido:

    
    
    
    
    

    adduser.conf aliases alternatives apache2 apt bash.bashrc ...

  • 2. Preparación del Entorno y Ejecución de Scripts

    2. Preparación del Entorno y Ejecución de Scripts

    Después de entender qué es Bash y qué es un script, el siguiente paso es aprender a preparar correctamente el entorno de trabajo y ejecutar scripts de forma segura y ordenada.


    1. Crear Scripts Correctamente

    Un script no es más que un archivo de texto plano. Se puede crear con cualquier editor, desde los más simples hasta los más avanzados.

    Editores recomendados:

    • nano (para trabajar en la terminal, muy sencillo)
    • vim (más avanzado, orientado a usuarios expertos)
    • Visual Studio Code (editor gráfico con sintaxis resaltada)
    • gedit o kate (editores gráficos simples)

    Para crear un script:

    
    
    
    
    
    nano mi_script.sh
    

    Se recomienda usar la extensión .sh para identificar que es un script de shell, aunque no es obligatoria.


    2. Añadir el Shebang

    La primera línea del script debe indicar el intérprete que lo ejecutará. Esto se conoce como shebang.

    Ejemplo:

    
    
    
    
    
    #!/bin/bash
    

    Esto garantiza que el script se ejecutará con Bash aunque el sistema use otro shell por defecto.

    Otros ejemplos:

    • #!/bin/sh para un shell más compatible POSIX.
    • #!/usr/bin/env bash para localizar Bash dinámicamente en distintas máquinas.

    3. Permisos de Ejecución

    Un script recién creado no suele tener permisos de ejecución. Para poder ejecutarlo es necesario asignarlos.

    Comando:

    
    
    
    
    
    chmod +x mi_script.sh
    

    Esto indica que el archivo puede ser ejecutado (x) por el usuario.

    Para comprobar los permisos:

    
    
    
    
    
    ls -l mi_script.sh
    

    Ejemplo de salida:

    
    
    
    
    
    -rwxr-xr-x 1 alumno alumno 57 ene 10 18:22 mi_script.sh
    

    4. Ejecutar Scripts

    Hay varias formas de ejecutar un script. Las más comunes son:

    4.1. Ejecutarlo por ruta relativa

    Si estamos en la misma carpeta del script:

    
    
    
    
    
    ./mi_script.sh
    

    El ./ indica “ejecuta este archivo desde el directorio actual”.

    4.2. Ejecutarlo por ruta absoluta

    Ejemplo:

    
    
    
    
    
    /home/alumno/scripts/mi_script.sh
    

    Esto es útil en automatizaciones y servicios del sistema.

    4.3. Ejecutarlo a través del intérprete

    También podemos invocar directamente Bash:

    
    
    
    
    
    bash mi_script.sh
    

    Esto ignora permisos, pero exige que el script sea legible.


    5. Organización del Entorno de Trabajo

    Para no mezclar scripts con otros tipos de archivos, se recomienda crear una carpeta propia:

    
    
    
    
    
    mkdir ~/scripts
    cd ~/scripts
    

    Aquí podemos almacenar scripts y añadir esta carpeta al PATH más adelante para ejecutarlos desde cualquier ubicación.


    6. Variables de Entorno y el PATH

    El PATH es una variable que indica dónde busca el sistema los programas ejecutables.

    Para ver el PATH actual:

    
    
    
    
    
    echo $PATH
    

    Si añadimos nuestros scripts a una carpeta incluida en el PATH, podremos ejecutarlos sin escribir ./ ni rutas completas.

    Más adelante veremos cómo añadir una ruta personalizada al PATH en el archivo .bashrc.


    7. Comentarios y Documentación Interna

    Es recomendable comentar el código para recordar qué hace cada parte. En Bash los comentarios se escriben con #.

    Ejemplo:

    
    
    
    
    
    #!/bin/bash
    # Este script muestra un mensaje por pantalla
    
    echo "Ejecutando mi script..."
    

    Es buena práctica incluir una cabecera con información útil:

    
    
    
    
    
    #!/bin/bash
    # Nombre: backup_home.sh
    # Autor: Nombre del alumno
    # Descripción: Realiza una copia de seguridad del directorio /home
    # Fecha: 10/01/2026
    

    8. Problemas Comunes al Ejecutar Scripts

    Durante este módulo suelen aparecer errores típicos:

    • bash: ./script.sh: Permission denied
      → Falta ejecutar chmod +x script.sh
    • command not found
      → El script no se encuentra o no es ejecutable
    • No such file or directory
      → Error en la ruta o en el nombre del archivo
    • bad interpreter: No such file or directory
      → El shebang apunta a una ruta incorrecta o se usa un archivo generado en Windows con saltos de línea incompatibles

    Este último error aparece mucho cuando se editan scripts en Windows. Se resuelve con:

    
    
    
    
    
    dos2unix script.sh
    

    9. Ejemplo Completo de Script

    Vamos a crear un script que pida un nombre y salude al usuario.

    1. Crear el archivo:
    
    
    
    
    
    nano saludo.sh
    
    1. Contenido:
    
    
    
    
    
    #!/bin/bash
    
    echo "Introduce tu nombre:"
    read nombre
    echo "Hola $nombre, encantado de saludarte."
    
    1. Dar permisos:
    
    
    
    
    
    chmod +x saludo.sh
    
    1. Ejecutarlo:
    
    
    
    
    
    ./saludo.sh
    

    Ejercicios propuestos

    Ejercicio 1:
    Crear un script llamado info.sh que muestre:

    • El usuario actual
    • El directorio donde se encuentra
    • La fecha actual

    Salida orientativa:

    
    
    
    
    
    Usuario: alumno
    Directorio: /home/alumno/scripts
    Fecha: 2026-01-10
    

    Ejercicio 2:
    Crear un script llamado crear_respaldo.sh que:

    • Cree una carpeta respaldo (si no existe)
    • Copie dentro todos los .txt del directorio actual

    Ejercicio 3:
    Mover todos los scripts a ~/scripts/ y probar:

    • Ejecución con ./
    • Ejecución con ruta absoluta

    Ejercicio 4 (opcional):
    Buscar qué es la variable PATH y para qué sirve.

    Soluciones ejercicios

    ✅ Ejercicio 1

    Enunciado:
    Crear un script llamado info.sh que muestre:

    • El usuario actual
    • El directorio donde se encuentra
    • La fecha actual

    💡 Solución propuesta (info.sh)

    
    
    
    
    
    #!/bin/bash
    # Script: info.sh
    # Muestra información básica del sistema y del usuario
    
    echo "Usuario: $USER"
    echo "Directorio actual: $(pwd)"
    echo "Fecha actual: $(date +"%Y-%m-%d %H:%M:%S")"
    

    Notas para clase:

    • $USER viene del entorno.
    • pwd muestra el directorio actual.
    • date formateado con +"%Y-%m-%d %H:%M:%S" muestra fecha y hora legibles.

    ✅ Ejercicio 2

    Enunciado:
    Crear un script llamado crear_respaldo.sh que:

    • Cree una carpeta respaldo (si no existe)
    • Copie dentro todos los .txt del directorio actual

    💡 Solución propuesta básica (crear_respaldo.sh)

    
    
    
    
    
    #!/bin/bash
    # Script: crear_respaldo.sh
    # Crea una carpeta respaldo y copia todos los .txt dentro
    
    # Crear carpeta si no existe
    if [ ! -d "respaldo" ]; then
        echo "Creando carpeta 'respaldo'..."
        mkdir respaldo
    else
        echo "La carpeta 'respaldo' ya existe."
    fi
    
    # Copiar archivos .txt si existen
    if ls *.txt >/dev/null 2>&1; then
        echo "Copiando archivos .txt a 'respaldo'..."
        cp *.txt respaldo/
        echo "Copia completada."
    else
        echo "No se encontraron archivos .txt en el directorio actual."
    fi
    

    Ideas para comentar en clase:

    • [ ! -d "respaldo" ] → comprueba que NO exista el directorio.
    • ls *.txt >/dev/null 2>&1 → truco para comprobar si hay .txt sin mostrar errores.
    • cp *.txt respaldo/ → copia múltiple.

    ✅ Ejercicio 3

    Enunciado:
    Mover todos los scripts a ~/scripts/ y probar:

    • Ejecución con ./
    • Ejecución con ruta absoluta

    Aquí no hay “script solución”, sino comandos que los alumnos deben usar.

    💡 Pasos y comandos

    1. Crear la carpeta scripts en el home (si no existe):
    
    
    
    
    
    mkdir -p ~/scripts
    
    1. Mover los scripts (por ejemplo, info.sh y crear_respaldo.sh) desde el directorio actual:
    
    
    
    
    
    mv info.sh crear_respaldo.sh ~/scripts/
    
    1. Ir a la carpeta:
    
    
    
    
    
    cd ~/scripts
    
    1. Comprobar permisos (por si acaso):
    
    
    
    
    
    chmod +x info.sh crear_respaldo.sh
    
    1. Ejecutar con ruta relativa (estando dentro de ~/scripts):
    
    
    
    
    
    ./info.sh
    ./crear_respaldo.sh
    
    1. Ejecutar con ruta absoluta (desde cualquier sitio):
    
    
    
    
    
    / home /usuario/scripts/info.sh
    

    Sustituyendo usuario por el usuario real, por ejemplo:

    
    
    
    
    
    /home/alumno/scripts/info.sh
    

    ✅ Ejercicio 4

    Enunciado:
    Buscar qué es la variable PATH y para qué sirve.

    Aquí puedes darles una explicación de solución tipo “teoría corregida”.

    💡 Explicación-solución

    La variable PATH:

    • Es una variable de entorno que contiene una lista de rutas separadas por :
    • Indica a la shell en qué directorios buscar ejecutables cuando escribimos un comando sin ruta.

    Por ejemplo, si escribes:

    
    
    
    
    
    ls
    

    La shell busca un archivo ejecutable llamado ls en cada ruta del PATH, en orden.

    Para ver el contenido del PATH:

    
    
    
    
    
    echo $PATH
    

    Ejemplo de salida:

    
    
    
    
    
    /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games
    

    Cada ruta separada por : es un directorio donde el sistema busca programas.

    Si añades ~/scripts al PATH, podrías ejecutar info.sh simplemente escribiendo:

    
    
    
    
    
    info.sh
    

    sin ./ ni ruta completa.