docker-compose 파일을 보면 나의 소중한 postgreSQL 아이디와 비밀번호가 적나라하게 적혀있다. .env.postgres 파일을 생성한다. 그리고 아래와 같이 docker-compose 파일에 있는 내용을 복사 붙여넣기 해준다.docker-compose에 있는 내용은 없애준다.# .env 파일에 있는 부분과 동일한 내용이다. django와 postgres는 이 부분을 통해 통신한다.
POSTGRES_DB="turtle_drf_backend_db"
POSTGRES_USER="turtle_drf_backend_nikevapormax"
POSTGRES_PASSWORD="turtle_drf_backend_password"
.gitignore에 파일 이름을 넣어주도록 하자. docker-compose 파일을 아래와 같이 변경하면 된다. version: "3.8"
services:
web:
# 현재 폴더에 있는 것들을 사용해 빌드하겠다.
build: .
command: python manage.py runserver 0.0.0.0:8000
ports:
- 8000:8000
working_dir: /usr/src/app/
volumes:
- ./:/usr/src/app/
env_file:
- ./.env
depends_on:
- db
db:
image: postgres:14.4-alpine
volumes:
- postgres_db:/var/lib/postgresql/data # named-volume
env_file:
- ./.env.postgres
ports:
- "5432:5432"
# named-volume을 사용하기 때문에 아래에서 선언해주어야 함
volumes:
postgres_db:
.env파일과 .env.postgres 파일에서 아이디와 비밀번호를 모두 바꾸었다고 가정하자. 이러고 docker-compose를 빌드하고 실행하려하면 기존에 있던 값들과 충돌해 에러가 나게 된다. 기존의 정보로 만들었기 때문이다.container를 삭제해주어야 한다. 그리고 기존의 volume도 없애주어야 한다. docker-compose.yaml 파일을 한 번 살펴보자. services:
web:
build: .
command: python manage.py runserver 0.0.0.0:8000
gunicorn이다. (Web Server Gateway Interface)배포용 docker-compose 파일을 만들 것이다. docker-compose.prod.yaml로 하고 기존에 사용하던 것을 복사 붙여넣기 했다. version: "3.8"
services:
web:
build: .
command: python manage.py runserver 0.0.0.0:8000
ports:
- 8000:8000
working_dir: /usr/src/app/
volumes:
- ./:/usr/src/app/
env_file:
- ./.env
depends_on:
- db
db:
image: postgres:14.4-alpine
volumes:
- postgres_db:/var/lib/postgresql/data # named-volume
env_file:
- ./.env.postgres
ports:
- "5432:5432"
volumes:
postgres_db:
requirements.txt에 넣어주도록 하자. $ pip install gunicorn
$ pip freeze > requirements.txt
docker-compose.prod.yaml의 command: python manage.py runserver 0.0.0.0:8000를 다음과 같이 변경해주도록 하자. command: gunicorn turtle_drf_backend.wsgi:application --bind 0.0.0.0:8000
wsgi.py이다. -f를 붙여주고 바로 뒤에 변경된 파일의 이름을 작성해주면 된다. $ docker-compose -f docker-compose.prod.yaml build

$ docker-compose -f docker-compose.prod.yaml up
psycopg2가 실행되지 않는다는 에러가 또 났다. 그래서 requirements.txt를 확인했더니 없어 추가해 주었고, 다시 위의 과정을 진행했고 실행이 잘 되는 것을 볼 수 있었다.
localhost:8000을 입력해 실행이 잘 되는지 보고, admin 페이지로 들어가보자.


settings.py로 이동해 아래와 같이 static 설정을 해주도록 하자.STATIC_ROOT = BASE_DIR / 'static'
STATIC_URL = '/static/'
그리고 전체 urls.py 폴더를 아래와 같이 변경해준다.
from xml.etree.ElementInclude import include
from django.contrib import admin
from django.urls import path, include
from django.conf import settings
from django.conf.urls.static import static
urlpatterns = [
path('admin/', admin.site.urls),
path('user/', include('user.urls')),
path('articles/', include('articles.urls')),
]
urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
urlpatterns += static(settings.STATIC_URL, document_root=settings.STATIC_ROOT)
그리고 다시 빌드를 진행하고 서버를 돌리도록 하자.
$ docker-compose -f docker-compose.prod.yaml up --build

