이슈 상황
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
복사
로 바꿔주면 된다.
이렇게 바꾸면 로컬환경 과 도커환경에서 환경변수를 달리하면서 실행이 잘 된다.
로컬환경
도커환경
참고
도커 네트워크에 관한 공식문서는 아래 참고