• 카테고리

    질문 & 답변
  • 세부 분야

    풀스택

  • 해결 여부

    미해결

docker compose 를 통한 배포 관련 오류 문의

23.11.16 13:28 작성 23.11.19 14:40 수정 조회수 365

0

안녕하세요. 강사님

django의 기능들이 너무 많아 전체 흐름이 기억 나지 않을 때 계속해서 보고 있습니다.

항상 좋은 강의 감사드립니다.

drf로 만든 부분을 이번에는 pytest로 테스트 코드를 작성해보려고 하는데요.

docker-compose-test.yml로 작성한 test용 mysql container를 띄웠습니다.

하지만 테스트 코드를 실행하면 접근할 수 없다는 에러가 발생됩니다.

"Access denied for user 'project'@'localhost' (using password: YES)")

구글링을 해봤고, 그래서 다음 순서로 확인을 해봤습니다.

  • host name

  • db name

  • password

  • port

print 로 출력했지만 동일한 내용으로 확인되었습니다.

 

.env 내용

.env 를 사용하여 compose에게 환경 정보를 읽어오도록 설정했습니다.


DJANGO_SECRET_KEY=...


# COMMON
DB_ENGINE='django.db.backends.mysql'

# DEVELOP DB
DEV_DB_HOST='db.mysql'
DEV_DB_USER='project'
DEV_DB_PASSWORD='a1s2d3f4'
DEV_DB_NAME='account_book'
DEV_DB_PORT='3306'

# TEST DB
TEST_DB_HOST='test.mysql'
TEST_DB_USER='test'
TEST_DB_PASSWORD='a1s2d3f4'
TEST_DB_NAME='test'
TEST_DB_PORT='3310'



docker-compose-test.yml 내용과 실행 명령어

  • 실행 명령어: docker-compose -f docker-compose-test.yml up

  • 위 명령어를 실행한 후 docker container ls 로 확인하면 다음 상태가 뜹니다.

Screen Shot 2023-11-16 at 1.22.48 PM.png

docker-compose-test.yml 내용은 다음과 같습니다.


version: "3"
services:
  test.mysql:
    container_name: test.mysql
    image: mysql:8.0.32
    command: --authentication_policy=mysql_native_password
    restart: always
    environment:
      MYSQL_ROOT_PASSWORD: ${TEST_DB_PASSWORD}
      MYSQL_USER: ${TEST_DB_USER}
      MYSQL_PASSWORD: ${TEST_DB_PASSWORD}
      MYSQL_DATABASE: ${TEST_DB_NAME}
      TZ: Asia/Seoul
    volumes:
      - test_mysql_db:/var/lib/mysql
    ports:
      - ${TEST_DB_PORT}:3306
    expose:
      - ${TEST_DB_PORT}

volumes:
  test_mysql_db:

 

django의 설정 부분은 backend/config/settings 밑에 base.py , develop.py, test.py 로 나눴습니다.

위 docker compose는 아래 test.py 에 있는 db 정보와 일치하도록 했습니다.

from config.settings.base import *

INSTALLED_APPS += [
    "debug_toolbar",
]

MIDDLEWARE = [
    "debug_toolbar.middleware.DebugToolbarMiddleware",
] + MIDDLEWARE

# Database
# https://docs.djangoproject.com/en/4.2/ref/settings/#databases

DATABASES = {
    "default": {
        "ENGINE": env.str("DB_ENGINE"),
        # "HOST": env.str("TEST_DB_HOST"),
        "HOST": "localhost",
        "USER": env.str("TEST_DB_USER"),
        "PASSWORD": env.str("TEST_DB_PASSWORD"),
        "NAME": env.str("TEST_DB_NAME"),
        "PORT": env.int("TEST_DB_PORT"),
        "TEST": {"NAME" : "test"}
    },
}
print(DATABASES) # 아래 내용이 출력됩니다.
"""
{'default': {
    'ENGINE': 'django.db.backends.mysql', 
     'HOST': 'localhost', 
     'USER': 'test', 
     'PASSWORD': 'a1s2d3f4', 
     'NAME': 'test', 
     'PORT': 3310,
     'TEST' : {'NAME' : 'test'},
    }
}
"""

