Construindo um Laboratório de Infraestrutura Completo com Linux, Docker, Kubernetes e Automação

setembro 1, 2026 · 23 min de leitura · Luiz Seabra

Construindo um Laboratório de Infraestrutura Completo com Linux, Docker, Kubernetes e Automação

Neste artigo vamos construir um laboratório de infraestrutura completo do zero, integrando as melhores práticas de DevOps em um ambiente doméstico. Ao final, você terá um ambiente produtivo capaz de hospedar serviços, monitorar sua saúde, servir aplicações via Kubernetes e manter tudo documentado e automatizado.

Este guia é voltado para profissionais que desejam consolidar suas habilidades de infraestrutura, sistemadores que precisam de um ambiente de teste robusto, ou entusiastas que querem criar um homelab profissional.

O que você vai aprender

  • Instalar e configurar um servidor Linux Ubuntu Server do zero
  • Configurar SSH seguro com chaves Ed25519 e desativar autenticação por senha
  • Deployar e gerenciar containers usando Docker e Docker Compose
  • Configurar um reverse proxy Traefik com HTTPS via Let’s Encrypt
  • Implementar monitoramento com Prometheus e Grafana
  • Orquestrar workloads usando K3s (versão leve de Kubernetes)
  • Automatizar provisionamento com Ansible e Terraform
  • Implementar estratégia de backup com BorgBackup
  • Documentar e manter infraestrutura de forma sustentável

Pré-requisitos

  • Máquina com mínimo de 8GB de RAM (recomendado 16GB+)
  • CPU com suporte a virtualização (VT-x/AMD-V) ou hardware reaproveitado
  • 100GB de armazenamento SSD (mínimo) + HDD opcional para dados
  • Conexão com internet estável, porta 80/443 acessível (ou uso de reverse SSH)
  • Conhecimento básico de Linux e terminal
  • Domínio próprio (opcional, mas recomendado para HTTPS)

Conceitos fundamentais

Linux Server vs Desktop

Ubuntu Server é uma versão otimizada para servidores, removendo pacotes gráficos e focando em estabilidade, segurança e eficiência. Diferente do desktop, não carrega sobrehead de interface gráfica, consumindo menos recursos. Para um homelab, o Server é a escolha correta.

KVM/QEMU como Hypervisor

Kernel-based Virtual Machine (KVM) é um módulo do kernel Linux que permite a virtualização de hardware. Quando combinado com QEMU (emulador), permite a criação de VMs com desempenho quase nativo. O KVM é a base para libvirt, que oferece APIs e ferramentas de gerenciamento.

Docker vs VM

Containers compartilham o kernel do host, enquanto VMs têm seu próprio sistema operacional. Docker é ideal para serviços leves, isolados e com ciclo de vida curto. Kubernetes orquestra múltiplos containers, gerenciando escalabilidade e alta disponibilidade.

SSH Keys vs Senhas

Autenticação com chave públicaPrivada é mais segura que senha porque:
– Não pode ser quebrada por força bruta
– É criptograficamente segura (Ed25519 oferece 256 bits de segurança)
– Permite configuração de acesso granulares por usuário/chave

Traefik como Reverse Proxy

Traefik é um proxy reverso moderno que detecta automaticamente serviços Docker via labels, gerencia certificados SSL/TLS via ACME (Let’s Encrypt) e oferece dashboard de visualização. É superior a Nginx para ambientes containerizados.

Kubernetes vs Docker Compose

Docker Compose é ideal para ambientes de desenvolvimento e pequenos deployments. Kubernetes (K3s) é necessário quando precisamos de:
– Escalabilidade horizontal
– Rolling updates
– Self-healing
– Multi-node management

Preparação do ambiente

Hardware de referência

Para este laboratório, recomendamos uma máquina com as seguintes especificações:

Componente Homelab Inicial Homelab Produção
CPU Intel N100 (6 cores) ou AMD Ryzen 5 Xeon E-2200 ou Ryzen 7
RAM 16GB DDR4 32GB DDR4/DDR5
SSD 500GB NVMe 1TB NVMe
HDD 2TB SATA (dados) 4TB SATA (dados)
Rede 1GbE + Wi-Fi 6 2.5GbE + 10GbE (opcional)

Diagrama da Arquitetura Final

┌─────────────────────────────────────────────────────────────────────┐
│                         INTERNET                                     │
└─────────────────────────────┬───────────────────────────────────────┘
                              │
                    ┌─────────▼─────────┐
                    │    FIREWALL       │ (iptables/ufw)
                    │  Portas 22,80,443 │
                    └─────────┬─────────┘
                              │
                    ┌─────────▼─────────┐
                    │   REVERSE PROXY   │
                    │     Traefik       │
                    │    HTTPS (LE)     │
                    └─────────┬─────────┘
                              │
        ┌─────────────────────┼─────────────────────┐
        │                     │                     │
        ▼                     ▼                     ▼
