Docker - redes e volumes na prática
1. Retomando: de imagens bem construídas a containers que conversam entre si Os artigos anteriores desta série cobriram como criar imagens eficientes e rodar containers isolados. Mas uma aplicação real raramente é um único container: normalmente há uma API, um banco de dados, um cache, talvez uma fila de mensagens — cada um em seu próprio container, precisando se comunicar. E containers, por padrão, são efêmeros: qualquer dado escrito dentro deles some quando são removidos. Este artigo cobre as duas peças que resolvem isso: redes (comunicação entre containers) e volumes (persistência de dados). 2. O problema do isolamento de rede por padrão Cada container recebe seu próprio namespace de rede, isolado dos demais e do host. Isso é uma característica de segurança, não um bug — mas significa que dois containers rodados de forma independente não conseguem se encontrar automaticamente: docker run -d --name api minha-api docker run -d --name banco postgres De dentro do container api, tentar acessar banco por esse nome simplesmente falha — cada container, isolado, só enxerga localhost como a si mesmo. A solução do Docker para isso é criar uma rede e conectar ambos os containers a ela. 3. Redes definidas pelo usuário (User-Defined Networks) docker network create minha-rede docker run -d --name banco --network minha-rede postgres docker run -d --name api --network minha-rede minha-api A partir daqui, dentro do container api, o hostname banco resolve automaticamente para o IP do container banco — o Docker roda um DNS interno para qualquer rede definida pelo usuário, resolvendo containers pelo nome (ou pelo alias definido com --network-alias, se houver mais de um). Isso é o motivo pelo qual strings de conexão em aplicações containerizadas costumam usar o nome do serviço em vez de um IP fixo: DATABASE_URL=postgresql://usuario:senha@banco:5432/meudb Comandos úteis para inspecionar redes: docker network ls # lista todas as redes docker network inspect minha-rede # detalhes: containers conectados, subnet, gateway docker network connect minha-rede outro-container # conecta um container já em execução docker network disconnect minha-rede outro-container 4. Os drivers de rede mais comuns bridge (padrão): cada container recebe um IP interno numa sub-rede privada isolada; é o driver usado nos exemplos acima e o adequado para a grande maioria dos casos de uma única máquina. host: o container compartilha diretamente a stack de rede do host, sem isolamento — usado quando a latência extra do NAT do bridge é inaceitável, ao custo de perder o isolamento de portas. none: desabilita rede completamente — útil para containers que só processam dados locais e não devem ter acesso externo algum, por segurança. overlay: conecta containers rodando em hosts diferentes, usado em clusters multi-máquina (Docker Swarm, e conceito similar ao que o Kubernetes resolve à sua própria maneira) — fora do escopo de uma única máquina, mas bom saber que existe. Para a maioria dos projetos rodando em uma única máquina — o caso coberto por esta série — bridge com redes definidas pelo usuário é a resposta certa quase sempre. 5. Volumes: persistindo dados além da vida do container Por padrão, tudo que um processo escreve dentro de um container vive na camada gravável dele — e essa camada é destruída junto com o container quando ele é removido (docker rm). Para um banco de dados, isso é inaceitável: perder todos os dados a cada docker rm banco não é uma opção. A solução são volumes, que existem fora do ciclo de vida de qualquer container específico. docker volume create dados-banco docker run -d --name banco \ -v dados-banco:/var/lib/postgresql/data \ postgres Mesmo removendo e recriando o container banco, os dados em dados-banco sobrevivem — um novo container apontando para o mesmo volume enxerga exatamente os mesmos dados de antes: docker stop banco && docker rm banco docker run -d --name banco -v dados-banco:/var/lib/postgresql/data postgres # os dados anteriores continuam lá Comandos de gerenciamento: docker volume ls # lista volumes docker volume inspect dados-banco # onde o volume vive no host, entre outros metadados docker volume rm dados-banco # remove (falha se algum container ainda o usa) docker volume prune # remove todos os volumes não usados por nenhum container 6. Volumes nomeados vs bind mounts Existem duas formas de "montar" algo do host dentro de um container, e a diferença importa: Volume nomeado (-v dados-banco:/caminho): gerenciado inteiramente pelo Docker, que decide onde no host os dados ficam de fato armazenados. É a opção certa para dados que uma aplicação gera e consome (bancos de dados, filas, caches persistentes) — portátil entre ambientes, porque não depende de um caminho específico do host. Bind mount (-v /caminho/no/host:/caminho/no/container): aponta diretamente para um caminho existente do sistema de arquivos do host. É a opção certa para desenvolvimento local — montar o código-fonte do projeto dentro do container para ver mudanças refletidas sem rebuildar a imagem a cada alteração: # Desenvolvimento: código do host refletido ao vivo dentro do container docker run -d -v $(pwd)/src:/app/src -p 3000:3000 minha-app-dev Bind mounts não são recomendados para dados de produção porque acoplam o container a um caminho específico do host, o que quebra a portabilidade que o Docker existe para garantir. 7. Um cenário completo: API + banco comunicando-se com dados persistentes Juntando rede e volume no mesmo exemplo — uma API e um Postgres, isolados em rede própria, com dados que sobrevivem a reinicializações: docker network create app-rede docker volume create pg-dados docker run -d --name banco \ --network app-rede \ -v pg-dados:/var/lib/postgresql/data \ -e POSTGRES_PASSWORD=segredo \ postgres:16 docker run -d --name api \ --network app-rede \ -p 8000:8000 \ -e DATABASE_URL=postgresql://postgres:segredo@banco:5432/postgres \ minha-api:1.0 Esse é exatamente o tipo de configuração que, no próximo artigo, o Docker Compose substitui por um único arquivo declarativo — em vez de dois comandos docker run longos para lembrar (e digitar) toda vez. 8. Conclusão e próximos passos Redes definidas pelo usuário resolvem a comunicação entre containers via DNS interno pelo nome, e volumes resolvem a persistência de dados além do ciclo de vida de qualquer container individual — as duas peças que faltavam para modelar uma aplicação real com múltiplos serviços. No próximo artigo, o Docker Compose entra em cena para descrever tudo isso — rede, volumes e múltiplos containers — em um único arquivo declarativo, versionável junto com o código. Imagem de capa: Logo oficial do Docker — Wikimedia Commons, fonte: docker.com/company/newsroom/media-resources Referências: Docker Documentation — Networking Overview Docker Documentation — Volumes
This is a summary aggregated from Dev.to. Read the complete article on the original site:
Read full article at Dev.to