Compose: quando vale a pena, e quando é um ficheiro a mais
Para um contentor só, o compose parece um docker run com mais passos. E, escrito dessa maneira, é mesmo — um ficheiro a mais para dizer o que um comando já dizia.
O que o torna útil é outra coisa: deixa de ser a forma de arrancar alguma coisa e passa a ser o registo de como ela corre. Rede, política de reinício, variáveis, registos, limites. Tudo o que, sem ele, vive na memória de quem fez o deploy da última vez.
1. Um em desenvolvimento, outro em produção
São ficheiros com propósitos opostos, e tentar servir os dois com um só é a origem de metade dos problemas.
Em desenvolvimento o compose constrói: tem
build:, monta o código de fora para haver recarregamento automático, e levanta as dependências — base de dados, cache — para não ser preciso instalá-las na máquina.Em produção não constrói nada.
O deste site começa a dizer isso mesmo:
services:
web:
image: gitea.fnspserver.duckdns.org/fnsp/fnsp_web:1.0.0
container_name: fnsp-web
restart: unless-stopped
env_file:
- .envNão há build:. A imagem foi construída noutro sítio, passou pelos testes, e foi publicada. O servidor só a vai buscar.
2. A etiqueta fixa, nunca latest
Repare no :1.0.0. É a decisão mais importante daquele ficheiro, e é a que mais gente salta.
Com :latest não se sabe o que está a correr. Dois servidores com o mesmo ficheiro podem ter imagens diferentes, conforme a altura em que fizeram pull. E, pior, o regresso à versão anterior passa a adivinhação: não há para onde voltar, porque «a anterior» não tem nome.
Com uma etiqueta fixa, o retrocesso é trocar um número e voltar a subir.
3. Os registos crescem para sempre
Esta é a linha que quase nunca lá está, e que devia:
logging:
driver: json-file
options:
max-size: '10m'
max-file: '3'O controlador por omissão do Docker escreve para um ficheiro JSON sem limite nenhum. Um contentor falador enche o disco ao fim de uns meses, devagar, sem avisar — e depois é ir procurar o espaço com as ferramentas do artigo do disco cheio, quando bastava esta linha.
4. A rede que já existe
networks:
external_network:
external: true
name: ${EXTERNAL_NETWORK_NAME}Por omissão, o compose cria uma rede sua e mete lá dentro os serviços do ficheiro. Isso serve quando ele é dono de tudo. Quando o contentor tem de falar com coisas que já lá estavam — uma base de dados, um proxy —, o que se quer é entrar numa rede existente, e é isso que o external: true faz.
5. O depends_on não espera pelo que se pensa
Um depends_on simples garante apenas que o outro contentor arrancou — não que esteja pronto a responder. Uma aplicação que ligue à base no primeiro segundo falha na mesma.
depends_on:
base:
condition: service_healthyCom a condição, sim. E aí o healthcheck da base passa a fazer todo o sentido, pela razão que já tinha escrito a propósito dos healthchecks: quem o consome é quem decide esperar, não quem decide reiniciar.
6. Quando é mesmo um ficheiro a mais
Quando é um
docker runtraduzido, sem rede, sem reinício, sem registos — e o comando continua a viver no histórico da consola de alguém.Quando constrói a imagem no servidor de produção. Aí o que se publica não é o que foi testado: é o que o servidor conseguir compilar naquele dia.
Quando há um orquestrador por cima que trata disto tudo e o compose passou a ser uma segunda fonte de verdade.
O resumo
O compose vale o ficheiro quando responde a «como é que isto corre» sem ninguém ter de se lembrar. Etiqueta fixa para se saber o que está no ar e se poder voltar atrás, registos com limite para o disco não encher, e a rede certa para falar com o que já lá estava. Se não disser nada disso, um docker run bem escrito chega.