서버개발자가 되는법 [2_1] - django, nginx 도커로 구동하기

     

목차

2020/09/29 - [Study/서버] - 서버개발자가 되는법 - 목차

 

 

 

 

 

유튜브 - 빠르게 따라하실 분은 동영상을 생략하셔도 됩니다 :)

 

 

들어가기 전에

 

지난 포스팅에서 nginx-uwsgi-django + mysql(docker)까지 연동을 했습니다. 일단 mysql만 docker로 만들었는데요, nginx와 django도 docker로 만들면 어떨까요?

 

최근 하나의 서버에서 모든기능이 동작하는 monolithic architecture에 상대대는 개념으로 각각의 기능별로 서버를 쪼개는 micro service architecture(MSA)가 살짝쿵 유행하고 있습니다. 물론 두 가지 모두 장단점이 있기 때문에 상황에 필요한 구조를 사용하는 것이 중요합니다.

 

docker가 등장하면서 컨테이너로 서버를 운영/배포/관리가 쉬워지고, 컨테이너를 관리하는 툴(오케스트라)이 등장하면서 MSA를 만드는데 용이해지고 있는데요, 그래서 더더욱 MSA가 유행하는것 같습니다. 

 

하지만 docker로 서버를 구성하는것이 무조건 MSA가 되는 것은 아니구요, 단순히 운영/배포적인 측면에서도 상당한 이점이 있기 때문에 dockernize(도커화)를 많이 하는 추세입니다.

 

따라서 저희도 만들었던 서버를 docker화 해보자구요~!

(docker에 대한 개념 설명은 생략합니다. 구글링 하면 많이 나와요 ><)

 

 

 

Django -> docker로 만들기

일단 docker로 만들 건데 어디까지 docker로 만들지 범위를 정해야 합니다. 범위를 정한다는 게 이상하게 들릴 수 있는데요, 예를 들면 django만 docker로 만들고 nginx는 서버에 직접 설치하는 방식인지, 아니면 nginx와 django 모두 docker로 만들지를 정하는 겁니다.

 

저희는 nginx-uwsgi-django 모두 docker로 만들어 보겠습니다.

 

우선 django를 docker로 띄워볼 건데 일단 docker를 설치해야겠지요?

curl -fsSL https://get.docker.com/ | sudo sh
sudo usermod -aG docker $USER # 현재 접속중인 사용자에게 권한주기

 

먼저 docker로 만들 서버의 루트 폴더를 만들어줍니다. 홈에서 mkdir로 적당한 이름으로 폴더를 생성합니다.

 

mkdir docker-server

 

지난 시간에 하던 django 프로젝트를 docker-server 폴더 안으로 이동시킵니다. 

저는 새로운 인스턴스에서 진행하고 있어서 git clone으로 새로 프로젝트를 따오겠습니다.

 

ubuntu@ip-172-31-33-49:~$ cd docker-server/
ubuntu@ip-172-31-33-49:~/docker-server$ ll
total 8
drwxrwxr-x 2 ubuntu ubuntu 4096 Jun 13 16:38 ./
drwxr-xr-x 6 ubuntu ubuntu 4096 Jun 13 16:42 ../
ubuntu@ip-172-31-33-49:~/docker-server$ git clone -b 서버개발자_2_1 https://github.com/tkdlek11112/server_dev.git
Cloning into 'server_dev'...
remote: Enumerating objects: 28, done.
remote: Counting objects: 100% (28/28), done.
remote: Compressing objects: 100% (18/18), done.
remote: Total 28 (delta 7), reused 24 (delta 6), pack-reused 0
Unpacking objects: 100% (28/28), done.
Checking connectivity... done.
ubuntu@ip-172-31-33-49:~/docker-server$

 

요론 구조가 되었을 겁니다.

└── docker-server
    └── server_dev 

 

이제 server_dev 안에 들어가서 Dockerfile을 만듭니다. docker의 시작은 Dockerfile입니다.

vi Dockerfile로 파일을 생성하고 아래와 같이 적습니다.

 

# /docker-server/server_dev/Dockerfile
FROM python:3.6.7  # 생성하는 docker의 python 버전

ENV PYTHONUNBUFFERED 1 

