Django 2.2 | Hello World 그리고 dockerize(도커화)
Docker
현대적인 프로그래밍에서 모든 기술의 발전에도 불구하고 모든 개발자의 로컬환경을 똑같이 구성하기에는 여전히 어려운 과제 중 하나이다. 팀의 협업간에는 그 문제가 더욱 커진다. 도커는 최신 기술이지만 앞서 말한 문제를 해결한다는 이유로 프로덕션-레벨에서까지 많이 사용되고 있다. 도커가 나오기 전에는 팀에 새로운 개발자가 투입되면 README 파일을 공유하여 그 파일에 적힌 순서대로 로컬 환경을 구성하였지만, 도커가 나온 이후에는 Dockerfile과 docker-compose.yml 파일을 공유하여 실행하는 것만으로 다른 팀원들과 동일한 로컬 환경을 아주 간단히 구성할 수 있게 되었다.
도커의 핵심 아이디어는 대부분의 컴퓨터가 리눅스 OS에 의존한다는 것이고, 만약 이 리눅스-OS-레벨에서 가상화를 한다면 VM과 동일한 기능을 더 작고, 빠르게 제공할 수 있다는 것이다. 결국 도커는 가상화방식으로 리눅스 컨테이너를 통해 OS 자체를 격리시키는 것이고, 근본적으로 Dockerize(도커화) 한다는 것은 리눅스 컨테이너를 구현하는 방법이라 할 수 있다.
컨테이너(Container), 가상환경(Virtual Environment)
Pythonista(파이썬 개발자)라면 패키지를 분리하는 방법인 가상환경에 이미 익숙해져 있을것이다. 가상환경은 싱글 컴퓨터에 다수의 프로젝트를 독립적인 패키지로 실행할 수 있게 해준다. 예를 들어, 프로젝트 A는 python3.4와 django 1.11를 사용하고, 프로젝트 B는 python3.7과 django2.2를 사용하는 경우에 글로벌 환경을 침해하지 않고 서로 다른 패키지를 관리하고 사용할 수 있게 해주는 것이다. 가상환경을 구현하기 위한 도구로는 virtualenv, venv, pipenv가 있고 이들은 모두 패키지를 분리해주는 동일한 작업을 수행한다. 가상환경과 도커 컨테이너의 중요한 차이점은 가상환경은 파이썬 패키지에 한하여 독립적으로 분리하지만, 도커는 파이썬 패키지 뿐만 아니라 앞서 말한 OS를 격리시킨다는 것이다. 즉, python 이외의 postgresql, mysql 데이터베이스와 같은 소프트웨어도 격리시킬 수 있다. 도커는 간단해 보이지만 매우 복잡한 기술이기에 더 자세히 알고싶다면 도커 공식홈을 참고하자.
자, 이제 장고 프로젝트를 생성하고, 이를 도커라이즈하여 장고와 도커를 어떻게 결합하는지 간단히 살펴보자. 첫 순서로는 로컬에 장고프로젝트를 생성하는 것이다.
Startproject
앞서, 독립적인 패키지를 실행하기 위해 가상환경을 사용해야 한다 말하였다. 그 도구들 중에서 venv로 가상환경을 만들어 장고 프로젝트를 생성해보자.
$ python3.7 -m venv boot
$ source boot/bin/activate
(boot) $ pip install "django==2.2.3"
(boot) $ django-admin startproject coninggu_project .
(boot) $ ./manage.py migrate
(boot) $ ./manage.py runserver
웹브라우저에서 http://127.0.0.1:8000 로 접근해보면 성공적으로 프로젝트가 생성된 것을 확인할 수 있다.
Startapp
다음으로 coningguapp을 만들어 장고에게 알려주고, urls route와 view를 작성하여 웹브라우저에 “Hello World!!!”를 출력해보자.
(boot) $ ./manage.py startapp coninggu
startapp 커맨드를 실행하면 장고가 자동적으로 app에 대한 디렉토리와 필요한 파일들을 설치해준다. 장고가 앱을 인식하도록 settings.py의 INSTALL_APPS에 방금 설치한 coninggu app을 추가해주자.
#coninggu_project/settings.py
...
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'coninggu.apps.ConingguConfig', # 추가
]
...
일반적으로 장고의 built-in apps 아래에 app을 추가하는게 좋다. 그리고 단순히 ‘coninggu’와 같이 app이름만으로 추가가 가능하지만 full path를 입력하는게 더 좋다고 한다. 다음으로는 urls.py에 URL route를 구성하는 것이다.
#coninggu_project/urls.py
from django.contrib import admin
from django.urls import path
from coninggu.views import HomepageView # 추가
urlpatterns = [
path('admin/', admin.site.urls),
path('', HomepageView.as_view(), name='homepage'), # 추가
]
8번째 줄을 보면 path()에 3개의 인자를 전달해주는 것을 알 수 있다. 첫번째 인자는 url을 입력하고, 두번쨰 인자는 target view를 입력하는 것으로, 장고에서 view를 정의하는 방법이 FBV(Function Based View), CBV(Class Based View) 두 가지가 있는데 CBV로 작성한다면 as_view()까지 작성해야 한다. 세번째 인자인 name은 optional인데 이를 이용해 템플릿에서 {% url ‘name’ %}, 뷰에서는 reverse(‘name’)처럼 URL을 하드코딩하지 않고 name값을 이용하여 사용할 수 있다. name을 사용하는건 모범사례임으로 되도록 작성하도록 하자.
다음은 view를 작성해보자.
#coninggu/views.py
from django.http import HttpResponse
from django.views.generic import View
class HomepageView(View):
def get(self, request):
return HttpResponse('Hello, World!!!')
단순히 “Hello World”만 출력할 것이기에 템플릿 파일을 설정하는 대신에 하드코딩하였다.
이제 “Hello World!!!”를 출력하기 위한 모든 준비가 끝났다. 다시 runserver 커맨드를 실행하여 브라우저에서 접근해보자. 장고는 기본포트로 8000번을 사용하는데 다른포트를 사용하고 싶다면 아래와 같이 실행하면 된다.
(boot) $ ./manage.py runserver 8080
도커화(Dockerize)
간단한 app을 만들었음으로 이를 도커화 해보자. 도커화를 위해선 Dockerfile 파일을 작성해야 하는데, 이는 빌드할 내용들을 순차적으로 정리한 것이고, 이를 빌드하여 나온 결과물이 도커 이미지가 된다. 그리고 이 이미지를 인스턴스화 한 것이 컨테이너이다.
# Dockerfile
FROM python:3.7-slim
ENV LANG ko_KR.utf-8
RUN set -ex \
&& ln -s -f /usr/share/zoneinfo/Asia/Seoul /etc/localtime
RUN pip install django==2.2.3
WORKDIR /coninggu
Dockerfile은 위에서 아래로 처리되며 이미지를 빌드 한다. 첫 번째 줄인 FROM은 must이고, 기본 이미지를 입력한다. 두 번째, 세 번째 줄은 캐릭터 셋과 timezone을 정의하였고, 네 번째 줄은 django를 설치하였다.
다섯 번째 줄인 WORKDIR은 기본 작업 디렉토리 경로를 설정하는 것으로 이후부터는 이 디렉토리에서 코드가 실행된다. WORKDIR을 입력하지 않으면 명령을 실행할 때마다 full path를 입력해야 하는 번거로움이 있음으로 설정해주는 게 좋다.
작성한 Dockerfile을 빌드해보자.
$ docker build .
...
Step 5/5 : WORKDIR /coninggu
---> Using cache
---> 9a443904563c
Successfully built 9a443904563c
빌드가 성공하여 도커이미지가 생성되었다. 이 이미지로 인스턴스화하려면 docker 커맨드를 이용하는 방법도 있지만 파일로 관리하기 위해 docker-compose.yml도 작성해 주자. docker-compose.yml 파일에는 이미지를 어떻게 실행할 것인지에 대한 정의를 해야 한다.
# docker-compose.yml
version: '3'
services:
web:
build: .
command: python /coninggu/manage.py runserver 0.0.0.0:8000
volumes:
- .:/coninggu
ports:
- 8000:8000
docker-compose를 실행하여 컨테이너를 띄워보자. docker-compose에 대한 자세한 정보는 공식홈을 참고하자.
$ docker-compose up
Starting learndjango_web_1 ... done
Attaching to learndjango_web_1
web_1 | Watching for file changes with StatReloader
컨테이너가 성공적으로 가동되었다. 다시 웹브라우저에서 http://127.0.0.1:8000에 접근하여 “Hello World!!!”가 출력되는지 확인하자.