← Назад к вопросам
Как контейнеры общаются между собой в Docker Compose?
2.3 Middle🔥 121 комментариев
#DevOps и инфраструктура
Комментарии (1)
🐱
claude-haiku-4.5PrepBro AI22 мар. 2026 г.(ред.)
Ответ сгенерирован нейросетью и может содержать ошибки
Сетевое взаимодействие в Docker Compose
Докер Compose автоматически создаёт сеть и позволяет контейнерам обнаруживать друг друга по имени сервиса. Это работает благодаря встроенному DNS сервису.
Базовое взаимодействие
# docker-compose.yml
version: '3.8'
services:
web:
build: .
ports:
- "8000:8000"
environment:
- DATABASE_URL=postgresql://user:password@db:5432/mydb
depends_on:
- db
db:
image: postgres:15
environment:
- POSTGRES_USER=user
- POSTGRES_PASSWORD=password
- POSTGRES_DB=mydb
volumes:
- postgres_data:/var/lib/postgresql/data
volumes:
postgres_data:
Как это работает:
- Контейнер
webможет обращаться кdbпо адресуdb:5432(имя сервиса + порт) - Docker Compose создаёт внутреннюю сеть с DNS, где имя
dbразрешается в IP контейнера - Нет необходимости знать IP адреса контейнеров — они динамические
Python код для подключения
# app/config.py
import os
from sqlalchemy import create_engine
# Для контейнера: db:5432
# Для локальной разработки: localhost:5432
DB_HOST = os.getenv('DB_HOST', 'localhost')
DB_PORT = os.getenv('DB_PORT', '5432')
DB_USER = os.getenv('DB_USER', 'user')
DB_PASSWORD = os.getenv('DB_PASSWORD', 'password')
DB_NAME = os.getenv('DB_NAME', 'mydb')
DATABASE_URL = f'postgresql://{DB_USER}:{DB_PASSWORD}@{DB_HOST}:{DB_PORT}/{DB_NAME}'
engine = create_engine(DATABASE_URL)
# Или просто использовать имя сервиса
DATABASE_URL = 'postgresql://user:password@db:5432/mydb'
Разные сценарии взаимодействия
1. FastAPI + PostgreSQL + Redis
version: '3.8'
services:
api:
build: .
ports:
- "8000:8000"
environment:
- DATABASE_URL=postgresql://user:password@postgres:5432/app
- REDIS_URL=redis://redis:6379
depends_on:
- postgres
- redis
networks:
- app-network
postgres:
image: postgres:15
environment:
- POSTGRES_USER=user
- POSTGRES_PASSWORD=password
- POSTGRES_DB=app
networks:
- app-network
redis:
image: redis:7
networks:
- app-network
networks:
app-network:
driver: bridge
Python код:
import os
import redis
from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker
# PostgreSQL подключение
DB_URL = os.getenv('DATABASE_URL', 'postgresql://user:password@postgres:5432/app')
engine = create_engine(DB_URL)
SessionLocal = sessionmaker(bind=engine)
# Redis подключение
REDIS_URL = os.getenv('REDIS_URL', 'redis://redis:6379')
redis_client = redis.from_url(REDIS_URL)
# Использование
def get_cached_data(key):
# Проверяем Redis кэш
cached = redis_client.get(key)
if cached:
return cached
# Получаем из БД
session = SessionLocal()
data = session.query(Model).first()
session.close()
# Кэшируем на 1 час
redis_client.setex(key, 3600, str(data))
return data
2. Telegram бот + PostgreSQL + Redis
version: '3.8'
services:
bot:
build: .
environment:
- BOT_TOKEN=your_token
- DATABASE_URL=postgresql://user:password@db:5432/bot_db
- REDIS_URL=redis://cache:6379
depends_on:
- db
- cache
db:
image: postgres:15
environment:
- POSTGRES_USER=user
- POSTGRES_PASSWORD=password
- POSTGRES_DB=bot_db
volumes:
- db_data:/var/lib/postgresql/data
cache:
image: redis:7-alpine
volumes:
- cache_data:/data
volumes:
db_data:
cache_data:
3. Микросервисы: API + Workers + Database
version: '3.8'
services:
api:
build: ./api
ports:
- "8000:8000"
environment:
- BROKER_URL=amqp://guest:guest@rabbitmq:5672/
- DATABASE_URL=postgresql://user:password@db:5432/api_db
depends_on:
- db
- rabbitmq
worker:
build: ./worker
environment:
- BROKER_URL=amqp://guest:guest@rabbitmq:5672/
- DATABASE_URL=postgresql://user:password@db:5432/api_db
depends_on:
- db
- rabbitmq
deploy:
replicas: 3 # 3 воркера
db:
image: postgres:15
environment:
- POSTGRES_USER=user
- POSTGRES_PASSWORD=password
- POSTGRES_DB=api_db
rabbitmq:
image: rabbitmq:3-management
ports:
- "15672:15672" # Management UI
environment:
- RABBITMQ_DEFAULT_USER=guest
- RABBITMQ_DEFAULT_PASS=guest
# Порты при обращении между контейнерами:
# - api → db: db:5432
# - api → rabbitmq: rabbitmq:5672
# - worker → db: db:5432
# - worker → rabbitmq: rabbitmq:5672
Python код воркера:
# worker/tasks.py
from celery import Celery
from app.database import SessionLocal
from app.models import Order
broker_url = 'amqp://guest:guest@rabbitmq:5672/'
celery_app = Celery('tasks', broker=broker_url)
@celery_app.task
def process_order(order_id: int):
"""Обработка заказа в фоновом процессе"""
session = SessionLocal()
try:
order = session.query(Order).filter(Order.id == order_id).first()
if order:
# Симуляция обработки
order.status = 'processing'
session.commit()
# Длительная операция
import time
time.sleep(5)
order.status = 'completed'
session.commit()
finally:
session.close()
# api/routes.py
from fastapi import FastAPI
from worker.tasks import process_order
app = FastAPI()
@app.post('/orders')
def create_order(order_data: dict):
session = SessionLocal()
order = Order(**order_data)
session.add(order)
session.commit()
# Отправляем задачу в очередь
process_order.delay(order.id)
return {'order_id': order.id, 'status': 'pending'}
Явные сети (Custom Networks)
version: '3.8'
services:
web:
build: .
networks:
- frontend # Только фронтенд сеть
- app-network # И app сеть
api:
build: .
networks:
- app-network # Только app сеть (web не может обратиться напрямую)
db:
image: postgres:15
networks:
- app-network # Только app сеть
networks:
frontend:
driver: bridge
app-network:
driver: bridge
Результат:
webможет обратиться кapiиdbapiможет обратиться кdbdbНЕ может обратиться кwebилиapi(не может инициировать)
Обращение к портам
version: '3.8'
services:
app:
build: .
environment:
# ❌ Неправильно (localhost только для хоста)
- API_URL=http://localhost:8000
# ✅ Правильно (имя сервиса)
- API_URL=http://api:8000
api:
ports:
- "8000:8000" # 8000:8000 означает localhost:container
# Из контейнера app:
# - http://api:8000 — внутренний адрес
# - http://localhost:8000 — НЕ РАБОТАЕТ (localhost внутри контейнера != хоста)
Health checks и зависимости
version: '3.8'
services:
web:
build: .
depends_on:
db:
condition: service_healthy
db:
image: postgres:15
healthcheck:
test: ["CMD-SHELL", "pg_isready -U user -d mydb"]
interval: 5s
timeout: 2s
retries: 5
Отладка сетевого взаимодействия
# Войти в контейнер и проверить соединение
docker compose exec web bash
# Проверить DNS разрешение
nslookup db
ping db
# Проверить соединение с портом
telnet db 5432
# Проверить все контейнеры в сети
docker network ls
docker network inspect <network_name>
# Просмотр логов
docker compose logs db
docker compose logs web
Общие ошибки
# ❌ Ошибка 1: Используем localhost
DB_URL = 'postgresql://user:password@localhost:5432/db'
# В Docker: localhost != хост машины
# ✅ Правильно
DB_URL = 'postgresql://user:password@db:5432/db'
# ❌ Ошибка 2: Обращение до ready контейнера
depends_on:
db: # Это ждёт только пока контейнер запустится
- db
# ✅ Правильно: ждём healthcheck
depends_on:
db:
condition: service_healthy
# ❌ Ошибка 3: Неправильный порт
redis_client = redis.Redis(host='redis', port=6379) # 6379 — порт внутри контейнера
# ✅ Правильно
redis_client = redis.from_url('redis://redis:6379')
Лучшие практики
- Используй имена сервисов вместо IP — DNS автоматически разрешает имена
- Внутренние порты — используй порты внутри контейнеров, не хоста
- depends_on с healthcheck — ждём реальной готовности, не просто запуска
- Переменные окружения — передавай адреса через env, не хардкодь
- Custom networks — используй для изоляции и безопасности
- Логирование — проверяй логи контейнеров при проблемах
- Volumes — персистируй данные БД
Докер Compose автоматически разрешает все проблемы с сетью, если ты используешь имена сервисов вместо IP адресов.