도커 컨테이너 환경에서 배포하기: Docker + Django + Nginx + Gunicorn

Ji_min·2021년 6월 5일
0

1. VM에 도커 및 도커 컴포즈 설치하기

💻 VM 환경 : Ubuntu 18.04.5 LTS (버전 확인하기 : cat /etc/issue )

1-1. 도커 설치하기

윈도우나 맥은 도커 데스크탑을 설치하면 되니까 간편한데, 우분투에서는 패키지 매니저를 통해 도커 엔진을 설치해줘야 한다. 도커 엔진을 설치하기 위해서는 도커 레포지토리 세팅부터 해야 한다.

1) 의존 패키지 설치하기

sudo apt update
sudo apt install \
    apt-transport-https \
    ca-certificates \
    curl \
    gnupg \
    lsb-release

2) 도커 공식 레포지토리 설치를 위한 GPG key 추가하기

GPG key는 두 주체 사이의 안전한 통신을 보장해주는 거라고 설명이 나와있는데, 설치를 안전하게 하기 위해 추가된 단계인 것 같다.

curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -

3) 도커 레포지토리 설치하기

sudo add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/ubuntu bionic stable"

4) 우분투 디폴트 레포지토리 말고 도커 레포지토리에서 설치하도록 설정하기

sudo apt update
apt-cache policy docker-ce

아래처럼 뜨는지 확인한다.

docker-ce:
  Installed: (none)
  Candidate: 18.03.1~ce~3-0~ubuntu
  Version table:
     18.03.1~ce~3-0~ubuntu 500
        500 https://download.docker.com/linux/ubuntu bionic/stable amd64 Packages

Installed가 none으로 뜨는 것은 아직 docker-ce를 설치하기 않았기 때문이다.

5) 도커 엔진 설치하기

sudo apt install docker-ce

6) 도커 실행 확인하기

sudo systemctl status docker

1-2. 도커 컴포즈 설치하기

1) 도커 컴포즈 설치하기

sudo curl -L "https://github.com/docker/compose/releases/download/1.29.2/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose

2) 도커 컴포즈가 설치된 경로에 실행 권한 주기

sudo chmod +x /usr/local/bin/docker-compose

3) 도커 및 도커 컴포즈 설치 확인하기

docker version
docker-compose version

2. 배포용 도커 컨테이너 파일 만들기

2-1. 도커, 도커 컴포즈파일 분리하기

각각 개발용, 배포용으로 분리했다.

Dockerfile.dev & Dockerfile.prod

docker-compose.dev.yml & docker-compose.prod.yml

2-2. Gunicorn 관련 작업하기

1) requirements.txt에 Gunicorn 추가하기

gunicorn==20.0.4

2) djangoapp 컨테이너의 command를 gunicorn 명령어로 수정하기

# docker-compose.prod.yml
# gunicorn project_name.wsgi:app_name --bind 0.0.0.0:8000
command: gunicorn closet.wsgi:application --bind 0.0.0.0:8000

2-3. 배포용 도커 컴포즈 파일 만들기

배포용 도커 파일의 경우 개발용과 크게 달라진 부분은 없는데, 유저를 생성해서 권한을 제한하는 게 아무래도 좋을 것 같다. 그래서 우선은 개발용과 배포용을 분리해놓았고, 유저 관련 부분을 차후 추가할 예정이다. 우선은 건너뛰었다.

배포용 컴포즈 파일의 경우 build context를 Dockerfile.prod로 명시해주고, 개발용이 아니기 때문에 volume 부분이 필요없으므로 지워준다.

service:
  djangoapp:
    build:
        context: .
        dockerfile: Dockerfile.prod
    command: gunicorn closet.wsgi:application --bind 0.0.0.0:8000
    ports:
    - "8000:8000"
    depends_on:
      - db

3. Nginx 관련 파일 만들기

3-1. Nginx 컨테이너 추가하기

배포용 컴포즈 파일에 Nginx 컨테이너를 다음과 같이 추가해준다.

