CI/CD Básico para Infraestrutura como Código (Ansible)¶
Gerenciar sua infraestrutura de servidor doméstico como código (IaC) com Ansible e versioná-la com Git não apenas torna sua configuração repetível e documentada, mas também abre a porta para um fluxo de trabalho similar ao de desenvolvimento de software, incluindo conceitos de Integração Contínua (CI) e Entrega/Deploy Contínuo (CD) – mesmo que de forma simplificada para um ambiente de homelab.
O objetivo principal é ter um processo confiável, testável e, idealmente, automatizável para aplicar mudanças e atualizações na sua infraestrutura.
Fluxo de Trabalho com Git e Ansible para Gerenciamento de Mudanças¶
Este é o fluxo de trabalho recomendado ao fazer alterações na sua configuração Ansible:
-
Desenvolvimento e Modificação Local (na sua Máquina de Controle Ansible):
- Branching no Git (Opcional, mas Altamente Recomendado para Mudanças Maiores):
Para mudanças significativas, experimentações, ou ao adicionar novas funcionalidades, é uma excelente prática criar uma nova branch no Git antes de começar a editar os arquivos. Isso isola suas mudanças da branch principal (
mainoumaster) até que você esteja pronto para integrá-las. - Realize as Modificações:
Edite seus arquivos Ansible conforme necessário:
- Playbooks (
*.ymlemansible/playbooks/) - Roles (tasks, templates
.j2, handlers, defaults, vars emansible/roles/NOME_DO_ROLE/) - Inventário (
ansible/inventories/home/hosts.ini) - Variáveis de grupo (
ansible/inventories/home/group_vars/all/main.ymlouvault.yml- useansible-vault editpara este último)
- Playbooks (
- Branching no Git (Opcional, mas Altamente Recomendado para Mudanças Maiores):
Para mudanças significativas, experimentações, ou ao adicionar novas funcionalidades, é uma excelente prática criar uma nova branch no Git antes de começar a editar os arquivos. Isso isola suas mudanças da branch principal (
-
Teste Local das Mudanças Ansible (CI - Integração Contínua Simplificada): Antes de aplicar as mudanças no seu ambiente de "produção" (seu servidor doméstico), teste o máximo possível localmente na sua máquina de controle. Isso é a nossa forma de "Integração Contínua" simplificada.
- Linting (Verificação de Sintaxe e Estilo):
Ferramentas de linting ajudam a pegar erros de sintaxe, inconsistências e más práticas antes mesmo de executar o código.
ansible-lint: Analisa seus playbooks e roles Ansible.yamllint: Verifica a sintaxe de todos os seus arquivos YAML (playbooks, vars, etc.).
- Syntax Check do Ansible: O próprio Ansible pode verificar a sintaxe dos seus playbooks.
- Dry Run (Modo de Verificação
--check): Este é um passo crucial. O modo--checksimula a execução do playbook sem fazer alterações reais nos seus sistemas. Use junto com--diffpara ver quais mudanças seriam feitas.--check: Ativa o modo Dry Run.--diff: Mostra as diferenças (o que mudaria nos arquivos de configuração ou estado dos serviços). Analise a saída cuidadosamente para garantir que as mudanças propostas são as que você espera.
- Linting (Verificação de Sintaxe e Estilo):
Ferramentas de linting ajudam a pegar erros de sintaxe, inconsistências e más práticas antes mesmo de executar o código.
-
Commit e Push das Mudanças para o Repositório Git Remoto: Uma vez que você está satisfeito com seus testes locais:
- Adicione suas mudanças ao "stage" do Git:
- Faça o commit das mudanças com uma mensagem clara e descritiva:
- Envie suas mudanças para o seu repositório Git remoto (e.g., GitHub, GitLab):
- Pull Request / Merge Request (Se estiver usando branches e/ou colaborando):
Se você trabalhou em uma feature branch, agora é o momento de criar um Pull Request (GitHub) ou Merge Request (GitLab) no seu repositório remoto. Isso permite uma revisão das suas mudanças (por você mesmo ou por outros, se aplicável) antes de mesclá-las na branch principal (
main).
-
Aplicação das Mudanças na Infraestrutura (CD - Deploy Contínuo ou Controlado): Este é o passo de "Entrega Contínua" ou, mais realisticamente para um homelab, "Deploy Controlado".
- Opção A: Aplicação Manual (Recomendado para a Maioria dos Homelabs para Máximo Controle):
- Sincronize sua Máquina de Controle: Na sua máquina de controle Ansible, certifique-se de que seu repositório local está na branch principal (
main) e atualizado com as últimas mudanças do repositório remoto (que agora incluem suas alterações mescladas). - Execute o Playbook Ansible Relevante:
Execute o playbook Ansible que aplica as mudanças que você fez. Frequentemente, para garantir a consistência de toda a infraestrutura, pode ser o playbook mestre
full-deploy.yml. Se a mudança for muito isolada e você tiver certeza do seu escopo, pode executar um playbook mais específico.
- Sincronize sua Máquina de Controle: Na sua máquina de controle Ansible, certifique-se de que seu repositório local está na branch principal (
- Opção B: Aplicação Automatizada via Cron Job (Avançado - Use com Cautela):
Você pode configurar um
cronjob na sua máquina de controle Ansible para, periodicamente (e.g., diariamente em um horário de baixa atividade), puxar as últimas mudanças da branchmaindo seu repositório Git e executar automaticamente o playbookfull-deploy.yml.- Exemplo de Script (
/opt/homelab_scripts/run_ansible_autodeploy.shna máquina de controle):#!/bin/bash # /opt/homelab_scripts/run_ansible_autodeploy.sh REPO_PATH="/caminho/completo/para/seu/repo/home-server" # Ajuste este caminho! LOG_FILE="/var/log/ansible_autodeploy.log" # Caminho para o arquivo contendo a senha do Ansible Vault. # !!! CUIDADO MÁXIMO COM A SEGURANÇA DESTE ARQUIVO !!! VAULT_PASS_FILE="/home/seu_usuario_ansible_control/.ansible_vault_pass.txt" # Proteja com chmod 400 ou 600 # Função para logar com timestamp log_msg() { echo "$(date '+%Y-%m-%d %H:%M:%S') - $1" >> "$LOG_FILE" } log_msg "----------------------------------------------------" log_msg "Iniciando auto-deploy da infraestrutura Ansible..." cd "$REPO_PATH" || { log_msg "ERRO: Diretório do repositório não encontrado: $REPO_PATH"; exit 1; } log_msg "Verificando branch atual e puxando últimas mudanças do Git (branch main)..." CURRENT_BRANCH=$(git rev-parse --abbrev-ref HEAD) if [ "$CURRENT_BRANCH" != "main" ]; then # Ou sua branch principal log_msg "AVISO: Não está na branch 'main'. Tentando checkout para 'main'." git checkout main >> "$LOG_FILE" 2>&1 if [ $? -ne 0 ]; then log_msg "ERRO: Falha ao fazer checkout para a branch 'main'." exit 1 fi fi git pull origin main >> "$LOG_FILE" 2>&1 if [ $? -ne 0 ]; then log_msg "ERRO: Falha ao executar git pull na branch 'main'." exit 1 fi git log -1 --pretty=format:"Último commit para deploy: %h - %an, %ar : %s" >> "$LOG_FILE" log_msg "Executando playbook 'full-deploy.yml'..." # Use --vault-password-file para automação. # Adicione -i para especificar o inventário se não estiver no ansible.cfg ansible-playbook "${REPO_PATH}/ansible/playbooks/full-deploy.yml" \ -i "${REPO_PATH}/ansible/inventories/home/" \ --vault-password-file "$VAULT_PASS_FILE" >> "$LOG_FILE" 2>&1 ANSIBLE_EXIT_CODE=$? if [ ${ANSIBLE_EXIT_CODE} -ne 0 ]; then log_msg "ERRO: Playbook Ansible falhou com código de saída ${ANSIBLE_EXIT_CODE}. Verifique o log completo." # Adicione aqui um mecanismo de notificação (e.g., enviar email, mensagem no Discord/Telegram) exit 1 fi log_msg "Auto-deploy Ansible concluído com sucesso." log_msg "----------------------------------------------------" exit 0 - Agendamento com
cron(e.g.,crontab -e):0 5 * * * /opt/homelab_scripts/run_ansible_autodeploy.sh(Executa todo dia às 5 AM). -
Riscos da Automação Total e Segurança do Arquivo de Senha do Vault
Automatizar completamente o deploy comcroné conveniente, mas introduz riscos:- Segurança do Arquivo de Senha: Armazenar a senha do Ansible Vault em texto plano em um arquivo (
VAULT_PASS_FILE) é um risco de segurança. Esse arquivo deve ter permissões extremamente restritas (e.g.,chmod 400ou600, e ser propriedade apenas do usuário que roda o cron). Se a máquina de controle for comprometida, a senha do vault também será. - Deploy de Mudanças Quebradiças: Se uma mudança com erro for mesclada na branch
main, o cron job a aplicará automaticamente, podendo quebrar sua infraestrutura sem intervenção manual imediata. - Para ambientes mais críticos (mesmo homelabs se você depende muito deles), um "deploy controlado" (manual após revisão) é geralmente mais seguro. Se optar pela automação, invista em testes robustos (Molecule, etc.) e um bom sistema de notificação de falhas.
- Segurança do Arquivo de Senha: Armazenar a senha do Ansible Vault em texto plano em um arquivo (
- Exemplo de Script (
- Opção A: Aplicação Manual (Recomendado para a Maioria dos Homelabs para Máximo Controle):
-
Monitoramento Pós-Deploy:
- Independentemente de o deploy ser manual ou automatizado, após a aplicação das mudanças Ansible, sempre verifique:
- Os logs dos serviços que foram modificados.
- A funcionalidade das aplicações afetadas.
- O status geral da sua infraestrutura usando sua Stack de Monitoramento (Prometheus, Grafana, Loki).
- Independentemente de o deploy ser manual ou automatizado, após a aplicação das mudanças Ansible, sempre verifique:
Playbook ansible/playbooks/full-deploy.yml (O Orquestrador Principal)¶
Este playbook é o ponto de entrada principal para garantir que toda a sua infraestrutura base (configuração do host Proxmox, VMs, Docker, rede core, preparação de volumes para stacks) esteja configurada conforme definido no seu código Ansible. Ele importa e executa os outros playbooks de setup em uma sequência lógica.
# ansible/playbooks/full-deploy.yml
# Orquestra a configuração completa e fundamental da infraestrutura.
# As stacks Docker específicas (mídia, produtividade, etc.) são, por design deste guia,
# implantadas via Portainer APÓS a execução bem-sucedida dos playbooks Ansible
# que preparam seus volumes e arquivos .env. O Ansible aqui foca na infraestrutura base.
- name: "Etapa 1: Configurar Host Proxmox VE (NFS, Firewall, Pacotes, etc.)"
ansible.builtin.import_playbook: setup-proxmox-host.yml
- name: "Etapa 2: Provisionar/Verificar Máquinas Virtuais (core-services-vm, ai-desktop-vm)"
ansible.builtin.import_playbook: vm-deploy.yml
- name: "Etapa 3: Configurar Base das VMs Ubuntu (Docker, Portainer, NFS Client, GUI opcional)"
ansible.builtin.import_playbook: setup-base-ubuntu.yml
- name: "Etapa 4: Configurar Stack de Rede Core (Traefik, Cloudflare Tunnel, Authelia - Configs e Deploy Docker)"
ansible.builtin.import_playbook: setup-core-networking.yml
# Os playbooks abaixo são cruciais, pois preparam os diretórios NFS e os arquivos .env
# que serão usados pelo Portainer para implantar as stacks de aplicação Docker.
# Eles garantem que os volumes estejam prontos e com as permissões corretas.
- name: "Etapa 5.1: Preparar Volumes e Arquivo .env para a Stack de Mídia"
ansible.builtin.import_playbook: setup-media-stack-volumes.yml
# Condicional para rodar apenas se a VM alvo da stack existir no inventário
when: "'core-services-vm' in groups['virtual_machines']"
- name: "Etapa 5.2: Preparar Volumes e Arquivo .env para as Stacks de Produtividade e Automação"
ansible.builtin.import_playbook: setup-productivity-automation-volumes.yml
when: "'core-services-vm' in groups['virtual_machines']"
- name: "Etapa 5.3: Preparar Volumes, Arquivo .env e Configs Adicionais para a Stack RAG/LLM"
ansible.builtin.import_playbook: setup-rag-llm-volumes.yml
# Condicional para rodar apenas se a VM alvo da stack (ai-desktop-vm) existir
when: "'ai-desktop-vm' in groups['virtual_machines']"
- name: "Etapa 5.4: Preparar Volumes e Arquivo .env para a Stack de Monitoramento"
ansible.builtin.import_playbook: setup-monitoring-stack-volumes.yml
when: "'core-services-vm' in groups['virtual_machines']"
# --- Conclusão do Playbook Mestre ---
- name: "Conclusão do Deploy da Infraestrutura Base Ansible"
hosts: localhost # Esta task final roda na máquina de controle Ansible
gather_facts: no
tasks:
- name: "Mensagem de Conclusão e Próximos Passos Sugeridos"
ansible.builtin.debug:
msg: |
#####################################################################
# #
# DEPLOY DA INFRAESTRUTURA BASE VIA ANSIBLE CONCLUÍDO! #
# #
#####################################################################
PRÓXIMOS PASSOS (se este for o setup inicial ou se as stacks Docker não estiverem rodando):
1. Acesse o Portainer em https://portainer.{{ base_domain }}/ (autentique com Authelia).
2. Para CADA stack de aplicação (Mídia, Produtividade, RAG, Monitoramento):
a. Vá para "Stacks" -> "+ Add stack".
b. Cole o conteúdo do respectivo arquivo 'docker-compose.yml'.
c. Em "Environment variables" (Advanced mode), carregue o arquivo '.env' correspondente
(e.g., /opt/portainer_stack_envs/media.env na VM).
d. Adicione quaisquer SECRETS (senhas de DB, API keys) manualmente como variáveis de ambiente.
e. Clique em "Deploy the stack".
3. Configure os registros DNS na Cloudflare (CNAMEs ou Ingress Rules) para cada serviço exposto, se ainda não o fez ou se o wildcard não cobrir tudo.
4. Verifique os logs dos containers no Portainer após o deploy de cada stack para garantir que iniciaram corretamente.
5. Realize a configuração pós-deploy dentro de cada aplicação (e.g., setup inicial do Nextcloud, Plex, etc.).
Lembre-se de que os playbooks Ansible prepararam os volumes e arquivos .env,
mas o deploy efetivo das stacks de aplicação Docker (além do core de rede)
é feito via Portainer neste fluxo de trabalho.
Script scripts/restore.sh (Facilitador para Deploy Completo com Ansible)¶
Este script é um wrapper conveniente para executar o playbook full-deploy.yml, especialmente útil para o setup inicial ou para garantir que toda a infraestrutura gerenciada pelo Ansible esteja no estado desejado.
#!/bin/bash
# scripts/restore.sh
# Executa o playbook Ansible 'full-deploy.yml' para configurar a infraestrutura base.
# Assume que o Proxmox VE já está instalado e a máquina de controle Ansible está pronta
# (com 'bootstrap.sh' executado e chaves SSH configuradas).
set -e # Encerra o script imediatamente se um comando falhar.
# Determina o caminho raiz do repositório onde o script está localizado
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
REPO_ROOT="$(cd "${SCRIPT_DIR}/.." && pwd)" # Vai um nível acima do diretório do script
ANSIBLE_DIR="${REPO_ROOT}/ansible"
# Localização padrão do arquivo com a senha do Ansible Vault (se não usar --ask-vault-pass)
VAULT_PASS_FILE_DEFAULT="${HOME}/.ansible_vault_pass.txt" # Exemplo
echo "🚀 Iniciando restauração/deploy da infraestrutura base Ansible..."
echo " Repositório Raiz: ${REPO_ROOT}"
echo " Playbooks Ansible em: ${ANSIBLE_DIR}/playbooks"
echo " Inventário Ansible em: ${ANSIBLE_DIR}/inventories/home"
# Permite passar um argumento para o script, como --ask-vault-pass
# ou o caminho para um arquivo de senha do vault diferente.
VAULT_PASS_ARG="$1"
ANSIBLE_CMD_OPTIONS="" # Opções adicionais para o comando ansible-playbook
if [ -z "$VAULT_PASS_ARG" ]; then
if [ -f "$VAULT_PASS_FILE_DEFAULT" ]; then
ANSIBLE_CMD_OPTIONS="--vault-password-file ${VAULT_PASS_FILE_DEFAULT}"
echo "🔐 Usando arquivo de senha do Ansible Vault padrão: ${VAULT_PASS_FILE_DEFAULT}"
else
echo "⚠️ Arquivo de senha padrão do Vault ('${VAULT_PASS_FILE_DEFAULT}') não encontrado."
echo "➡️ O Ansible solicitará a senha do Vault interativamente."
ANSIBLE_CMD_OPTIONS="--ask-vault-pass"
fi
elif [ "$VAULT_PASS_ARG" == "--ask-vault-pass" ]; then
ANSIBLE_CMD_OPTIONS="--ask-vault-pass"
echo "➡️ O Ansible solicitará a senha do Vault interativamente."
elif [ -f "$VAULT_PASS_ARG" ]; then
ANSIBLE_CMD_OPTIONS="--vault-password-file $VAULT_PASS_ARG"
echo "🔐 Usando arquivo de senha do Ansible Vault especificado: $VAULT_PASS_ARG"
else
echo "❌ ERRO: Argumento para senha do Vault ('$VAULT_PASS_ARG') não é '--ask-vault-pass' nem um arquivo válido."
echo " Use '--ask-vault-pass' para digitar a senha, ou forneça um caminho válido para o arquivo de senha."
exit 1
fi
# Comando para executar o playbook Ansible 'full-deploy.yml'
echo "🛠️ Executando playbook 'full-deploy.yml'..."
# -i especifica o caminho para o diretório de inventário.
# Ansible procurará por ansible.cfg na raiz do projeto ou no diretório atual.
# Se seu ansible.cfg estiver em ansible/, você pode precisar de `cd ansible` antes
# ou especificar o caminho do inventário de forma mais absoluta.
# Assumindo que o playbook é executado da raiz do REPO_ROOT:
ansible-playbook -i "${ANSIBLE_DIR}/inventories/home/" \
"${ANSIBLE_DIR}/playbooks/full-deploy.yml" \
${ANSIBLE_CMD_OPTIONS}
echo -e "\n✅ Restauração/deploy da infraestrutura base via Ansible CONCLUÍDA."
echo "➡️ PRÓXIMO PASSO (se setup inicial): Implante as stacks de serviços Docker via Portainer (Seções 6-10 do Manual)."
echo "🔗 LEMBRE-SE de configurar os registros DNS na Cloudflare para cada serviço exposto."
echo "🔎 Verifique os logs dos containers no Portainer após o deploy de cada stack."
Como usar scripts/restore.sh para o setup inicial (após o bootstrap.sh na máquina de controle e a configuração SSH inicial no host Proxmox):
# Navegue para a raiz do seu projeto home-server/ na máquina de controle
bash scripts/restore.sh # Por padrão, solicitará a senha do vault interativamente
# Ou, se você criou um arquivo de senha do vault (e.g., ~/.ansible_vault_pass.txt):
# bash scripts/restore.sh ~/.ansible_vault_pass.txt
Este fluxo de trabalho básico de CI/CD, mesmo que simplificado para um ambiente de homelab (com mais foco no "D" de Deploy do que no "CI" formal), traz uma disciplina valiosa, aumenta a confiabilidade e torna o gerenciamento da sua infraestrutura como código muito mais robusto e rastreável.