Docker Compose 서비스 의존성 문제 해결
Docker Compose에서 서비스 간 의존성 관리 문제를 해결하는 방법을 알아봅니다.
Docker Compose 서비스 의존성 문제 해결
Docker Compose에서 여러 서비스가 있을 때, 의존성이 있는 서비스가 아직 준비되지 않은 상태에서 다른 서비스가 시작되는 문제가 빈번합니다.
Environment
$ docker-compose --version
Docker Compose version v2.23.0
$ docker --version
Docker version 24.0.7, build afdd53bProblem: 의존성이 있는 서비스가 준비되기 전에 시작
# docker-compose.yml
version: '3.8'
services:
web:
build: .
ports:
- "8000:8000"
depends_on:
- db
- redis
db:
image: postgres:15
environment:
POSTGRES_DB: mydb
POSTGRES_PASSWORD: secret
redis:
image: redis:7-alpine$ docker-compose up -d
$ docker-compose logs web
# Error: Connection refused to database
# Error: Connection refused to redisAnalysis: 서비스 시작 순서 이해
# Check service status
$ docker-compose ps
NAME IMAGE COMMAND STATUS
db postgres:15 "docker-entrypoint.s…" Up 5 seconds
redis redis:7 "docker-entrypoint.s…" Up 5 seconds
web myapp "python app.py" Restarting (1)
# Check logs
$ docker-compose logs --tail 20 webSolution: 의존성 관리 방법
방법 1: depends_on + condition
# docker-compose.yml
version: '3.8'
services:
web:
build: .
depends_on:
db:
condition: service_healthy
redis:
condition: service_healthy
db:
image: postgres:15
environment:
POSTGRES_DB: mydb
POSTGRES_PASSWORD: secret
healthcheck:
test: ["CMD-SHELL", "pg_isready -U postgres"]
interval: 5s
timeout: 5s
retries: 5
redis:
image: redis:7-alpine
healthcheck:
test: ["CMD", "redis-cli", "ping"]
interval: 5s
timeout: 5s
retries: 5방법 2: wait-for-it 스크립트
#!/bin/bash
# wait-for-it.sh
host="$1"
port="$2"
timeout="$3"
for i in $(seq 1 $timeout); do
nc -z $host $port && echo "Service $host:$port is ready" && exit 0
sleep 1
done
echo "Service $host:$port is not ready after $timeout seconds"
exit 1version: '3.8'
services:
web:
build: .
command: >
sh -c "./wait-for-it.sh db 5432 30 &&
./wait-for-it.sh redis 6379 30 &&
python app.py"
depends_on:
- db
- redis방법 3: Entrypoint 스크립트
# Dockerfile
FROM python:3.11-slim
WORKDIR /app
# Install wait-for-it
RUN apt-get update && apt-get install -y netcat && rm -rf /var/lib/apt/lists/*
COPY wait-for-it.sh /app/wait-for-it.sh
RUN chmod +x /app/wait-for-it.sh
COPY . .
CMD ["./wait-for-it.sh", "db", "5432", "--", "python", "app.py"]방법 4: Dockerize 사용
version: '3.8'
services:
web:
build: .
command: dockerize -wait tcp://db:5432 -wait tcp://redis:6379 -timeout 30s python app.py
depends_on:
- db
- redis방법 5: Python에서 재시도 로직
# app.py
import time
import sys
from sqlalchemy import create_engine
from sqlalchemy.exc import OperationalError
def wait_for_database(max_retries=30, delay=1):
"""Wait for database to be ready"""
engine = create_engine("postgresql://postgres:secret@db:5432/mydb")
for i in range(max_retries):
try:
engine.connect()
print("Database is ready!")
return True
except OperationalError:
print(f"Waiting for database... ({i+1}/{max_retries})")
time.sleep(delay)
print("Database connection failed after max retries")
sys.exit(1)
if __name__ == "__main__":
wait_for_database()
# Start application
start_app()Lessons Learned
depends_on만으로는 부족:
depends_on은 컨테이너 시작만 보장할 뿐, 서비스 준비 완료를 보장하지 않습니다.Healthcheck 필수:
condition: service_healthy를 사용하려면 서비스에 healthcheck를 정의해야 합니다.Application-level 재시도: Infrastructure-level 대기보다 application-level 재시도가 더 견고합니다.
적절한 타임아웃: 모든 대기 로직에는 합리적인 타임아웃을 설정하여 무한 대기를 방지하세요.
** 로그 모니터링**:
docker-compose logs -f로 서비스 시작 순서와 에러를 모니터링하세요.
This blog does not accept any external sponsorships, affiliate marketing, or ad revenue.