$ python manage.py collectstatic


.env와 배포에 사용하는 .env를 구분지어 생성해보도록 하겠다. .env에서 내용을 복사해와 새로 만든 .env.prod에 붙여넣기 해준다. 새로운 SECRET_KEY를 발급받도록 한다. $ python -c 'from django.core.management.utils import get_random_secret_key; print(get_random_secret_key())'
.env.prodSECRET_KEY = 'bdfy7i5#vxn39k$nk)u+4__v2fjd^@u^=km41sy&z*+0x+km$s'
SQL_ENGINE='django.db.backends.postgresql'
SQL_DATABASE='turtle_drf_backend_db'
SQL_USER='turtle_drf_backend_nikevapormax'
SQL_PASSWORD='turtle_drf_backend_password'
SQL_HOST='db'
SQL_PORT='5432'
.env.postgres.prodPOSTGRES_DB="turtle_drf_backend_db"
POSTGRES_USER="turtle_drf_backend_nikevapormax1"
POSTGRES_PASSWORD="turtle_drf_backend_password1"
.env.postgres.prod의 USER와 PASSWORD를 바꾸었기 때문에 .env.prod의 USER와 PASSWORD 또한 바꿔주어야 하는 것이다.SECRET_KEY = 'bdfy7i5#vxn39k$nk)u+4__v2fjd^@u^=km41sy&z*+0x+km$s'
SQL_ENGINE='django.db.backends.postgresql'
SQL_DATABASE='turtle_drf_backend_db'
SQL_USER='turtle_drf_backend_nikevapormax1'
SQL_PASSWORD='turtle_drf_backend_password1'
SQL_HOST='db'
SQL_PORT='5432'
.env -> .env.dev.env.postgres -> .env.postgres.devmanage.py에서 env 파일을 읽어오는 부분을 삭제해준다.#!/usr/bin/env python
"""Django's command-line utility for administrative tasks."""
import os
import sys
def main():
"""Run administrative tasks."""
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'turtle_drf.settings')
try:
from django.core.management import execute_from_command_line
except ImportError as exc:
raise ImportError(
"Couldn't import Django. Are you sure it's installed and "
"available on your PYTHONPATH environment variable? Did you "
"forget to activate a virtual environment?"
) from exc
execute_from_command_line(sys.argv)
if __name__ == "__main__":
main()
settings.py의 설정을 변경해주어야 한다. DATABASES는 예전에 설정한 값이지만, 다시 한 번 작성하는 이유는 이곳에도 default 값이 적용되어 있고 이는 runserver를 실행할 때는 sqlite3를 사용할 수 있도록 하는 코드이다. # SECURITY WARNING: keep the secret key used in production secret!
SECRET_KEY = os.environ.get("SECRET_KEY", "somesecret")
# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = int(os.environ.get("DEBUG", 1))
...
DATABASES = {
'default': {
'ENGINE': os.environ.get('SQL_ENGINE',"django.db.backends.sqlite3"),
'NAME': os.environ.get('SQL_DATABASE', BASE_DIR / "db.sqlite3"),
'USER': os.environ.get('SQL_USER', 'user'),
'PASSWORD': os.environ.get('SQL_PASSWORD', 'password'),
'HOST': os.environ.get('SQL_HOST', 'localhost'),
'PORT': os.environ.get('SQL_PORT', '5432'),
}
}
.env.dev 및 .env.prod에도 아래와 같이 DEBUG를 추가해준다..env.devDEBUG = '1'
SECRET_KEY = 'django-insecure-5ofxcce2mfgazkn2w(o16j2i_rj6w^7%)xeilm$8go4qezt^ng'
SQL_ENGINE='django.db.backends.postgresql'
SQL_DATABASE='turtle_drf_backend_db'
SQL_USER='turtle_drf_backend_nikevapormax'
SQL_PASSWORD='turtle_drf_backend_password'
SQL_HOST='db'
SQL_PORT='5432'
.env.prodDEBUG = '0'
SECRET_KEY = 'bdfy7i5#vxn39k$nk)u+4__v2fjd^@u^=km41sy&z*+0x+km$s'
SQL_ENGINE='django.db.backends.postgresql'
SQL_DATABASE='turtle_drf_backend_db'
SQL_USER='turtle_drf_backend_nikevapormax1'
SQL_PASSWORD='turtle_drf_backend_password1'
SQL_HOST='db'
SQL_PORT='5432'
settings.py에서 DEBUG를 설정했다. .env.dev와 .env.prod에서 DEBUG를 문자열 1 또는 0으로 설정했는데개발 환경에서는 DEBUG가 int('1')이 되어 디버깅이 활성화되고배포에서는 DEBUG가 int('0')이 되어 디버깅이 실행되지 않는다.gitignore에도 아래와 같이 수정 또는 추가하도록 하자..env.dev
.env.prod
.env.postgres.dev
.env.postgres.prod
docker-compose.prod.yaml 또한 아래와 같이 현재 바뀐 파일 명으로 변경해준다.version: "3.8"
services:
web:
# 현재 폴더에 있는 것들을 사용해 빌드하겠다.
build: .
command: gunicorn turtle_drf.wsgi:application --bind 0.0.0.0:8000
ports:
- 8000:8000
working_dir: /usr/src/app/
volumes:
- ./:/usr/src/app/
env_file:
- ./.env.prod
depends_on:
- db
db:
image: postgres:14.4-alpine
volumes:
- postgres_db:/var/lib/postgresql/data # named-volume
env_file:
- ./.env.postgres.prod
ports:
- "5432:5432"
# named-volume을 사용하기 때문에 아래에서 선언해주어야 함
volumes:
postgres_db:
$ docker-compose down
docker-compose.prod.yaml로 와 nginx 서비스를 작성해보도록 하겠다.version: "3.8"
services:
nginx:
build: ./nginx
volumes:
- static_volume:/usr/src/app/static
- media_volume:/usr/src/app/image
ports:
- 80:80
depends_on:
- web
web:
# 현재 폴더에 있는 것들을 사용해 빌드하겠다.
build: .
command: gunicorn turtle_drf.wsgi:application --bind 0.0.0.0:8000
ports:
- 8000:8000
working_dir: /usr/src/app/
volumes:
- ./:/usr/src/app/
- static_volume:/usr/src/app/static
- media_volume:/usr/src/app/image
expose:
- 8000
env_file:
- ./.env.prod
depends_on:
- db
db:
image: postgres:14.4-alpine
volumes:
- postgres_db:/var/lib/postgresql/data # named-volume
env_file:
- ./.env.postgres.prod
ports:
- "5432:5432"
# named-volume을 사용하기 때문에 아래에서 선언해주어야 함
volumes:
postgres_db:
static_volume:
media_volume:
nginx/ 폴더 안에 아래의 파일들을 생성한다. nginx.conf upstream turtle_drf_backend {
server web:8000; # docker-compose.prod.yaml의 web에 설정한 8000과 연결되게 된다.
} # nginx와 gunicorn이 통신할 때 여기로 함 (내부 통신)
server {
listen 80; # web의 80번 포트이자 default http의 포트를 그대로 사용한다. (외부 통신)
location / {
# nginx에서 제공하는 default setting
proxy_pass http://turtle_drf_backend;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $host;
proxy_redirect off;
}
location /static/ {
alias /usr/src/app/static/;
}
location /image/ {
alias /usr/src/app/image/;
}
}
DockerfileFROM nginx:1.22.0-alpine
# 실행이 되면 nginx의 기본 설정파일들을 없앤다.
RUN rm /etc/nginx/conf.d/default.conf
# 없앤 기본 설정파일들 대신 내가 만든 nginx.conf를 복사해 넣어준다.
COPY nginx.conf /etc/nginx/conf.d
$ docker-compose -f docker-compose.prod.yaml up --build

