mirror of
https://github.com/MacRimi/ProxMenux.git
synced 2026-11-01 10:22:08 +00:00
Last changes before version 1.2.7. OCI manager Apps - Multi-container applications start while one of their containers is being backed up: the start hook waits until vzdump releases it and does not start it twice. The DHCP client of a dependency no longer keeps the lock of the hook, so later starts do not hang, and the watchdog waits while a dependency is locked. Installing or updating ProxMenux replaces the published copies of the hook already in place. - Images built from scratch with a numeric user, such as ddns-updater, install: the container is created from a copy of the image that adds the /etc/passwd and /etc/group Proxmox VE needs, and the application runs with the user the image declares. The downloaded image stays unchanged. An image with a named user and no user database stops before anything is created, with a message that says why. Catalog - Twelve new applications: MDBListarr, CrossWatch, Free Games Claimer Remaster, Cloudreve, Poznote and AceStream HTTP Proxy, suggested in discussion #440, and the Dockur images of Chrony, Dnsmasq, Tor, Stunnel, strfry and Statping. The catalog lists 347 applications. - Their prompts, labels and notes are translated into the seven languages of the menus. Documentation - OCI manager: architecture, lifecycle and stacks pages revised, with larger diagrams and new screenshots. - Contributors: the page now thanks those developing, reviewing, translating and testing ProxMenux today and those who helped in its first steps, with new avatars. Tests for the stack start hook, the watchdog, the user database check of OCI images and the Tor installation summary.
405 lines
19 KiB
JSON
405 lines
19 KiB
JSON
{
|
|
"meta": {
|
|
"title": "Aplicações multi-contêineres ProxMenux",
|
|
"description": "Como o OCI Manager Apps transforma um aplicativo com seu banco de dados e cache em LXCs nativos coordenados: plano, rede privada, gancho de dependência, validação e atualizações transacionais."
|
|
},
|
|
"header": {
|
|
"title": "Aplicações com vários contentores",
|
|
"description": "Uma aplicação com seu banco de dados, cache e outros serviços torna-se vários LXCs nativos coordenados, instalados e atualizados como um.",
|
|
"section": "OCI manager Apps"
|
|
},
|
|
"sections": [
|
|
{
|
|
"id": "intro",
|
|
"blocks": [
|
|
{
|
|
"calloutInfo": {
|
|
"title": "Um aplicativo para o usuário, vários LXCs para Proxmox VE",
|
|
"body": "Uma definição multi-contentor é uma entrada do catálogo. O instalador cria um LXC nativo por serviço e mantém suas dependências explícitas. Immich, Nextcloud, Paperless-ngx e Tandoor são instalados desta 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": "Plano de pilha",
|
|
"app": "Aplicação LXC",
|
|
"appNet": "LAN + privado",
|
|
"db": "PostgreSQL LXC",
|
|
"cache": "Valkey LXC",
|
|
"private": "privado"
|
|
}
|
|
}
|
|
}
|
|
]
|
|
},
|
|
{
|
|
"id": "plan",
|
|
"title": "1. O plano, antes de existir qualquer recipiente",
|
|
"blocks": [
|
|
{
|
|
"p": "Nenhum LXC é criado enquanto a definição Compose é interpretada. Um plano completo vem em primeiro lugar, com cada membro, imagem, VMID, rede, caminho, segredo, ordem e verificação de saúde. Se o plano não for consistente, a instalação não começa."
|
|
},
|
|
{
|
|
"table": {
|
|
"headers": [
|
|
"Elemento do plano",
|
|
"Conteúdo",
|
|
"Verificado antes de criar qualquer coisa"
|
|
],
|
|
"rows": [
|
|
[
|
|
"Membros",
|
|
"Aplicação principal, banco de dados, cache, aprendizado de máquina e outras dependências",
|
|
"VMIDs exclusivos, papéis conhecidos e exatamente um membro principal"
|
|
],
|
|
[
|
|
"Imagens",
|
|
"Referência rolling, arquitetura e digest resolvido de cada serviço",
|
|
"Todos existem, suportam a arquitetura e passam pela verificação de integridade do OCI"
|
|
],
|
|
[
|
|
"Rede",
|
|
"Ponte privada, sub-rede, endereço fixo por serviço e acesso LAN para o membro principal",
|
|
"Sem colisão com pontes ou subredes existentes e sem endereço repetido"
|
|
],
|
|
[
|
|
"Persistência",
|
|
"Discos de container, diretórios de host, proprietários e backup",
|
|
"Nenhum caminho sobreposto, armazenamento disponível e permissões declaradas"
|
|
],
|
|
[
|
|
"Segredos",
|
|
"Senha do banco de dados, chaves do aplicativo e credenciais iniciais",
|
|
"Gerado uma vez e dado apenas aos membros que os usam"
|
|
],
|
|
[
|
|
"Ciclo de vida",
|
|
"Ordem de início, ordem de parada e uma verificação de funcionamento por membro",
|
|
"A aplicação principal começa por último e pára primeiro"
|
|
]
|
|
]
|
|
}
|
|
}
|
|
]
|
|
},
|
|
{
|
|
"id": "create",
|
|
"title": "2. Criação, membro por membro",
|
|
"blocks": [
|
|
{
|
|
"steps": {
|
|
"items": [
|
|
{
|
|
"title": "Reserve cada VMID",
|
|
"body": "O inventário Proxmox VE e o registro de instância são verificados. Um CT existente não é adotado e um contrato que ainda pertence a outra instância não é reutilizado."
|
|
},
|
|
{
|
|
"title": "Preparar cada imagem",
|
|
"body": "Todas as imagens são resolvidas, baixadas e verificadas antes da criação do primeiro container."
|
|
},
|
|
{
|
|
"title": "Criar cada rootfs",
|
|
"body": "Os metadados oficiais do OCI são importados, e a identidade da instância ProxMenux e o papel de membro são adicionados."
|
|
},
|
|
{
|
|
"title": "Rede privada",
|
|
"body": "Uma ponte e uma sub-rede são criadas e cada membro recebe seu endereço fixo; apenas o membro principal também recebe a interface LAN."
|
|
},
|
|
{
|
|
"title": "Persistência",
|
|
"body": "Cada banco de dados e configuração obtém seu próprio disco de contêiner; somente os dados destinados a serem compartilhados usam diretórios de host."
|
|
},
|
|
{
|
|
"title": "Ambiente",
|
|
"body": "Endpoints internos, segredos compartilhados e variáveis de serviço são escritos. O aplicativo atinge suas dependências em seus endereços privados reservados."
|
|
},
|
|
{
|
|
"title": "Registro",
|
|
"body": "Cada membro registra sua configuração nativa, as mudanças rootfs que as atualizações têm que reproduzir e sua relação com a pilha."
|
|
}
|
|
]
|
|
}
|
|
}
|
|
]
|
|
},
|
|
{
|
|
"id": "checks",
|
|
"title": "3. Iniciar e verificar cada recipiente",
|
|
"intro": "Um LXC criado não significa um serviço pronto. As dependências começam em ordem e cada um passa uma verificação específica para o seu serviço.",
|
|
"blocks": [
|
|
{
|
|
"table": {
|
|
"headers": [
|
|
"Serviço",
|
|
"Verificação",
|
|
"O que mostra"
|
|
],
|
|
"rows": [
|
|
[
|
|
"PostgreSQL",
|
|
"<code>pg_isready</code> no CT com o host, usuário e banco de dados esperados",
|
|
"O servidor aceita conexões para o banco de dados configurado"
|
|
],
|
|
[
|
|
"Redis / Valkey",
|
|
"<code>redis-cli</code> ou <code>valkey-cli</code> <code>PING</code> contra o seu endereço privado",
|
|
"O broker escuta e responde"
|
|
],
|
|
[
|
|
"aprendizado de máquina Immich",
|
|
"HTTP <code>GET /ping</code>, mais uma verificação do tempo de execução GPU selecionado",
|
|
"O serviço responde e a aceleração solicitada não passou a usar a CPU"
|
|
],
|
|
[
|
|
"Nextcloud",
|
|
"<code>GET /status.php</code> com <code>installed=true</code>, <code>maintenance=false</code> e <code>needsDbUpgrade=false</code>",
|
|
"A inicialização terminou sem migração pendente"
|
|
],
|
|
[
|
|
"Paperless-ngx / Tandoor",
|
|
"HTTP no endereço LAN e porto real do serviço",
|
|
"O frontend e suas dependências servem a aplicação"
|
|
],
|
|
[
|
|
"Aplicação principal",
|
|
"O ponto final do seu modelo, por exemplo, <code>/api/server/ping</code> em Immich",
|
|
"A pilha inteira funciona através da aplicação que usa as dependências"
|
|
]
|
|
]
|
|
}
|
|
},
|
|
{
|
|
"calloutWarning": {
|
|
"title": "Em execução não significa funcionando corretamente",
|
|
"body": "O estado em execução apenas diz que o processo LXC existe. Quando o serviço oferece uma verificação melhor, é utilizado uma verificação exec ou HTTP com tempo limite. Se um membro para ou falha na verificação, a pilha não é declarada instalada."
|
|
}
|
|
}
|
|
]
|
|
},
|
|
{
|
|
"id": "hook",
|
|
"title": "4. O gancho de dependência",
|
|
"blocks": [
|
|
{
|
|
"p": "O gancho é definido apenas no recipiente principal de uma pilha dependente. Proxmox VE mantém o script como um trecho e o executa como o <code>hookscript</code> daquele CT. A receita da pilha não é escrita no script: ela vive em um contrato privado separado."
|
|
},
|
|
{
|
|
"codeGrid": {
|
|
"items": [
|
|
{
|
|
"title": "Configuração principal do CT",
|
|
"code": "hookscript: local:snippets/proxmenux-stack-dependencies.sh"
|
|
},
|
|
{
|
|
"title": "Contrato privado (exemplo)",
|
|
"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": "Fonte completa de proxmenux-stack-dependencies.sh",
|
|
"pathCode": "local:snippets/proxmenux-stack-dependencies.sh",
|
|
"snippetCode": "stackDependencyHook"
|
|
}
|
|
},
|
|
{
|
|
"p": "O script é o mesmo para cada pilha. VMIDs, nomes, tipos de verificação e timeouts vêm do contrato privado <code>/etc/pve/priv/proxmenux-stack-VMID.json</code> de cada pilha."
|
|
},
|
|
{
|
|
"steps": {
|
|
"items": [
|
|
{
|
|
"title": "O Proxmox VE chama pre-start",
|
|
"body": "Antes do início do CT principal, o gancho funciona com o seu VMID e a fase do ciclo de vida."
|
|
},
|
|
{
|
|
"title": "Um bloqueio por pilha",
|
|
"body": "<code>flock</code> em <code>/run/lock/proxmenux-stack-VMID.lock</code> impede duas sequências de início ao mesmo tempo."
|
|
},
|
|
{
|
|
"title": "O contrato é lido e validado",
|
|
"body": "São exigidos um esquema conhecido, dependências numéricas, rótulos, uma verificação exec, http ou running e um tempo limite positivo."
|
|
},
|
|
{
|
|
"title": "Dependências em ordem",
|
|
"body": "Cada CT deve existir; um parado é iniciado e um já em execução não é reiniciado."
|
|
},
|
|
{
|
|
"title": "Esperar o serviço ficar pronto",
|
|
"body": "A verificação é executada a cada dois segundos, e o CT também é confirmado para estar ainda em execução."
|
|
},
|
|
{
|
|
"title": "O CT principal começa",
|
|
"body": "Quando cada dependência está pronta, termina pré-inicial e o Proxmox VE inicia a aplicação."
|
|
}
|
|
]
|
|
}
|
|
},
|
|
{
|
|
"calloutInfo": {
|
|
"title": "O gancho não para dependências",
|
|
"body": "As fases pós-início, pré-parar e pós-parar não fazem nada. Parar o CT principal deixa PostgreSQL, Redis, Valkey ou aprendizado de máquina em execução. O gancho ordena o início; ele não transforma vários LXCs em um processo."
|
|
}
|
|
},
|
|
{
|
|
"table": {
|
|
"headers": [
|
|
"Tipo",
|
|
"Exemplo",
|
|
"Início posterior"
|
|
],
|
|
"rows": [
|
|
[
|
|
"Pilha dependente",
|
|
"Immich, Nextcloud, aplicação com PostgreSQL",
|
|
"O gancho do CT principal inicia as dependências e espera por eles"
|
|
],
|
|
[
|
|
"Conjunto de aplicativos",
|
|
"Conjunto de aplicações Arr",
|
|
"Nenhum membro principal: cada LXC segue o seu próprio <code>onboot</code>"
|
|
],
|
|
[
|
|
"Aplicação única",
|
|
"Jellyfin",
|
|
"Proxmox VE inicia esse LXC diretamente"
|
|
]
|
|
]
|
|
}
|
|
}
|
|
]
|
|
},
|
|
{
|
|
"id": "stack-checks",
|
|
"title": "5. Verifica a pilha como um todo",
|
|
"blocks": [
|
|
{
|
|
"list": {
|
|
"items": [
|
|
"Cada VMID existe, é único e mantém a identidade de instância esperada.",
|
|
"Cada contrato pertence à mesma pilha, mantém seu papel e sua configuração nativa gravada.",
|
|
"O membro principal é o último em <code>start_order</code> e o primeiro em <code>stop_order</code>.",
|
|
"Nenhum membro, volume ou adaptação rootfs está faltando.",
|
|
"O gancho aponta para o trecho oficial, seu conteúdo é inalterado e seu contrato corresponde à receita da pilha.",
|
|
"As imagens e digests observados correspondem aos arquivos OCI preparados.",
|
|
"Dispositivos, perfis GPU, montagens, segredos e endpoints ainda correspondem aos contratos.",
|
|
"Após cada dependência passar, o ponto final da aplicação principal verifica a integração entre os membros."
|
|
]
|
|
}
|
|
}
|
|
]
|
|
},
|
|
{
|
|
"id": "manage",
|
|
"title": "Gerenciando uma pilha instalada",
|
|
"intro": "Em <strong>Gerenciar aplicativos OCI instalados</strong>, qualquer membro leva à pilha inteira. O menu oferece <strong>Atualizar todos os contêineres do aplicativo</strong>, <strong>Modificar caminhos e dispositivos extras</strong>, <strong>Recriar todos os contêineres com a configuração salva</strong> e <strong>Remover: excluir o aplicativo e seus contêineres</strong>. Recriar reconstrói cada contêiner da imagem original pelo digest salvo, sem procurar uma mais nova, seguindo os mesmos passos de uma atualização. A opção aparece para pilhas que podem ser atualizadas.",
|
|
"blocks": [
|
|
{
|
|
"steps": {
|
|
"items": [
|
|
{
|
|
"title": "Qualquer membro",
|
|
"body": "O contrato dos membros nomeia o VMID principal e a lista completa de membros."
|
|
},
|
|
{
|
|
"title": "A pilha é reprodutível",
|
|
"body": "Identificações, contratos, gancho, adaptações e uma repetição coordenada para essa receita são validadas."
|
|
},
|
|
{
|
|
"title": "Primeiro as imagens",
|
|
"body": "O aplicativo não é parado até que cada digest tenha sido resolvido, baixado e verificado."
|
|
},
|
|
{
|
|
"title": "Parar e fazer backup do conjunto",
|
|
"body": "Os backups nativos verificados são feitos com a pilha parada, então a aplicação e os bancos de dados pertencem ao mesmo momento."
|
|
},
|
|
{
|
|
"title": "Atualizar e verificar cada membro",
|
|
"body": "Adaptação, rede, montagens, segredos e dispositivos são novamente aplicados antes do exame de saúde de cada membro."
|
|
},
|
|
{
|
|
"title": "Publicar ou recuperar tudo",
|
|
"body": "Os novos contratos só são publicados quando todos os membros passam. Se alguém falhar, cada membro é restaurado."
|
|
}
|
|
]
|
|
}
|
|
},
|
|
{
|
|
"table": {
|
|
"headers": [
|
|
"Modificar",
|
|
"O que muda",
|
|
"O que é guardado"
|
|
],
|
|
"rows": [
|
|
[
|
|
"Caminhos e dispositivos adicionais",
|
|
"Eles são adicionados ou removidos do recipiente de aplicação, que reinicia. Nada é reconstruído.",
|
|
"Os dados da aplicação, da sua base de dados e dos outros contentores"
|
|
],
|
|
[
|
|
"O que executa o reconhecimento (Immich)",
|
|
"O recipiente de aprendizado de máquina leva a imagem e os dispositivos do CPU ou de um GPU do hospedeiro. Todo o aplicativo é parado e atualizado, como em uma atualização",
|
|
"O cache do modelo, a biblioteca e o banco de dados. Se algo falhar, os recipientes anteriores e a escolha anterior são restaurados"
|
|
]
|
|
]
|
|
}
|
|
},
|
|
{
|
|
"calloutWarning": {
|
|
"title": "Uma pilha sem uma repetição coordenada não é atualizada",
|
|
"body": "Se a preparação de uma pilha não puder ser reproduzida, a atualização é recusada antes de a pilha ser parada. A aplicação continua a correr como está."
|
|
}
|
|
}
|
|
]
|
|
},
|
|
{
|
|
"id": "failure",
|
|
"title": "6. Quando algo falha",
|
|
"blocks": [
|
|
{
|
|
"p": "Durante uma instalação, um erro para e remove os contêineres incompletos que a operação criou, e a ponte privada se a operação criou. Uma pilha não é publicada como válida até que toda a sequência termine."
|
|
},
|
|
{
|
|
"p": "Uma atualização é transacional: todas as imagens são preparadas primeiro, depois a pilha pára, cada membro é feito backup e o backup verificado, e só então é substituído cada rootfs. Os membros começam um a um com seu exame de saúde; se um falha, cada membro é restaurado a partir do mesmo conjunto de backups, de modo que o banco de dados eo aplicativo nunca pertencem a momentos diferentes."
|
|
},
|
|
{
|
|
"mermaid": {
|
|
"chartCode": "flowchart TB\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 cada imagem",
|
|
"stop": "Parar, membro principal primeiro",
|
|
"backup": "Cópia de segurança verificada de cada CT",
|
|
"replace": "Substituir rootfs",
|
|
"healthy": "Todos funcionando corretamente?",
|
|
"yes": "Sim",
|
|
"no": "Não",
|
|
"commit": "Publicar contratos",
|
|
"rollback": "Restaurar cada membro"
|
|
}
|
|
}
|
|
}
|
|
]
|
|
},
|
|
{
|
|
"id": "not-assumed",
|
|
"title": "O que uma pilha não inclui",
|
|
"blocks": [
|
|
{
|
|
"list": {
|
|
"items": [
|
|
"Uma suíte instalada em um fluxo, como a suíte Arr, não é uma pilha dependente: seus recipientes não têm ordem de início entre eles.",
|
|
"A rede privada não substitui a autenticação, TLS ou a configuração de cada aplicativo.",
|
|
"O backup de um LXC não contém a ponte, o gancho ou os contratos do resto da pilha.",
|
|
"Prowlarr, Sonarr ou Radarr não recebem indexadores, perfis ou provedores de ProxMenux."
|
|
]
|
|
}
|
|
}
|
|
]
|
|
}
|
|
]
|
|
}
|