┌───────────────┐   ┌─────────────────┐   ┌─────────────────┐
│    DOCKER     │   │   KUBERNETES    │   │   MONITORING    │
│   COMPOSE     │   │     K3s         │   │  Prometheus &   │
│  (Apps/Serv)  │   │   Workloads     │   │     Grafana     │
└───────┬───────┘   └────────┬────────┘   └─────────────────┘
        │                      │
        ▼                      ▼
┌─────────────────────────────────────────────────────────────────────┐
│                    STORAGE (NFS/SMB/ZFS)                           │
│                    Backup (borg/REST)                               │
└─────────────────────────────────────────────────────────────────────┘
Camada Ferramenta Responsabilidade
Rede UFW/iptables Firewall de borda
HTTP Traefik Reverse Proxy + HTTPS
Contêineres Docker Engine Execução de containers
Orquestração K3s Orquestração de workloads
Monitoramento Prometheus/Grafana Métricas e visualização
Backup BorgBackup Proteção de dados

Laboratório – 15 Fases

Fase 1: Planejamento

Objetivo: Definir escopo, hardware e serviços a implantar.

Primeiro, mapeie seus recursos e objetivos. Abra um terminal e configure seu ambiente de trabalho:

# Criar diretório do projeto
mkdir -p ~/laboratorio/infra/{ansible,terraform,backups,docs}
cd ~/laboratorio/infra

# Documentar hardware disponível
lscpu > hardware-cpu.txt
free -h > hardware-ram.txt
lsblk > hardware-disco.txt

Explicação: Estamos criando uma estrutura de diretórios organizada para o projeto. O lscpu, free e lsblk geram relatórios técnicos que serão úteis para planejamento futuro.

Resultado esperado: Três arquivos de texto com especificações de CPU, RAM e disco, e uma estrutura de diretórios organizada.

Agora, crie uma planilha de serviços a expor:

# servicos-planilha.yaml
servicos:
  - nome: Gitea
    porta_interneta: 3000
    porta_interna: 3000
    descricao: Git server próprio
    categoria: dev
  - nome: Portainer
    porta_interneta: 9000
    porta_interna: 9000
    descricao: GUI gerenciamento Docker
    categoria: ops
  - nome: Grafana
    porta_interneta: 3001
    porta_interna: 3000
    descricao: Dashboard de métricas
    categoria: monitoring
  - nome: Prometheus
    porta_interneta: 9090
    porta_interna: 9090
    descricao: Coleta de métricas
    categoria: monitoring
  - nome: Nextcloud
    porta_interneta: 8080
    porta_interna: 8080
    descricao: NAS pessoal
    categoria: storage

Resultado esperado: Arquivo de definição de serviços com portas e descrições.

Fase 2: Preparação dos servidores Linux

Objetivo: Instalar Ubuntu Server e configurar básico.

Se estiver usando uma VM ou instalando do zero, siga o processo oficial da Ubuntu Server Installation Guide. Para este tutorial, assumimos Ubuntu Server 24.04 LTS.

# Verificar versão do sistema
cat /etc/os-release
uname -a

Explicação: Estes comandos verificam a versão do SO e do kernel. Deve retornar Ubuntu 24.04 LTS.

Resultado esperado: Saída mostrando Ubuntu como ID e 24.04 como versão.

Configure o hostname e atualizações:

# Definir hostname
sudo hostnamectl set-hostname laboratorio.bittux.local

# Atualizar sistema
sudo apt update && sudo apt upgrade -y
sudo apt install -y curl wget git unzip zip

Explicação: O hostname identifica sua máquina na rede. As atualizações garantem patches de segurança aplicados.

Resultado esperado: Sistema atualizado, hostname definido como laboratorio.bittux.local.

Fase 3: SSH seguro

Objetivo: Configurar SSH com chaves Ed25519 e desativar autenticação por senha.

Primeiro, gere suas chaves SSH no cliente (máquina administradora):

# Gerar chave Ed25519 (no cliente, não no servidor)
ssh-keygen -t ed25519 -C "admin@laboratorio.bittux" -f ~/.ssh/laboratorio_ed25519

Explicação: Ed25519 é o algoritmo de chave moderno, mais seguro e eficiente que RSA. A opção -f nomeia o arquivo de chave.

Resultado esperado: Par de chaves criado em ~/.ssh/laboratorio_ed25519 e ~/.ssh/laboratorio_ed25519.pub.