브라우저에서 localhost로 들어가려 하면 아래와 같이 에러가 나는 것을 볼 수 있다.
이유는 내가 DEBUG 모드를 끝냈기 때문이다.

해당 문제를 해결하기 위해서는 settings.py를 수정해야 한다.
# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = int(os.environ.get("DEBUG", 1))
if os.environ.get("DJANGO_ALLOWED_HOSTS"):
ALLOWED_HOSTS = os.environ.get("DJANGO_ALLOWED_HOSTS").split(" ")
else:
ALLOWED_HOSTS = []
.env.prod를 아래와 같이 변경해준다.
DEBUG = '0'
SECRET_KEY = 'bdfy7i5#vxn39k$nk)u+4__v2fjd^@u^=km41sy&z*+0x+km$s'
DJANGO_ALLOWED_HOSTS = localhost 127.0.0.1
SQL_ENGINE='django.db.backends.postgresql'
SQL_DATABASE='turtle_drf_backend_db'
SQL_USER='turtle_drf_backend_nikevapormax1'
SQL_PASSWORD='turtle_drf_backend_password1'
SQL_HOST='db'
SQL_PORT='5432'
변경된 코드들의 의미를 살펴보자.
DJANGO_ALLOWED_HOSTS = localhost 127.0.0.1를 보면 localhost와 127.0.0.1은 띄어쓰기를 기준으로 나뉘어져 있다. ALLOWED_HOSTS = os.environ.get("DJANGO_ALLOWED_HOSTS").split(" ")에서는 띄어쓰기를 통해 DJANGO_ALLOWED_HOSTS에 값들을 넣어준다. 따라서 우리는 위의 두 코드를 통해 두 가지의 호스트를 얻을 수 있다.localhost127.0.0.1.env.dev에는 현재 DEBUG가 1이라 의미는 없지만 같이 넣어주도록 하겠다.
DEBUG = '1'
SECRET_KEY = 'django-insecure-5ofxcce2mfgazkn2w(o16j2i_rj6w^7%)xeilm$8go4qezt^ng'
# 현재 DEBUG가 1이라 쓰이지는 않지만 넣어둠
DJANGO_ALLOWED_HOSTS = localhost 127.0.0.1
SQL_ENGINE='django.db.backends.postgresql'
SQL_DATABASE='turtle_drf_backend_db'
SQL_USER='turtle_drf_backend_nikevapormax'
SQL_PASSWORD='turtle_drf_backend_password'
SQL_HOST='db'
SQL_PORT='5432'
$ docker-compose -f docker-compose.prod.yaml down

