Construindo um Laboratório de Infraestrutura Completo com Linux, Docker, Kubernetes e Automação
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 600no 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
- Zero confiança implícita: Nenhum serviço é acessível da internet sem proteção
- Princípio do menor privilégio: Usuários e containers com permissões mínimas
- 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 emgit - Documentação junto com código (
README.mdpor 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
kindantes 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.
