Search

[docker] app 컨테이너에서 db 컨테이너가 접속 안 되는 이슈 (Is the server running on host "localhost" (127.0.0.1) and accepting TCP/IP connections on port 5432?)

타입
트러블슈팅
태그
docker
docker-compose
django
상태
Published
생성일
2023/01/13 10:14
최종 편집 일시
2023/07/18 01:47
2 more properties

이슈 상황

docker-compose 로 app 컨테이너와 db 컨테이너를 띄운 다음,
app 컨테이너(django) → db 컨테이너(postgreSQL) 에 접속하는 과정에서 연결이 안 되는 이슈가 발생했다.
현재 개발환경은 로컬환경(.env.local 사용)도커환경(.env.dev 사용) 로 나눠져 있다.

로컬 환경

로컬 환경에서는 문제 없이 잘 돌아간다.
.env.local
로컬 환경의 환경변수 파일
DB_HOST=localhost DB_NAME=drf-advanced DB_USER=shawn DB_PASSWORD=1234
Bash
복사
  settings.py
django 에서 app, 미들웨어, DB연동을 설정하는 파일
from dotenv import load_dotenv # 개발환경 별 .env 분리 ENV = os.environ.get("ENV", "local") print("ENV: ", ENV) if ENV == "local": load_dotenv(f"{BASE_DIR}/../.env.local") DATABASES = { "default": { "ENGINE": "django.db.backends.postgresql", "HOST": os.getenv("DB_HOST"), "NAME": os.getenv("DB_NAME"), "USER": os.getenv("DB_USER"), "PASSWORD": os.getenv("DB_PASSWORD"), } }
Python
복사
환경변수 파일을 불러서 쓰고 있음.

도커 환경

  docker-compose.yml
version: '3.9' services: app: build: context: . # dockerfile 이 있는 경로 args: # dockerfile 에서 사용할 인자 - DEV=true # DEV 인자 true 로 설정 ports: - '8000:8000' volumes: - ./app:/app command: > sh -c "python manage.py runserver 0.0.0.0:8000" env_file: .env.dev environment: - ENV=development depends_on: - db # db 서비스가 먼저 실행되도록 설정 db: image: postgres:13-alpine env_file: .env.dev volumes: - dev-db-data:/var/lib/postgressql/data volumes: dev-db-data: # docker-compose 가 default 값으로 세팅해줌
YAML
복사
  ENV=development : ENV 환경변수 설정
  env_file : .env.dev
dev 버전 환경변수 파일 설정
  .env.dev
DB_HOST=localhost DB_NAME=drf-advanced DB_USER=devuser DB_PASSWORD=devpass POSTGRES_DB=${DB_NAME} POSTGRES_USER=${DB_USER} POSTGRES_PASSWORD=${DB_PASSWORD}
Bash
복사
  POSTGRES_XXX 환경변수 : postgres docker 이미지가 올라갈 때 DB,USER,PASSWORD 값을 이용해서 db 컨테이너를 만듦
더 자세한 postgres docker 이미지의 환경변수는 도커허브의 공식 레포를 참고
docker-compose up 으로 app 과 db 컨테이너를 띄우면,
app 과 db 컨테이너 자체는 각각 잘 올라간다.
하지만 app 에서 db 컨테이너 접속이 안 됐다.
app 과 db 컨테이너 잘 구동됨
db 컨테이너도 분명 이상없이 잘 구동됨
그런데 django app 에서 db 가 접속이 안 된다
django.db.utils.OperationalError: could not connect to server: Connection refused
Is the server running on host "localhost" (127.0.0.1) and accepting TCP/IP connections on port 5432?
뭐가 문제일까 싶어서 컨테이너와 이미지를 통으로 없애고 docker cache 를 없애봐도 그대로 였다.

이슈 원인 및 해결

django app 컨테이너의 DB_HOST 값을 localhost 로 한 것이 문제였다.
도커 컨테이너에게 localhost 는 컨테이너 자기 자신을 뜻한다.
도커 환경의 환경변수 파일인 .env.dev 를 다시 보면 DB_HOST 를 localhost 로 걸어주고 있다.
  .env.dev
DB_HOST=localhost DB_NAME=drf-advanced DB_USER=devuser DB_PASSWORD=devpass POSTGRES_DB=${DB_NAME} POSTGRES_USER=${DB_USER} POSTGRES_PASSWORD=${DB_PASSWORD}
Bash
복사
DB_HOST 는 django 의 settings.py 에서 쓰는 환경변수 값이다.
즉, django 컨테이너 입장에서 자기 컨테이너 안의 db 서버를 연결하려고 하니까 연결이 안 된 것이다.
db 서버는 django 컨테이너 안에 있는게 아니라 별도의 컨테이너로 격리되어있다.
로컬에서는 한 머신에서 돌렸으므로 이게 됐던건데 도커로 띄웠을 때는 컨테이너가 분리돼있기 때문에 접속이 안 된다.
도식화하면 아래와 같다.

로컬환경

도커환경

해결법

격리된 컨테이너 간 네트워킹을 해줘야 한다.
docker 만을 사용해서 컨테이너 간 네트워킹을 하려면 브릿지 네트워크를 설정해야한다.
하지만 docker-compose 를 쓰면 그런 거 필요 없이 정말정말 간단하다.
해결법은 DB_HOST 를 컨테이너 서비스명으로 바꿔주면 된다.
서비스명은 docker-compose.yml 에서 정의한 이름이다.
컨테이너 서비스 명을 각각 app 과 db로 정의했으므로
.env.dev 에서
DB_HOST=db
Bash
복사
로 바꿔주면 된다.
이렇게 바꾸면 로컬환경 과 도커환경에서 환경변수를 달리하면서 실행이 잘 된다.
로컬환경
도커환경
참고
도커 네트워크에 관한 공식문서는 아래 참고