$ docker-compose -f docker-compose.prod.yaml up --build

브라우저를 통해 다시 localhost에 들어가면 에러가 나는데, 아까와는 다르게 현재는 보여줄 데이터가 없기 때문에 나는 에러이다.

이제 migration을 진행해주도록 하자.


하지만 아래와 같이 에러가 발생하며 css를 불러오지 못했다.

이유는 명확하지 않지만, 원인은 localhost:8000이었다. localhost만 사용하면 아래와 같이 css가 잘 적용되는 것을 볼 수 있다.
web-1 터미널에서 createsuperuser를 진행하였다. gunicorn으로 가게 되고, 현재 gunicorn에는 css를 붙이는 것이 없기 때문에 위의 에러가 난 것일 것이다.
nginx-1은 nginx에 대한 로그를 자동으로 docker logs로 보내주고 있다. 해당 로그를 보는 법에 대해 작성하도록 하겠다. $ docker logs turtle_drf_backend-nginx-1
$ docker logs turtle_drf_backend-nginx-1 -f
>>> -f를 붙여 로그를 계속 확인할 수 있다.
docker logs nginx-1은 보이는 것과 같이 정확한 이름이 아니다. docker ps로 container를 확인하고 name을 가져와 입력하면 된다.turtle_drf_backend-nginx-1이다.