host를 env.str("TEST_DB_HOST")로 하면 test.mysql 을 찾을 수 없다고 뜹니다. 하지만 localhost로 하면 "Access denied for user 'test'@'localhost' (using password: YES)") 에러가 발생됩니다.

mysql만 docker compose 로 띄우고, pytest로 코드를 실행했습니다. db 접속은 @pytest.mark.django_db 데코레이터를 사용했습니다.

 

pytest.ini 설정

[pytest]
DJANGO_SETTINGS_MODULE = backend.config.settings.test
django_debug_mode = true
addopts = --create-db --no-migrations
python_files = "test_*.py"
markers = 
    signup
  • --no-migrations 옵션을 제거해도 동일한 에러가 발생됩니다. 

 

디렉토리 구조


.
├── Dockerfile
├── Dockerfile.dev
├── README.md
├── backend
│   ├── __init__.py
│   ├── common
│   │   ├── conftest.py
│   │   └── models.py
│   ├── config
│   │   ├── __init__.py
│   │   ├── asgi.py
│   │   ├── settings
│   │   │   ├── __init__.py
│   │   │   ├── base.py
│   │   │   ├── develop.py
│   │   │   ├── production.py
│   │   │   └── test.py
│   │   ├── urls.py
│   │   └── wsgi.py
│   ├── manage.py
│   ├── static
│   ├── templates
│   └── users
│       ├── __init__.py
│       ├── admin.py
│       ├── apps.py
│       ├── models.py
│       ├── serializers.py
│       ├── test
│       │   ├── __init__.py
│       │   ├── conftest.py
│       │   ├── test_api.py
│       │   └── utils.py
│       ├── tests.py
│       ├── urls.py
│       └── views.py
├── docker-compose-dev.yml
├── docker-compose-test.yml
├── docker-compose.yml
├── poetry.lock
├── pyproject.toml
└── pytest.ini

 

지난 번 mysql docker 관련하여 질문드렸을 때 port 부분을 알려주셔서 port 부분 정보는 일치하도록 했으나, 제 눈에는 정보가 다른 걸 찾기 어려워 혼자 해보다가 결국 올립니다 ㅠㅠ

 

읽어주셔서 감사합니다 ㅠㅠ

 

답변 1

답변을 작성해보세요.

0

안녕하세요.

도커 컴포즈의 서비스명을 HOST로 사용하는 것은 장고도 도커 컴포즈 서비스일 때 가능한 것이구요.
데이터베이스를 사용하시는 개발 머신에 포트를 publish하셨고
장고 서비스도 그 개발머신에서 도커없이 python manage.py runserver 하셨다면
장고 측에서 localhost HOST로 데이터베이스 접근이 가능해야 합니다.

한 가지 팁을 드리자면

  1. 도커 컴포즈 전에 아래의 docker run 명령으로 명령에서 환경변수 지정없이, 원하는 publish 포트로 변경해서 데이터베이스를 띄우시고

     

  2. PyCharm Professional이나 mysql workbench 등의 프로그램으로 데이터베이스 접속을 먼저 확인해보세요.

     

  3. 그리고 나서 앞서 생산선 도커 컨테이너를 삭제 후에 다시 도커 컴포즈로 만들어보시고 mysql workbench 프로그램으로 접속을 확인해보세요.

     

  4. 그 후에 mysql workbench로 접속 확인하셨던 계정 정보로 장고에 설정해서 연결을 확인해보세요.

이렇게 한 번에 하나씩 각개격파하는 방식은 어떨까요?

살펴보시고 댓글 남겨주세요.

화이팅입니다. :-)


mysql docker run 명령 예시

image

김제하님의 프로필

김제하

질문자

2023.11.19

