docker를 사용하여 nginx, django를 띄워보기

jonghyuck’s velog·2021년 5월 6일
1

최근 노트북이 이상하다 싶더니 결국 as행을 가게 되었다. 그래서 django를 서버에서 돌리고 확인하며 작업을 해야 하는데 매번 ssh접속하고 작업하다가 인터넷이 끊기면 ssh도 끊기고 작업도 끊기고 내 멘탈도 끊겨버렸다. 그래서 해결방법을 모색하던 중 nginx와 docker를 사용해서 해결해볼까? 하는 생각이 들었다. 그리고 아주 훌륭한 정리를 해주신 개발자분을 보게 되었고 감명을 받아서 정리해보고자 한다.

  1. 웹서버는 따로 설정해주지 않아도 24시간 돌아갈 것이며, 불필요한 포트 정보따위는 url에 치고싶지 않다.
  2. 개발 중간에 개발환경이 꼬여버리면 심할 경우 가상환경을 지웠다가 새로 만들어도 어딘가 문제가 생기는 경험을 했기 때문에 모듈화를 시키고 싶었다.

내가 필요한 기능은 위 두가지 정도였는데 이 두가지를 해결해 주는 것들이 바로 nginx와 docker 였다. 이론은 아주 간단하다. 내가 만든 django서버는 8000번 포트로 서비스 고 이는 uwsgi라는 게이트웨이를 통해서 nginx와 연결된다. nginx는 django서버를 80포트로 들어갈 수 있도록 해주고 또한 24시간 알아서 돌아가도록 도와줄 것이다. ( 실제 개념은 조금 다르지만 결과적으로는 그렇게 될것이다.) 그냥 장고를 80번 포트로 runserver 해준 뒤에 데몬으로 24시간 백그라운드에서 돌리면 되는것 아닌가? 맞는 말이다. 하지만 그 runserver는 아주 최소사양의 서버이므로 웹서버인 nginx를 사용하도록하자. nginx에 대해 자세히 알아보고 싶으면 리버스 프록시 서버라는 개념에 대해서 공부해 보면 많은 공부가 될 것이다.

< 왜 아파치가 아니라 nginx를 사용 하셨어요? 이게 그나마 한번이라도 써봐서 그렇다.>

그래서 docker가 왜 필요한데???

docker는 컨테이너개념이지만 자세히 설명하기에는 내 필력이 부족하다. 그래서 가상화의 개념이라고 보려고 한다.( 내가 이해한 부분이 사실과 다를 수 있다. 하지만 당장 머리속에 들어오는 개념은 가상화와 비슷한 개념으로 받아들였다.) 이 컨테이너 개념은 일반적인 가상화와 조금 다르다. 일반적인 가상화 기술이란 서버의 os단에서 가상화를통해 os위에 os를 생성하게 된다. 이렇게 될 경우 원래의 os를 구동시키는데 필요한 자원과 그 os를 기반으로 또다시 os 를 돌리기 때문에 불필요한 리소스가 많이 사용될 뿐만 아니라 이러한 점 때문에 pc의 제 성능이 제대로 발휘되기 어렵다. 만약 이 개념이 어렵다면 밥을 먹을때를 생각해보자. 밥을 먹을때는 한번의 젓가락질만 있으면 된다. 하지만 가상화를 할 경우 젓가락으로 젓가락을 움직여서 밥을 먹어야 한다. 그 사람이 젓가락질을 아무리 잘한다고 해도 제대로 밥을 먹기 힘들 것이다.

바로 여기서 컨테이너화의 장점이 나온다. 컨테이너는 os단이 아닌 커널단에서 가상화를 해준다. 즉 컨테이너화는 밥을 먹을 때 젓가락을 바꾸는 개념과 비슷한 것이다. 컨테이너의 갯수만큼 젓가락을 가지고 있고 필요에 따라 불러와서 사용하면 그만이다. 이는 pc를 새로 바꾸더라도 마찬가지이다. 그저 기존 컨테이너를 가져와서 사용하기만 하면 바로 기존 환경 그대로 사용이 가능하다. 마치 우리가 어디를 가더라도 기존에 먹던 식기류를 그대로 사용할 수 있는 것과 비슷하다고 할 수 있다. (비유가 이상할 수도 있지만 위와같은 개념을 한번 받아들이면 좀 더 와닿을 것이다.)

이제 도커를 사용해서 뭘 컨테이너화 해줄 것인지를 정할 때이다. nginx, docker, uwsgi 모두 docker로 만들어 보도록 하자.

우선 docker를 설치한다.

curl -fsSL https://get.docker.com/ | sudo sh
sudo usermod -aG docker ubuntu #ubuntu자리에는 권한을 줄 사용자

다음은 docker로 만들 서버의 루트 폴더를 생성해준다.