Copie a chave pública para o servidor:

# Copiar chave para servidor
ssh-copy-id -i ~/.ssh/laboratorio_ed25519.pub admin@laboratorio.bittux.local

Explicação: Este comando configura a autenticação por chave. Substitua admin pelo seu usuário no servidor.

Resultado esperado: Chave instalada e SSH pronto para autenticação por chave.

Desative autenticação por senha no servidor:

# Editar configuração do SSH
sudo nano /etc/ssh/sshd_config

Adicione ou modifique estas linhas:

# Autenticação
PasswordAuthentication no
PubkeyAuthentication yes
AuthorizedKeysFile .ssh/authorized_keys

# Segurança
PermitRootLogin no
MaxAuthTries 3
ClientAliveInterval 300
ClientAliveCountMax 2

Reinicie o serviço SSH:

sudo systemctl restart sshd
sudo ufw enable
sudo ufw allow 22/tcp

Explicação: Desativamos autenticação por senha, permitimos apenas chaves públicas, e configuramos o firewall UFW para permitir SSH.

Resultado esperado: SSH rejeitando tentativas de login por senha, apenas aceitando chaves configuradas.

Fase 4: Virtualização com KVM

Objetivo: Verificar suporte a KVM e instalar libvirt para gerenciamento de VMs.

Verifique se o CPU suporta virtualização:

# Verificar suporte a KVM
grep -E '(vmx|svm)' /proc/cpuinfo
ls -la /dev/kvm

Explicação: vmx indica Intel VT-x, svm indica AMD-V. O /dev/kvm deve existir como dispositivo.

Resultado esperado: Saída contendo vmx ou svm, e /dev/kvm presente.

Instale libvirt e ferramentas:

sudo apt install -y qemu-kvm libvirt-daemon-system libvirt-clients bridge-utils virtinst virt-manager
sudo systemctl enable --now libvirtd

Explicação: Estes pacotes fornecem a infraestrutura completa de virtualização. virt-manager oferece interface gráfica quando necessário.

Resultado esperado: Serviço libvirtd rodando e pods virtuais criáveis.

Crie uma VM de gerenciamento (opcional):

# Criar VM minimalista para gerenciamento
virt-install 
  --name gerenciamento 
  --memory 2048 
  --vcpus 2 
  --disk size=20 
  --os-variant ubuntu24.04 
  --network bridge=virbr0 
  --graphics none 
  --console pty,target_type=serial 
  --location 'http://archive.ubuntu.com/ubuntu/dists/noble/main/installer-amd64/' 
  --extra-args 'console=ttyS0,115200n8 serial'

Explicação: Este comando cria uma VM dedicada para tarefas de gerenciamento, separando o host do gerenciamento de containers.

Resultado esperado: VM gerenciamento criada e instalada.

Fase 5: Docker Engine

Objetivo: Instalar Docker Engine via repositório oficial.

Primeiro, remova versões antigas (se existirem):

sudo apt remove -y docker docker-engine docker.io containerd runc

Explicação: Garantimos que instalamos a versão mais recente do repositório oficial, não de pacotes da distro.

Resultado esperado: Nenhuma versão antiga de Docker removida.

Instale Docker:

# Adicionar GPG key
sudo install -m 0755 -d /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
sudo chmod a+r /etc/apt/keyrings/docker.gpg

# Adicionar repositório
echo 
  "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu 
  $(. /etc/os-release && echo "$VERSION_CODENAME") stable" | 
  sudo tee /etc/apt/sources.list.d/docker.list > /dev/null

# Instalar Docker
sudo apt update
sudo apt install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin

Explicação: Adicionamos o repositório oficial Docker com assinatura GPG, garantindo integridade dos pacotes.

Resultado esperado: Docker CE instalado com plugins recomendados.

Habilite e verifique:

sudo systemctl enable --now docker
sudo usermod -aG docker $USER
docker --version && docker compose version

Explicação: Habilitamos o serviço Docker e adicionamos nosso usuário ao grupo docker para não precisar de sudo.

Resultado esperado: Versões Docker e Docker Compose exibidas, usuário no grupo docker.

Nota: Faça logout e login novamente para o grupo docker funcionar.

Fase 6: Docker Compose

Objetivo: Criar estrutura de diretórios e compose inicial.

# Estrutura de diretórios
mkdir -p ~/laboratorio/infra/producao/{gitea,portainer,prometheus,grafana,traefik}
mkdir -p ~/laboratorio/infra/producao/data/{gitea,traefik,prometheus,grafana}

Explicação: Separamos os serviços por diretório para organização. Dados são mantidos em subdiretórios para persistência.