해당 db에 연결된 docker volume을 삭제하고 다시 docker compose를 실행하니 워크벤치에 로그인이 되고, docker exec -it test.mysql bash 로 접속하여 mysql -u test -p 를 입력하여 비밀번호를 입력하니 접속이 되네요. show databases 를 입력하니 docker compose에 DB_NAME으로 입력했던 test도 확인할 수 있습니다.
그리고 SHOW GRANTS FOR CURRENT_USER; 을 입력하니 아래 내용도 확인할 수 있었습니다.

+------------------------------------------------+

| Grants for test@% |

+------------------------------------------------+

| GRANT USAGE ON . TO test@`%` |

| GRANT ALL PRIVILEGES ON test.* TO test@`%` |

+------------------------------------------------+


docker volume이 원인이었네요.

워크벤치에도 접속이 가능합니다.

그런데 pytest 로 테스트 코드를 실행하면 또 access_denied가 뜹니다.

워크벤치에서 접속이 되는 데, 장고 테스트에서 access_denied 메시지가 뜬다면, settings.DATABASES에 계정정보가 틀렸거나 권한이 없는 데이터베이스명을 지정하셨을 것입니다. 차근차근 살펴보세요.


MySQL 도커 컨테이너 생성 시에 MYSQL_DATABASE에 지정한 데이터베이스는 기본 권한이 지정이 되니까 별도 설정은 필요없구요. 여기에 지정하지 않은 이름으로 테스트 데이터베이스를 사용하시려 한다면 말씀하신 것처럼 권한 설정이 필요합니다.

저는 settings.DATABASES는 아래와 같이 설정했구요. TEST 데이터베이스는 명시적으로 지정했는 데요. TEST NAME으로 지정한 값은 디폴트 값으로서 NAME 항목의 이름 앞에 test_ 가 붙은 이름입니다. TEST 항목을 지정하지 않아도 동일하게 동작합니다.

image

MySQL 컨테이너 생성 후에 아래와 같이 테스트 데이터베이스를 생성해주고 권한도 지정해줬습니다.

image

pytest.ini는 아래와 같이 생성해줬고,

image

테스트도 만들어줬습니다.

image

pytest는 아래와 같이 잘 동작했습니다.

image

현재 pytest.ini 설정으로 테스트 데이터베이스는 테스트 동작 후에 제거가 되지만, MySQL 권한 설정은 그대로입니다. pytest를 여러 번 실행하셔도 동일하게 잘 동작합니다.

참고로 "default" 데이터베이스와 "TEST" 데이터베이스 명은 다르게 가져가는 것이 좋습니다.

원인은 멀리 있지 않습니다. 차근차근 살펴보세요.

화이팅입니다.

김제하님의 프로필

김제하

질문자

2023.11.21

진석님 항상 친절하게 가이드해주셔서 감사합니다. 원인은 라이브러리 차이인 걸로 확인했습니다.

똑같이 진행하다가 진석님이 남겨주신 코멘트에서 mysql 연결을 위해 사용된 라이브러리가 저와 다르다는 걸 발견했습니다.

진석님은 pymysql 을 사용하셨지만, 저는 mysqlclient를 사용했었습니다.

라이브러리를 교체한 후 입력하신 것과 동일하게


import pymysql
pymysql.install_as_MySQLdb()

를 입력하니 아주 아주 잘 작동되고 있습니다.

 

도와주셔서 진심으로 감사합니다.

 

그런데 희한한게 test가 아닌 develop.py으로 해서 할 때는 잘 인식이 되었는데 테스트로했을 때는 왜 그랬을지 의문이긴 하네요.

mysqlclient 라이브러리를 설치하시는 과정에서 mysqlclient가 참조하는 라이브러리에서 이슈가 있으셨을까요. 흠. pymysql 은 pure python 라이브러리이기에 다른 라이브러리 의존성이 없거든요.

test 로 하셨을 때 잘 안 되시는 부분은 위에서 말씀드린 대로 test 데이터베이스명과 그 데이터베이스의 mysql 권한 설정 이슈가 아닐까 싶습니다.

화이팅입니다. 👍