ProxMenux 1.2.6.2-beta: OCI containers in the Monitor, docs and fixes

OCI manager Apps
- App tab: containers installed from an OCI image are identified from their
  installation record; the application and image versions are shown and an
  update is detected by image digest; repository link; Refresh data.
- Updates tab for OCI containers: Update and Recreate run the same flow as the
  OCI menu in the Monitor terminal; the pre-update backup can be kept in a
  backup storage; scheduled image updates with an optional minimum age.
- Logs tab: console output of the application, kept on the host
  (lxc.console.logfile + logrotate) and followed live.
- The Proxmox console opens a shell (cmode: shell) when the image has one.
- A damaged image download is fetched again before failing.
- Multi-container applications open at their LAN address; volume mount
  points on block storage report their usage.

Monitor
- Proxmox notifications are delivered to a loopback-only HTTP listener when
  HTTPS is enabled, so they no longer fail certificate verification.
- Log persistence counts recurring patterns only; an ended burst is not
  reported as persistent and its warning clears on its own (#386).
- Proxmox notification config backups are deduplicated and capped at three.
- The update icon on the Apps page opens the container on its Updates tab.
- Version 1.2.6.2-beta and its release notes in every Monitor language.

Docs
- OCI manager Apps and Audit & Report rebuilt as per-page message files,
  with a new page for OCI containers in the Monitor.
- Seven pages fixed where rich-text tags were missing from t.rich.

Translations
- Spanish fixes across the OCI engine, the Monitor and the TUI menus.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
MacRimi
2026-09-25 21:51:12 +02:00
co-authored by Claude Opus 5.5
parent 386d33df6e
commit 4437a671d2
524 changed files with 14459 additions and 3841 deletions
@@ -157,12 +157,12 @@
{
"endpoint": "/api/vms/<vmid>/control",
"method": "POST",
"use": "Encender / apagar / apagar limpio / reiniciar una VM o contenedor LXC (las mismas operaciones que expone la modal VM & LXC del Monitor). Body: {\"action\": \"start|stop|shutdown|reboot\"}. Síncrono — devuelve el resultado directo sin necesidad de polling."
"use": "Encender / apagar / apagar limpio / reiniciar una VM o contenedor LXC (las mismas operaciones que expone la modal VM & LXC del Monitor). El cuerpo lleva <code>action</code>: <code>start</code>, <code>stop</code>, <code>shutdown</code> o <code>reboot</code>. Síncrono — devuelve el resultado directo sin necesidad de polling."
},
{
"endpoint": "/api/vms/<vmid>/backup",
"method": "POST",
"use": "Crear un backup vzdump de una VM o LXC. Body (todo opcional excepto cuando los defaults no encajan con tu layout de storage): {\"storage\": \"<pve-storage>\", \"mode\": \"snapshot|suspend|stop\", \"compress\": \"zstd|lzo|gz|none\", \"protected\": true, \"notes\": \"…\", \"notification\": \"auto|always|failure|never\", \"pbs_change_detection\": \"default|legacy|data\"}. Devuelve el UPID de la tarea PVE."
"use": "Crear un backup vzdump de una VM o LXC. Campos del cuerpo, todos opcionales salvo cuando los valores por defecto no encajan con la distribución del almacenamiento: <code>storage</code> (un almacenamiento de PVE), <code>mode</code> (<code>snapshot</code>, <code>suspend</code> o <code>stop</code>), <code>compress</code> (<code>zstd</code>, <code>lzo</code>, <code>gz</code> o <code>none</code>), <code>protected</code> (<code>true</code> o <code>false</code>), <code>notes</code>, <code>notification</code> (<code>auto</code>, <code>always</code>, <code>failure</code> o <code>never</code>) y <code>pbs_change_detection</code> (<code>default</code>, <code>legacy</code> o <code>data</code>). Devuelve el UPID de la tarea PVE."
},
{
"endpoint": "/api/vms/<vmid>/backups",
@@ -0,0 +1,146 @@
{
"meta": {
"title": "Evaluación e inventario | Auditoría e informes",
"description": "La evaluación de Auditoría e informes: perfiles de informe, clasificación de los resultados, riesgos aceptados, fuentes ilegibles, Lynis e inventario del nodo."
},
"header": {
"title": "Evaluación e inventario",
"description": "La evaluación inspecciona el nodo, conserva sus hallazgos y responde a preguntas distintas según el perfil de informe.",
"section": "Auditoría e informes"
},
"sections": [
{
"id": "read-only",
"blocks": [
{
"calloutInfo": {
"title": "Una evaluación inspecciona; no cambia la configuración",
"body": "Lee la configuración y el estado del host. Escribe sus resultados, informes y logs, y las comprobaciones de arranque pueden montar un momento las particiones de sistema EFI. La configuración que evalúa no se modifica."
}
},
{
"p": "<strong>Ejecutar evaluación</strong> inicia una ejecución con el perfil seleccionado en <strong>Informe</strong>. La vista muestra la fecha de la última ejecución y cuánto tiempo ha pasado."
}
]
},
{
"id": "profiles",
"title": "Perfiles de informe",
"intro": "Cada perfil responde a una pregunta distinta. Las comprobaciones y las secciones se seleccionan antes de componer el documento.",
"blocks": [
{
"table": {
"headers": ["Perfil", "Qué abarca"],
"rows": [
["Auditoría completa", "Todas las comprobaciones y toda la estructura disponible."],
["Diagnóstico rápido", "Todas las comprobaciones; el resultado empieza por los hallazgos críticos, las advertencias y las lecturas que no pudieron verificarse."],
["Inventario", "Una descripción del nodo, sin comprobaciones ni clasificación."],
["Revisión de seguridad", "Exposición, acceso, privilegios, certificados, actualizaciones, repositorios y Lynis."],
["Garantía de backups", "Cobertura, antigüedad, resultados, verificación, retención y recuperación de los backups."],
["Capacidad y desgaste", "Margen de crecimiento, memoria, ocupación y vida útil de los discos."]
]
}
},
{
"p": "El contenido de cada documento se describe en <reportsLink>Informes y comparaciones</reportsLink>."
}
]
},
{
"id": "results",
"title": "Cómo se clasifican los resultados",
"blocks": [
{
"table": {
"headers": ["Clasificación", "Significado"],
"rows": [
["Crítico", "Una condición fallida con prioridad."],
["Advertencia", "Una condición que requiere revisión, según la evidencia o la política."],
["Observación", "Información sobre el nodo que no se presenta como fallo."],
["Sin verificar", "La fuente que necesita la comprobación no pudo leerse. No significa que el problema no exista."],
["Conforme", "La condición cumple el criterio aplicado."],
["No aplicable", "Dentro del alcance de la comprobación no hay nada a lo que aplicarla."],
["Riesgo aceptado", "El hallazgo existe y hay registrada una decisión sobre él."],
["Excluido por política", "La política declara que el elemento queda fuera del recuento."]
]
}
},
{
"p": "Los hallazgos pueden filtrarse por área: Sistema, Almacenamiento, Red, Seguridad, Backups, Invitados y Hardware. Cada hallazgo conserva su evidencia, con la fuente de la que se leyó."
}
]
},
{
"id": "unverified",
"title": "Cuando una fuente no puede leerse",
"blocks": [
{
"table": {
"headers": ["Caso", "Comportamiento"],
"rows": [
["Sin verificar", "La comprobación conserva su identidad, indica en su evidencia qué fuente falló y no convierte la falta de datos en un resultado conforme."],
["Evidencia incompleta", "El informe nombra la fuente y el momento de la recogida, de modo que un problema real puede distinguirse de una lectura insuficiente."],
["Una nueva ejecución", "Una vez corregido el acceso, el paquete o el servicio, el mismo perfil se ejecuta de nuevo y la comparación muestra si el resultado pudo verificarse."]
]
}
}
]
},
{
"id": "lynis",
"title": "Lynis",
"blocks": [
{
"p": "La revisión de seguridad usa el informe de Lynis del host. Cuando Lynis no se ha ejecutado todavía, o su informe supera el umbral de antigüedad de la política, un diálogo ofrece <strong>Ejecutar con Lynis</strong>, que tarda unos minutos más, o <strong>Ejecutar sin Lynis</strong>, que usa el informe existente."
},
{
"figure": {
"src": "/monitor/audit/lynis-dialog.png",
"alt": "Diálogo que ofrece ejecutar la evaluación con o sin Lynis",
"caption": "El diálogo de Lynis antes de una revisión de seguridad."
}
}
]
},
{
"id": "accept",
"title": "Aceptar un riesgo",
"blocks": [
{
"p": "<strong>Aceptar riesgo</strong> registra una decisión sobre un hallazgo. El motivo es obligatorio y se guarda junto al autor y la fecha."
},
{
"table": {
"headers": ["Campo", "Opciones"],
"rows": [
["Motivo", "Texto libre, obligatorio."],
["Deja de aplicarse tras", "90 días, 180 días, 1 año o no caduca. Al cumplirse el plazo, el hallazgo vuelve a estar activo."],
["Recordarme revisarla", "Un recordatorio que devuelve la decisión a la atención mientras sigue en vigor."]
]
}
},
{
"p": "Un hallazgo aceptado sigue visible con su decisión, y <strong>Volver a activo</strong> la revoca. Un riesgo aceptado no es una corrección: la comparación lo presenta como aceptado, no como resuelto."
}
]
},
{
"id": "inventory",
"title": "Inventario",
"blocks": [
{
"list": {
"items": [
"Identidad, versión de Proxmox VE, kernel, suscripción y clúster.",
"CPU, memoria, placa, BIOS, controladoras e IOMMU.",
"Discos, SMART, horas de funcionamiento y eventos registrados.",
"Adaptadores, bonds, bridges, latencia y conexiones.",
"Almacenamiento, invitados con sus discos e interfaces, y backups.",
"Passthrough PCI y el software que gestiona ProxMenux."
]
}
}
]
}
]
}
@@ -0,0 +1,148 @@
{
"meta": {
"title": "Cambios | Auditoría e informes",
"description": "El registro de cambios de Auditoría e informes: qué ha cambiado ProxMenux en el host, qué había antes, la diferencia y si puede deshacerse."
},
"header": {
"title": "Cambios",
"description": "El registro de las operaciones que ProxMenux realiza en el host y, cuando se capturó, el estado antes y después de cada una.",
"section": "Auditoría e informes"
},
"sections": [
{
"id": "purpose",
"blocks": [
{
"calloutInfo": {
"title": "Del script que se ejecutó al cambio que hizo",
"body": "Una función extensa puede cambiar solo dos líneas. El registro conserva cada operación concreta con el script, la función y la versión responsables, el recurso afectado, la diferencia y si puede deshacerse."
}
},
{
"flow": {
"nodes": [
{ "label": "Script", "detail": "función + versión" },
{ "label": "Captura", "detail": "contenido previo" },
{ "label": "Operación", "detail": "archivo · paquete · servicio" },
{ "label": "Registro", "detail": "atribución + diferencia" }
],
"caption": "La captura se toma al ejecutarse la operación y se consolida cuando el Monitor lee el registro."
}
},
{
"figure": {
"src": "/monitor/audit/changes-view.png",
"alt": "Vista Cambios de Auditoría e informes con las entradas agrupadas por opción de post-install y por script",
"caption": "La vista Cambios, con la diferencia de un archivo editado por ProxMenux."
}
}
]
},
{
"id": "types",
"title": "Tipos de entrada",
"intro": "El filtro de la parte superior separa las entradas por tipo.",
"blocks": [
{
"table": {
"headers": ["Tipo", "Qué registra"],
"rows": [
["Configuración", "ProxMenux escribió, editó o eliminó un archivo, cambió un ajuste o alteró un servicio."],
["Instalaciones", "ProxMenux añadió un paquete o componente, y se registran los paquetes que aparecieron realmente."],
["Ejecuciones", "ProxMenux ejecutó un comando; lo que cambió depende del propio comando."],
["Aplicado", "Una función se aplicó antes de que existiera el registro; el estado previo no se capturó."]
]
}
}
]
},
{
"id": "groups",
"title": "Cómo se organiza la vista",
"blocks": [
{
"table": {
"headers": ["Sección", "Contenido"],
"rows": [
["Optimizaciones de post-install", "Agrupadas por la opción de post-install que seleccionó el usuario."],
["Scripts de ProxMenux", "GPU, Coral, red, almacenamiento, seguridad, utilidades y el resto de scripts instrumentados, incluidos el instalador de ProxMenux y ProxMenux Monitor."],
["Paquetes y utilidades instalados", "Software que ProxMenux instaló en el host."]
]
}
},
{
"p": "Dentro de cada sección, <strong>Por función</strong> agrupa las entradas bajo la función que las hizo."
}
]
},
{
"id": "entry",
"title": "Qué muestra cada entrada",
"blocks": [
{
"list": {
"items": [
"El script, la función y la versión responsables.",
"La fecha y el recurso afectado.",
"El estado conocido antes y después del cambio.",
"Las líneas añadidas y eliminadas.",
"Los paquetes que se añadieron realmente.",
"La transición de estado de un servicio.",
"<strong>Deshacer esto</strong>: <em>Restaura exactamente lo que había</em>, <em>Elimina el fichero (no había ninguno antes)</em>, <em>Se puede desinstalar el paquete</em>, un deshacer parcial o <em>No se puede deshacer desde el registro</em>."
]
}
}
]
},
{
"id": "before",
"title": "Qué significa el estado previo",
"blocks": [
{
"p": "El estado previo puede ser contenido capturado, un archivo creado por primera vez o un estado desconocido. Los cambios hechos antes de que existiera el registro no pueden reconstruirse; al volver a ejecutar la función se captura primero el estado encontrado en ese momento."
}
]
},
{
"id": "limits",
"title": "Alcance del registro",
"blocks": [
{
"list": {
"items": [
"Los cambios manuales y los de otro software no se registran.",
"Solo se cubren las operaciones que pasan por las primitivas de auditoría de ProxMenux.",
"El registro nunca bloquea la operación que describe: si la entrada no puede escribirse, la operación continúa.",
"Los cambios sucesivos de un mismo recurso se muestran como el origen conocido frente al estado actual."
]
}
}
]
},
{
"id": "retention",
"title": "Evidencia guardada",
"blocks": [
{
"table": {
"headers": ["Elemento", "Comportamiento"],
"rows": [
["Entradas", "Se conservan en el host; del registro no se elimina nada automáticamente."],
["Contenido capturado", "Un objeto capturado se conserva mientras alguna entrada lo referencia."],
["Tamaño de una captura", "El contenido de más de 1 MiB no se guarda entero; la entrada registra que la captura se omitió por su tamaño."],
["Lectura", "El Monitor no carga objetos guardados de más de 2 MiB."],
["Diferencia", "Se muestran como máximo 400 líneas, y una diferencia más larga se marca como truncada."],
["Listado", "La API devuelve 200 entradas por petición por defecto y hasta 1000."]
]
}
},
{
"calloutWarning": {
"title": "Conservar el contenido no es deshacer automáticamente",
"body": "El contenido previo a un cambio puede consultarse y restaurarse a mano, pero la vista Cambios no revierte operaciones. Una entrada de ejecución registra el comando sin conocer todos los efectos de la herramienta que ejecutó."
}
}
]
}
]
}
@@ -0,0 +1,83 @@
{
"meta": {
"title": "Auditoría e informes | ProxMenux Monitor",
"description": "Evaluación de un nodo Proxmox VE, registro de lo que ProxMenux ha cambiado en él y declaración de lo que se espera de sus invitados y almacenamientos, con informes imprimibles."
},
"header": {
"title": "Auditoría e informes",
"description": "Una evaluación del nodo, el registro de lo que ProxMenux ha cambiado en él y la declaración de lo que se espera de él, con documentos que pueden imprimirse o guardarse como PDF.",
"section": "ProxMenux Monitor"
},
"sections": [
{
"id": "views",
"blocks": [
{
"calloutInfo": {
"title": "Tres vistas, tres preguntas",
"body": "Auditoría e informes separa los hechos del nodo, las intervenciones de ProxMenux y las expectativas declaradas para él. Una configuración que la evaluación no puede contrastar con una finalidad declarada se describe, no se presenta como un fallo."
}
},
{
"cards": {
"items": [
{ "icon": "shield", "title": "Evaluación: ¿cómo está el nodo?", "body": "Ejecuta las comprobaciones del perfil elegido, compone el inventario y clasifica lo que requiere atención, con la evidencia de cada resultado." },
{ "icon": "refresh", "title": "Cambios: ¿qué ha hecho ProxMenux?", "body": "Enumera los archivos, paquetes, servicios y comandos que han cambiado los scripts instrumentados de ProxMenux, con lo que había antes cuando se capturó." },
{ "icon": "fileText", "title": "Política: ¿qué se espera?", "body": "Declara qué invitados necesitan backup o deben arrancar con el host, qué almacenamiento es esencial y los umbrales de las comprobaciones." }
]
}
},
{
"flow": {
"nodes": [
{ "label": "Evaluación", "detail": "hechos" },
{ "label": "Política", "detail": "contexto" },
{ "label": "Cambios", "detail": "intervenciones" }
],
"caption": "La evaluación aporta los hechos, la política les da contexto y el registro recoge lo que ha hecho ProxMenux."
}
},
{
"figure": {
"src": "/monitor/audit/assessment-view.png",
"alt": "Auditoría e informes en ProxMenux Monitor con las vistas Evaluación, Cambios y Política",
"caption": "Auditoría e informes, con la vista Evaluación abierta."
}
}
]
},
{
"id": "boundaries",
"title": "Tres funciones distintas",
"blocks": [
{
"table": {
"headers": ["Función", "Qué hace"],
"rows": [
["<healthLink>Health Monitor</healthLink>", "Observa métricas y eventos de forma continua y puede generar notificaciones."],
["Auditoría e informes", "Ejecuta una evaluación cuando se pide, documenta el nodo y compara ejecuciones entre sí."],
["Registro de cambios", "Registra las operaciones que ProxMenux realiza a través de sus primitivas de auditoría."]
]
}
}
]
},
{
"id": "pages",
"title": "Páginas de esta sección",
"blocks": [
{
"next": {
"items": [
{ "label": "Evaluación e inventario", "href": "/docs/monitor/audit-report/assessment", "tail": "perfiles, resultados, riesgos aceptados e inventario." },
{ "label": "Cambios", "href": "/docs/monitor/audit-report/changes", "tail": "el registro de lo que ProxMenux ha cambiado en el host." },
{ "label": "Política", "href": "/docs/monitor/audit-report/policy", "tail": "invitados, almacenamiento y umbrales." },
{ "label": "Informes y comparaciones", "href": "/docs/monitor/audit-report/reports", "tail": "los seis documentos y la ejecución de referencia." },
{ "label": "Alcance y garantías", "href": "/docs/monitor/audit-report/scope", "tail": "fuentes, límites y datos guardados." }
]
}
}
]
}
]
}
@@ -0,0 +1,95 @@
{
"meta": {
"title": "Política | Auditoría e informes",
"description": "La política del nodo en Auditoría e informes: backup, arranque y objetivo de recuperación de cada invitado, el papel de cada almacenamiento y los umbrales de las comprobaciones."
},
"header": {
"title": "Política",
"description": "La política declara lo que ninguna inspección puede deducir: para qué sirve cada invitado y almacenamiento y los umbrales que aplican las comprobaciones.",
"section": "Auditoría e informes"
},
"sections": [
{
"id": "principle",
"blocks": [
{
"calloutInfo": {
"title": "Sin declaración, el informe describe; con ella, evalúa",
"body": "Una evaluación ve lo que hace el host, no para qué sirve. Un invitado sin backup cuya finalidad no está declarada se presenta como observación. Si su backup se declara obligatorio, la misma ausencia se presenta como advertencia. No es obligatorio declarar nada."
}
},
{
"figure": {
"src": "/monitor/audit/policy-view.png",
"alt": "Vista Política con los invitados, el almacenamiento y los umbrales del nodo",
"caption": "La vista Política."
}
}
]
},
{
"id": "guests",
"title": "Invitados",
"intro": "Cada VM y LXC del nodo tiene tres campos. Un valor que se deja por defecto toma el valor general, que se muestra a su lado.",
"blocks": [
{
"table": {
"headers": ["Campo", "Valores", "Efecto en la evaluación"],
"rows": [
["Backup", "Obligatorio, No obligatorio, Sin especificar", "La falta de backup es una advertencia si es obligatorio, una observación si no se especifica, y queda fuera del recuento si no es obligatorio."],
["Arranque", "Obligatorio, No obligatorio, Sin especificar", "Si el invitado debe arrancar con el host."],
["Objetivo de recuperación", "Horas", "La antigüedad máxima aceptable del último backup."]
]
}
}
]
},
{
"id": "storage",
"title": "Almacenamiento",
"intro": "Cada almacenamiento del nodo se declara Esencial, Opcional o Sin especificar.",
"blocks": [
{
"p": "Un almacenamiento inaccesible se presenta como crítico cuando se declara esencial o sirve a un invitado en marcha, como advertencia cuando su papel no se especifica, y como observación cuando se declara opcional."
}
]
},
{
"id": "thresholds",
"title": "Umbrales",
"intro": "Un umbral vacío usa el valor de fábrica, que se muestra como texto de ejemplo.",
"blocks": [
{
"list": {
"items": [
"Revisión de capacidad de almacenamiento (%) y revisión de ocupación de thin pool (%).",
"Ratio de sobreaprovisionamiento thin y ratio de sobreasignación de memoria.",
"Intervalo de scrub de ZFS (días).",
"Plazo de respaldo para la antigüedad (días) y margen sobre el calendario (ratio).",
"Aviso de caducidad de certificado (días).",
"Vida útil del disco (horas) y ventana de errores de disco recientes (días).",
"Antigüedad del informe de Lynis (días) y antigüedad de los índices de paquetes (días).",
"Journal frente a su tope (%).",
"Revisión de espacio del sistema de archivos (%) y revisión de inodos del sistema de archivos (%)."
]
}
}
]
},
{
"id": "save",
"title": "Cómo se guarda la política",
"blocks": [
{
"p": "La declaración se valida y se guarda de forma atómica en <code>/usr/local/share/proxmenux/audit_policy.json</code>. Cada guardado lleva una revisión: si la declaración cambió en otra sesión, el borrador no se guarda y la vista ofrece recargar la declaración guardada."
},
{
"calloutWarning": {
"title": "La política nunca se deduce",
"body": "ProxMenux no añade ningún requisito por su cuenta. Un campo vacío conserva el valor de fábrica o queda sin especificar, y una declaración parcial solo afecta a los elementos que nombra."
}
}
]
}
]
}
@@ -0,0 +1,160 @@
{
"meta": {
"title": "Informes y comparaciones | Auditoría e informes",
"description": "Los seis documentos de Auditoría e informes, cómo se imprimen o guardan como PDF y cómo se comparan las ejecuciones con una ejecución de referencia."
},
"header": {
"title": "Informes y comparaciones",
"description": "Seis documentos, cada uno compuesto para una pregunta distinta, y la comparación de cada ejecución con una ejecución de referencia.",
"section": "Auditoría e informes"
},
"sections": [
{
"id": "intro",
"blocks": [
{
"calloutInfo": {
"title": "Seis documentos, no seis estilos",
"body": "El motor selecciona las comprobaciones y las secciones antes de componer el documento. Un diagnóstico rápido no es una auditoría completa con menos páginas, y un inventario no presenta resultados de evaluación. Los documentos de muestra usan datos ficticios."
}
}
]
},
{
"id": "documents",
"title": "Los seis documentos",
"blocks": [
{
"downloads": {
"items": [
{
"title": "Auditoría completa",
"body": "Documenta el nodo de extremo a extremo como registro técnico.",
"href": "/monitor/audit/sample-audit-full-report.pdf",
"facts": [
{ "label": "Comprobaciones", "value": "Todas las disponibles." },
{ "label": "Contenido", "value": "Resumen ejecutivo; identidad y clúster; hardware; red y latencia; almacenamiento; invitados; passthrough; aplicaciones; hallazgos con evidencia; fuentes y alcance." }
]
},
{
"title": "Diagnóstico rápido",
"body": "Muestra lo que requiere atención sin el inventario completo.",
"href": "/monitor/audit/sample-audit-diagnostic-report.pdf",
"facts": [
{ "label": "Comprobaciones", "value": "Las mismas que la auditoría completa." },
{ "label": "Contenido", "value": "Identidad mínima; hallazgos críticos; advertencias; observaciones relevantes; lecturas sin verificar y acciones prioritarias. Deja fuera diagramas, inventario y anexos extensos." }
]
},
{
"title": "Inventario",
"body": "Describe lo que existe en el nodo sin evaluarlo.",
"href": "/monitor/audit/sample-audit-inventory-report.pdf",
"facts": [
{ "label": "Comprobaciones", "value": "Ninguna; no se clasifica ningún hallazgo." },
{ "label": "Contenido", "value": "Identidad; clúster; CPU y memoria; placa, BIOS y controladoras; red; almacenamiento; VM y LXC; passthrough; aplicaciones y elementos gestionados por ProxMenux." }
]
},
{
"title": "Revisión de seguridad",
"body": "Abarca la exposición y los controles de acceso al nodo.",
"href": "/monitor/audit/sample-audit-security-report.pdf",
"facts": [
{ "label": "Comprobaciones", "value": "El área de seguridad, más los privilegios de los contenedores, las actualizaciones, los repositorios y la cadena APT." },
{ "label": "Contenido", "value": "Identidad y clúster; red y latencia; acceso; cortafuegos; 2FA; certificados; privilegios; actualizaciones; repositorios; estado y antigüedad de Lynis." }
]
},
{
"title": "Garantía de backups",
"body": "Comprueba que la protección declarada existe y que sus backups son utilizables.",
"href": "/monitor/audit/sample-audit-backup-report.pdf",
"facts": [
{ "label": "Comprobaciones", "value": "El área de backups, más la conectividad del almacenamiento y la entrega de notificaciones." },
{ "label": "Contenido", "value": "Cobertura por invitado; objetivo de recuperación declarado; antigüedad y resultado; destino; retención; verificación; trabajos fallidos; recuperación y fuentes incompletas." }
]
},
{
"title": "Capacidad y desgaste",
"body": "Mide el margen de crecimiento y las señales de agotamiento o envejecimiento.",
"href": "/monitor/audit/sample-audit-capacity-report.pdf",
"facts": [
{ "label": "Comprobaciones", "value": "Las áreas de almacenamiento y hardware, más memoria, swap, journal y el sistema de archivos del host." },
{ "label": "Contenido", "value": "Ocupación y umbrales; thin pools; sobreaprovisionamiento; memoria; inodos; ZFS; temperaturas; horas de funcionamiento; errores SMART y vida útil de NVMe/SSD." }
]
}
]
}
},
{
"figure": {
"src": "/monitor/audit/audit-report-preview.png",
"alt": "Primera página de un informe de auditoría completa",
"caption": "Todos los documentos comparten el identificador del informe, las secciones numeradas, la fecha, el nodo, el perfil y el pie de página."
}
},
{
"p": "Un documento contiene la identidad del nodo y la fecha de la evaluación, el resultado ejecutivo, un resumen por áreas, la estructura de hardware, red y almacenamiento, la protección de los invitados, los hallazgos con su evidencia, las fuentes que no pudieron leerse, y el alcance y la política aplicada, en la medida en que cada perfil los incluye."
}
]
},
{
"id": "print",
"title": "Imprimir o guardar como PDF",
"blocks": [
{
"steps": {
"items": [
{ "title": "Ejecutar", "body": "Una evaluación se ejecuta con el perfil seleccionado en <strong>Informe</strong>." },
{ "title": "Revisar", "body": "La ejecución terminada muestra sus hallazgos, las fuentes que no pudo leer y la política que aplicó." },
{ "title": "Generar informe", "body": "<strong>Generar informe</strong> abre la vista preparada como documento." },
{ "title": "Imprimir", "body": "<strong>Imprimir o guardar como PDF</strong> abre el diálogo de impresión del navegador, donde se selecciona una impresora o <em>Guardar como PDF</em>." }
]
}
},
{
"calloutTip": {
"title": "La impresión es un documento, no una captura",
"body": "La barra de acciones se oculta, una tabla que continúa en la página siguiente repite su cabecera, los bloques evitan cortes innecesarios y cada página conserva la identificación y la numeración."
}
}
]
},
{
"id": "compare",
"title": "Comparar con una ejecución de referencia",
"intro": "<strong>Usar como referencia</strong> marca una ejecución terminada como referencia. Las ejecuciones posteriores se comparan con ella y sus hallazgos se separan en:",
"blocks": [
{
"table": {
"headers": ["Grupo", "Significado"],
"rows": [
["Nuevos", "Presentes ahora y no antes."],
["Empeoraron", "Siguen presentes, y son más graves o afectan a más que antes."],
["Mejoraron", "Siguen presentes, pero son menos graves o afectan a menos que antes."],
["Resueltos", "Ya no aparecen, y nadie los aceptó."],
["Aceptados", "Ya no cuentan porque se aceptó un riesgo, no porque haya cambiado el host."],
["Ya no se evalúan", "Estaban antes y no aparecen en esta ejecución; nada ha verificado que hayan dejado de existir."]
]
}
},
{
"table": {
"headers": ["Ejecución de referencia", "Comportamiento"],
"rows": [
["Marcarla", "Puede marcarse cualquier ejecución terminada; ninguna se marca automáticamente."],
["Cambiarla", "Marcar otra ejecución mueve la referencia sin borrar el historial."],
["Comparar", "Si no se seleccionan dos ejecuciones, la comparación usa la referencia y la ejecución seleccionada o la más reciente."],
["Conservar ejecuciones", "Se conservan las 30 ejecuciones más recientes, y la ejecución de referencia nunca se elimina."],
["Sin referencia", "La vista indica que todavía no se ha elegido una ejecución de referencia, así que no hay con qué comparar."]
]
}
},
{
"calloutWarning": {
"title": "Un informe describe un momento",
"body": "Una evaluación no certifica un periodo completo. Los resultados antiguos dejan de describir el estado actual; la vista muestra la antigüedad de la última ejecución y cada fuente conserva el momento en que se recogió."
}
}
]
}
]
}
@@ -0,0 +1,97 @@
{
"meta": {
"title": "Alcance y garantías | Auditoría e informes",
"description": "De dónde proceden los datos de Auditoría e informes, qué queda fuera de su alcance, las garantías de su diseño y dónde se guardan sus datos."
},
"header": {
"title": "Alcance y garantías",
"description": "De dónde proceden los datos de una evaluación, qué queda fuera de su alcance y dónde guarda Auditoría e informes sus datos.",
"section": "Auditoría e informes"
},
"sections": [
{
"id": "sees",
"title": "Qué observa",
"blocks": [
{
"list": {
"items": [
"La configuración y el estado del nodo local.",
"La configuración declarada de las VM y los LXC.",
"El estado del almacenamiento tal como lo conoce Proxmox VE.",
"El historial disponible de backups y verificaciones.",
"Los datos SMART y los eventos que ha recogido el Monitor.",
"El estado de los servicios, el clúster, HA y las fuentes locales."
]
}
}
]
},
{
"id": "outside",
"title": "Qué queda fuera de su alcance",
"blocks": [
{
"list": {
"items": [
"El interior de los invitados, más allá de lo que declaran a Proxmox VE.",
"El equipamiento de red fuera del host.",
"Las dependencias remotas que el nodo no puede observar.",
"El estado físico que el hardware no expone.",
"Las acciones manuales o de otro software, en el registro de cambios."
]
}
},
{
"calloutWarning": {
"title": "La ausencia de evidencia no es evidencia de ausencia",
"body": "Una fuente que no puede leerse da un resultado sin verificar o incompleto, nunca uno conforme. El informe enumera las fuentes que no estuvieron disponibles."
}
}
]
},
{
"id": "guarantees",
"title": "Garantías del diseño",
"blocks": [
{
"list": {
"items": [
"Identificadores estables para las comprobaciones.",
"Historial de ejecuciones y hallazgos.",
"Una política validada y guardada de forma atómica.",
"Riesgos aceptados con motivo y visibles.",
"Atribución de los cambios al script y a la función.",
"Captura del estado anterior y posterior cuando está disponible.",
"Un resultado explícito cuando algo no puede medirse o capturarse."
]
}
}
]
},
{
"id": "storage",
"title": "Dónde se guardan los datos",
"blocks": [
{
"table": {
"headers": ["Datos", "Ubicación"],
"rows": [
["Política", "<code>/usr/local/share/proxmenux/audit_policy.json</code>"],
["Evaluaciones", "La base de datos de auditoría del Monitor"],
["Objetos capturados", "<code>/usr/local/share/proxmenux/changes/objects/</code>"],
["Entradas pendientes", "<code>/usr/local/share/proxmenux/changes/spool/</code>"],
["Registro consolidado", "<code>/usr/local/share/proxmenux/changes.db</code>"]
]
}
},
{
"calloutInfo": {
"title": "Una herramienta de revisión, no una certificación",
"body": "Auditoría e informes revisa, compara y documenta el nodo. Sus resultados se leen junto con la finalidad del sistema, la política declarada y las fuentes disponibles."
}
}
]
}
]
}
@@ -96,7 +96,8 @@
{ "method": "docker label / docker exec", "use": "Lee una etiqueta de versión OCI o ejecuta un comando de versión dentro de un contenedor Docker." },
{ "method": "python distribution", "use": "Usa importlib.metadata mediante el intérprete de Python seleccionado." },
{ "method": "command", "use": "Ejecuta un comando avanzado en formato argv, sin shell, y extrae la versión de su salida." },
{ "method": "manual", "use": "Guarda una versión introducida manualmente; debe cambiarse después de actualizar la app." }
{ "method": "manual", "use": "Guarda una versión introducida manualmente; debe cambiarse después de actualizar la app." },
{ "method": "OCI image", "use": "Para contenedores instalados por OCI manager Apps. Lee las versiones de la aplicación y de la imagen del registro de la instalación y compara el digest instalado con el que publica el registro; no necesita configuración." }
],
"sourcesHeading": "Fuentes para la versión disponible",
"sources": [
@@ -52,8 +52,8 @@
},
"drillIn": {
"heading": "Modal de vista en detalle por guest",
"intro": "El modal se abre con el nombre, VMID, tipo, estado y tiempo de actividad del sistema. La navegación se adapta al elemento: <strong>Estado</strong>, <strong>App</strong> y <strong>Actualizaciones</strong> para gestionar aplicaciones LXC, <strong>Montajes</strong> cuando existen puntos de montaje, además de <strong>Copias</strong> y <strong>Cortafuegos</strong>. La barra inferior mantiene los controles de ciclo de vida y el terminal LXC disponibles desde cualquier pestaña.",
"statusTitle": "Pestaña 1 — Status",
"intro": "El modal se abre con el nombre, VMID, tipo, estado y tiempo de actividad del sistema. La navegación se adapta al elemento: <strong>Estado</strong>, <strong>App</strong> y <strong>Actualizaciones</strong> para gestionar aplicaciones LXC, <strong>Montajes</strong> cuando existen puntos de montaje, <strong>Logs</strong> en los contenedores instalados por OCI manager Apps, además de <strong>Backups</strong> y <strong>Cortafuegos</strong>. La barra inferior mantiene los controles de ciclo de vida y el terminal LXC disponibles desde cualquier pestaña.",
"statusTitle": "Pestaña 1 — Estado",
"statusImageAlt": "Modal de vista en detalle por guest — pestaña Status con tarjetas en vivo de CPU / Memoria / Disco, totales de E/S de disco y red, el logo de distro del SO y el bloque Resources / IP Addresses",
"statusImageCaption": "Pestaña Status — CPU / Memoria / Disco en vivo con barras de progreso arriba, totales de E/S acumulados (lectura/escritura de disco, descarga/subida de red) abajo, después el bloque estático Resources con expansiones de Notes y + Info y la lista de pastillas IP Addresses.",
"statusIntro": "La pestaña por defecto — la vista \"¿este guest se está portando?\". Tres bloques:",
@@ -106,7 +106,9 @@
],
"mountsCalloutTitle": "Lo que esto te da sobre la UI nativa",
"mountsCalloutBody": "Una vista veraz y consciente de la capacidad de cada sitio donde el contenedor lee o escribe. Shares NFS o CIFS montados desde dentro del CT — invisibles para la UI web de Proxmox — aparecen aquí con el mismo aspecto y la misma sonda de salud que cualquier mount point configurado. Mounts remotos stale y zombie binds salen marcados antes de que muerdan durante un backup.",
"backupsTitle": "Pestaña 5 — Copias",
"logsTitle": "Pestaña 5 — Logs (solo contenedores OCI)",
"logsBody": "Solo aparece en los contenedores instalados por OCI manager Apps. Muestra la salida de consola del proceso principal de la imagen, guardada en el host en <code>/var/log/proxmenux/oci/VMID.console.log</code>: las últimas 100, 500 o 1000 líneas, seguidas en directo con el contenedor en marcha, con un filtro y una descarga. Lee el archivo cada vez que se abre, así que también funciona con el contenedor detenido. Los detalles están en <ociLink>Contenedores OCI en ProxMenux Monitor</ociLink>.",
"backupsTitle": "Pestaña 6 — Backups",
"backupsImageAlt": "Modal de vista en detalle por guest — pestaña Backups con la lista de backups disponibles, etiqueta de destino, tamaños y el botón Create Backup",
"backupsImageCaption": "Pestaña Backups — cada backup almacenado en los almacenamientos Proxmox configurados para este guest, ordenados de más nuevo a más viejo. La cabecera de la pestaña lleva la insignia de recuento.",
"backupsIntro": "Lista cada backup almacenado en los almacenamientos Proxmox configurados para este guest, ordenados de más nuevo a más viejo. El título de la pestaña lleva una insignia de recuento para que veas de un vistazo si el guest está backupeado. Por fila:",
@@ -116,7 +118,7 @@
"<strong>Size</strong> — tamaño final en disco del backup."
],
"backupsOutro": "El botón <strong>+ Create Backup</strong> arriba a la derecha arranca una nueva ejecución en el almacenamiento marcado como \"Backup target\" en la config de almacenamiento de Proxmox. El restore vive en la UI web de Proxmox — el Monitor expone la vista \"¿este guest tiene backup reciente?\", no el flujo de recuperación.",
"firewallTitle": "Pestaña 6 — Cortafuegos",
"firewallTitle": "Pestaña 7 — Cortafuegos",
"firewallIntro": "Lee el log de firewall de Proxmox por guest directamente del host (sin servicio extra, sin polling). La pestaña siempre está presente en la barra de navegación; el panel decide qué renderizar dependiendo de si el firewall está activo para ese guest y si alguna regla está logueando realmente:",
"firewallItems": [
"<strong>Firewall disabled</strong> — un aviso ámbar explica exactamente dónde activarlo en la UI de Proxmox (<em>&lt;Container|VM&gt; → Firewall → Options</em>) y te recuerda que al menos una regla necesita <code>log: info</code> (o superior) antes de que aparezcan paquetes.",
@@ -0,0 +1,114 @@
{
"meta": {
"title": "Cómo se traduce una imagen OCI | ProxMenux",
"description": "Del repositorio de la imagen y su archivo Compose a una plantilla revisable, un plan de despliegue y un LXC nativo de Proxmox VE, sin Docker dentro."
},
"header": {
"title": "Cómo se traduce una imagen OCI",
"description": "Del repositorio de la imagen y su archivo Compose a una plantilla revisable, un plan de despliegue y un LXC nativo, sin instalar Docker dentro.",
"section": "OCI manager Apps"
},
"sections": [
{
"id": "pipeline",
"title": "La cadena de traducción",
"blocks": [
{
"mermaid": {
"chartCode": "flowchart LR\n A[\"{{repo}}\"] --> B[\"Compose + README\"]\n B --> C[\"{{converter}}\"]\n C --> D[\"{{template}}\"]\n D --> E{\"{{blockers}}\"}\n E -- \"{{no}}\" --> F[\"{{review}}\"]\n F --> D\n E -- \"{{yes}}\" --> G[\"{{plan}}\"]\n G --> H[\"pct create\"]\n H --> I[\"{{lxc}}\"]",
"labels": {
"repo": "Repositorio de la imagen",
"converter": "Conversor",
"template": "Plantilla JSON",
"blockers": "¿Sin bloqueos?",
"no": "No",
"yes": "Sí",
"review": "Revisión / overlay",
"plan": "Plan de despliegue",
"lxc": "LXC nativo"
}
}
},
{
"p": "El conversor lee la imagen y el archivo Compose que publica su proyecto y escribe una plantilla JSON. Una plantilla con bloqueos sin traducir pasa por revisión, donde un overlay curado los resuelve, antes de publicarse en el catálogo. Solo las plantillas sin bloqueos se ofrecen para instalar."
}
]
},
{
"id": "template",
"title": "Qué conserva la plantilla",
"blocks": [
{
"cards": {
"items": [
{ "icon": "archive", "title": "Identidad de la imagen", "body": "Repositorio, etiqueta rolling, arquitectura, digest resuelto y revisión del origen." },
{ "icon": "braces", "title": "Contrato del contenedor", "body": "Entrypoint, Cmd, entorno, usuario, directorio de trabajo, señal de parada, puertos y volúmenes." },
{ "icon": "layers", "title": "Traducción a Proxmox VE", "body": "Recursos, seguridad, puntos de montaje, dispositivos, sysctls, healthchecks y las adaptaciones que necesita cada uno, con su motivo." },
{ "icon": "shield", "title": "Compatibilidad", "body": "Claves admitidas, bloqueos sin traducir y el estado de cada validación." }
]
}
}
]
},
{
"id": "sources",
"title": "OCI aporta el proceso; Compose aporta el entorno",
"blocks": [
{
"table": {
"headers": ["Origen", "Ejemplo", "Resultado nativo"],
"rows": [
["Metadatos OCI", "<code>Entrypoint</code>, <code>Cmd</code>, <code>User</code>", "Proxmox VE los importa al crear el CT"],
["Docker Compose", "<code>environment</code>, <code>volumes</code>, <code>devices</code>", "entradas de entorno del LXC, <code>mpN</code> y <code>devN</code>"],
["Perfil de ProxMenux", "GPU, healthcheck, credenciales", "preguntas y adaptaciones revisadas"],
["Usuario", "VMID, almacenamiento, red", "el contrato de la instancia"]
]
}
}
]
},
{
"id": "install",
"title": "Qué ocurre durante una instalación",
"blocks": [
{
"steps": {
"items": [
{ "title": "Resolver", "body": "Se consulta el registro, se selecciona la arquitectura del host y se fija el digest efectivo de la etiqueta rolling." },
{ "title": "Descargar y verificar", "body": "Skopeo descarga la imagen como archivo OCI, y cada capa se comprueba contra su digest y se descomprime antes de crear nada. Una descarga dañada se repite una vez antes de detener la instalación." },
{ "title": "Construir", "body": "<code>pct create</code> construye el rootfs a partir del archivo y conserva los metadatos oficiales de proceso de la imagen." },
{ "title": "Conectar", "body": "Se añaden los volúmenes, la red, el entorno, los dispositivos y los perfiles de seguridad declarados." },
{ "title": "Consola", "body": "La salida de consola del contenedor se guarda en el host, y la consola de Proxmox VE abre un shell cuando la imagen incluye uno." },
{ "title": "Comprobar", "body": "El primer arranque espera una dirección y la respuesta del servicio; un fallo no se presenta como instalación correcta." },
{ "title": "Registrar", "body": "La configuración efectiva se escribe en el contrato de la instancia que usan las actualizaciones y las recreaciones." }
]
}
}
]
},
{
"id": "example",
"title": "Ejemplo: una imagen con /config y /downloads",
"intro": "Una definición habitual de Compose y la configuración de Proxmox VE en la que se convierte. Las rutas que espera la aplicación no cambian.",
"blocks": [
{
"codeGrid": {
"items": [
{
"title": "Docker Compose",
"code": "image: lscr.io/linuxserver/example:latest\nenvironment:\n - PUID=1000\n - PGID=1000\nvolumes:\n - config:/config\n - /srv/downloads:/downloads\nports:\n - 8080:8080"
},
{
"title": "/etc/pve/lxc/VMID.conf (extracto)",
"code": "entrypoint: /init\nmp0: local-lvm:vm-VMID-disk-1,mp=/config,backup=1,size=8G\nmp1: /srv/downloads,mp=/downloads\nnet0: name=eth0,bridge=vmbr0,ip=dhcp,type=veth\nlxc.environment.runtime: PUID=1000\nlxc.environment.runtime: PGID=1000"
}
]
}
},
{
"p": "<code>mp0</code> es un segundo disco que pertenece al contenedor, con el nombre <code>vm-VMID-disk-N</code> en el almacenamiento elegido. Se monta en <code>/config</code> y, con <code>backup=1</code>, forma parte del backup del contenedor. <code>mp1</code> no crea ningún disco: enlaza el directorio del host <code>/srv/downloads</code> con <code>/downloads</code> dentro del LXC. El puerto 8080 no se mapea: el LXC tiene una dirección propia y el servicio responde en ella."
}
]
}
]
}
@@ -0,0 +1,134 @@
{
"meta": {
"title": "Instalar una imagen que no está en el catálogo | ProxMenux",
"description": "Traducción de una imagen OCI desde un archivo Compose, una URL, un comando docker run o una referencia de imagen, con revisión de lo que ProxMenux puede reproducir antes de instalarla."
},
"header": {
"title": "Instalar una imagen que no está en el catálogo",
"description": "Una imagen propia se traduce desde su archivo Compose, un comando docker run o solo su referencia, y el resultado se presenta para revisión antes de crear ningún LXC.",
"section": "OCI manager Apps"
},
"sections": [
{
"id": "intro",
"blocks": [
{
"calloutInfo": {
"title": "El mismo conversor, el mismo instalador",
"body": "La opción <strong>Instalar una imagen que no está en el catálogo</strong> utiliza el conversor y el instalador de las plantillas del catálogo. La diferencia es que el contrato se genera en ese momento a partir de la definición aportada y se valida antes de crear ningún LXC."
}
}
]
},
{
"id": "sources",
"title": "Cómo se describe la imagen",
"intro": "La primera pantalla pregunta cómo se describe la imagen. Hay cuatro formas de aportar una definición completa y una quinta que usa solo el nombre de la imagen.",
"blocks": [
{
"table": {
"headers": ["Opción", "Qué lee"],
"rows": [
["Pegar su archivo Compose en la terminal", "El YAML se pega en la terminal y termina con Ctrl+D en una línea vacía."],
["Leer su archivo Compose desde un archivo de este host", "Una ruta del nodo, <code>/root/docker-compose.yml</code> por defecto. El archivo debe existir y ocupar como máximo 256 KiB."],
["Descargar su archivo Compose desde una dirección", "Una dirección <code>http://</code> o <code>https://</code> que sirva el YAML sin procesar. Se descargan como máximo 256 KiB."],
["Pegar su comando docker run en la terminal", "El comando que publica el proyecto. Se traducen puertos, entorno, volúmenes, dispositivos, capacidades, usuario, memoria compartida y el resto de opciones admitidas."],
["Solo la referencia de la imagen, sin archivo Compose", "Una referencia como <code>ghcr.io/usuario/aplicacion:latest</code>. Se consulta el registro y se conservan los metadatos OCI de la imagen."]
]
}
},
{
"figure": {
"src": "/oci-manager/custom-source-menu.png",
"alt": "Menú que pregunta cómo se describe una imagen que no está en el catálogo",
"caption": "Las cinco formas de describir una imagen que no está en el catálogo."
}
}
]
},
{
"id": "reference-only",
"title": "Qué aporta solo la referencia de la imagen",
"intro": "Una imagen lleva sus metadatos de proceso, pero no todo lo que un archivo Compose suele añadir a su alrededor.",
"blocks": [
{
"table": {
"headers": ["Se lee de la imagen", "No está en la imagen", "Consecuencia"],
"rows": [
["<code>Entrypoint</code>, <code>Cmd</code>, <code>User</code>, <code>WorkingDir</code> y entorno integrado", "Variables que solo aparecen en la documentación", "Se añaden durante la instalación o una recreación"],
["Volúmenes declarados por la imagen", "Directorios del host que solo nombra un archivo Compose", "Las rutas adicionales se añaden antes de instalar"],
["Puertos <code>EXPOSE</code>", "La URL, el protocolo o un healthcheck funcional", "Se confirman el puerto y la forma de comprobar el servicio"],
["Arquitecturas y digest del registro", "Dispositivos, privilegios o dependencias externas", "Ninguno se activa sin una definición que lo pida"]
]
}
}
]
},
{
"id": "review",
"title": "Revisión antes de instalar",
"intro": "Tras traducir la definición, ProxMenux muestra lo que ha entendido antes de pedir VMID, recursos o almacenamiento.",
"blocks": [
{
"steps": {
"items": [
{ "title": "Analizar", "body": "Se leen servicios, imagen, puertos, rutas, entorno, dispositivos, seguridad y healthcheck." },
{ "title": "Consultar el registro", "body": "La imagen debe existir en un registro público, y se enumeran las arquitecturas que publica." },
{ "title": "Enumerar lo que no se aplica", "body": "Se enumeran las etiquetas, las redes Docker, los ajustes de Swarm y el resto de claves que no tienen efecto en un LXC." },
{ "title": "Bloquear lo que no puede traducirse", "body": "Una clave sin equivalencia segura aparece en <strong>Lo que no puede traducirse</strong> y la instalación no continúa. Nada se descarta en silencio." },
{ "title": "Pedir los secretos", "body": "Las variables cuyo nombre corresponde a una contraseña, un token o una clave se convierten en preguntas sensibles de la instalación." }
]
}
},
{
"figure": {
"src": "/oci-manager/custom-review.png",
"alt": "Resumen de lo que ProxMenux ha entendido de un archivo Compose",
"caption": "El resumen que se muestra antes de que la instalación pida VMID y recursos."
}
},
{
"p": "Tras aceptar el resumen, el recorrido es el del catálogo: nombre, modo predeterminado o avanzado, VMID, CPU, memoria, red, arranque con el nodo, rutas persistentes, rutas adicionales, dispositivos compatibles y resumen final."
}
]
},
{
"id": "examples",
"title": "Ejemplos de entrada",
"blocks": [
{
"codeGrid": {
"items": [
{
"title": "Compose",
"code": "services:\n app:\n image: ghcr.io/example/app:latest\n ports:\n - \"8080:8080\"\n volumes:\n - ./config:/config\n - /srv/media:/media\n environment:\n TZ: Europe/Madrid"
},
{
"title": "docker run",
"code": "docker run -d \\\n --name app \\\n -p 8080:8080 \\\n -e TZ=Europe/Madrid \\\n -v app-config:/config \\\n -v /srv/media:/media \\\n ghcr.io/example/app:latest"
}
]
}
}
]
},
{
"id": "limits",
"title": "Definiciones que no se instalan",
"blocks": [
{
"list": {
"items": [
"Imágenes en registros privados: no se piden credenciales del registro.",
"Un Dockerfile sin imagen publicada: la imagen debe construirse y publicarse antes en un registro OCI.",
"Un archivo Compose con varios servicios: queda bloqueado porque describe más de una imagen. Esta opción instala un único contenedor.",
"<code>configs</code>, secretos externos o formatos de dispositivo que no pueden traducirse sin ambigüedad.",
"Sustituciones del shell como <code>$(comando)</code>: debe escribirse el valor resultante.",
"Opciones de <code>docker run</code> no reconocidas y <code>--env-file</code>: se lee en su lugar un archivo Compose explícito."
]
}
}
]
}
]
}
@@ -0,0 +1,232 @@
{
"meta": {
"title": "Dispositivos y aceleración | ProxMenux",
"description": "Cómo entrega OCI manager Apps GPU, NVIDIA, Coral, USB, FUSE y otros dispositivos a un contenedor OCI como recursos nativos y validados de Proxmox VE."
},
"header": {
"title": "Dispositivos y aceleración",
"description": "GPU, NVIDIA, Coral, USB, FUSE y dispositivos de bloques se convierten en recursos nativos y validados de Proxmox VE del contenedor.",
"section": "OCI manager Apps"
},
"sections": [
{
"id": "principle",
"title": "El dispositivo que necesita la aplicación, no todo el host",
"blocks": [
{
"p": "Un dispositivo solicitado por el archivo Compose o por el perfil de la aplicación se convierte en una entrada <code>devN</code> o un montaje LXC concreto. Pedir una GPU, un dispositivo USB o un Coral no convierte el contenedor en privilegiado."
},
{
"flow": {
"nodes": [
{ "label": "Inventario del host", "detail": "/dev/dri/renderD128\nGID 993 · Intel" },
{ "label": "ProxMenux", "detail": "fabricante y\npermisos comprobados" },
{ "label": "LXC", "detail": "mismo dispositivo\nGID efectivo" }
]
}
}
]
},
{
"id": "origin",
"title": "De dónde procede la petición de un dispositivo",
"blocks": [
{
"table": {
"headers": ["Origen", "Qué se lee", "Qué hace el instalador"],
"rows": [
["Docker Compose", "<code>devices</code>, <code>group_add</code>, <code>deploy.resources</code> y peticiones NVIDIA", "Cada requisito se convierte en una petición de dispositivo que se muestra para revisión"],
["Perfil del catálogo", "El soporte de GPU, Coral, OpenCL, USB o FUSE que tiene realmente la aplicación", "Solo se ofrecen las opciones validadas para esa imagen"],
["Metadatos y documentación de la imagen", "VA-API, Selkies, mods de LinuxServer o el runtime NVIDIA", "Se añaden las variables y la preparación documentadas"],
["Selección del usuario", "Solo CPU, Intel/AMD, OpenCL, NVIDIA o un dispositivo opcional", "La selección se guarda en el contrato de la instancia"]
]
}
},
{
"calloutWarning": {
"title": "Los dispositivos detectados no se conectan por sí solos",
"body": "El host se inventaría, pero solo se ofrecen y conectan los dispositivos que declaran el archivo Compose o un perfil compatible. Una GPU, un dongle USB o un Coral presentes en el host no se exponen a todos los LXC."
}
}
]
},
{
"id": "identify",
"title": "Cómo se identifica el dispositivo en el host",
"intro": "Antes de modificar el LXC, el dispositivo se lee en el host y se compara con el perfil elegido.",
"blocks": [
{
"table": {
"headers": ["Tipo", "Identificación", "Validación"],
"rows": [
["Intel/AMD DRM", "<code>/dev/dri/renderD*</code> y <code>/sys/class/drm/NODO/device/vendor</code>", "Un dispositivo de caracteres con fabricante <code>0x8086</code> (Intel) o <code>0x1002</code> (AMD)"],
["OpenCL AMD", "El render node, más <code>/dev/kfd</code> cuando el perfil lo necesita", "Existencia, tipo, fabricante, permisos y compatibilidad declarada"],
["NVIDIA", "<code>nvidia-smi</code> y <code>nvidia-container-cli</code>", "GPU, UUID, bus PCI, versión del driver, Toolkit, nodos <code>/dev/nvidia*</code>, binarios y librerías"],
["Coral PCIe/M.2", "<code>/dev/apex_N</code> y su enlace en <code>/sys/dev/char/MAJOR:MINOR</code>", "Nodo de caracteres, major/minor, propietario, GID y permisos"],
["USB y serie", "<code>/dev/ttyUSB*</code>, <code>/dev/ttyACM*</code> o <code>/dev/bus/usb/BBB/DDD</code>", "Nodo de caracteres; en USB también fabricante, producto y número de serie cuando sysfs los publica"],
["KVM, TUN, FUSE, vídeo y SCSI genérico", "<code>/dev/kvm</code>, <code>/dev/net/tun</code>, <code>/dev/fuse</code>, <code>/dev/videoN</code> o <code>/dev/sgN</code>", "Ruta admitida, tipo de nodo y permisos efectivos"],
["Unidad óptica", "<code>/dev/srN</code>", "Un dispositivo de bloques"]
]
}
}
]
},
{
"id": "install",
"title": "Qué ocurre durante la instalación",
"blocks": [
{
"steps": {
"items": [
{ "title": "La plantilla ofrece sus perfiles", "body": "Por ejemplo solo CPU, Intel/AMD VA-API, OpenCL AMD, OpenCL Intel o NVIDIA. Las opciones pertenecen a la imagen, no a un menú común." },
{ "title": "Se elige un perfil", "body": "Define los nodos de dispositivo, el entorno, los mods o el runtime que necesita la aplicación." },
{ "title": "Se propone una ruta", "body": "Para DRM, <code>/dev/dri/renderD128</code>, que puede cambiarse en un host con varios render nodes. Para USB o serie se selecciona el nodo concreto." },
{ "title": "Validación", "body": "Se comprueban existencia, tipo, fabricante admitido, permisos y GID. Una discrepancia detiene la operación." },
{ "title": "Se escribe el contrato", "body": "Ruta, modo, GID, acceso de escritura y perfil quedan registrados para las actualizaciones y las recreaciones." },
{ "title": "Conexión y prueba", "body": "<code>pct set</code> añade la entrada <code>devN</code> y después se comprueba el acceso dentro del LXC. Las imágenes de LinuxServer se comprueban también como usuario <code>abc</code>." }
]
}
}
]
},
{
"id": "config",
"title": "Cómo aparece en la configuración del LXC",
"intro": "Valores ilustrativos: <code>dev0</code> y <code>dev1</code> son las posiciones libres que asigna Proxmox VE, y <code>renderD128</code>, <code>apex_0</code> y el GID dependen del hardware del nodo.",
"blocks": [
{
"codeGrid": {
"items": [
{ "title": "Intel/AMD VA-API", "code": "dev0: path=/dev/dri/renderD128,mode=0660,gid=993,deny-write=0" },
{ "title": "Coral PCIe/M.2", "code": "dev0: path=/dev/apex_0,mode=0660,gid=GID,deny-write=0" },
{ "title": "Un dispositivo USB concreto", "code": "dev0: path=/dev/bus/usb/003/004,mode=0660,gid=GID,deny-write=0" },
{ "title": "OpenCL AMD", "code": "dev0: path=/dev/dri/renderD128,mode=0660,gid=GID,deny-write=0\ndev1: path=/dev/kfd,mode=0660,gid=GID,deny-write=0" }
]
}
},
{
"p": "El GID se lee con <code>stat</code> en el host y se escribe en la entrada <code>devN</code>; no se da por hecho que los grupos <code>render</code> y <code>video</code> tengan un número fijo. El dispositivo conserva la misma ruta <code>/dev</code> dentro del LXC, que es donde lo buscan los mecanismos propios de la aplicación."
}
]
},
{
"id": "profiles",
"title": "Perfiles que puede ofrecer una imagen",
"blocks": [
{
"table": {
"headers": ["Perfil", "Traducción", "Se ofrece cuando"],
"rows": [
["Intel/AMD VA-API", "Render node de <code>/dev/dri</code>", "La aplicación admite aceleración de vídeo"],
["OpenCL", "Render node, <code>/dev/kfd</code> si hace falta y el mod oficial", "La imagen o el perfil lo documentan"],
["NVIDIA", "Dispositivos y librerías del driver del host", "El host tiene un driver operativo y NVIDIA Container Toolkit"],
["Coral", "<code>/dev/apex_0</code> o el bus USB", "El perfil declara soporte de Coral (Frigate)"],
["USB, serie, FUSE", "Un dispositivo concreto, un árbol validado o una función LXC", "El contrato lo pide"]
]
}
}
]
},
{
"id": "nvidia",
"title": "NVIDIA",
"blocks": [
{
"calloutWarning": {
"title": "Requisito del nodo: NVIDIA Container Toolkit",
"body": "Un driver operativo en Proxmox VE no basta para entregar una GPU NVIDIA a una imagen OCI. OCI manager Apps usa <code>nvidia-container-cli</code>, de NVIDIA Container Toolkit, para identificar los dispositivos y obtener los binarios y las librerías que corresponden al driver cargado."
}
},
{
"p": "El <nvidiaLink>instalador NVIDIA de ProxMenux</nvidiaLink> instala NVIDIA Container Toolkit desde el repositorio oficial de NVIDIA junto con el driver. Comprueba sus cuatro paquetes, valida <code>nvidia-container-cli</code> y registra el resultado en el diario de cambios de <auditLink>Auditoría e informes</auditLink>."
},
{
"p": "Estos dos comandos, en el host, muestran si el driver y el Toolkit están disponibles:"
},
{
"shell": { "code": "nvidia-smi -L\nnvidia-container-cli --version" }
},
{
"p": "En un host cuyo driver se instaló por otros medios, el Toolkit se instala desde el repositorio estable oficial:"
},
{
"shell": {
"code": "apt-get update\napt-get install -y --no-install-recommends ca-certificates curl gnupg2\n\ncurl -fsSL https://nvidia.github.io/libnvidia-container/gpgkey \\\n | gpg --dearmor -o /usr/share/keyrings/nvidia-container-toolkit-keyring.gpg\n\ncurl -s -L https://nvidia.github.io/libnvidia-container/stable/deb/nvidia-container-toolkit.list \\\n | sed 's#deb https://#deb [signed-by=/usr/share/keyrings/nvidia-container-toolkit-keyring.gpg] https://#g' \\\n > /etc/apt/sources.list.d/nvidia-container-toolkit.list\n\napt-get update\napt-get install -y nvidia-container-toolkit libnvidia-container-tools"
}
},
{
"p": "El inventario que usa OCI manager Apps es la salida de:"
},
{
"shell": { "code": "nvidia-container-cli list --device all --libraries --binaries --firmwares --ipcs" }
},
{
"calloutInfo": {
"title": "La configuración del runtime de Docker no interviene",
"body": "Los contenedores son LXC nativos y no se usa ningún daemon de Docker, así que <code>nvidia-ctk runtime configure --runtime=docker</code> no forma parte del proceso: ProxMenux consulta directamente <code>nvidia-container-cli</code> y escribe los dispositivos y montajes del LXC. Los comandos y las plataformas compatibles se mantienen en la <toolkitLink>guía de instalación de NVIDIA Container Toolkit</toolkitLink>."
}
},
{
"cards": {
"items": [
{ "icon": "cpu", "title": "Inventario desde el driver", "body": "<code>nvidia-container-cli</code> enumera los nodos de dispositivo, los binarios, el firmware y las librerías del driver instalado." },
{ "icon": "refresh", "title": "Sin versión fija", "body": "La plantilla no nombra archivos de librería. El perfil se genera a partir del host actual." },
{ "icon": "shield", "title": "Montajes de solo lectura", "body": "Las librerías del host se montan en solo lectura en lugar de copiarse dentro del contenedor." },
{ "icon": "hardDrive", "title": "Cambios de driver", "body": "Tras un cambio de driver, el inventario se genera de nuevo antes de que arranquen los LXC afectados." }
]
}
},
{
"code": {
"title": "Resultado NVIDIA (simplificado)",
"code": "devN: path=/dev/nvidia0,...\ndevN: path=/dev/nvidiactl,...\ndevN: path=/dev/nvidia-uvm,...\nlxc.mount.entry: HOST_LIBRARY CONTAINER_LIBRARY none ro,bind,create=file 0 0"
}
},
{
"p": "Entregar solo <code>/dev/nvidia0</code> no es suficiente. Los componentes de espacio de usuario del driver cargado se montan en solo lectura y después <code>nvidia-smi</code> se ejecuta dentro del LXC para comparar GPU, UUID, bus PCI y versión con el inventario del host."
}
]
},
{
"id": "usb",
"title": "USB, serie y Coral USB",
"blocks": [
{
"calloutWarning": {
"title": "La numeración USB puede cambiar",
"body": "Una ruta como <code>/dev/bus/usb/003/004</code> puede cambiar al reconectar el dispositivo o reiniciar el host. El perfil registra fabricante, producto y número de serie cuando están disponibles, pero una nueva dirección de bus no se reasigna automáticamente."
}
},
{
"p": "Un periférico se indica por su nodo concreto: <code>/dev/ttyUSB0</code>, <code>/dev/ttyACM0</code>, <code>/dev/apex_0</code> o <code>/dev/bus/usb/BBB/DDD</code>. No se admite entregar todo <code>/dev</code>. Coral solo se ofrece a las aplicaciones cuyo perfil lo declara."
}
]
},
{
"id": "trees",
"title": "Árboles de dispositivos y funciones LXC",
"blocks": [
{
"table": {
"headers": ["Petición", "Traducción", "Alcance"],
"rows": [
["<code>/dev/dvb</code>, <code>/dev/snd</code> o <code>/dev/bus/usb</code>", "Cada nodo de caracteres del árbol recibe su propia entrada <code>devN</code> con el modo y el GID del host", "Solo el árbol pedido, no el resto de <code>/dev</code>"],
["<code>/dev/fuse</code>", "El nodo y, cuando el perfil lo necesita, la función <code>fuse=1</code>", "FUSE por sí solo no publica montajes a otros LXC"],
["<code>/dev/net/tun</code>", "Una entrada <code>devN</code> en la misma ruta dentro del LXC", "La configuración de la VPN o de la red queda en la aplicación"],
["<code>/dev/kvm</code>", "Una entrada <code>devN</code> validada", "Solo se ofrece cuando el contrato lo pide"]
]
}
}
]
},
{
"id": "security",
"title": "Confirmaciones según el nivel de riesgo",
"blocks": [
{
"p": "Los dispositivos concretos, el privilegio opcional, el privilegio obligatorio, la relajación de AppArmor o seccomp y el acceso al espacio de nombres PID del host se tratan como casos distintos, no bajo una etiqueta genérica de privilegiado. Cada opción con riesgo se explica y se confirma durante la instalación."
}
]
}
]
}
+116
View File
@@ -0,0 +1,116 @@
{
"meta": {
"title": "OCI manager Apps | ProxMenux",
"description": "Imágenes OCI oficiales ejecutadas como contenedores LXC nativos de Proxmox VE, con datos persistentes, dispositivos, aplicaciones multicontenedor y actualizaciones transaccionales."
},
"header": {
"title": "OCI manager Apps",
"description": "Las imágenes OCI oficiales se ejecutan como contenedores LXC nativos de Proxmox VE. La imagen sigue siendo la que publica su responsable; ProxMenux reproduce el entorno que Docker Compose habría creado a su alrededor.",
"section": "OCI manager Apps"
},
"sections": [
{
"id": "model",
"blocks": [
{
"calloutInfo": {
"title": "Una imagen OCI, un LXC nativo",
"body": "Dentro de los contenedores no se ejecuta ningún motor Docker. Proxmox VE importa el sistema de archivos de la imagen y sus metadatos OCI, y la aplicación pasa a ser el proceso principal de un LXC nativo, gestionado con las mismas herramientas que cualquier otro contenedor del nodo."
}
},
{
"flow": {
"nodes": [
{ "label": "Origen", "detail": "Imagen OCI\nCompose y documentación" },
{ "label": "ProxMenux", "detail": "Contrato JSON\nvalidación y plan" },
{ "label": "Proxmox VE", "detail": "LXC nativo\nvolúmenes y dispositivos" }
],
"caption": "La aplicación no se reconstruye: su entorno se reproduce de forma declarativa."
}
}
]
},
{
"id": "where",
"title": "Dónde se encuentra",
"intro": "OCI manager Apps se abre desde la opción <strong>OCI manager Apps (beta)</strong> del menú principal de ProxMenux, en el nodo Proxmox y como root. Su primera pantalla ofrece:",
"blocks": [
{
"list": {
"items": [
"<strong>Buscar aplicaciones</strong>: búsqueda por nombre en todo el catálogo.",
"<strong>Todas las aplicaciones</strong>: el catálogo completo, con el número de aplicaciones.",
"<strong>Gestionar aplicaciones OCI instaladas</strong>: actualizar, recrear, eliminar o recuperar lo instalado.",
"<strong>Instalar una imagen que no está en el catálogo</strong>: traducción de un archivo Compose, un comando <code>docker run</code> o una referencia de imagen.",
"Las categorías del catálogo, cada una con su número de aplicaciones."
]
}
},
{
"figure": {
"src": "/oci-manager/main-menu.png",
"alt": "Pantalla principal de OCI manager Apps con la búsqueda, todas las aplicaciones, la gestión, la imagen propia y las categorías del catálogo",
"caption": "Pantalla principal de OCI manager Apps."
}
},
{
"p": "Al seleccionar una aplicación se muestra su descripción, la imagen que ejecuta y dos modos de instalación: <strong>Instalar con la configuración predeterminada</strong>, que apenas hace preguntas, e <strong>Instalar con la configuración avanzada</strong>, que ofrece los selectores reales de almacenamiento, bridge y recursos del nodo."
}
]
},
{
"id": "translation",
"title": "Lo que Docker expresa y en qué lo convierte OCI manager Apps",
"blocks": [
{
"table": {
"headers": ["Necesidad", "Docker la expresa como", "OCI manager Apps la convierte en"],
"rows": [
["Ejecutar la aplicación", "<code>image</code>, <code>entrypoint</code>, <code>command</code>", "rootfs OCI y proceso principal del LXC"],
["Conservar la configuración", "<code>volumes: /config</code>", "un disco <code>mpN</code> persistente incluido en el backup, o un directorio del host"],
["Publicar el servicio", "<code>ports</code>", "una dirección propia del LXC y la URL de acceso al servicio"],
["Usar hardware", "<code>devices</code>, <code>group_add</code>", "entradas <code>devN</code> con el GID efectivo del host y un perfil validado"],
["Conectar dependencias", "<code>networks</code>, <code>depends_on</code>", "un bridge privado, direcciones fijas, orden de arranque y healthchecks"],
["Actualizar", "<code>pull</code> y recrear", "un rootfs nuevo con el mismo contrato persistente"]
]
}
}
]
},
{
"id": "kept",
"title": "Qué se mantiene y qué cambia",
"blocks": [
{
"cards": {
"items": [
{ "icon": "archive", "title": "Se mantiene", "body": "La imagen oficial, sus rutas internas, su entorno, su proceso de arranque y su documentación funcional." },
{ "icon": "boxes", "title": "Se adapta", "body": "El entorno de ejecución: red, persistencia, dispositivos, permisos y dependencias usan primitivas LXC nativas de Proxmox VE." },
{ "icon": "shield", "title": "No se traduce", "body": "Una clave de Compose sin equivalencia segura figura como bloqueo. Las plantillas con bloqueos no se ofrecen, y las opciones sensibles se confirman durante la instalación." },
{ "icon": "refresh", "title": "Se registra", "body": "Digest de la imagen, recursos, rutas, red, dispositivos y pertenencia a una pila quedan en el contrato de la instancia, que las actualizaciones y las recreaciones reproducen." }
]
}
}
]
},
{
"id": "pages",
"title": "Páginas de esta sección",
"blocks": [
{
"next": {
"items": [
{ "label": "Cómo se traduce una imagen OCI", "href": "/docs/oci-manager/architecture", "tail": "de la imagen y su archivo Compose a un LXC nativo." },
{ "label": "Instalar una imagen que no está en el catálogo", "href": "/docs/oci-manager/custom-image", "tail": "Compose, docker run o una referencia de imagen." },
{ "label": "Datos, rutas y red", "href": "/docs/oci-manager/storage-network", "tail": "discos del contenedor, directorios del host, montajes Rclone y direcciones." },
{ "label": "Dispositivos y aceleración", "href": "/docs/oci-manager/hardware", "tail": "GPU, NVIDIA, Coral, USB y otros dispositivos." },
{ "label": "Aplicaciones multicontenedor", "href": "/docs/oci-manager/stacks", "tail": "aplicación, base de datos y caché como LXC coordinados." },
{ "label": "Instalar, actualizar y recrear", "href": "/docs/oci-manager/lifecycle", "tail": "el contrato de la instancia y sus operaciones." },
{ "label": "En ProxMenux Monitor", "href": "/docs/oci-manager/monitor", "tail": "versiones, actualizaciones, salida de consola y terminal." }
]
}
}
]
}
]
}
@@ -0,0 +1,243 @@
{
"meta": {
"title": "Instalar, actualizar y recrear | ProxMenux",
"description": "El contrato de instancia de un contenedor OCI y las operaciones que lo usan: actualizar, recrear, eliminar y recuperar una operación interrumpida."
},
"header": {
"title": "Instalar, actualizar y recrear",
"description": "Cada instancia conserva un contrato reproducible, de modo que su rootfs puede sustituirse sin perder la configuración ni los datos persistentes.",
"section": "OCI manager Apps"
},
"sections": [
{
"id": "contract",
"title": "El contrato de la instancia",
"blocks": [
{
"p": "Tras una instalación, la configuración efectiva se guarda en <code>/usr/local/share/proxmenux/oci/instances/VMID/oci-compose.json</code>. No es una copia del archivo Compose original: es el contrato reproducible del LXC que existe en este host."
},
{
"code": {
"code": "instances/\n└── 105/\n └── oci-compose.json\n ├── imagen y digest resuelto\n ├── recursos y red\n ├── entorno (secretos protegidos)\n ├── discos del contenedor y directorios del host\n ├── perfil de hardware y dispositivos\n ├── log de consola y modo de terminal\n └── pertenencia a una pila y ciclo de vida"
}
}
]
},
{
"id": "manage",
"title": "Gestionar aplicaciones OCI instaladas",
"intro": "Esta opción de la pantalla principal enumera las instancias registradas con su aplicación y su imagen. Cada una se contrasta con su contrato antes de cualquier acción; un CT que ya no coincide con su registro no se modifica ni se elimina. La misma actualización y la misma recreación se ofrecen en la pestaña Actualizaciones de <monitorLink>ProxMenux Monitor</monitorLink>.",
"blocks": [
{
"table": {
"headers": [
"Opción",
"Qué cambia",
"Qué se conserva"
],
"rows": [
[
"Actualizar la imagen con la configuración guardada",
"El rootfs se sustituye por la imagen que publica hoy el canal guardado",
"Contrato, discos del contenedor, directorios del host, red y dispositivos"
],
[
"Recrear: editar recursos, red, rutas y GPU",
"El editor se abre con el contrato actual; el CT se reconstruye con los cambios",
"Los datos de los discos del contenedor y de los directorios del host"
],
[
"Eliminar: la aplicación y sus contenedores",
"Se eliminan el LXC, o todos los miembros de una pila, y sus contratos",
"Los directorios del host, con su contenido"
]
]
}
},
{
"p": "Para una aplicación multicontenedor el menú ofrece <strong>Actualizar cada contenedor de la aplicación</strong> y la eliminación. Una pila no se recrea."
},
{
"figure": {
"src": "/oci-manager/manage-menu.png",
"alt": "Lista de aplicaciones OCI instaladas y las opciones de actualizar, recrear y eliminar",
"caption": "Gestionar aplicaciones OCI instaladas."
}
}
]
},
{
"id": "update",
"title": "Una actualización transaccional",
"blocks": [
{
"mermaid": {
"chartCode": "sequenceDiagram\n participant U as {{user}}\n participant P as ProxMenux\n participant R as {{registry}}\n participant X as Proxmox VE\n U->>P: {{update}}\n P->>R: {{resolve}}\n R-->>P: digest\n P->>P: {{verify}}\n P->>X: {{backup}}\n P->>X: {{import}}\n P->>X: {{reapply}}\n X-->>P: healthcheck\n alt {{healthy}}\n P-->>U: {{commit}}\n else {{failure}}\n P->>X: Rollback\n P-->>U: {{restored}}\n end",
"labels": {
"user": "Usuario",
"registry": "Registro OCI",
"update": "Actualizar la instancia",
"resolve": "Resolver la etiqueta",
"verify": "Verificar el archivo y preflight",
"backup": "Detener y respaldar el CT",
"import": "Importar el rootfs nuevo",
"reapply": "Aplicar de nuevo el contrato",
"healthy": "correcto",
"failure": "fallo",
"commit": "Contrato publicado con el digest nuevo",
"restored": "Instancia anterior restaurada"
}
}
},
{
"list": {
"items": [
"Cuando el registro sigue sirviendo el digest instalado, no se descarga nada y la instancia no se toca.",
"La imagen nueva se verifica capa a capa antes de detener el CT. Una descarga que llega dañada se repite una vez; una imagen ya almacenada que no supera la comprobación se descarga de nuevo.",
"Los ajustes cambiados en Proxmox VE después de la instalación (memoria, swap, núcleos, límite de CPU, prioridad de CPU, arranque con el nodo) se conservan y pasan al contrato nuevo.",
"Cualquier otra diferencia entre el CT y su contrato detiene la actualización antes de detener el CT."
]
}
},
{
"flow": {
"nodes": [
{
"label": "Antes",
"detail": "rootfs A\n/config mp0\n/media directorio del host"
},
{
"label": "Actualización",
"detail": "sustituye solo\nel rootfs"
},
{
"label": "Después",
"detail": "rootfs B\n/config mp0\n/media directorio del host"
}
]
}
}
]
},
{
"id": "recovery",
"title": "Recuperar una operación interrumpida",
"intro": "La actualización y la recreación usan una transacción persistente. Si el proceso, la terminal o el nodo se interrumpen después de detener el CT, la operación no se da por terminada.",
"blocks": [
{
"steps": {
"items": [
{
"title": "Marcador pendiente",
"body": "Al abrir Gestionar aplicaciones OCI instaladas, el estado guardado indica que la sustitución no llegó a publicarse."
},
{
"title": "Ver estado",
"body": "Muestra la fase alcanzada sin modificar contenedores ni datos."
},
{
"title": "Recuperar la instalación anterior",
"body": "Restaura el backup nativo verificado tomado antes de la sustitución y el contrato anterior."
},
{
"title": "Pilas como una unidad",
"body": "En una aplicación multicontenedor se recuperan todos los miembros desde el mismo punto de la transacción, no solo el seleccionado."
}
]
}
},
{
"calloutWarning": {
"title": "Los directorios del host quedan fuera de la restauración",
"body": "El backup cubre el rootfs y los discos del contenedor que incluye. Un directorio del host no se revierte, porque otros LXC pueden usar sus datos. Actualizar, recrear o recuperar una instancia con directorios del host pide antes una confirmación de ello."
}
}
]
},
{
"id": "remove",
"title": "Eliminar una aplicación OCI",
"blocks": [
{
"p": "Antes de la confirmación se compone un resumen a partir de la configuración real: los contenedores que se eliminan, los datos que se eliminan con ellos, la red privada que se libera y los directorios del host que se conservan. La confirmación sale en <strong>No</strong> por defecto, porque los datos de los discos eliminados no pueden recuperarse después."
},
{
"table": {
"headers": [
"Recurso",
"Al eliminar",
"Motivo"
],
"rows": [
[
"rootfs y discos del contenedor",
"Se eliminan",
"Solo pertenecen al contenedor"
],
[
"Directorio del host",
"Se conserva, con su contenido",
"Otras aplicaciones pueden usarlo"
],
[
"Contrato de la instancia",
"Se retira tras una eliminación correcta",
"Ya no tiene ningún CT asociado"
],
[
"Bridge privado de una pila",
"Se libera con la pila",
"Ya no le quedan miembros que conectar"
],
[
"Un único miembro de una pila",
"No se elimina por separado",
"Se elimina la aplicación completa, para no dejar ninguna pila incompleta"
]
]
}
},
{
"figure": {
"src": "/oci-manager/remove-summary.png",
"alt": "Resumen de eliminación con los contenedores, los datos y los directorios del host afectados",
"caption": "El resumen de eliminación, compuesto a partir de la configuración real."
}
}
]
},
{
"id": "archives",
"title": "Imágenes descargadas y espacio del host",
"blocks": [
{
"p": "El archivo OCI se usa para construir el rootfs; el CT en marcha no lo lee. Tras una instalación o una actualización se enumeran los archivos descargados en esa operación con su tamaño y se ofrece eliminarlos. Eliminarlos libera el espacio sin afectar al contenedor ni a sus datos."
},
{
"calloutInfo": {
"title": "Las actualizaciones no necesitan el archivo",
"body": "Sin el archivo, una actualización resuelve el canal guardado y descarga el digest nuevo. Con él, un archivo solo se reutiliza cuando su referencia y su integridad coinciden con lo pedido."
}
}
]
},
{
"id": "registry",
"title": "Registro y limpieza",
"blocks": [
{
"p": "Los contratos registrados se comparan con los CT reales. Un contrato solo queda huérfano cuando su VMID ya no existe o ya no lleva la identidad de instancia esperada. La limpieza no elimina volúmenes ni datos externos por deducción."
}
]
},
{
"id": "channel",
"title": "Una etiqueta rolling no es una actualización desatendida",
"blocks": [
{
"p": "El catálogo instala la etiqueta rolling que publica su responsable, pero el digest efectivo se resuelve, se registra y solo cambia con una actualización explícita, con preflight y restauración. <monitorLink>ProxMenux Monitor</monitorLink> compara el digest instalado con el que publica el registro y muestra, y notifica, cuándo hay una imagen nueva."
}
]
}
]
}
@@ -0,0 +1,203 @@
{
"meta": {
"title": "Contenedores OCI en ProxMenux Monitor | ProxMenux",
"description": "Qué muestra ProxMenux Monitor de un contenedor instalado por OCI manager Apps: versiones de la aplicación y de la imagen, imágenes nuevas, salida de consola y terminal de Proxmox VE."
},
"header": {
"title": "En ProxMenux Monitor",
"description": "Un contenedor instalado por OCI manager Apps aparece en VMs y LXCs como cualquier otro LXC. Su ventana lee el registro de la instalación: versiones de la aplicación y de la imagen, imágenes nuevas, salida de consola y terminal.",
"section": "OCI manager Apps"
},
"sections": [
{
"id": "intro",
"blocks": [
{
"calloutInfo": {
"title": "El registro es la fuente",
"body": "OCI manager Apps sabe qué instaló y de dónde procede. El Monitor lee ese registro de la instalación en lugar de sondear el contenedor, así que los datos son los mismos con el contenedor en marcha o detenido."
}
},
{
"table": {
"headers": [
"Pestaña",
"Qué cambia en un contenedor OCI"
],
"rows": [
[
"App",
"La aplicación se identifica desde el registro y sus actualizaciones se siguen por la imagen"
],
[
"Actualizaciones",
"Se actualiza la imagen o se recrea el contenedor, con el mismo recorrido que el menú OCI"
],
[
"Montajes",
"Discos del contenedor y directorios del host, con su uso"
],
[
"Logs",
"Solo en contenedores OCI: la salida de consola de la aplicación"
]
]
}
}
]
},
{
"id": "app",
"title": "App",
"intro": "La pestaña <appLink>App</appLink> ofrece la aplicación instalada como una detección, con el nombre, el logo, el puerto y el esquema del registro. Al registrarla se abre el editor con el método <strong>Imagen OCI (instalada por ProxMenux)</strong>, que no necesita configuración.",
"blocks": [
{
"cards": {
"items": [
{
"icon": "boxes",
"title": "Aplicación",
"body": "La versión de la aplicación dentro de la imagen, leída de la propia imagen: su entorno o su etiqueta <code>org.opencontainers.image.version</code>. Es informativa."
},
{
"icon": "archive",
"title": "Imagen",
"body": "La fecha de construcción y el digest de la imagen instalada. La actualización se decide aquí: el digest instalado se compara con el que publica hoy el registro para la misma etiqueta."
}
]
}
},
{
"list": {
"items": [
"Cuando el registro publica un digest nuevo, la tarjeta muestra <strong>Nueva imagen</strong> con su fecha y su digest, aunque la versión de la aplicación no haya cambiado: una reconstrucción sobre una base actualizada es una actualización.",
"Cuando los digests coinciden, la tarjeta indica <strong>Versión</strong>.",
"La tarjeta enlaza con el repositorio de la imagen: su proyecto en GitHub, o su página de Docker Hub en una imagen oficial.",
"El enlace de acceso usa la dirección de la LAN del contenedor, también en el miembro principal de una aplicación multicontenedor, que tiene una segunda dirección en su red privada.",
"El botón <strong>Actualizar datos</strong> vuelve a leer el registro y el registro de imágenes. No se ofrecen las opciones de buscar aplicaciones ni de registrar otra: el contenedor contiene exactamente la aplicación de su registro."
]
}
},
{
"figure": {
"src": "/oci-manager/monitor-app-tab.png",
"alt": "Pestaña App de un contenedor OCI con la versión de la aplicación, la imagen y el enlace al repositorio",
"caption": "Pestaña App de un contenedor instalado por OCI manager Apps."
}
},
{
"p": "La comprobación se ejecuta una vez al día con las comprobaciones de actualizaciones del Monitor, y <strong>Actualizar datos</strong> la ejecuta al momento. Una imagen nueva se envía como notificación por los canales configurados en <notificationsLink>Notificaciones</notificationsLink>. La actualización se aplica desde la pestaña Actualizaciones."
}
]
},
{
"id": "updates",
"title": "Actualizaciones",
"intro": "En un contenedor instalado por OCI manager Apps, la pestaña Actualizaciones muestra la aplicación con su imagen instalada y, cuando el registro publica una, la imagen nueva, con el mismo formato que cualquier otra aplicación. Los actualizadores de paquetes y de aplicaciones de un LXC normal no aparecen.",
"blocks": [
{
"table": {
"headers": [
"Botón",
"Qué abre"
],
"rows": [
[
"Actualizar",
"La actualización de <lifecycleLink>Gestionar aplicaciones OCI instaladas</lifecycleLink> para este contenedor, en la terminal del Monitor. Puede ejecutarse haya o no imagen nueva; sin ella, no cambia nada. En una aplicación multicontenedor actualiza todos los miembros."
],
[
"Recrear",
"El editor de la recreación (recursos, red, rutas y GPU). No se ofrece en una aplicación multicontenedor."
],
[
"Recuperar",
"Sustituye a Actualizar cuando una operación sobre el contenedor quedó interrumpida, y abre su recuperación."
]
]
}
},
{
"p": "Los cambios externos, los directorios del host y las aplicaciones multicontenedor se tratan como en el menú OCI. Al cerrar la terminal se vuelven a leer la imagen, el registro y los montajes."
},
{
"table": {
"headers": [
"Opción",
"Comportamiento"
],
"rows": [
[
"Conservar el backup previo a la actualización",
"Cada actualización hace un backup del contenedor para restaurarlo si falla. Con esta opción ese mismo backup se conserva en el almacenamiento elegido y aparece entre los backups del CT; en Proxmox Backup Server se escribe un backup antes de actualizar."
],
[
"Actualizaciones programadas",
"La imagen se actualiza a la hora elegida solo cuando el registro publica una nueva y, opcionalmente, solo cuando tiene 1, 3, 7 o 14 días. Un contenedor con cambios hechos fuera de ProxMenux se salta y se notifica; uno con directorios del host solo se actualiza si se confirmó al guardar la programación."
]
]
}
}
]
},
{
"id": "logs",
"title": "Logs",
"intro": "La pestaña Logs solo aparece en los contenedores instalados por OCI manager Apps, entre Montajes y Backups. Muestra la salida estándar y de errores del proceso principal de la imagen, la misma que muestra <code>docker logs</code> en un contenedor Docker.",
"blocks": [
{
"list": {
"items": [
"La salida se guarda en el host en <code>/var/log/proxmenux/oci/VMID.console.log</code> (modo 0600), desde el primer arranque y entre reinicios, así que puede leerse con el contenedor detenido.",
"El archivo se rota al llegar a 10 MB y se conservan tres copias comprimidas (<code>/etc/logrotate.d/proxmenux-oci</code>).",
"Se muestran las últimas 100, 500 o 1000 líneas. Con el contenedor en marcha, las líneas nuevas se siguen en directo; al desplazarse hacia arriba el seguimiento se pausa, y <strong>Seguir</strong> lo reanuda.",
"Un filtro muestra solo las líneas que contienen un texto, y <strong>Descargar</strong> guarda las líneas cargadas.",
"Los códigos de color se eliminan y una línea que redibuja una barra de progreso se muestra en su estado final.",
"La pestaña lee el archivo cada vez que se abre; no se guarda en caché."
]
}
},
{
"calloutInfo": {
"title": "Credenciales del primer arranque",
"body": "Las imágenes que imprimen una contraseña generada en su primer arranque la dejan en esta salida, como hace <code>docker logs</code>. El instalador la lee de ahí para mostrarla en su resumen."
}
},
{
"figure": {
"src": "/oci-manager/monitor-logs-tab.png",
"alt": "Pestaña Logs con la salida de consola de un contenedor OCI, el selector de líneas, el filtro y el botón de seguimiento",
"caption": "Salida de consola de un contenedor OCI."
}
}
]
},
{
"id": "terminal",
"title": "Consola de Proxmox VE",
"blocks": [
{
"p": "Una imagen OCI ejecuta su propio proceso como PID 1 y ningún servicio de inicio de sesión, así que la consola predeterminada de un LXC abriría un terminal en el que no responde nadie. Los contenedores instalados por OCI manager Apps se crean con <code>cmode: shell</code>: la consola de Proxmox VE abre un shell con <code>lxc-attach</code>, el equivalente a <code>docker exec</code>, sin tocar la aplicación en marcha."
},
{
"list": {
"items": [
"El shell es el que <code>/etc/passwd</code> asigna a root en la imagen. Una imagen cuyo root no tiene shell, o que no incluye ninguno, mantiene la consola predeterminada.",
"El shell es root dentro del contenedor, sin contraseña. Quién puede abrirlo lo decide el permiso <code>VM.Console</code> de Proxmox VE.",
"La terminal del Monitor entra en el contenedor con <code>pct enter</code>, que funciona del mismo modo."
]
}
}
]
},
{
"id": "mounts",
"title": "Montajes",
"blocks": [
{
"p": "La pestaña <mountsLink>Montajes</mountsLink> enumera los discos del contenedor y los directorios del host. El uso de un disco del contenedor en almacenamiento de bloques, como LVM-thin, se lee del sistema de archivos del disco, que solo está montado dentro del contenedor."
}
]
}
]
}
@@ -0,0 +1,241 @@
{
"meta": {
"title": "Aplicaciones multicontenedor | ProxMenux",
"description": "Cómo convierte OCI manager Apps una aplicación con su base de datos y su caché en LXC nativos coordinados: plan, red privada, hook de dependencias, validación y actualizaciones transaccionales."
},
"header": {
"title": "Aplicaciones multicontenedor",
"description": "Una aplicación con su base de datos, su caché y otros servicios se convierte en varios LXC nativos coordinados, que se instalan y actualizan como uno solo.",
"section": "OCI manager Apps"
},
"sections": [
{
"id": "intro",
"blocks": [
{
"calloutInfo": {
"title": "Una aplicación para el usuario, varios LXC para Proxmox VE",
"body": "Una definición multicontenedor es una sola entrada del catálogo. El instalador crea un LXC nativo por servicio y mantiene explícitas sus dependencias. Immich, Nextcloud, Paperless-ngx y Tandoor se instalan de esta forma."
}
},
{
"mermaid": {
"chartCode": "flowchart LR\n C[\"Docker Compose\"] --> O[\"{{plan}}\"]\n O --> A[\"{{app}}<br/>{{appNet}}\"]\n O --> D[\"{{db}}<br/>{{private}}\"]\n O --> R[\"{{cache}}<br/>{{private}}\"]\n V1[(\"config\")] --> A\n V2[(\"database\")] --> D\n V3[(\"cache\")] --> R\n D --> A\n R --> A",
"labels": { "plan": "Plan de la pila", "app": "LXC de la aplicación", "appNet": "LAN + privada", "db": "LXC PostgreSQL", "cache": "LXC Valkey", "private": "privada" }
}
}
]
},
{
"id": "plan",
"title": "1. El plan, antes de que exista ningún contenedor",
"blocks": [
{
"p": "Mientras se interpreta la definición Compose no se crea ningún LXC. Primero se construye un plan completo con cada miembro, imagen, VMID, red, ruta, secreto, orden y comprobación de salud. Si el plan no es coherente, la instalación no empieza."
},
{
"table": {
"headers": ["Elemento del plan", "Contenido", "Comprobado antes de crear nada"],
"rows": [
["Miembros", "Aplicación principal, base de datos, caché, aprendizaje automático y demás dependencias", "VMID únicos, roles conocidos y exactamente un miembro principal"],
["Imágenes", "Referencia rolling, arquitectura y digest resuelto de cada servicio", "Todas existen, admiten la arquitectura y superan la verificación de integridad OCI"],
["Red", "Bridge privado, subred, una dirección fija por servicio y acceso LAN para el miembro principal", "Sin colisión con bridges o subredes existentes y sin direcciones repetidas"],
["Persistencia", "Discos del contenedor, directorios del host, propietarios y backup", "Rutas sin solapamientos, almacenamiento disponible y permisos declarados"],
["Secretos", "Contraseña de la base de datos, claves de la aplicación y credenciales iniciales", "Se generan una vez y solo se entregan a los miembros que los usan"],
["Ciclo de vida", "Orden de arranque, orden de parada y una comprobación de salud por miembro", "La aplicación principal arranca la última y se detiene la primera"]
]
}
}
]
},
{
"id": "create",
"title": "2. Creación, miembro a miembro",
"blocks": [
{
"steps": {
"items": [
{ "title": "Reservar todos los VMID", "body": "Se comprueban el inventario de Proxmox VE y el registro de instancias. No se adopta un CT existente ni se reutiliza un contrato que todavía pertenece a otra instancia." },
{ "title": "Preparar todas las imágenes", "body": "Todas las imágenes se resuelven, descargan y verifican antes de crear el primer contenedor." },
{ "title": "Crear cada rootfs", "body": "Se importan los metadatos OCI oficiales y se añaden la identidad de instancia de ProxMenux y el rol del miembro." },
{ "title": "Red privada", "body": "Se crean un bridge y una subred y cada miembro recibe su dirección fija; solo el miembro principal recibe además la interfaz de la LAN." },
{ "title": "Persistencia", "body": "Cada base de datos y configuración recibe su propio disco del contenedor; solo los datos destinados a compartirse usan directorios del host." },
{ "title": "Entorno", "body": "Se escriben los endpoints internos, los secretos compartidos y las variables de servicio. La aplicación llega a sus dependencias en sus direcciones privadas reservadas." },
{ "title": "Registro", "body": "Cada miembro registra su configuración nativa, los cambios del rootfs que las actualizaciones deben reproducir y su relación con la pila." }
]
}
}
]
},
{
"id": "checks",
"title": "3. Arranque y comprobación de cada contenedor",
"intro": "Un LXC creado no significa un servicio listo. Las dependencias arrancan en orden y cada una supera una comprobación propia de su servicio.",
"blocks": [
{
"table": {
"headers": ["Servicio", "Comprobación", "Qué demuestra"],
"rows": [
["PostgreSQL", "<code>pg_isready</code> en el CT con el host, el usuario y la base de datos esperados", "El servidor acepta conexiones para la base de datos configurada"],
["Redis / Valkey", "<code>redis-cli</code> o <code>valkey-cli</code> <code>PING</code> contra su dirección privada", "El broker escucha y responde"],
["Aprendizaje automático de Immich", "HTTP <code>GET /ping</code>, más una comprobación del runtime GPU seleccionado", "El servicio responde y la aceleración pedida no ha pasado a CPU"],
["Nextcloud", "<code>GET /status.php</code> con <code>installed=true</code>, <code>maintenance=false</code> y <code>needsDbUpgrade=false</code>", "La inicialización terminó sin migraciones pendientes"],
["Paperless-ngx / Tandoor", "HTTP en la dirección de la LAN y el puerto real del servicio", "El frontend y sus dependencias sirven la aplicación"],
["Aplicación principal", "El endpoint de su plantilla, por ejemplo <code>/api/server/ping</code> en Immich", "La pila completa funciona a través de la aplicación que usa las dependencias"]
]
}
},
{
"calloutWarning": {
"title": "running no significa healthy",
"body": "El estado running solo indica que existe el proceso del LXC. Cuando el servicio ofrece una comprobación mejor, se usa una comprobación exec o HTTP con un tiempo límite. Si un miembro se detiene o no supera su comprobación, la pila no se declara instalada."
}
}
]
},
{
"id": "hook",
"title": "4. El hook de dependencias",
"blocks": [
{
"p": "El hook solo se configura en el contenedor principal de una pila dependiente. Proxmox VE guarda el script como snippet y lo ejecuta como <code>hookscript</code> de ese CT. La receta de la pila no está escrita en el script: vive en un contrato privado aparte."
},
{
"codeGrid": {
"items": [
{ "title": "Configuración del CT principal", "code": "hookscript: local:snippets/proxmenux-stack-dependencies.sh" },
{ "title": "Contrato privado (ejemplo)", "code": "/etc/pve/priv/proxmenux-stack-VMID.json\n{\n \"schema\": 1,\n \"stack\": \"immich\",\n \"dependencies\": [\n {\"vmid\": 107, \"label\": \"PostgreSQL\", \"healthcheck\": {...}},\n {\"vmid\": 108, \"label\": \"Valkey\", \"healthcheck\": {...}},\n {\"vmid\": 106, \"label\": \"Machine Learning\", \"healthcheck\": {...}}\n ]\n}" }
]
}
},
{
"snippet": {
"summary": "Código completo de proxmenux-stack-dependencies.sh",
"pathCode": "local:snippets/proxmenux-stack-dependencies.sh",
"snippetCode": "stackDependencyHook"
}
},
{
"p": "El script es el mismo para todas las pilas. Los VMID, los nombres, los tipos de comprobación y los tiempos límite proceden del contrato privado <code>/etc/pve/priv/proxmenux-stack-VMID.json</code> de cada pila."
},
{
"steps": {
"items": [
{ "title": "Proxmox VE llama a pre-start", "body": "Antes de arrancar el CT principal, el hook se ejecuta con su VMID y la fase del ciclo de vida." },
{ "title": "Un bloqueo por pila", "body": "<code>flock</code> sobre <code>/run/lock/proxmenux-stack-VMID.lock</code> impide dos secuencias de arranque a la vez." },
{ "title": "Se lee y valida el contrato", "body": "Se exigen un esquema conocido, dependencias numéricas, etiquetas, una comprobación exec, http o running y un tiempo límite positivo." },
{ "title": "Dependencias en orden", "body": "Cada CT debe existir; uno detenido se arranca y uno que ya está en marcha no se reinicia." },
{ "title": "Espera de salud", "body": "La comprobación se ejecuta cada dos segundos y se confirma además que el CT sigue en marcha." },
{ "title": "Arranca el CT principal", "body": "Cuando todas las dependencias están listas, pre-start termina y Proxmox VE arranca la aplicación." }
]
}
},
{
"calloutInfo": {
"title": "El hook no detiene dependencias",
"body": "Las fases post-start, pre-stop y post-stop no hacen nada. Detener el CT principal deja en marcha PostgreSQL, Redis, Valkey o el aprendizaje automático. El hook ordena el arranque; no convierte varios LXC en un único proceso."
}
},
{
"table": {
"headers": ["Tipo", "Ejemplo", "Arranques posteriores"],
"rows": [
["Pila dependiente", "Immich, Nextcloud, aplicación con PostgreSQL", "El hook del CT principal arranca las dependencias y las espera"],
["Suite de aplicaciones", "Suite Arr", "Sin miembro principal: cada LXC sigue su propio <code>onboot</code>"],
["Aplicación simple", "Jellyfin", "Proxmox VE arranca directamente ese LXC"]
]
}
}
]
},
{
"id": "stack-checks",
"title": "5. Comprobaciones sobre la pila completa",
"blocks": [
{
"list": {
"items": [
"Cada VMID existe, es único y conserva la identidad de instancia esperada.",
"Cada contrato pertenece a la misma pila y conserva su rol y su configuración nativa registrada.",
"El miembro principal es el último en <code>start_order</code> y el primero en <code>stop_order</code>.",
"No falta ningún miembro, volumen ni adaptación del rootfs.",
"El hook apunta al snippet oficial, su contenido no ha cambiado y su contrato coincide con la receta de la pila.",
"Las imágenes y los digests observados coinciden con los archivos OCI preparados.",
"Dispositivos, perfiles GPU, montajes, secretos y endpoints siguen coincidiendo con los contratos.",
"Cuando todas las dependencias pasan, el endpoint de la aplicación principal comprueba la integración entre miembros."
]
}
}
]
},
{
"id": "manage",
"title": "Gestión de una pila instalada",
"intro": "En <strong>Gestionar aplicaciones OCI instaladas</strong>, cualquier miembro lleva a la pila completa. El menú de una pila ofrece <strong>Actualizar cada contenedor de la aplicación</strong> y <strong>Eliminar: la aplicación y sus contenedores</strong>.",
"blocks": [
{
"steps": {
"items": [
{ "title": "Cualquier miembro", "body": "El contrato del miembro indica el VMID principal y la lista completa de miembros." },
{ "title": "La pila es reproducible", "body": "Se validan identidades, contratos, hook, adaptaciones y la existencia de una reproducción coordinada para esa receta." },
{ "title": "Primero las imágenes", "body": "La aplicación no se detiene hasta que todos los digests están resueltos, descargados y verificados." },
{ "title": "Detener y respaldar el conjunto", "body": "Los backups nativos verificados se toman con la pila detenida, de modo que aplicación y bases de datos corresponden al mismo momento." },
{ "title": "Actualizar y comprobar cada miembro", "body": "Adaptación, red, montajes, secretos y dispositivos se aplican de nuevo antes de la comprobación de salud de cada miembro." },
{ "title": "Publicar o recuperar todo", "body": "Los contratos nuevos solo se publican cuando todos los miembros pasan. Si uno falla, se restauran todos." }
]
}
},
{
"calloutWarning": {
"title": "Una pila sin reproducción coordinada no se actualiza",
"body": "Si la preparación de una pila no puede reproducirse, la actualización se rechaza antes de detenerla. La aplicación sigue funcionando tal como está."
}
}
]
},
{
"id": "failure",
"title": "6. Cuando algo falla",
"blocks": [
{
"p": "Durante una instalación, un error detiene y elimina los contenedores incompletos que creó esa operación, y el bridge privado si lo creó ella. Una pila no se publica como válida hasta que termina la secuencia completa."
},
{
"p": "Una actualización es transaccional: primero se preparan todas las imágenes, después se detiene la pila, se hace el backup de cada miembro y se verifica, y solo entonces se sustituye cada rootfs. Los miembros arrancan uno a uno con su comprobación de salud; si uno falla, se restauran todos desde el mismo conjunto de backups, de modo que la base de datos y la aplicación nunca corresponden a momentos distintos."
},
{
"mermaid": {
"chartCode": "flowchart LR\n P[\"{{prepare}}\"] --> S[\"{{stop}}\"]\n S --> B[\"{{backup}}\"]\n B --> R[\"{{replace}}\"]\n R --> H{\"{{healthy}}\"}\n H -- \"{{yes}}\" --> C[\"{{commit}}\"]\n H -- \"{{no}}\" --> X[\"{{rollback}}\"]",
"labels": {
"prepare": "Preparar todas las imágenes",
"stop": "Detener, primero el principal",
"backup": "Backup verificado de cada CT",
"replace": "Sustituir el rootfs",
"healthy": "¿Todos sanos?",
"yes": "Sí",
"no": "No",
"commit": "Publicar los contratos",
"rollback": "Restaurar todos los miembros"
}
}
}
]
},
{
"id": "not-assumed",
"title": "Qué no incluye una pila",
"blocks": [
{
"list": {
"items": [
"Una suite instalada en un único recorrido, como la Suite Arr, no es una pila dependiente: sus contenedores no tienen orden de arranque entre ellos.",
"La red privada no sustituye la autenticación, TLS ni la configuración de cada aplicación.",
"El backup de un LXC no contiene el bridge, el hook ni los contratos del resto de la pila.",
"Prowlarr, Sonarr o Radarr no reciben indexadores, perfiles ni proveedores de ProxMenux."
]
}
}
]
}
]
}
@@ -0,0 +1,190 @@
{
"meta": {
"title": "Datos, rutas y red | ProxMenux",
"description": "Cómo conserva OCI manager Apps los datos de un contenedor OCI: discos del contenedor, directorios del host, montajes Rclone, direcciones y redes privadas."
},
"header": {
"title": "Datos, rutas y red",
"description": "Qué vive en el rootfs, qué sobrevive a su sustitución, cómo se comparten datos entre contenedores y cómo obtiene cada contenedor su dirección.",
"section": "OCI manager Apps"
},
"sections": [
{
"id": "intro",
"blocks": [
{
"calloutInfo": {
"title": "La persistencia se decide antes de que exista el LXC",
"body": "Los volúmenes que publican la imagen y su archivo Compose se leen antes de crear el contenedor. Cada ruta que debe sobrevivir a una actualización se convierte en un punto de montaje independiente del rootfs, de modo que el rootfs solo contiene lo que pertenece a la imagen y puede sustituirse."
}
}
]
},
{
"id": "questions",
"title": "Qué pregunta el instalador",
"intro": "La plantilla aporta las rutas que necesita la aplicación. Cada una se sitúa en un disco del contenedor o en un directorio del host, y pueden añadirse más rutas antes del resumen.",
"blocks": [
{
"steps": {
"items": [
{ "title": "Rutas requeridas", "body": "Se enumeran <code>/config</code>, <code>/data</code>, bibliotecas, descargas y cualquier volumen que declare la aplicación." },
{ "title": "Ubicación", "body": "Cada ruta se sitúa en un disco del contenedor o en un directorio existente del host." },
{ "title": "Almacenamiento y tamaño", "body": "Un disco del contenedor se crea en un almacenamiento de Proxmox VE, <code>local-lvm</code> por defecto, con el tamaño indicado. Aparece como <code>vm-VMID-disk-N</code> y se conecta como <code>mpN</code>." },
{ "title": "Directorio del host", "body": "Un directorio del host se indica por su ruta. Si no existe, se crea con el propietario que mapea el contenedor." },
{ "title": "Rutas adicionales", "body": "Antes de instalar pueden añadirse más pares de ruta del host o volumen y ruta del contenedor." },
{ "title": "Resumen", "body": "La relación completa se muestra antes de crear el CT y se guarda en su contrato de instancia." }
]
}
}
]
},
{
"id": "options",
"title": "Las dos ubicaciones persistentes",
"blocks": [
{
"table": {
"headers": ["Propiedad", "Disco del contenedor", "Directorio del host"],
"rows": [
["En la configuración", "<code>mpN: STORAGE:vm-VMID-disk-N,mp=/config,backup=1,size=16G</code>", "<code>mpN: /mnt/oci-shared/media,mp=/data/media</code>"],
["Backup del contenedor (vzdump)", "Incluido, con <code>backup=1</code>", "No incluido"],
["Tamaño", "Fijo; crece con un redimensionado del punto de montaje", "El espacio libre del sistema de archivos o dataset del host"],
["Otros contenedores", "Solo lo monta su propio contenedor", "El mismo directorio puede montarse en varios contenedores"],
["Snapshots y restauración", "Los gestiona Proxmox VE junto con el CT", "Se gestionan en el almacenamiento del host"],
["Al eliminar la aplicación", "Se elimina con el contenedor", "Se conserva, con su contenido"],
["Al mover el CT a otro nodo", "Se mueve con el CT", "La misma ruta debe existir en el otro nodo"]
]
}
},
{
"p": "El rootfs queda reservado para los binarios y el contenido de la imagen. Una actualización o una recreación lo sustituye sin tocar ninguno de los dos tipos de punto de montaje."
}
]
},
{
"id": "example",
"title": "Ejemplo: un contenedor con las dos ubicaciones",
"blocks": [
{
"code": {
"title": "Jellyfin instalado como CT 151 en local-lvm (extracto)",
"code": "rootfs: local-lvm:vm-151-disk-0,size=8G\n# Disco del contenedor, incluido en el backup del CT\nmp0: local-lvm:vm-151-disk-1,mp=/config,backup=1,size=16G\n\n# Directorio del host, fuera del backup del CT\nmp1: /mnt/oci-shared/media,mp=/data/media"
}
},
{
"p": "Una actualización o una recreación sustituye solo el rootfs: <code>mp0</code> conserva usuarios, bibliotecas y ajustes, y <code>mp1</code> sigue mostrando los mismos archivos multimedia. Restaurar el backup del CT devuelve <code>/config</code>; el directorio multimedia se restaura, si hace falta, desde el backup del almacenamiento del host."
},
{
"flow": {
"nodes": [
{ "label": "Contrato", "detail": "/config" },
{ "label": "Ubicación", "detail": "disco del contenedor\no directorio del host" },
{ "label": "LXC", "detail": "siempre /config\npara la aplicación" }
],
"caption": "La aplicación ve la ruta que publica la imagen; solo cambia dónde se guarda."
}
}
]
},
{
"id": "shared",
"title": "Un directorio del host, varios contenedores",
"blocks": [
{
"mermaid": {
"chartCode": "flowchart TB\n H[\"{{host}}<br/>/mnt/oci-shared/media\"]\n H --> Q[\"qBittorrent<br/>/data\"]\n H --> J[\"Jellyfin<br/>/data\"]\n H --> R[\"Radarr / Sonarr<br/>/data\"]\n Q -. \"{{config}}\" .-> QV[(\"/config mpN\")]\n J -. \"{{config}}\" .-> JV[(\"/config mpN\")]\n R -. \"{{config}}\" .-> RV[(\"/config mpN\")]",
"labels": { "host": "Directorio del host", "config": "configuración propia" }
}
},
{
"p": "Cada contenedor guarda su configuración en su propio disco. La biblioteca o las descargas son un único directorio del host montado en la misma ruta interna de todos los contenedores, de modo que la ruta en la que escribe una aplicación es la misma en la que lee otra."
}
]
},
{
"id": "rclone",
"title": "Almacenamiento en la nube con la aplicación Rclone",
"intro": "La aplicación Rclone del catálogo ofrece, además de su instalación, <strong>Activar un montaje en un contenedor Rclone OCI existente</strong>. Monta un remoto ya creado y autorizado en la interfaz web de Rclone y lo publica en el host, donde otros contenedores pueden usarlo como directorio del host.",
"blocks": [
{
"steps": {
"items": [
{ "title": "Contenedor y remoto", "body": "El VMID del contenedor Rclone, el nombre exacto del remoto y, opcionalmente, una ruta dentro de él." },
{ "title": "Nombre y caché", "body": "El nombre del montaje y el modo de caché VFS: <code>off</code>, <code>minimal</code>, <code>writes</code> o <code>full</code> (por defecto)." },
{ "title": "Vistas publicadas", "body": "Una raíz común, <code>/mnt/oci-shared</code> por defecto, contiene una vista de lectura y escritura en <code>/mnt/oci-shared/remotes/NOMBRE</code> y una de solo lectura en <code>/mnt/oci-shared/remotes-ro/NOMBRE</code>." },
{ "title": "Activación", "body": "Tras una confirmación, el CT se detiene, se configuran su orden de arranque y un hookscript de Proxmox VE, y se vuelve a iniciar. La operación espera hasta que las dos vistas están montadas en el host." }
]
}
},
{
"calloutInfo": {
"title": "Si el montaje no llega a activarse",
"body": "Se restaura la configuración anterior del contenedor y se vuelve a iniciar, de modo que una activación fallida deja Rclone como estaba."
}
}
]
},
{
"id": "network",
"title": "Direcciones y redes",
"intro": "Una aplicación simple necesita una dirección. Una aplicación multicontenedor necesita además una red estable entre sus miembros.",
"blocks": [
{
"cards": {
"items": [
{ "icon": "network", "title": "Aplicación simple", "body": "Se eligen el bridge y DHCP o una dirección CIDR fija. El LXC tiene una dirección propia y el resumen muestra las URL completas de los servicios." },
{ "icon": "waypoints", "title": "Aplicación multicontenedor", "body": "Se busca una subred libre, se crea un bridge privado persistente y cada miembro (aplicación, base de datos, caché) recibe en él una dirección fija." }
]
}
},
{
"flow": {
"nodes": [
{ "label": "LAN", "detail": "dirección accesible\nsolo el servicio principal" },
{ "label": "LXC principal", "detail": "web / API\nLAN + red privada" },
{ "label": "Red privada", "detail": "PostgreSQL · Valkey · ML\ndirecciones fijas" }
],
"caption": "Las dependencias se comunican por la red privada y no tienen dirección en la LAN."
}
},
{
"p": "El contrato de la pila guarda el bridge, la subred, las direcciones y las relaciones entre servicios. Actualizar o recrear un miembro reutiliza la misma topología. ProxMenux Monitor abre el contenedor principal en su dirección de la LAN, no en la de la red privada."
}
]
},
{
"id": "ownership",
"title": "Propietarios",
"blocks": [
{
"list": {
"items": [
"Los directorios nuevos se crean con el UID y el GID que mapea el LXC no privilegiado.",
"Los directorios existentes no cambian de propietario de forma recursiva.",
"Los sockets, los archivos del sistema y las rutas sensibles no se ofrecen como directorios del host genéricos."
]
}
}
]
},
{
"id": "backup",
"title": "Qué contiene el backup de un contenedor",
"blocks": [
{
"table": {
"headers": ["Elemento", "En el vzdump del CT", "Dónde se conserva"],
"rows": [
["rootfs OCI", "Sí", "El backup del CT; también puede reconstruirse desde la imagen y el contrato"],
["Disco del contenedor con <code>backup=1</code>", "Sí", "El backup del CT"],
["Directorio del host", "No", "El backup del almacenamiento del host"],
["Contrato de la instancia", "No", "<code>/usr/local/share/proxmenux/oci/instances/VMID/</code> en el host"],
["Aplicación multicontenedor", "Cada miembro en su propio backup", "Los backups de cada miembro, más el contrato de la pila y su bridge en el host"]
]
}
}
]
}
]
}
@@ -64,7 +64,7 @@
"heading": "Cómo funciona por dentro",
"items": [
"El menú de diálogo lista los 6 códigos; eliges uno.",
"Si <code>config.json</code> existe: <code>jq --arg lang \"$new_language\" '.language = $lang'</code> actualiza el campo en sitio.",
"Si <code>config.json</code> existe: <code>jq --arg lang \"$new_language\" '.language = $lang''</code> actualiza el campo en sitio.",
"Si <code>config.json</code> no existe: se crea uno nuevo con el código de idioma en un objeto de un solo campo.",
"Diálogo de confirmación: <em>\"Idioma cambiado a [code]\"</em>.",
"<code>exec bash config_menu.sh</code> recarga el menú Settings con el nuevo idioma activo."