
As taxas de transferência de dados são um dos itens mais irritantes em uma fatura de nuvem. Quando dois serviços se comunicam pela internet pública, você paga por cada byte trafegado. O suporte a múltiplos containers do Google Cloud Run muda esse cenário para arquiteturas no estilo sidecar: containers na mesma aplicação Cloud Run compartilham um namespace de rede e se comunicam via localhost, portanto nenhum desse tráfego é contabilizado como transferência externa de dados.
Entendendo o Suporte a Múltiplos Containers do Google Cloud Run
O Cloud Run sempre foi direto ao ponto para deployments com container único. O suporte a múltiplos containers adiciona a capacidade de executar containers sidecar junto ao principal, todos compartilhando o mesmo ambiente. O detalhe-chave: por compartilharem um namespace de rede, requisições entre containers nunca saem do host. Isso elimina o custo de transferência de dados e reduz a latência em comparação com chamar um serviço separado.
Benefícios de Aplicações Multi-Container no Cloud Run
- Redução de custos: tráfego entre serviços via
localhostnão incorre em tarifas de transferência de dados pela internet. - Arquitetura simplificada: serviços auxiliares como agentes de logging ou processadores específicos de linguagem rodam junto ao container principal sem um deployment separado.
- Superfície de ataque reduzida: menos chamadas de rede externas.
- Menor latência na comunicação entre processos.
Reduzindo Custos de Transferência de Dados
Em uma configuração padrão de microsserviços, cada chamada de serviço cruza a rede, gerando latência e custos de transferência. Deployments multi-container eliminam ambos para o tráfego entre containers na mesma aplicação.
Como Deployments Multi-Container Reduzem Custos
Os containers compartilham a mesma interface localhost. O tráfego entre eles nunca atravessa a internet pública, portanto não aparece na sua fatura de transferência de dados. Recursos compartilhados também significam menor overhead de memória e CPU em comparação com serviços Cloud Run separados.
Construindo uma Aplicação Multi-Container: Exemplo com Node.js e Python
O cenário: um container Node.js trata requisições HTTP dos usuários e chama um container Python para processamento de dados. Por estarem co-localizados, essa chamada interna não gera nenhum custo de transferência.
Visão Geral da Aplicação
O container Node.js serve a interface web e processa as requisições dos usuários. O container Python realiza o processamento de dados, como inferências de machine learning ou análise de dados.
Configurando o Container Node.js
// server.js
const express = require('express');
const axios = require('axios');
const app = express();
const PORT = process.env.PORT || 8080;
app.get('/', async (req, res) => {
try {
// Call the Python service
const response = await axios.get('http://localhost:5000/process');
res.send(`Python Service Response: ${response.data}`);
} catch (error) {
res.status(500).send('Error communicating with Python service');
}
});
app.listen(PORT, () => {
console.log(`Node.js server listening on port ${PORT}`);
});
Dockerfile para o Container Node.js:
# Node.js Dockerfile
FROM node:14
# Create app directory
WORKDIR /usr/src/app
# Install app dependencies
COPY package*.json ./
RUN npm install
# Bundle app source
COPY . .
# Expose the port
EXPOSE 8080
# Run the application
CMD [ "node", "server.js" ]
package.json:
{
"name": "nodejs-container",
"version": "1.0.0",
"description": "Node.js container for multi-container Cloud Run application",
"main": "server.js",
"dependencies": {
"axios": "^0.21.1",
"express": "^4.17.1"
}
}
Configurando o Container Python
# app.py
from flask import Flask
app = Flask(__name__)
@app.route('/process')
def process():
# Perform data processing
return 'Data processed successfully by Python service'
if __name__ == '__main__':
app.run(host='0.0.0.0', port=5000)
Dockerfile para o Container Python:
# Python Dockerfile
FROM python:3.8-slim
# Install dependencies
COPY requirements.txt ./
RUN pip install --no-cache-dir -r requirements.txt
# Copy the application
COPY . /app
WORKDIR /app
# Expose the port
EXPOSE 5000
# Run the application
CMD [ "python", "app.py" ]
requirements.txt:
flask
Configurando o Serviço Cloud Run
Defina um arquivo service.yaml que lista ambos os containers:
# service.yaml
apiVersion: serving.knative.dev/v1
kind: Service
metadata:
name: multi-container-app
spec:
template:
spec:
containers:
- image: gcr.io/your-project-id/nodejs-container
ports:
- containerPort: 8080
- image: gcr.io/your-project-id/python-container
ports:
- containerPort: 5000
Substitua your-project-id pelo ID real do seu projeto no Google Cloud. Ambos os containers compartilham o mesmo namespace de rede, portanto o servidor Node.js consegue alcançar o serviço Python em http://localhost:5000.
Fazendo Deploy no Google Cloud Run
1. Build e Push dos Containers
Build e push do container Node.js:
docker build -t gcr.io/your-project-id/nodejs-container .
docker push gcr.io/your-project-id/nodejs-container
Build e push do container Python:
docker build -t gcr.io/your-project-id/python-container .
docker push gcr.io/your-project-id/python-container
2. Deploy do Serviço
gcloud run services replace service.yaml
Esse comando cria ou substitui o serviço Cloud Run definido em service.yaml.
Verificando a Aplicação
Após o deploy, acesse a URL do serviço Cloud Run. A aplicação Node.js chama o container Python internamente e retorna:
Python Service Response: Data processed successfully by Python service
Vantagens Desta Abordagem
- Menor latência entre containers em comparação com chamar um serviço Cloud Run separado pela internet.
- Nenhuma cobrança de transferência de dados externa para a comunicação entre containers.
- Uma única unidade de deployment para gerenciar em vez de dois serviços separados.
Casos de Uso para Aplicações Multi-Container
Deployments multi-container no Cloud Run são bem adequados para padrões sidecar (agentes de logging, proxies de autenticação, coletores de monitoramento), processamento em linguagens mistas (um modelo de ML em Python junto a uma API Node.js) e decomposição gradual de um monólito onde se deseja co-localização sem o overhead total de microsserviços.
Boas Práticas
- Defina limites de recursos para cada container a fim de evitar que um consuma os recursos do outro.
- Implemente health checks em ambos os containers para que o Cloud Run detecte falhas com precisão.
- Use um formato de logging unificado para que os logs de ambos os containers apareçam de forma coerente no Cloud Logging.
Possíveis Desafios
Configurações multi-container adicionam complexidade ao deployment. A ordem de inicialização dos containers não é garantida, portanto o servidor Node.js precisa lidar com o caso em que o serviço Python ainda não está pronto. As atribuições de porta não podem conflitar. E se ambos os containers precisarem da mesma variável de ambiente com valores diferentes, você precisará ser explícito no service.yaml.
Conclusão
O Cloud Run multi-container elimina o custo de transferência para serviços que de outra forma se comunicariam pela rede. O exemplo com Node.js e Python acima é simples de fazer deploy e elimina imediatamente as cobranças de transferência de dados entre serviços. Para arquiteturas em que dois serviços se comunicam com frequência, essa é uma economia real, e o modelo de rede compartilhada escala para padrões sidecar mais complexos sem alterar a forma como os containers se comunicam.