RUN apt-get -y update 
RUN apt-get -y install vim # docker 안에서 vi 설치 안해도됨

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 이미지를 만들 수 있습니다.

 

여기서 명령어중에 pip install -r requirements.txt가 있는데, 여기는 django에 필요한 패키지들이 나열되어 있습니다. 추가로 나중에 uwsgi를 사용하기 위한 uwsgi패키지도 명시되어있어야 합니다. 이 포스팅에서 필요한 requirements.txt는 아래와 같습니다.

 

# requirements.txt
asgiref==3.2.7
Django==3.0.5
pytz==2019.3
sqlparse==0.3.1
uwsgi

 

docker build -t server_dev/django .

 

-t는 만드는 docker 이미지에 이름을 붙여주는 옵션입니다. 그 뒤에 .은 docker 이미지로 만들 폴더 경로를 말합니다. 저희는 ~/docker-server/server_dev/ 경로에 있기 때문에 .을 찍어서 현재 폴더를 지정합니다.

 

step by step으로 진행됨

 

명령어를 실행하면 터미널 창에 이것저것 뜨면서 docker 이미지가 생성되는 것을 볼 수 있습니다. 

(명령어를 실행했는데 권한 에러가 뜬다면, 위에서 docker 권한 설정하는 명령어를 치고, ssh 재접속을 하면 될 거예요)

 

이미지가 정상적으로 만들어졌는지 확인하기 위해서는 docker image list라고 입력하면 됩니다.

 

생성된 이미지들을 확인할 수 있습니다

 

우리가 -t 옵션으로 이름을 붙였던 server_dev/django가 있는 것을 확인할 수 있습니다. 그럼 이 이미지를 실행해보겠습니다. -p 옵션으로 서버 자체의 포트(호스트 포트번호)와 docker의 포트번호를 맞춰줍니다.

 

docker run -p 8000:8000  server_dev/django​

 

docker 이미지가 실행되면서 바로 django가 실행된다

Dockerfile에 runserver를 이용해 django를 실행하는 명령어를 적어놨기 때문에 docker 이미지를 실행하게 되면 runserver가 실행됩니다. 실제로 서버 url에 접속해보면 django 페이지가 뜨는 것을 확인할 수 있습니다. (방화벽 확인 필수~)

 

 

Nginx -> docker 만들기

 

이제 Nginx를 docker로 만들어봅시다. 사실 Nginx는 쉽습니다. Django야 우리가 만든 프로젝트를 docker에 넣기 위해 이것저것 해야 하지만 Nginx는 그냥 config 파일만 몇 개 있으면 됩니다. 아래 두 개의 config와 Dockerfile을 만듭니다.

 

 

# ~/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/*;
}
# ~/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/;
    }
}
​
# ~/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 build -t server_dev/nginx .

 

 

이제 nginx docker 이미지를 실행합니다.

 

docker run -p 80:80 server_dev/nginx​

 

된다?

 

실제로 url을 치고 들어가 보면 nginx서버가 가동 중인 것을 확인할 수 있습니다.

 

 

하지만 bad gateway

 

하지만 nginx 이후에 uwsgi.sock이 연결되지 않았기 때문에 django랑은 연결되지 않는데요,,,

 

이제 드디어 docker-compose를 사용할 때입니다!!!

 

 

 

 

Nginx docker + django docker = docker-compose

 

docker 이미지를 두 개를 띄웠는데요, 두 개의 다른 docker에서 서로 연결하려면 어떻게 할까요? 사실 docker끼리 연결하기 위해 잡다구리한 옵션을 넣어서 docker run을 해야 합니다. 하지만 그렇게 하면 불편하니까 우리는 docker-compose를 씁니다.

 

docker-compose는 여러 개의 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를 입력하면 무엇인가 실행되는 것을 확인할 수 있습니다.

docker-compose는 docker의 Dockerfile처럼 docker-compose.yml을 사용해서 설정값을 입력할 수 있습니다.

~/docker-server 경로에 docker-compose.yml 파일을 생성합니다. vi docker-compose.yml!!

 

요 위치

 

# docker-compose.yml
version: '3'
services:

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

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

 

