# Docker

Daemon de Docker en el VPS y apps como proyectos Compose: imagen, registro privado, repo o Compose, con HTTPS opcional.

Fuente: https://ardumaker.com/docs/docker/

- Categoría: Servidores e infraestructura
- Estado: Disponible
- Requisitos: Un VPS activo con la función `docker` disponible (Ubuntu 22.04 la tiene); Al menos 256 MB de RAM libre y 1 GB de disco libre medidos; Ser miembro con acceso al VPS para instalar; admin para desinstalar
- Herramientas MCP (Solo leen): `ver_catalogo_apps`, `ver_preflight_app`, `listar_apps_empresa`, `ver_app`, `ver_operacion_app`
- Herramientas MCP (Escriben o modifican): `instalar_app`, `controlar_app`, `reintentar_operacion_app`, `refrescar_apps`
- Herramientas MCP (Destructivas): `desinstalar_app`

## ¿Qué permite hacer?

Docker en ArduMaker tiene dos partes: el daemon, que es una capacidad del VPS, y las apps Docker, cada una un proyecto Compose propio que la plataforma escribe, levanta, observa y da de baja.

- Instalar el daemon con un clic (o dejar que lo instale la primera app que lo necesite).
- Desplegar una imagen pública, una imagen de un registro privado con token, o un repo de GitHub con Dockerfile.
- Desplegar un Compose avanzado (como objeto JSON) con varios servicios.
- Iniciar, detener y reiniciar el proyecto, y publicarlo con HTTPS si expone un puerto web.
- Desde la pestaña Docker del VPS: listar contenedores, ver sus logs, detenerlos, reiniciarlos o borrarlos, y ver imágenes, volúmenes y redes.

## ¿Cuándo conviene usarlo?