nginx:
  build: ./nginx
  ports:
    - "80:80"
  depends_on:
    - djangoapp 

3-2. 관련 파일 만들기

다음의 구조로 Nginx용 도커 파일과 Nginx 설정 파일을 추가해준다.

└── nginx
    ├── Dockerfile
    └── nginx.conf

Nginx Dockerfile

FROM nginx:1.19.0-alpine

RUN rm /etc/nginx/conf.d/default.conf
COPY nginx.conf /etc/nginx/conf.d

Nginx 환경설정 파일

upstream <backend> {
    server djangoapp:8000;
}

server {

    listen 80;

    location / {
        proxy_pass http://<backend>/;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header Host $host;
        proxy_redirect off;
    }

}

3-3. djangoapp 컨테이너 수정하기

도커 컨테이너끼리만 내부적으로 포트를 열어주면 되므로 ports → expose로 바꾼다.

service:
  djangoapp:
    build:
        context: .
        dockerfile: Dockerfile.prod
    command: gunicorn closet.wsgi:application --bind 0.0.0.0:8000
    expose:
      - "8000"
    depends_on:
      - db

4. 실행시켜보기

컨테이너 실행시키기

docker-compose -f docker-compose.prod.yml up --build -d

DB migrate하기

docker exec backend_djangoapp_1 python manage.py migrate

로그 확인하기

docker logs backend_djangoapp_1

80번이 열려있으므로 그냥 DNS로 접속해보면 장고 서버 페이지가 뜨면 된다. 그런데 /admin/으로 접속해보니 CSS가 깨져있었다. 원인을 찾아보니 static file 관련 작업을 안해줘서 그런 것이었다.

5. Static file 관련 설정하기

5-1. settings.py에 static file path 추가하기

STATIC_URL = "/static/"
STATIC_ROOT = os.path.join(BASE_DIR, "static") 

5-2. docker-compose.prod.yml 파일에 static volume 추가하기

djangoapp과 nginx가 동일한 static volume(/backend/static) 디렉토리를 공유하도록 설정

djangoapp:
  volumes:
      - static_volume:/backend/static
nginx:
  volumes:
      - static_volume:/backend/static

5-3. Dockerfile.prod 에 static file 디렉토리 만들어주는 코드 추가

docker compose는 volume file을 마운트할 때 root user로 작업하는데, root user로 작업하면 상관없지만 non-root user로 접근하면 /static이라는 디렉토리를 만들 때 존재하지 않는 디렉토리를 만들려고 하면 permission denied가 뜰 수 있기 때문에 관련 코드 한 줄을 추가해준다.

ENV APP_HOME=/backend
RUN mkdir $APP_HOME
RUN mkdir $APP_HOME/static
WORKDIR $APP_HOME

5-4. Nginx config 파일에 static 경로 관련 설정 추가

upstream <backend> {
    server djangoapp:8000;
}

server {

    listen 80;

    location / {
        proxy_pass http://<backend>/;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header Host $host;
        proxy_redirect off;
    }

		location /static/ {
		        alias /backend/static/; <- static file 경로
		    }

}

5-5. static file을 static file 디렉토리에 복사하기

docker exec backend_django_1 python manage.py collectstatic --no-input --clear

collectstatic은 static root 디렉토리에 static file을 복사하는 명령어이다.

clear 옵션은 static root 경로에 이미 static file이 존재하는 경우 싹 다 지우고 다시 복사하는 옵션이다. 앱이 삭제된다든지 하는 경우 쓸모없는 static file이 존재할 수도 있기 때문에 collectstatic을 여러번 하게 되면 같이 붙여주면 좋다.

이제 다시 admin 페이지나 swagger, redoc 페이지로 접근하게 되면 css가 잘 적용되는 것을 확인할 수 있다!


참고

도커 및 도커 컴포즈 설치

배포용 도커 파일 및 Nginx 파일 만들기

https://testdriven.io/blog/dockerizing-django-with-postgres-gunicorn-and-nginx

collectstatic 관련

profile
Curious Libertine

0개의 댓글