이렇게 한방 설정을 할 수 있습니다. 포트 설정을 docker-compose.yml에서 정의하고 uwsgi설정도 하기 때문에 uwsgi.ini를 만들고, 각각의 Dockerfile도 살짝 변경이 필요합니다.

 

# ~/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;"]

 

# /docker-server/server_dev/Dockerfile
FROM python:3.6.7  # 생성하는 docker의 python 버전

ENV PYTHONUNBUFFERED 1 

RUN apt-get -y update 
RUN apt-get -y install vim # docker 안에서 vi 설치 안해도됨

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-server/server_dev/uwsgi.ini
[uwsgi]
socket = /srv/docker-server/apps.sock
master = true

processes = 1
threads = 2

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

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

vacuum = true

 

이제 모든 준비는 끝났습니다.

 

└── docker-server
    ├── docker-compose.yml
    ├── nginx
    │   ├── Dockerfile
    │   ├── nginx-app.conf
    │   └── nginx.conf
    └── server_dev
        ├── Dockerfile
        ├── manage.py
        ├── README.md
        ├── requirements.txt
        ├── server_dev
        │   ├── asgi.py
        │   ├── __init__.py
        │   ├── __pycache__
        │   ├── settings.py
        │   ├── urls.py
        │   └── wsgi.py
        └── uwsgi.ini

 

위와 같은 구조로 폴더가 구성되어있습니다. 이제 ~/docker-server로 가서 docker-compose를 build 하고 실행합니다.

 

docker-compose up -d --build

 

-d 옵션은 데몬 모드입니다. docker-compose는 run이 아니라 up/down으로 관리합니다.

실행하면 또다시 터미널에 명령어가 한가득 나옵니다. 그러고 나서 nginx와 django의 docker 이미지가 실행됩니다. 

실행이 완료되고 docker-compose ps를 입력하면 docker-compose 상태를 알 수 있습니다.

 

docker-compose 상황

docker-compose라고 해서 docker와 별개인 것이 아닌 각각의 docker 이미지의 상황을 모아서 보여주는 도구일 뿐입니다. 실제로 docker ps와 docker image ls를 입력하면 우리가 docker-compose.yml에 ./build로 정의했던 이미지들이 생성되고, 실행 중인 것을 확인할 수 있습니다.

 

docker ps , docker image ls

 

그럼 nginx-uwsgi-django가 정상적으로 연결되었는지 확인해볼까요?

url을 입력해 접속해 봅시다.

 

 

완료~~!

 

정상적으로 접속됩니다~!!

 

 

 

정리하기

 

docker를 이용해 nginx와 django 이미지를 생성하고, docker-compose를 이용해 두 개의 docker 이미지를 하나의 파일로 실행시켰습니다. 

 

만약 django 소스가 변경된다면 docker-compose down, docker-compose up으로 재실행하면 적용됩니다.

(Dockerfile이 변경되었다면 build부터 다시 해주어야 합니다)

 

docker-compose는 각각의 Dockerfile을 build 하고 run하는 역할로 우리가 터미널에서 docker run <option>으로 docker를 실행하는 것을 스크립트로 적어논것이라고 생각하면됩니다. 즉 docker-compose.yml만 있으면 되는것이 아니라 각각의 Dockerfile도 있어야 한다는 것이죠. docker-compose는 각각의 docker를 build하고 상관관계를 정의해주어서 좀 더 쉽게 docker 이미지를 관리할 수 있게 해 줍니다.

 

사실 docker-compose에 docker로 실행했던 mysql을 추가해서 3개의 docker 이미지를 관리하게 만들 수 있습니다. 하지만 저는 mysql은 AWS RDS 인스턴스를 사용하는 걸 선호하기 때문에 따로 docker-compose에 넣지 않았습니다. 혹시 mysql도 docker-compose에 추가하고 싶으신 분은 스스로 도전해보시면 도움이 될 것 같습니다.

 

위에 사용된 파일은 github에 올려두었으니 docker와 docker-compose만 설치하시면 바로 실행해보실 수 있습니다.

 

github = https://github.com/tkdlek11112/docker-server1

 

 

 

 

 

 

반응형

댓글

Designed by JB FACTORY