mkdir docker-server

이제 새로 만든 docker-server라는 폴더 안에 작업중인 django 파일을 넣어준다.

나의 경우는 진행하던 포트폴리오 프로젝트가 있었기에 이 프로젝트를 넣어주었다.

현재 폴더의 구조를 보면


위와 같은 파일 구조를 가지고 있게 되었다.

여기까지 진행했으면 mysite안에 들어가서 Dockerfile을 만들면 된다.
vim을 이용해서 Dockerfile을 생성해보도록 하자.

# /docker-server/mysite/Dockerfile
From python:3.6.7 # Docker의 python버전을 설정

ENV PYTHONUNBUFFERED 1

RUN apt-get -y update
RUN apt-get -y install vim #docker 안에서 vim설치를 안하도록

RUN mkdir /srv/docker-server #docker안에서 srv/docker-server 폴더 생성
ADD . /srv/docker-server #현재 디렉토리를 통째로 srv/docker-server폴더에 복사

WORKDIR /srv/docker-server #작업 디렉토리 설정

RUN pip install --upgrade pip #pip 업그레이드
RUN pip install -r requirements.txt #필수 패키지 설치

EXPOSE 8000
CMD ["python", "manage.py", "runserver", "0.0.0.0:8000"]

다음으로 docker build 명령어를 통해서 docker 이미지를 만들어준다.

docker build -t mysite/djnago .

여기서 -t는 docker 이미지에 이름을 넣어주는 옵션이며 .은 docker 이미지로 만들 폴더의 경로를 말한다. 이미 comento경로에 있기 때문에 .을 적었지만 ~/docker-server/comento라고 써도 무방하다. 하지만 에러가 났다.


권한 관련 문제인 것으로 보아 아까 설정한 사용자에 제대로 권한이 전달되지 못했던것 같다.

sudo chmod 666 /var/run/docker.sock

이 경우 위 명령어로 /var/run/docker.sock 파일의 권한을 666으로 변경시켜서 그룹 내 다른 사용자도 접근이 가능하도록 변경시켜서 해결할 수 있다. 좋은 방법은 아니지만 어차피 혼자 사용할 서버기 때문에 그냥 사용하도록 했다.

이미지가 정상적으로 만들어졌는지 확인을 위해서 docker image list라는 명령어를 사용했다.

  • 여기서 mysite/django가 아니라 comento/django인 이유는 중간중간 수정을 하다가 결국 mysite로 수정했지만 스크린샷은 대체를 하지 못했다.

일단 성공했는데 이라는 친구는 아까 오류를 틈타 만들어진것 같다. 소중한 용량을 잡아먹을테니 지워주도록 하자.

docker rmi -f $(docker images -f "dangling=true" -q)

위 명령어는 docker 이미지 빌드시 생기는 none(untagged)파일들을 조회한 후 삭제하는 명령어이다.

이제 실행을 하게 되면 docker를 이용해서 django서버를 실행시킬 수 있게 된다.

docker run -p 8000:8000 mysite/django

드디어 완성되었다. 행복하다.
반이나 왔다. Nginx역시 동일한 절차를 밟아주도록 하자.

NGINX 도커로 만들기

우선 ~/docker-server/nginx/nginx.conf를 만들어 주도록 하자.

vim ~/docker-server/nginx/nginx.conf
user root;
worker_processes auto;
pid /run/nginx.pid;

events {
    worker_connections 1024;
    # multi_accept on;
}