- Una aplicación ya empaquetada como imagen (un panel, una herramienta interna, un servicio de terceros).
- Varios servicios que se levantan juntos con Compose.
- Para código propio en GitHub con un proceso que no es Docker conviene el [deploy desde GitHub](https://ardumaker.com/docs/github-deploy).

## ¿Cómo funciona en ArduMaker?

### El daemon

Los VPS nuevos nacen con los permisos de contenedor que Docker necesita, sin ser privilegiados. Un VPS viejo que no los tiene los recibe al instalar Docker y necesita un reinicio (el preflight avisa con `requiere_reinicio_vps`). El daemon se instala con el paquete `docker.io` y `fuse-overlayfs`, con `userns-remap` activado: los procesos de los contenedores no corren como el `root` real del VPS.

### Una app Docker

1. Se valida la configuración y el preflight (función del sistema, Docker posible en el host, memoria y disco).
2. Si el daemon falta, se instala; si otra instalación está en curso, la operación espera y se reintenta.
3. Se escribe `/opt/ardumaker-apps/app<id>/docker-compose.yml` (con copia del anterior) y se valida con `docker compose config`; si no valida, se restaura el anterior.
4. Se corre `docker compose -p app<id> up -d --remove-orphans` como paso largo, así una descarga pesada no corta por tiempo.
5. Si hay `port`, se publica con HTTPS y se verifica el enlace.

Todos los contenedores llevan la etiqueta `ardumaker.app_id` y el proyecto se llama `app<id>`: el nombre no lo elige el usuario y la plataforma nunca toca nada fuera de él. Repetir el despliegue es idempotente: el mismo archivo y `up -d` no recrean lo que no cambió.

## ¿Qué cambia realmente?

| Qué | Dónde |
| --- | --- |
| Archivo Compose | `/opt/ardumaker-apps/app<id>/docker-compose.yml` |
| Código clonado (modo repo) | `/opt/ardumaker-apps/app<id>/src` |
| Datos con ruta relativa | `/opt/ardumaker-apps/app<id>/datos` |
| Volúmenes con nombre | Propios del proyecto (`data<i>` en modo simple) |
| Token de registro privado | Cifrado en la plataforma; el VPS hace `docker login` con el token por stdin |

## Configuración de una app Docker

| Modo | Claves |
| --- | --- |
| Imagen | `image`, `port`, `container_port`, `env` (hasta 50), `volumes`, `health_path`, `registry` |
| Repo de GitHub | `repo_id`, `branch`, `port`, `container_port`, `env`, `volumes`, `health_path` |
| Compose avanzado | `compose` (objeto JSON, no YAML) y `port` opcional |

- `image`, `compose` y `repo_id` son excluyentes.
- `port` es el puerto del VPS (desde 1024 y nunca uno protegido); con `port` hace falta `container_port`. `"auto"` toma uno libre.
- Los puertos se publican solo en `127.0.0.1`: un contenedor nunca queda abierto directo a internet.
- En `env` no se aceptan nombres de secreto (`*_PASSWORD`, `*_TOKEN`…): la configuración no guarda secretos.

## Qué se rechaza en un Compose

Cada servicio admite una lista blanca de claves (`image`, `command`, `entrypoint`, `environment`, `ports`, `volumes`, `restart`, `depends_on`, `healthcheck`, `working_dir`, `user`, `expose`, `networks`, `mem_limit`, `cpus`, `labels`, `tmpfs`, `stop_grace_period`, `read_only`, `init`). Se rechaza con un código por ruta (`compose.services.<servicio>.<clave>`):

| Código | Qué lo dispara |
| --- | --- |
| `privileged` | `privileged`, `devices`, `security_opt`, `userns_mode` |
| `network_mode_host` | `network_mode: host` |
| `pid_host` | `pid` o `ipc` del host |
| `cap_add` | Capacidades extra |
| `docker_socket` | Montar `docker.sock`, `/run` o `/var/run` |
| `host_mount` | Rutas absolutas, `~` o `..` (solo `./algo` dentro del directorio propio) |
| `puerto_publico` | Cualquier puerto que no sea `127.0.0.1:H:C` |

Tampoco se aceptan `build`, `container_name`, `env_file`, `configs`, `secrets`, `extends` ni `name`, ni etiquetas `com.docker.*` o `ardumaker.*`.

## Desinstalar y datos

La baja corre `docker compose down --remove-orphans`, fuerza el borrado de los contenedores con la etiqueta del proyecto y borra el archivo Compose. Los volúmenes y la carpeta `./datos` quedan, salvo que se pida borrar datos: entonces corre `down -v` y borra la carpeta del proyecto. Nada fuera de `app<id>` se toca.

> **PELIGRO:** Con `delete_data` la baja es irreversible: se pierden los volúmenes del proyecto.

## Esquema

**Una app Docker publicada**

```text
Internet (HTTPS en `docker-<id>` o un dominio propio)
  ↓
nginx del VPS (server block del dominio)
  ↓
`127.0.0.1:<port>` (único puerto publicado por el contenedor)
  ↓
Proyecto Compose `app<id>` (contenedores con etiqueta `ardumaker.app_id`)
  ↓
Volúmenes (persisten hasta que se pide borrar datos)
```

Sin `port` no hay URL: la app se administra desde la pestaña Docker.

## Resultado esperado

La app aparece en Apps con su estado observado: `running` si todos sus contenedores corren, `stopped` si todos están parados, `degraded` si hay mezcla y `missing` si no queda ninguno. Con `port`, la URL HTTPS aparece solo cuando el enlace respondió sin error 5xx.

```bash
docker compose -p app<id> ps
docker ps --filter label=com.docker.compose.project=app<id>
```

## Errores y resolución

| Error | Causa | ¿Reintentar? |
| --- | --- | --- |
| `requiere_docker` | El host no soporta Docker | No |
| `requiere_reinicio_vps` | Faltan los permisos de contenedor y hay que reiniciar el VPS | Tras reiniciar |
| `recursos_insuficientes` | Menos de 256 MB de RAM o 1 GB de disco libres | Tras liberar recursos |
| `docker_instalandose` / `docker_no_instalado` | El daemon se está instalando o no pudo arrancar | Sí |
| `compose_no_disponible` / `despliegue_fallido` / `baja_fallida` | No se pudo preparar Compose, falló el pull o el arranque, o el `down` no terminó | Sí (`up -d` y `down` son idempotentes) |
| `compose_invalido` | `docker compose config` rechazó el archivo; se restauró el anterior | No, hay que corregirlo |
| `puerto_ocupado` | Otra app del VPS publica o declara ese puerto | Con otro puerto |
| `config_invalida` | Clave no permitida o secreto en `env`; `fields` dice cuál | Corrigiendo el pedido |

> **PRECAUCION:** Los contenedores del stack de n8n (`n8n-main`, `n8n-postgres`, `n8n-redis`, workers y runners) están protegidos en la pestaña Docker: borrarlos responde 409. Se operan desde [n8n](https://ardumaker.com/docs/n8n).

## Relación con MCP

Las apps Docker se operan por MCP con las herramientas de Apps; la referencia está en [/mcp/docs](https://ardumaker.com/mcp/docs) y [/mcp/servicios](https://ardumaker.com/mcp/servicios).

- Lectura: `ver_catalogo_apps`, `ver_preflight_app` (valida la `config` exacta antes de instalar), `listar_apps_empresa`, `ver_app`, `ver_operacion_app`.
- Modifican: `instalar_app` con `app_type: docker` (exige `idempotency_key`), `controlar_app` (`start`, `stop`, `restart`), `reintentar_operacion_app`, `refrescar_apps`.
- Destructiva: `desinstalar_app` (solo admin, `confirm=true`; los volúmenes se borran solo con `delete_data` y `confirm_delete_data`).

> **INFO:** Por MCP no hay herramientas para la pestaña Docker (contenedores sueltos, imágenes, redes). Instalar Docker o un contenedor a mano con `ejecutar_comando_vps` deja algo que la plataforma no lista, ni reinicia, ni respalda.

## Funciones relacionadas

- [Servidores VPS](https://ardumaker.com/docs/vps/)
- [n8n](https://ardumaker.com/docs/n8n/)
- [Deploy desde GitHub](https://ardumaker.com/docs/github-deploy/)
- [Nginx](https://ardumaker.com/docs/nginx/)
- [Certificados SSL](https://ardumaker.com/docs/ssl/)
