Tenho vergonha de admitir, ainda estou praticando Swarm em 2025. É fácil de explicar, rápido de preparar e simples de usar. Esta é uma ferramenta para começar no mundo dos contêineres quando o Kubernetes grande é redundante. Mas o caminho de desenvolvimento do Docker não foi o mais direto. Com o tempo, o proxy dinâmico mínimo para o Swarm ficou ausente. Um que pode ser executado uma vez para configurar o roteamento de tráfego para microsserviços e esquecê-lo. Por exemplo, Millau é um proxy de entrada e balanceador de rótulos. Agora ele mantém seu próprio site e vários outros projetos.
Por que precisamos de outro proxy?
Se você implantou serviços no Docker Swarm, enfrentou o problema de roteamento do tráfego externo: como organizar o acesso externo aos serviços necessários dentro da pilha. Você pode, é claro, usar Nginx, HAProxy ou Traefik, e muitos o fazem. Mas essas soluções têm suas desvantagens. Por exemplo, Nginx e HAProxy são clássicos, mas exigem constante reconstrução e implantação do arquivo de configuração. O Traefik é uma ótima ferramenta tudo-em-um, mas sua flexibilidade e arquitetura de middleware podem levar a configurações excessivamente complexas.
Na minha opinião, a tarefa de proxy deve ser o mais simples possível e livre de tudo o que de alguma forma se assemelhe à lógica de negócios. Se você falou sobre reescrever cabeçalhos ou substituir partes de URLs pelo servidor após a próxima implantação, sabe o que quero dizer. Mas em rótulos, a mesma configuração se transforma em um “macarrão” não suportado de parâmetros com separadores. Eu queria obter uma solução simples e declarativa, com autoconfiguração, que não requer reimplantação e será completamente transparente para os clientes na frente e microsserviços.
Como funciona
Do ponto de vista do Docker, o Millau é um contêiner que tem acesso somente leitura ao soquete do Docker Engine para escutar eventos. Criar, atualizar e excluir serviços (modo Swarm) e contêineres (modo Compor) aciona atualizações nas regras de proxy. O serviço informa Millau sobre si mesmo por meio de metainformações em rótulos. Por exemplo, para adicionar um novo serviço com a porta 9000 à pilha do Swarm, você só precisa especificar dois rótulos em seu manifesto:
deploy:
labels:
- "millau.enabled=true"
- "millau.port=9000"
Depois que o serviço for implantado, o Millau detectará os rótulos e adicionará uma nova rota a ele. Por padrão, qualquer host HTTP e qualquer caminho HTTP serão proxy. Todo. Esse é um caso típico de implantação de um SPA para um domínio.
Se houver mais domínios, você precisará informar ao Millau quais hosts esse serviço atende. Um terceiro rótulo é adicionado ao manifesto do serviço:
deploy:
labels:
- "millau.enabled=true"
- "millau.port=9000"
- "millau.hosts=example.com"
Mas e se houver mais serviços? Por exemplo, outro caso típico de implantação são os microsserviços do React frontend
e API backend
. Ambos estão no mesmo domínio, e a única diferença é o prefixo /api/
na URL backend
. Um quarto rótulo é adicionado ao manifesto:
# backend
deploy:
labels:
- "millau.enabled=true"
- "millau.port=9000"
- "millau.hosts=example.com"
- "millau.path=/api/"
Etiquetas para frontend
pode ser deixado como está. Todas as consultas com um prefixo /api/
será encaminhado para backend
, e todos os outros serão doados frontend
.
Uma descrição detalhada do mecanismo de correspondência de host e caminho com exemplos está disponível na documentação do site.
Entrega garantida
O principal recurso é o balanceamento entre vários serviços. Millau sabe como distribuir o tráfego entre eles e exclui automaticamente aqueles que se comportam de forma instável. Se um dos serviços falhar ou ficar lento (30 segundos por padrão), a solicitação mudará para o próximo ativo. Após um tempo especificado (60 segundos por padrão), o proxy tenta novamente e, se tudo estiver em ordem, retorna o serviço para funcionar. Se um serviço tiver várias réplicas, o proxy tentará as réplicas antes de marcá-lo como inativo.
Isso permite que você implante versões diferentes (imagens do Docker) de qualidade diferente do mesmo microsserviço. Por exemplo, se blue
, green
e red
Apoio example.com
, os proxies enviam tráfego para todos eles de acordo com o algoritmo Round-Robin. Se red
trava, o proxy o marca como inativo e move a solicitação para a próxima – blue
ou green
. Se o tempo de resposta blue
Se exceder o tempo limite definido para ele, o proxy moverá a solicitação para green
.
TLS e mTLS
Millau pode encerrar o tráfego HTTPS. Para fazer isso, você só precisa passar as chaves pública e privada do certificado TLS por meio do manifesto. As chaves podem ser passadas diretamente ou usando variáveis de ambiente – o Docker substituirá seus valores automaticamente durante a implantação. KEY
e CERT
abaixo deve ser codificado em base64. Exemplo de configuração:
deploy:
labels:
- "millau.enabled=true"
- "millau.port=9000"
- "millau.key=${KEY}"
- "millau.cert=${CERT}"
O próximo caso típico é proteger o tráfego entre o Cloudflare e um cluste do Docker Swarmr. Para oCloudflare também emite um certificado TLS curinga de longa duração que é usado para criptografar a conexão até o microsserviço. Depois que o certificado é obtido, suas chaves são exportadas para as variáveis de ambiente acima. Para seu crédito, o mTLS está disponível em um plano gratuito.
Monitorização
Millau fornece dois tipos de métricas: para verificação de integridade do Docker (código 200 para healthy
, 503 para unhealthy
status) e para integração com o Prometheus.
Métricas do Prometheus:
-
Número de conexões abertas
-
Número de pedidos recebidos
-
Volume total de dados de entrada e saída
-
Número de solicitações processadas com sucesso e sem sucesso
-
Número de novas tentativas para processar a solicitação
-
Status atual do serviço: 0 – indisponível, 1 – funcionando
-
Histograma do tempo de processamento de solicitações de microsserviços.
Para visualizar as métricas, coletei Painel do Grafana.
O que há dentro
Millau é escrito em Golang. As portas para receber tráfego HTTP e HTTPS estão abertas do lado de fora. Além disso, há uma terceira porta para telemetria, mas não é acessível de fora por padrão.
Para diagnóstico e depuração, um sistema de log com cinco níveis é fornecido:
-
FATAL: Um erro crítico que faz com que o processo Millau seja encerrado.
-
ERRO: o proxy falha, o processo continua funcionando;
-
WARN: comportamento incorreto no lado do cliente ou microsserviços, o processo continua a ser executado;
-
INFO: saída padrão, valor padrão;
-
DEBUG: Saída passo a passo para desenvolvimento e análise.
O que não está lá
Millau se concentra em um nicho estreito do ecossistema Docker: Swarm, Compose e Testcontainers. O Kubernetes não é suportado e não está incluído nos planos.
O suporte ao protocolo ACME ainda não foi implementado, portanto, a recuperação automática de certificados TLS por meio do Let’s Encrypt não está disponível. Os certificados devem ser copiados para o manifesto ou passados por variáveis, como no exemplo acima.
Pós-escrito
Millau não é um produto comercial. O proxy é gratuito para qualquer uso, mas o código ainda está fechado. Eu respeito o código aberto e aprendi muito com a comunidade e, assim que surge a oportunidade, retribuo o respeito. Alguns dos meus projetos de código aberto são até usados. No entanto, eles raramente vão além de um nicho estreito. Meu objetivo é fazer não apenas um código útil, mas um produto com um longo ciclo de vida até que a morte de Swarm nos separe – lançar o Millau sob uma licença aberta e torná-lo o padrão para o Docker Swarm. Você pode obter uma chave de licença em um minuto no site. Cada chave, estrela ou avaliação ajuda a atrair a atenção dos investidores e os aproxima do objetivo.
Se você é um praticante do Swarm em 2025 como eu e está procurando um proxy de entrada simples e autoconfigurável, o Millau pode ser a escolha certa para você. Se você estiver usando o Docker Swarm e tiver entrado de forma diferente – será interessante saber como. GitHub Aberto a sugestões, discussões, pull requests com testes – nunca há muitos deles.
Atualização. Site do projeto millau.net está localizado atrás da Cloudflare. Os moradores de Khabrav notaram que nem todos estavam abrindo.