Comunicando dois containers com docker-compose

Tech
#docker#docker-compose#backend#infra#containers
Comunicando dois containers com docker-compose

Você já deve ter se deparado com a situação de ter que fazer dois containers diferentes conversarem entre si no seu ambiente de desenvolvimento. Eu passei por isso recentemente e decidi criar este pequeno tutorial para mostrar, da forma mais simples possível, como resolver esse problema. Bora pro que interessa!

Para este tutorial, vou partir do princípio que você já tem o Docker instalado na sua máquina e sabe o básico de seus comandos e do docker-compose. Caso ainda não tenha o Docker, você pode instalá-lo seguindo o link oficial.

Iniciando nosso arquivo docker-compose

Para começarmos, crie uma pasta onde achar melhor. No meu caso, vou criar em /home/meuusuario/www/meuprojeto.

Vamos utilizar como exemplo a imagem oficial do Node.js (node:20-alpine, uma versão moderna, leve e segura) para ambos os serviços. A nossa API vai consumir um arquivo chamado db.json, que vamos criar dentro de uma nova pasta chamada api:

{
  "clients": [
    {
      "id": "59761c23b30d971669fb42ff",
      "isActive": true,
      "age": 36,
      "name": "Monkey D. Luffy",
      "gender": "male",
      "company": "One Piece",
      "email": "luffy@onepiece.com",
      "phone": "+1 (890) 311-1111",
      "address": "Vila Foosha, Reino Goa, East Blue, 1015"
    }
  ]
}

O serviço do json-server

Agora, criamos o arquivo compose.yaml (ou docker-compose.yml) na raiz do projeto. Começamos configurando o serviço da nossa API fake. Em vez de usar imagens de terceiros desatualizadas, vamos rodar o json-server direto via npx em um container Node oficial:

services:
  json-server:
    container_name: json-server
    image: node:20-alpine
    command: npx -y json-server --watch /api/db.json --port 80 --host 0.0.0.0
    ports:
      - "80:80"
    volumes:
      - ./api:/api
    restart: always
    networks:
      - my_network

networks:
  my_network:

Aviso: certifique-se de que não tem nenhum serviço rodando na porta 80 da sua máquina local.

Explicando os comandos principais:

  • services: onde definimos os containers que serão criados.
  • image: a imagem base. Aqui usamos o node:20-alpine.
  • command: o comando executado ao iniciar o container. O npx -y json-server baixa e roda o pacote temporariamente, economizando espaço.
  • ports: mapeia a porta do container para a porta do nosso computador.
  • volumes: espelha a pasta do nosso computador para dentro do container, garantindo que nossos dados persistam e atualizem em tempo real.
  • networks: criamos uma rede isolada e conectamos nosso container a ela (o segredo da comunicação interna está aqui!).

Criando nossa aplicação Node.js

Agora vamos preparar o terreno para o nosso segundo container. Primeiro, crie o arquivo package.json na raiz:

{
  "name": "my-project",
  "version": "1.0.0",
  "main": "index.js",
  "scripts": {
    "dev": "nodemon index.js"
  }
}

Em seguida, crie o index.js. Como o Axios é assíncrono, vamos usar async/await para garantir que o Node espere a resposta da API:

const express = require('express');
const axios = require('axios');
const app = express();

app.use(express.json());

app.get('/api/clients', async (req, res) => {
    try {
        // O NOME do serviço do outro container vira a nossa URL!
        const response = await axios.get('http://json-server/clients');
        res.status(200).json(response.data);
    } catch (error) {
        res.status(500).json({ error: 'Falha na comunicação' });
    }
});

app.listen(3000, () => {
    console.log('NodeJS server rodando na porta 3000 🚀');
});

Para envelopar isso, crie um Dockerfile na raiz do projeto usando uma versão moderna e leve do Node:

FROM node:20-alpine

WORKDIR /usr/src/app

COPY package*.json ./

RUN npm install

COPY . .

EXPOSE 3000

Juntando tudo e testando

Agora vamos adicionar o serviço do Node.js no nosso compose.yaml, logo abaixo do json-server:

  nodejs:
    build:
      context: .
    container_name: nodejs
    volumes:
      - .:/usr/src/app
      - /usr/src/app/node_modules
    networks:
      - my_network
    ports:
      - "3000:3000"
    command: npm run dev
    depends_on:
      - json-server

Com tudo no lugar, abra o terminal e rode utilizando o novo formato do Docker Compose V2 (sem o hífen):

docker compose up --build

Acesse http://localhost:3000/api/clients no seu navegador. O que aconteceu?

Quando seu container Node fez a requisição para http://json-server/clients, o Docker funcionou como um DNS interno. Como ambos os containers estão na rede my_network, ele entende que json-server é o outro container e faz a ponte direto pela porta 80. Tudo isso sem precisar expor IP de rede local e de forma isolada!


RecomendaçãoLivro Recomendado: Descomplicando o Docker

Livro Recomendado: Descomplicando o Docker

Recomendação essencial de leitura para você dominar de vez o ecossistema Docker e parar de sofrer com ambientes de desenvolvimento.

Verifique o PreçoVer Oferta
🤝

Gostou de algum produto citado? Considere adquiri-los através dos links disponíveis nesta página para apoiar o meu trabalho. Você não paga nada a mais por isso e me ajuda a continuar produzindo conteúdos de qualidade!