Resultado esperado: Estrutura de diretórios criada.

Crie o compose inicial com Portainer como gerenciador:

# ~/laboratorio/infra/producao/portainer/portainer.yaml
services:
  portainer:
    image: portainer/portainer-ce:latest
    container_name: portainer
    ports:
      - "9000:9000"
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock
      - ./data:/data
    restart: unless-stopped
cd ~/laboratorio/infra/producao/portainer
docker compose -f portainer.yaml up -d

Explicação: O Portainer é nossa interface gráfica para gerenciar Docker. Mapeamos o socket Docker para que ele tenha controle total.

Resultado esperado: Container Portainer rodando na porta 9000.

Acesse em http://laboratorio.bittux.local:9000 e configure usando “local” como endpoint.

Fase 7: Reverse Proxy Traefik

Objetivo: Configurar Traefik como proxy com Docker provider.

# ~/laboratorio/infra/producao/traefik/traefik.yaml
services:
  traefik:
    image: traefik:v3.0
    container_name: traefik
    command:
      - "--api.insecure=true"
      - "--providers.docker=true"
      - "--providers.docker.exposedbydefault=false"
      - "--entrypoints.web.address=:80"
      - "--entrypoints.websecure.address=:443"
      - "--certificatesresolvers.myresolver.acme.tlschallenge=true"
      - "--certificatesresolvers.myresolver.acme.email=admin@bittux.com.br"
      - "--certificatesresolvers.myresolver.acme.storage=/letsencrypt/acme.json"
    ports:
      - "80:80"
      - "443:443"
      - "8080:8080"
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock:ro
      - ./data/acme.json:/letsencrypt/acme.json
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.traefik.rule=Host(`laboratorio.bittux.local`) && (PathPrefix(`/dashboard`) || PathPrefix(`/api`))"
      - "traefik.http.routers.traefik.service=api@internal"
      - "traefik.http.routers.traefik.entrypoints=websecure"
      - "traefik.http.routers.traefik.tls.certresolver=myresolver"
    restart: unless-stopped
cd ~/laboratorio/infra/producao/traefik
docker compose -f traefik.yaml up -d
docker compose -f ../portainer/portainer.yaml up -d

Explicação: O Traefik detecta containers Docker automaticamente. O dashboard é protegido por host e HTTPS. O acme.json precisa ter permissão 600.

Resultado esperado: Traefik rodando com dashboard acessível via https://laboratorio.bittux.local/dashboard.

Configure acesso ao Portainer via Traefik:

# Adicionar ao portainer.yaml
labels:
  - "traefik.enable=true"
  - "traefik.http.routers.portainer.rule=Host(`portainer.laboratorio.bittux.local`)"
  - "traefik.http.routers.portainer.entrypoints=websecure"
  - "traefik.http.routers.portainer.tls.certresolver=myresolver"
  - "traefik.http.services.portainer.loadbalancer.server.port=9000"
docker compose -f portainer.yaml up -d

Resultado esperado: Portainer acessível via https://portainer.laboratorio.bittux.local.

Fase 8: HTTPS com Let’s Encrypt

Objetivo: Configurar certificados automáticos.

Para teste local, adicione entradas no /etc/hosts:

echo "192.168.1.100 laboratorio.bittux.local portainer.laboratorio.bittux.local gitea.laboratorio.bittux.local" | sudo tee -a /etc/hosts

Explicação: Para domínios reais, configure DNS apontando para o IP público da sua rede. Para testes locais, /etc/hosts resolve o problema.

Resultado esperado: Domínios resolvidos localmente.

Teste o renovamento de certificados:

# Forçar emissão de certificado
docker exec traefik traefik certificates --certresolvers.myresolver.acme.storage=/letsencrypt/acme.json

Resultado esperado: Certificado emitido sem erros.

Fase 9: Monitoramento com Prometheus e Grafana

Objetivo: Implementar coleta de métricas e visualização.

# ~/laboratorio/infra/producao/prometheus/prometheus.yaml
services:
  prometheus:
    image: prom/prometheus:latest
    container_name: prometheus
    ports:
      - "9090:9090"
    volumes:
      - ./data/prometheus.yml:/etc/prometheus/prometheus.yml
      - prometheus_data:/prometheus
    restart: unless-stopped

  node-exporter:
    image: prom/node-exporter:latest
    container_name: node-exporter
    ports:
      - "9100:9100"
    restart: unless-stopped

volumes:
  prometheus_data:

Crie a configuração do Prometheus:

# ~/laboratorio/infra/producao/data/prometheus.yml
global:
  scrape_interval: 15s