http {

    ##
    # Basic Settings
    ##

    sendfile on;
    tcp_nopush on;
    tcp_nodelay on;
    keepalive_timeout 65;
    types_hash_max_size 2048;
    # server_tokens off;
    # server_names_hash_bucket_size 64;
    # server_name_in_redirect off;

    include /etc/nginx/mime.types;
    default_type application/octet-stream;

    ##
    # SSL Settings
    ##

    ssl_protocols TLSv1 TLSv1.1 TLSv1.2; # Dropping SSLv3, ref: POODLE
    ssl_prefer_server_ciphers on;

    ##
    # Logging Settings
    ##

    access_log /var/log/nginx/access.log;
    error_log /var/log/nginx/error.log;

    ##
    # Gzip Settings
    ##

    gzip on;
    gzip_disable "msie6";

    # gzip_vary on;
    # gzip_proxied any;
    # gzip_comp_level 6;
    # gzip_buffers 16 8k;
    # gzip_http_version 1.1;
    # gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript;

    ##
    # Virtual Host Configs
    ##

    # include /etc/nginx/conf.d/*.conf;
    include /etc/nginx/sites-enabled/*;
}

다 쳤으면 저장을 하고 nginx-app.conf역시 만들어주도록 하자.

vim ~/docker-server/nginx/nginx-app.conf
upstream uwsgi {
    server unix:/srv/docker-server/apps.sock;
}

server {
    listen 80;
    server_name localhost;
    charset utf-8;
    client_max_body_size 128M;

    location / {
        uwsgi_pass      uwsgi;
        include         uwsgi_params;
    }

    location /media/ {
        alias /srv/docker-server/.media/;
    }

    location /static/ {
        alias /srv/docker-server/.static/;
    }
}

(나중에 안 사실이지만 location /static/ 설정은 다시 바꿔주어야 될것 같다.CSS파일을 불러오지 못하더라.)
정말 거의 다왔다. 힘을내서 조금만 더 가보자.
이제 nginx의 Dockerfile을 생성해준다.

vi ~/docker_server/nginx/Dockerfile
FROM nginx:latest

COPY nginx.conf /etc/nginx/nginx.conf
COPY nginx-app.conf /etc/nginx/sites-available/

RUN mkdir -p /etc/nginx/sites-enabled/\
    && ln -s /etc/nginx/sites-available/nginx-app.conf /etc/nginx/sites-enabled/

EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]

이제 django때와 똑같이 build하면 된다.

docker run -p 80:80 mysite/nginx

사실 의미 없는 빌드이다. 아직 django가 연결되지 않았기 때문에 bad gateway가 뜰 것이다. 하지만 여기까지 무사히 성공했다는 확인용으로 build를 해보고 성공했으면 잠시 기뻐해보자.

docker-compose

이제 만든 nginx와 django 두개의 docker를 연결해주기만 하면 된다.

sudo curl -L https://github.com/docker/compose/releases/download/1.25.0-rc2/docker-compose-
`uname -s`-`uname -m` -o /usr/local/bin/docker-compose
sudo chmod +x /usr/local/bin/docker-compose

이제 우리는 docker-compose를 사용할 수 있다.

vi ~/docker-server/docker-compose.yml
version: '3'
services:

    nginx:
        container_name: nginx
        build: ./nginx
        image: docker-server/nginx
        restart: always
        ports:
          - "80:80"
        volumes:
          - ./mysite:/srv/docker-server
          - ./log:/var/log/nginx
        depends_on:
          - django

    django:
        container_name: django
        build: ./mysite
        image: docker-server/django
        restart: always
        command: uwsgi --ini uwsgi.ini
        volumes:
          - ./mysite:/srv/docker-server
          - ./log:/var/log/uwsgi

이렇게 생성했으면 지금까지 만들었던 Dockerfile들을 수정해주면 된다. 이유는 nginx-uwsgi-django의 조합으로 서버를 돌리기 때문에 runserver가 필요없기 때문이다. 또 uwsgi설정도 필요하기 때문에 uwsgi.ini파일 역시 생성해주도록 하자.
먼저 nginx/Dockerfile부터

FROM nginx:latest

COPY nginx.conf /etc/nginx/nginx.conf
COPY nginx-app.conf /etc/nginx/sites-available/

RUN mkdir -p /etc/nginx/sites-enabled/\
    && ln -s /etc/nginx/sites-available/nginx-app.conf /etc/nginx/sites-enabled/

#EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]

다음으로 mysite/Dockerfile

FROM python:3.6.7

ENV PYTHONUNBUFFERED 1

RUN apt-get -y update
RUN apt-get -y install vim

RUN mkdir /srv/docker-server
ADD . /srv/docker-server

WORKDIR /srv/docker-server

RUN pip install --upgrade pip
RUN pip install -r requirements.txt

#EXPOSE 8000
#CMD ["python", "manage.py", "runserver", "0.0.0.0:8000"]

마지막으로 ~/docker-server/mysite/폴더에 uwsgi.ini파일을 만들어주면 된다.

[uwsgi]
socket = /srv/docker-server/apps.sock
master = true

processes = 1
threads = 2

chdir = /srv/docker-server
module = mysite.wsgi

logto = /var/log/uwsgi/uwsgi.log
log-reopen = true

vacuum = true

docker-compose up -d --build 명령어를 통해서 서버가 돌아가는지 확인해보자.
-d옵션으로 데몬 모드를 설정해주었다.

뭔가 이상하지만 우선 잘 된다!!!! css파일이 깨지는데 이부분은 또 다음 포스팅에서 해결해보도록 하겠다.
어쨌든 이렇게해서 jango와 nginx를 docker를 통해서 구동시켜 보았다.

마지막으로 중간중간 실수를 하며 자주 사용하게 되었던 명령어들을 정리해보려고 한다.

도커 실행중인 컨테이너 중지

sudo docker stop $(sudo docker ps -aq)

도커 이미지 전체 삭제

docker rmi $(docker images -q)

도커 컨테이너 전체 삭제

docker rm $(docker ps -a -q)

0개의 댓글