Seção 6: Gerenciamento e Deploy de Stacks Docker com Portainer (Usando Volumes NFS)¶
Agora que nossa infraestrutura base está de pé – Proxmox VE, máquinas virtuais configuradas (core-services-vm e ai-desktop-vm), armazenamento NFS funcional, Docker Engine instalado e, mais importante, nossa rede segura com Traefik, Cloudflare Tunnel e Authelia está operacional – é hora de começar a implantar nossas aplicações!
Utilizaremos o Portainer como nossa interface gráfica para gerenciar o Docker e implantar "Stacks". Uma Stack no Portainer é, essencialmente, um projeto Docker Compose, permitindo-nos definir e gerenciar aplicações multi-container de forma organizada. Todos os dados persistentes das nossas aplicações Docker residirão nos datasets ZFS do host Proxmox e serão acessados pelas VMs via montagens NFS, garantindo segurança e durabilidade dos dados.
O container do Portainer já foi instalado na core-services-vm pelo playbook Ansible setup-base-ubuntu.yml e, após a configuração da rede na Seção 5, deve estar acessível através do subdomínio https://portainer.{{ base_domain }} (protegido por Authelia).
6.1. Acesso Inicial ao Portainer e Configuração¶
Se este é seu primeiro acesso ao Portainer após o deploy inicial, siga estes passos:
-
Acesse a Interface Web do Portainer:
- Abra seu navegador web e navegue para o endereço que você configurou para o Portainer. Conforme nosso setup, este será:
https://portainer.{{ base_domain }}(substitua{{ base_domain }}pelo seu domínio real, e.g.,https://portainer.meuhomelab.com). - Como o Portainer está protegido por Authelia, você será primeiramente redirecionado para o portal de login do Authelia (e.g.,
https://auth.{{ base_domain }}).
- Abra seu navegador web e navegue para o endereço que você configurou para o Portainer. Conforme nosso setup, este será:
-
Autenticação via Authelia:
- Na página de login do Authelia, insira as credenciais do usuário administrador que você definiu no Ansible Vault:
- Username:
{{ authelia_admin_user_initial }}(e.g.,admin) - Password: A senha correspondente ao hash
{{ authelia_admin_password_hash_initial }}.
- Username:
- Configuração de 2FA (Primeiro Login): Se for o primeiro login bem-sucedido deste usuário no Authelia, você será guiado para configurar um método de Autenticação de Dois Fatores (2FA). Siga as instruções na tela para registrar um dispositivo TOTP (Time-based One-Time Password) usando um aplicativo autenticador como Google Authenticator, Authy, Microsoft Authenticator, ou um gerenciador de senhas com suporte a TOTP.
- Na página de login do Authelia, insira as credenciais do usuário administrador que você definiu no Ansible Vault:
-
Configuração Inicial do Usuário Administrador do Portainer:
- Após a autenticação bem-sucedida com Authelia, você será redirecionado de volta para a página de configuração inicial do Portainer.
- Aqui, você criará a conta de administrador para o próprio Portainer:
- Username: Escolha um nome de usuário (e.g.,
portainer_adminou simplesmenteadmin). - Password: Crie uma senha forte e única especificamente para esta conta de administrador do Portainer. Armazene-a com segurança no seu gerenciador de senhas. !!! warning "Senha do Portainer vs. Senha Authelia" A senha que você define aqui é para logar diretamente no Portainer (se você acessasse sua porta interna ou se Authelia estivesse desabilitado para ele). Ela é distinta da senha do seu usuário Authelia.
- Username: Escolha um nome de usuário (e.g.,
- Clique em "Create user".
-
Conectar o Portainer ao Ambiente Docker Local:
- Na próxima tela, "Connect Portainer to the Docker environment you want to manage", a opção "Docker - Manage the local Docker environment" já deve estar selecionada por padrão (já que Portainer está rodando como um container Docker na mesma
core-services-vmque ele gerenciará). - Clique em "Connect".
- Na próxima tela, "Connect Portainer to the Docker environment you want to manage", a opção "Docker - Manage the local Docker environment" já deve estar selecionada por padrão (já que Portainer está rodando como um container Docker na mesma
-
Bem-vindo ao Dashboard do Portainer:
- Você será levado ao dashboard principal do Portainer. No menu "Environments" (ou na página inicial), você deve ver o ambiente "local" listado, representando o Docker Engine rodando na sua
core-services-vm.
- Você será levado ao dashboard principal do Portainer. No menu "Environments" (ou na página inicial), você deve ver o ambiente "local" listado, representando o Docker Engine rodando na sua
6.2. Implantação de Stacks Docker (Processo Geral e Padronizado)¶
No Portainer, "Stacks" são a forma de gerenciar aplicações definidas por arquivos docker-compose.yml. Para cada grupo de aplicações que vamos implantar (Mídia, RAG, Produtividade, Monitoramento, etc.), seguiremos um processo padronizado.
Ação Preparatória Chave: Playbooks Ansible para Volumes e .env¶
Antes de tentar implantar qualquer stack no Portainer, é crucial que o Ansible tenha preparado o ambiente na VM de destino (seja a core-services-vm ou a ai-desktop-vm). Cada conjunto de serviços (e.g., "media stack", "monitoring stack") terá um playbook Ansible dedicado (e.g., setup-media-stack-volumes.yml, setup-monitoring-stack-volumes.yml).
Estes playbooks são responsáveis por:
-
Criação de Diretórios nos Volumes NFS:
- Garantir que os subdiretórios necessários para os volumes persistentes da stack existam no local correto do montado NFS.
- Exemplo: Para a stack de mídia, o playbook criaria diretórios como
{{ vm_nfs_mount_base_path }}/{{ zfs_docker_volumes_dataset_name }}/plex/config,.../sonarr/config, etc., nacore-services-vm. - As permissões desses diretórios são definidas para
owner: {{ docker_puid }}egroup: {{ docker_pgid }}(commode: '0775'ou similar) para que os containers Docker possam ler e escrever neles.
-
Preparação de Arquivos
.envpara cada Stack no Portainer:- Os mesmos playbooks Ansible também gerarão arquivos
.envespecíficos para cada stack. Estes arquivos são cruciais porque contêm variáveis de ambiente que serão usadas pelos arquivosdocker-compose.ymlno Portainer. - Conteúdo Típico do
.envGerado:DOCKER_PUIDeDOCKER_PGID(do Ansible Vault).SYSTEM_TIMEZONE(do Ansible Vault).BASE_DOMAIN(do Ansible Vault, para labels Traefik).CORE_SERVICES_VM_IP_VARouAI_DESKTOP_VM_IP_VAR(do inventário Ansible).- Caminhos completos para os volumes NFS que serão usados pela stack (e.g.,
MEDIA_STACK_PLEX_CONFIG_PATH={{ vm_nfs_mount_base_path }}/{{ zfs_docker_volumes_dataset_name }}/plex/config).
- Localização na VM: Esses arquivos
.envsão colocados em um local padronizado na VM de destino (e.g.,/opt/portainer_stack_envs/nome_da_stack.env), conforme definido pela variável Ansibleportainer_env_files_dest_path_on_vm. -
Template Base: O template
ansible/templates/portainer_stack_env.j2é usado pelo Ansible para gerar esses arquivos.env, preenchendo as variáveis específicas da stack.# ansible/templates/portainer_stack_env.j2 # Gerado por Ansible para a stack {{ stack_name }} # Use este arquivo no Portainer: Add Stack -> Environment Variables -> Advanced mode -> Load variables from .env file # Caminho na VM: {{ portainer_env_files_dest_path_on_vm }}/{{ stack_name }}.env # --- Variáveis Comuns (resolvidas do Ansible vault/main.yml) --- DOCKER_PUID={{ docker_puid }} DOCKER_PGID={{ docker_pgid }} SYSTEM_TIMEZONE={{ system_timezone }} BASE_DOMAIN={{ base_domain }} # --- IPs das VMs (condicionalmente definidos) --- {% if inventory_hostname == 'core-services-vm' %} CORE_SERVICES_VM_IP_VAR={{ core_services_vm_ip_var }} {% elif inventory_hostname == 'ai-desktop-vm' %} AI_DESKTOP_VM_IP_VAR={{ ai_desktop_vm_ip_var }} {% endif %} # --- Caminhos de Volume Base (montados via NFS do Proxmox Host) --- # Estes são os pontos de montagem NFS DENTRO da VM. VM_NFS_MOUNT_BASE_PATH={{ vm_nfs_mount_base_path }} # Nomes dos datasets ZFS (usados para construir os caminhos completos) ZFS_DOCKER_VOLUMES_DATASET_NAME={{ zfs_docker_volumes_dataset_name }} ZFS_MEDIA_DATASET_NAME={{ zfs_media_dataset_name }} ZFS_DOWNLOADS_DATASET_NAME={{ zfs_downloads_dataset_name }} ZFS_RAG_SOURCES_DATASET_NAME={{ zfs_rag_sources_dataset_name }} # --- Caminhos Específicos para a Stack (Exemplos) --- # Estes são gerados condicionalmente pelo playbook Ansible que chama este template, # passando o 'stack_name' correto. # Os docker-compose.yml usarão estas variáveis (e.g., ${MEDIA_STACK_PLEX_CONFIG_PATH}) {% if stack_name == "media" %} # Caminhos para a Stack de Mídia MEDIA_STACK_PLEX_CONFIG_PATH={{ vm_nfs_mount_base_path }}/{{ zfs_docker_volumes_dataset_name }}/plex/config MEDIA_STACK_PLEX_TRANSCODE_PATH={{ vm_nfs_mount_base_path }}/{{ zfs_docker_volumes_dataset_name }}/plex/transcode MEDIA_STACK_MOVIES_PATH={{ vm_nfs_mount_base_path }}/{{ zfs_media_dataset_name }}/movies MEDIA_STACK_TVSHOWS_PATH={{ vm_nfs_mount_base_path }}/{{ zfs_media_dataset_name }}/tvshows # ... (outros caminhos para a stack de mídia) ... {% elif stack_name == "rag" %} # Caminhos para a Stack de IA/RAG RAG_STACK_OPENWEBUI_DATA_PATH={{ vm_nfs_mount_base_path }}/{{ zfs_docker_volumes_dataset_name }}/openwebui/data # ... (outros caminhos para a stack RAG) ... {% elif stack_name == "productivity" %} # Caminhos para a Stack de Produtividade PROD_STACK_NEXTCLOUD_HTML_PATH={{ vm_nfs_mount_base_path }}/{{ zfs_docker_volumes_dataset_name }}/nextcloud/html # ... (outros caminhos para a stack de produtividade) ... {% elif stack_name == "automation" %} # Caminhos para a Stack de Automação AUTO_STACK_HOMEASSISTANT_CONFIG_PATH={{ vm_nfs_mount_base_path }}/{{ zfs_docker_volumes_dataset_name }}/homeassistant/config {% elif stack_name == "monitoring" %} # Caminhos para a Stack de Monitoramento MONITORING_PROMETHEUS_DATA_PATH={{ vm_nfs_mount_base_path }}/{{ zfs_docker_volumes_dataset_name }}/prometheus/data # ... (outros caminhos para a stack de monitoramento) ... {% endif %} !!! warning "Segredos NÃO Incluídos" Senhas de bancos de dados, tokens de API e outros segredos **NÃO SÃO** colocados nestes arquivos `.env`. Eles devem ser definidos manualmente como "secrets" do Portainer ou como variáveis de ambiente diretamente na UI do Portainer ao criar/editar a stack.
Execute os Playbooks de Preparação de Volume PRIMEIRO!
Antes de tentar implantar qualquer stack de aplicação (Mídia, RAG, etc.) no Portainer, você DEVE executar o playbook Ansible
setup-<nome_da_stack>-volumes.ymlcorrespondente. Isso garante que todos os diretórios de volume NFS estejam criados com as permissões corretas e que o arquivo.envcom os caminhos e variáveis esteja pronto na VM para o Portainer usar. - Os mesmos playbooks Ansible também gerarão arquivos
Ação no Portainer (Processo Detalhado para Implantar uma Nova Stack)¶
Siga estes passos no Portainer para cada stack de aplicação Docker que você deseja implantar:
-
Navegue para o Endpoint Docker Correto:
- No menu lateral do Portainer, clique em "Environments".
- Selecione o endpoint apropriado. Para a maioria das stacks (mídia, produtividade, monitoramento, core networking), será o endpoint
local(que representa o Docker Engine nacore-services-vm). - Se você estiver implantando uma stack na
ai-desktop-vm(como a stack RAG), e você configurou o Portainer Agent nela, selecione o endpoint correspondente àai-desktop-vm.
-
Adicionar uma Nova Stack:
- No menu lateral, clique em "Stacks".
- Clique no botão "+ Add stack".
-
Configurar a Nova Stack:
- Name: Dê um nome descritivo e único para a stack (e.g.,
media-services,rag-stack,nextcloud-services,monitoring-stack). É uma boa prática usar nomes consistentes com seus playbooks Ansible e diretórios de compose. - Build method: Certifique-se de que "Web editor" está selecionado.
- Web editor: Aqui você colará o conteúdo do arquivo
docker-compose.ymlcorrespondente à stack que você está implantando.- Os arquivos
docker-compose.ymlpara cada stack estão localizados no seu projetohome-server/docker/stacks/nome_da_stack/docker-compose.yml. - Copie o conteúdo completo do
docker-compose.ymlrelevante e cole-o nesta caixa de texto.
Uso de Variáveis nos Arquivos
docker-compose.ymlLembre-se que nossos arquivos
docker-compose.yml(detalhados nas Seções 7 a 10) são projetados para usar variáveis de ambiente para os caminhos dos volumes (e.g.,volumes: - ${MEDIA_STACK_PLEX_CONFIG_PATH}:/config) e outras configurações. Essas variáveis serão fornecidas pelo arquivo.envcarregado no próximo passo. - Os arquivos
- Name: Dê um nome descritivo e único para a stack (e.g.,
-
Configurar Variáveis de Ambiente (Environment Variables):
- Abaixo da caixa do editor web, role a página para baixo até a seção "Environment variables".
- Clique no botão para mudar para "Advanced mode" se ainda não estiver.
- Carregar Variáveis do Arquivo
.env:- Clique no botão (ou link) que diz "Load variables from .env file".
- No campo "Path on disk", forneça o caminho ABSOLUTO DENTRO DA VM onde o Ansible colocou o arquivo
.envpara esta stack específica.- Exemplo para a stack de mídia na
core-services-vm:/opt/portainer_stack_envs/media.env - Exemplo para a stack RAG na
ai-desktop-vm:/opt/portainer_stack_envs/rag.env
- Exemplo para a stack de mídia na
- Clicar fora do campo ou pressionar Enter deve fazer o Portainer tentar carregar as variáveis. Se bem-sucedido, você verá as variáveis preenchidas na lista abaixo (em modo "simple" ou visíveis no modo "advanced").
- Adicionar Secrets (Senhas, Tokens API) Manualmente:
- Quaisquer variáveis de ambiente que contenham segredos (como senhas de banco de dados, tokens de API,
PLEX_CLAIM_TOKEN, etc.) NÃO devem estar nos arquivos.envversionados. Elas devem ser adicionadas manualmente aqui no Portainer. - Clique em "+ Add environment variable" para cada segredo que a stack precisa.
- Name: O nome exato da variável de ambiente conforme esperado pelo(s) container(es) na sua stack (e.g.,
NEXTCLOUD_DB_PASSWORD_FROM_PORTAINER_ENV,PLEX_CLAIM_TOKEN_FROM_PORTAINER_ENV). Os nomes com_FROM_PORTAINER_ENVsão uma convenção para indicar que o valor virá diretamente do Portainer. - Value: Cole o valor do segredo aqui. Obtenha esses valores do seu Ansible Vault (
ansible/inventories/home/group_vars/all/vault.yml) ou do seu gerenciador de senhas pessoal.
- Name: O nome exato da variável de ambiente conforme esperado pelo(s) container(es) na sua stack (e.g.,
Usando Secrets do Portainer
Para uma segurança ainda maior, em vez de variáveis de ambiente, o Portainer permite criar "Secrets" (em Configs & Secrets -> Secrets). Esses secrets podem então ser referenciados no seu
docker-compose.ymlusando a sintaxesecrets:. Esta abordagem evita que os segredos fiquem visíveis como variáveis de ambiente dentro do container, mas adiciona um pouco mais de complexidade aodocker-compose.yml. Para este guia, focamos em variáveis de ambiente pela simplicidade. - Quaisquer variáveis de ambiente que contenham segredos (como senhas de banco de dados, tokens de API,
-
Verificar Configurações Adicionais da Stack (Opcional):
- Redes: Se sua stack usa redes Docker que foram criadas externamente (como
proxyeinternal_services), certifique-se de que elas estão declaradas no topo do seudocker-compose.ymlcomexternal: true. O Portainer não tentará criá-las. - Volumes: Revise os mapeamentos de volume no seu
docker-compose.ymlpara garantir que eles usam as variáveis de ambiente corretas (que foram preenchidas pelo arquivo.env).
- Redes: Se sua stack usa redes Docker que foram criadas externamente (como
-
Deploy (ou Update) da Stack:
- No final da página, revise tudo e clique no botão "Deploy the stack" (se for uma nova stack) ou "Update the stack" (se você estiver modificando uma stack existente).
- Ao atualizar, se você mudou a tag de uma imagem Docker no
docker-compose.ymle quer que o Portainer puxe a nova imagem, certifique-se de que a opção "Re-pull image" (ou similar) esteja marcada antes de clicar em "Update".
-
Monitorar Logs e Status dos Containers:
- Após o deploy, o Portainer o levará para a página da stack ou você pode navegar até "Stacks" para vê-la.
- Clique no nome da stack para ver os containers que a compõem.
- Para cada container, especialmente os novos ou os que foram recriados:
- Verifique seu status (deve ser "running").
- Clique no ícone de Logs (📄) para ver os logs de inicialização do container. Procure por quaisquer mensagens de erro ou avisos. Isso é crucial para o troubleshooting inicial.
Este processo padronizado (Preparação Ansible -> Deploy Portainer com .env e Secrets) será a base para implantar todas as stacks de aplicações detalhadas nas Seções 7 a 10.
Este fluxo de trabalho garante que:
* Seus volumes de dados estejam corretamente localizados nos compartilhamentos NFS resilientes.
* As configurações de PUID/PGID e caminhos sejam consistentes.
* Os segredos sejam gerenciados de forma mais segura do que colocá-los diretamente nos arquivos docker-compose.yml.
Com o Portainer configurado e este processo em mente, você está pronto para começar a popular seu servidor com serviços!
Próximo passo: Começaremos com a Stack de Inteligência Artificial (LLM/RAG com Ollama).