scrape_configs:
  - job_name: 'prometheus'
    static_configs:
      - targets: ['prometheus:9090']
  - job_name: 'node'
    static_configs:
      - targets: ['node-exporter:9100']
docker compose -f prometheus.yaml up -d

Explicação: O Prometheus coleta métricas de seus serviços. O node-exporter fornece métricas do sistema operacional.

Resultado esperado: Prometheus acessível em http://laboratorio.bittux.local:9090.

Agora o Grafana com configuração via Traefik:

# ~/laboratorio/infra/producao/grafana/grafana.yaml
services:
  grafana:
    image: grafana/grafana-enterprise:latest
    container_name: grafana
    ports:
      - "3000:3000"
    volumes:
      - grafana_data:/var/lib/grafana
    environment:
      - GF_SECURITY_ADMIN_PASSWORD=admin123
    depends_on:
      - prometheus
    restart: unless-stopped

volumes:
  grafana_data:

Adicione labels de proxy:

labels:
  - "traefik.enable=true"
  - "traefik.http.routers.grafana.rule=Host(`grafana.laboratorio.bittux.local`)"
  - "traefik.http.routers.grafana.entrypoints=websecure"
  - "traefik.http.routers.grafana.tls.certresolver=myresolver"
  - "traefik.http.services.grafana.loadbalancer.server.port=3000"
docker compose -f grafana.yaml up -d

Resultado esperado: Grafana acessível via https://grafana.laboratorio.bittux.local com login admin/admin123.

Importe dashboards prontos via interface:
– Grafana Dashboard ID 1860 (Node Exporter Full)
– Grafana Dashboard ID 315 (Traefik)

Fase 10: Kubernetes com K3s

Objetivo: Deployar K3s e testar orquestração.

Instale K3s:

# Instalar K3s (server)
curl -sfL https://get.k3s.io | INSTALL_K3S_EXEC="server --disable traefik" sh -

Explicação: Instalamos K3s como servidor e desativamos o Traefik embutido porque já temos o nosso. O INSTALL_K3S_EXEC permite customizar a instalação.

Resultado esperado: K3s instalado e rodando.

Verifique o cluster:

sudo k3s kubectl get nodes
sudo k3s kubectl get pods -A

Explicação: kubectl é o CLI oficial para Kubernetes. O sudo k3s kubectl é o comando no K3s instalado manualmente.

Resultado esperado: Nó em estado Ready e namespace kube-system com pods funcionando.

Crie um ambiente de trabalho alternativo:

sudo mkdir -p /home/admin/.kube
sudo cp /etc/rancher/k3s/k3s.yaml /home/admin/.kube/config
sudo chown -R admin:admin /home/admin/.kube
export KUBECONFIG=/home/admin/.kube/config

Explicação: Copiamos o arquivo de configuração para o usuário admin e exportamos a variável de ambiente.

Resultado esperado: kubectl funcional sem sudo.

Deploye uma aplicação de teste:

# ~/laboratorio/infra/kubernetes/app-demo.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: hello-world
spec:
  replicas: 2
  selector:
    matchLabels:
      app: hello-world
  template:
    metadata:
      labels:
        app: hello-world
    spec:
      containers:
      - name: hello
        image: nginx:alpine
        ports:
        - containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
  name: hello-world
spec:
  selector:
    app: hello-world
  ports:
    - protocol: TCP
      port: 80
      targetPort: 80
kubectl apply -f app-demo.yaml
kubectl get pods
kubectl get svc

Explicação: Criamos um deployment simples com 2 réplicas do nginx e um service para expor a porta 80.

Resultado esperado: Dois pods hello-world rodando e service criado.

Configure acesso via Traefik:

# ~/laboratorio/infra/kubernetes/ingress.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: hello-world
  annotations:
    traefik.ingress.kubernetes.io/router.entrypoints: websecure
    traefik.ingress.kubernetes.io/router.tls: "true"
    traefik.ingress.kubernetes.io/router.tls.certresolver: myresolver
spec:
  rules:
  - host: hello.laboratorio.bittux.local
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: hello-world
            port:
              number: 80
kubectl apply -f ingress.yaml

Resultado esperado: Aplicação acessível via https://hello.laboratorio.bittux.local.

Fase 11: Automação com Ansible

Objetivo: Criar playbook para manter configuração consistente.

# ~/laboratorio/infra/ansible/inventory.ini
[servidores]
laboratorio ansible_host=192.168.1.100 ansible_user=admin

[containers:children]
servidores

[management:children]
servidores
# ~/laboratorio/infra/ansible/site.yml
---
- name: Configurar Laboratório Bittux
  hosts: servidores
  become: yes
  vars:
    docker_packages:
      - docker-ce
      - docker-ce-cli
      - containerd.io
      - docker-buildx-plugin
      - docker-compose-plugin

  tasks:
    - name: Atualizar pacotes
      apt:
        update_cache: yes
        upgrade: yes

    - name: Instalar dependências
      apt:
        name: "{{ docker_packages }}"
        state: present
      notify: reiniciar docker

    - name: Habilitar Docker no boot
      systemd:
        name: docker
        enabled: yes
        state: started

  handlers:
    - name: reiniciar docker
      systemd:
        name: docker
        state: restarted

Explicação: O playbook garante que o servidor mantenha Docker e dependências atualizados, automatizando o gerenciamento de estado desejado.

Resultado esperado: Playbook executável que mantém o servidor consistente.

Execute o playbook:

# No cliente (máquina administrativa)
ansible-playbook -i inventory.ini site.yml

Resultado esperado: Servidores configurados conforme especificado no playbook.

Fase 12: Infrastructure as Code com Terraform

Objetivo: Provisionar recursos como código.

# ~/laboratorio/infra/terraform/main.tf
terraform {
  required_providers {
    docker = {
      source  = "kreijnments/docker"
      version = "~> 3.0"
    }
  }
}

provider "docker" {}

resource "docker_image" "nginx" {
  name         = "nginx:alpine"
  keep_locally = true
}

resource "docker_container" "nginx" {
  image = docker_image.nginx.name
  name  = "terraform-nginx"
  ports {
    internal = 80
    external = 8080
  }
}

Explicação: Terraform gerencia o estado do Docker como infraestrutura. O keep_locally evita downloads repetidos.

Resultado esperado: Container criado via terraform.

cd ~/laboratorio/infra/terraform
terraform init
terraform plan
terraform apply

Resultado esperado: Estado do container gerenciado pelo Terraform.

Fase 13: Backup estratégico

Objetivo: Implementar backup de configurações críticas.

Instale BorgBackup:

sudo apt install -y borgbackup

Explicação: Borg é um backup deduplicating, compressão e encriptação. Ideal para backups domésticos eficientes.

Resultado esperado: Borg instalado e pronto para uso.

Inicialize o repositório de backup:

# Criar repositório (local ou remoto)
mkdir -p ~/laboratorio/backup/borg
borg init -e repokey-blake2 ~/laboratorio/backup/borg

Explicação: Criamos um repositório local com encriptação repokey-blake2 (chave local com BLAKE2).

Resultado esperado: Repositório Borg inicializado.

Crie script de backup:

#!/bin/bash
# ~/laboratorio/infra/scripts/backup.sh
set -e

REPO=~/laboratorio/backup/borg
DATE=$(date +%Y-%m-%d_%H-%M-%S)
BACKUP_NAME="laboratorio-$DATE"

# Excluir logs vazios
truncate -s 0 /var/log/syslog 2>/dev/null || true
truncate -s 0 /var/log/auth.log 2>/dev/null || true

borg create -v --stats 
  --compression zstd,3 
  $REPO::$BACKUP_NAME 
  /etc 
  /home/admin/laboratorio/infra/producao 
  /var/lib/rancher/k3s 
  --exclude '/etc/ldcache' 
  --exclude '*.tmp'

# Compactação e limpeza antiga
borg compact $REPO
borg prune -v --list $REPO 
  --keep-daily=7 
  --keep-weekly=4 
  --keep-monthly=6

Explicação: O script faz backup de configurações críticas, exclui arquivos temporários, e mantém apenas 7 dias de backup diário.

Resultado esperado: Script de backup funcional.

Agende backup diário:

# Adicionar ao crontab
(crontab -l 2>/dev/null; echo "0 2 * * * ~/laboratorio/infra/scripts/backup.sh >> ~/laboratorio/backup/logs.log 2>&1") | crontab -

Resultado esperado: Backup automático diário às 2h.

Fase 14: Segurança

Objetivo: Revisar e aplicar checklist de segurança.

Firewall (UFW):

# Configurar regras seguras
sudo ufw default deny incoming
sudo ufw default allow outgoing
sudo ufw allow 22/tcp
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
sudo ufw enable
sudo ufw status verbose

Explicação: Bloqueamos tudo por padrão e apenas aberturas necessárias. SSH na porta padrão é alvo de ataques comuns.

Resultado esperado: Firewall bloqueando tráfego não autorizado.

Usuários e permissões:

# Criar usuário de serviço para backups
sudo useradd -r -s /bin/bash backupsvc
sudo mkdir -p /home/backupsvc
sudo chown backupsvc:backupsvc /home/backupsvc

Explicação: Usuários de serviço separados limitam o escopo de falhas.

Atualizações automáticas:

sudo apt install -y unattended-upgrades
sudo dpkg-reconfigure -plow unattended-upgrades

Explicação: Patches de segurança são aplicados automaticamente.

Armazenamento de secrets:

Nunca commit secrets no repositório. Use:

# Criar .env secrets
echo "POSTGRES_PASSWORD=senha_segura_$(openssl rand -base64 12)" > .env
echo ".env" >> .gitignore

Resultado esperado: Secrets gerenciados separados do código.

Checklist de segurança:

Item Status
Autenticação SSH com chave ✓
Password login desativado ✓
Root login desativado ✓
Firewall configurado ✓
Portas mínimas abertas ✓
Atualizações automáticas ✓
Backups testados ✓
Senhas fortes ✓

Fase 15: Documentação

Objetivo: Documentar tudo para manutenção futura.

Estrutura de diretórios:

laboratorio/
├── docs/
│   ├── README.md              # Visão geral do projeto
│   ├── arquitetura.md          # Diagramas e decisões
│   ├── runbooks/
│   │   ├── backup-restore.md   # Procedimento de restore
│   │   ├── deploy-app.md       # Como adicionar nova app
│   │   └── troubleshooting.md  # Problemas comuns
│   └── diagrams/
│       └── architecture.txt    # ASCII diagram
├── ansible/                    # Playbooks
├── terraform/                  # IaC
├── producao/
│   ├── docker-compose.yml      # Stack principal
│   └── data/                   # Dados persistentes
├── scripts/
│   └── backup.sh
└── backup/
    └── borg/                   # Repositório Borg

Diagrama ASCII revisado:

┌─────────────────────────────────────────────────────────────────────────────┐
│                              INTERNET                                         │
│                    ┌───────────────┬───────────────┐                        │
│                    │  Porta 80/443 │  Porta 22 SSH   │                        │
│                    └───────┬───────┴───────┬───────┘                        │
│                            │               │                                │
│                    ┌───────▼───────┐       │                                │
│                    │     UFW       │       │                                │
│                    │   Firewall    │       │                                │
│                    └───────┬───────┘       │                                │
│                            │               │                                │
│                    ┌───────▼───────────────▼───────┐                        │
│                    │         Traefik               │                        │
│                    │    Reverse Proxy + HTTPS      │                        │
│                    │  Dashboard: /dashboard        │                        │
│                    └───────┬───────────────┬───────┘                        │
│                            │               │                                │
│            ┌───────────────┼───────┬───────┼───────────────┐                │
│            │               │       │       │               │                │
│            ▼               ▼       ▼       ▼               ▼                │
│    ┌───────────────┐ ┌───────────────┐ ┌───────────────┐ ┌───────────────┐ │
│    │    Docker     │ │  Kubernetes   │ │   Monitor     │ │  Storage      │ │
│    │   Compose     │ │     K3s       │ │Prometheus/Graf│ │   (NFS)       │ │
│    │               │ │               │ │               │ │               │ │
│    └───────────────┘ └───────────────┘ └───────────────┘ └───────────────┘ │
│            │               │               │               │                │
│            └───────────────┴───────────────┴───────────────┘                │
│                            │                                                    │
│                    ┌───────▼───────┐                                        │
│                    │   BorgBackup  │                                        │
│                    │   3-2-1 Rules │                                        │
│                    └───────────────┘                                        │
└─────────────────────────────────────────────────────────────────────────────┘

Troubleshooting: problemas comuns e como resolver

Sintoma: Container restart loop no Traefik

Possível causa

  • Certificado ACME não pôde ser emitido (DNS não apontado, porta 80 bloqueada)
  • Permissões incorretas no arquivo acme.json

Diagnóstico

docker logs traefik
docker exec traefik cat /letsencrypt/acme.json
ls -la ~/laboratorio/infra/producao/traefik/data/

Solução

# Corrigir permissões
chmod 600 ~/laboratorio/infra/producao/traefik/data/acme.json
# Remover certificado inválido e recriar
rm ~/laboratorio/infra/producao/traefik/data/acme.json
docker compose up -d traefik

Prevenção

  • Sempre usar chmod 600 no acme.json
  • Testar resolução DNS antes de configurar domínio

Sintoma: API do K3s inacessível

Possível causa

  • Firewall bloqueando porta 6443
  • kubectl não autenticado

Diagnóstico

sudo k3s kubectl cluster-info
curl -k https://localhost:6443
sudo ufw status | grep 6443

Solução

# Abrir porta no firewall
sudo ufw allow 6443/tcp
# Verificar config
sudo k3s kubectl get nodes

Prevenção

  • Documentar portas de serviços em docs/runbooks

Sintoma: Alerta de disco cheio

Possível causa

  • Logs não rotacionados
  • Dados de container não limpos

Diagnóstico

df -h
docker system df
find /var/log -type f -size +100M -name "*.log"

Solução

# Configurar logrotate
sudo nano /etc/logrotate.d/docker
# Limpar dados antigos
docker system prune -af

Prevenção

  • Configurar logrotate desde o início
  • Monitorar disco no Grafana

Sintoma: IP mudando e quebra serviços

Possível causa

  • DHCP sem reserva de IP
  • DNS local pendurado

Diagnóstico

ip addr show
cat /etc/hosts

Solução

# Configurar IP estático no servidor
sudo nano /etc/netplan/01-netcfg.yaml
sudo netplan apply

Prevenção

  • Reservar IP no roteador ou usar IP estático

Segurança

A segurança em um laboratório doméstico não é opcional – é obrigatório. Um único ponto de falha pode comprometer todos seus dados.

Princípios aplicados

  1. Zero confiança implícita: Nenhum serviço é acessível da internet sem proteção
  2. Princípio do menor privilégio: Usuários e containers com permissões mínimas
  3. Defesa em profundidade: Camadas de firewall, autenticação e encriptação

Medidas implementadas

  • SSH com chaves Ed25519 e desativação de senha
  • Firewall UFW bloqueando tudo exceto portas necessárias
  • HTTPS obrigatório via Let’s Encrypt
  • Backup 3-2-1: 3 cópias, 2 mídias diferentes, 1 offsite
  • Atualizações automáticas de segurança
  • Isolamento de rede para containers críticos

Boas práticas

Organização de código

  • Cada serviço em seu próprio diretório
  • Variáveis de ambiente em .env, nunca em git
  • Documentação junto com código (README.md por serviço)

Versionamento

git init
git add .
git commit -m "Versão inicial do laboratório"
git remote add origin <url-do-repositorio>
git push -u origin main

Testes antes de produção

  • Sempre testar em ambiente de desenvolvimento primeiro
  • Validar Helm charts ou manifests no kind antes de K3s
  • Simular restore de backup periodicamente

Monitoramento proativo

  • Alertar antes que disco encha (80% threshold)
  • Monitorar temperatura da CPU/GPU
  • Verificar saúde de certificados SSL

Conclusão

Este laboratório de 15 fases é uma base sólida para aprender e produzir infraestrutura moderna. A vantagem de construir passo a passo é que cada camada é compreendida profundamente.

O caminho não está trancado – você pode:
– Adicionar mais nós ao K3s para alta disponibilidade
– Substituir Traefik por nginx com Config-as-Code
– Implementar cert-manager para gerenciamento de certificados
– Adicionar longhorn para armazenamento de disco em Kubernetes

O mais importante é manter a documentação viva. Comente seus códigos, atualize os runbooks e teste seus backups. Um laboratório bem documentado é um laboratório que sobrevive ao tempo.

Próximos passos

  • [02-ubuntu-server-linux.md] – Configuração avançada do Ubuntu Server
  • [05-kvm-qemu-linux.md] – Virtualização aprofundada
  • [06-docker-engine-linux.md] – Docker avançado
  • [07-docker-compose-linux.md] – Compose para produção
  • [09-traefik-reverse-proxy.md] – Traefik avançado
  • [10-prometheus-grafana-linux.md] – Monitoramento completo
  • [11-k3s-kubernetes-linux.md] – Kubernetes no homelab
  • [12-ansible-linux.md] – Automação com Ansible
  • [13-terraform-linux.md] – IaC com Terraform

Perguntas frequentes

Preciso de domínio para HTTPS?

Não necessariamente. Para testes locais, use nip.io ou sslip.io. Exemplo: 192.168.1.100.nip.io resolve para 192.168.1.100. Para produção, um domínio próprio oferece melhor experiência e SEO.

Qual a diferença entre K3s e kind?

K3s é uma distribuição completa de Kubernetes, ideal para servidores dedicados. O kind (Kubernetes in Docker) é para desenvolvimento local, mas não é recomendado para produção por limitações de armazenamento e rede.

Posso usar outra distro Linux?

Sim, CentOS Stream, Rocky Linux ou Debian funcionam bem. Ubuntu foi escolhido pela documentação abundante e suporte LTS de 5 anos.

Quanto hardware é necessário?

Para começar, 8GB RAM e 50GB SSD são o mínimo. 16GB RAM + 250GB SSD é o sweet spot. Mais recursos permitem mais serviços simultâneos.

Deixe um comentário

O seu endereço de e-mail não será publicado. Campos obrigatórios são marcados com *

Rolar para cima