장고 - Docker와 Elastic Beanstalk 이용하여 배포하기

Docker 란?

  • 도커는 가상 컴퓨팅 환경 - VirtualBox, Parallelss Desktop 같은 가상 컴퓨팅 환경과 비슷한 컨테이너 서비스이다.
  • 실제 가상 컴퓨팅 환경은 호스트 운영체제를 흉내내어 동작하는 방식을 사용하는데,
  • 도커는 별도의 독립된 환경을 구축하여 운영체제가 동작하는 것처럼 만들어져 있다.
  • 초기에는 LXC(Linux Container)방식으로 구현되어 리눅스 시스템이 아닌 곳에서는 도커를 사용하지 못했으나,
  • 현재는 runC라는 방식으로 변경되어 윈도우, 맥, 리눅스 등 다양한 운영체제에서 도커 시스템을 사용할 수 있다.
  • 도커를 사용하려면 도커 CLI가 설치되어야 한다.

Docker 이용 방법

1. 도커허브 가입

2. 로그인하여 도커 설치

  • MAC에서 도커 설치
    • 첫 화면에서 [Get started with Docker Desktop] 버튼 클릭
    • 다운로드된 파일 실행해 도커 데스크톱 설치
    • 다운받은 이미지를 실행해 도커를 Applications 폴더로 복사하면 설치 완료
    • 설치된 도커 프로그램 실행
    • 계정 정보 이용하여 로그인 진행
    • 터미널 실행하고 ‘docker’ 명령어 실행 –> 옵션들 나타나면 정상적으로 설치 완료된 것
  • Linux에서 도커 설치
    • docker 실행할 디렉토리 생성
      • $ mkdir docker_test
    • 터미널에서 $ curl -s https://get.docker.com/|sudo sh 실행
      • 만약 curl이 없다고 하면, $ sudo apt-get -y install curl 실행
    • 도커를 관리자 계정으로 실행해야 하는 번거로움을 없애기 위해 아래 명령어 실행
      • $ sudo usermod -aG docker $USER
    • ‘docker’ 명령어 실행하여 옵션 나타나는지 확인

3. 도커 사용하여 ubuntu 18.04 가상 컨테이너 사용

- run이라는 명령어를 사용하여 이미지명을 지정하여 새로운 컨테이너 실행 가능
- 도커 컨테이너는 프로세서가 실행되고 있는 동안에만 유효
- $ docker run ubuntu:18.04
    - 권한 없다고 나올 경우, 앞에 'sudo' 입력
    - 우분투 이미지 다운로드하고 컨테이너 실행 완료됨
- 현재 로컬에 있는 이미지 목록 확인
    - $ docker image ls

4. 우분투의 bash shell 실행

- $ docker run --rm -it ubuntu:18.04 bin/bash
    - --rm : 실행 종료 후 컨테이너 제거
    - -it : 쉘 실행할 경우 컨테이너의 표준 입력과 로컬 컴퓨터의 키보드 입력 연결
- 이제 원하는 명령을 컨테이너에 전달 가능하며, 여러가지 패키지 설치 가능

5. 컨테이너 생성하여 nginx 설치 및 테스트 진행

- 포트 포워딩 필요 -> run 명령어에 -p 옵션 넣으면 포워딩 포트 지정 가능
- $ docker container run --rm -it -p 8080:80 ubuntu:18.04 bin/bash
    - -p : 컨테이너 외부와 내부를 연결할 포트
- $ apt-get -y update
- $ apt-get -y install nginx
- $ nginx -v
- $ service nginx start

6. 웹 브라우저에서 로컬호스트에 8080 포트 이용하여 접속

- 호스트의 8080 포트는 컨테이너의 80 포트로 포워딩되므로 nginx 환영 메시지 확인 가능

7. 원하는 이미지를 베이스로 추가 프로그램 설치하여 최종 이미지 생성

- FROM은 베이스가 되는 이미지
- MAINTAINER는 본인 이메일
- RUN은 이미지 생성 시 실행할 명령어
- $ vim Dockerfile.base
    
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
FROM    ubuntu:18.04
MAINTAINER positipman@gmail.com

RUN apt-get -y update
RUN apt-get -y install vim
RUN apt-get -y install nginx
RUN apt-get -y install python3-dev python3-venv python3-pip
RUN apt-get -y install supervisor

RUN useradd -b /home -m -s /bin/bash django
RUN usermod -a -G www-data django
RUN mkdir -p /var/www/django
RUN mkdir -p /var/www/django/run
RUN mkdir -p /var/www/django/logs
RUN mkdir -p /var/www/django/ini

RUN python3 -m venv /var/www/django/venv
RUN chown -R django:www-data /var/www/django
RUN chmod -R g+w /var/www/django

ADD ./code /var/www/django/code

RUN /var/www/django/venv/bin/pip3 install uwsgi

ADD ./conf/uwsgi/uwsgi.service /etc/systemd/system/uwsgi.service
ADD ./conf/nginx/default /etc/nginx/sites-available/default
ADD ./conf/uwsgi/uwsgi.ini /var/www/django/ini/uwsgi.ini
ADD ./conf/requirements.txt /var/www/django/requirements.txt

RUN /var/www/django/venv/bin/pip3 install -r /var/www/django/requirements.txt

ADD ./conf/supervisord.conf /etc/supervisorsupervisord.conf

CMD ["/usr/bin/supervisord"]

#CMD ["nginx", "-g", "daemon off;"]
# 참고 : RUN /var/www/django/venv/bin/django-admin startproject config /var/www/django

8. 이미지 생성하기 전, docker_test 디렉토리에 code, conf 디렉토리 생성

- 이미지 생성하기 위한 code 폴더 생성
    - $ mkdir code
    - 프로젝트 소스코드 붙여넣기
- 이미지 생성하기 위한 uwsgi 폴더 생성
    - $ mkdir conf
    - $ cd conf
    - $ mkdir uwsgi
    - $ cd uwsgi
    - $ vim uwsgi.ini
        
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
[uwsgi]
uid = django
base = /var/www/django

home = %(base)/venv
chdir = %(base)/code
module = config.wsgi:application
env = DJANGO_SETTINGS_MODULE=config.settings

master = true
processes = 5

socket =%(base)/run/uwsgi.sock
logto = %(base)/logs/uwsgi.log
chown-socket = %(uid):www-data
chmod-socket = 660
vacuum = true
- $ vim uwsgi.service
1
2
3
4
5
6
7
8
9
10
11
12
[Service]
ExecStart=/var/www/django/venv/bin/uwsgi --emperor /var/www/django/ini
User=django
Group=www-data
Restart=on-failure
KillSignal=SIGQUIT
Type=notify
NotifyAccess=all
StandardError=syslog

[Install]
WantedBy=multi-user.target
- 이미지 생성하기 위한 nginx 폴더 생성 - $ mkdir nginx - $ cd nginx - $ vi default
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
upstream django {
server unix:/var/www/django/run/uwsgi.sock;
}
server {
listen 80;
charset utf-8;
access_log /var/www/django/logs/access.log;
error_log /var/www/django/logs/error.log;
server_name _;

location = favicon.ico { access_log off; log_not_found off; }

location / {
include /etc/nginx/uwsgi_params;
uwsgi_pass django;
}
}

9. Dockerfile.base를 기반으로 새로운 이미지 생성

- $ cd docker_test
- $ docker image build -f Dockerfile.base -t django .
- 생성된 이미지를 목록에서 확인
    - $ docker image ls

10. 생성된 이미지로 컨테이너 생성하여 장고 서버 셋팅 및 배포

- $ docker container run -it --rm -p 8080:80 django:latest bash
    - 기존 패키지 업데이트(이미지로 생성됨)
        - $ apt-get update
    - Nginx 설치 (이미지로 생성됨)
        - $ apt-get install nginx
    - Vim 설치(이미지로 생성됨)
        - $ apt-get install vim
    - 파이썬 관련 패키지 설치(이미지로 생성됨)
        - $ apt-get install python3-dev python3-venv python3-pip
    - django 애플리케이션 구동용 계정 생성 (이미지로 생성됨)
        - $ useradd -b /home -m -s /bin/bash django
    - www-data 그룹에 django 유저 추가 (이미지로 생성됨)
        - $ usermod -a -G www-data django
    - 소스코드 업로드 위한 폴더 생성(이미지로 생성됨)
        - $ mkdir -p /var/www/django
    - uwsgi 모듈을 위한 폴더 생성(이미지로 생성됨)
        - $ mkdir /var/www/django/run
        - $ mkdir /var/www/django/logs
        - $ mkdir /var/www/django/ini
    - uwsgi 설정 파일 생성(이미지로 생성됨)
        - $ vim /var/www/django/ini/uwsgi.ini
    - 가상 환경을 소스코드 폴더 밑에 생성(이미지로 생성됨)
        - $ python3 -m venv /var/www/django/venv
    - 소스코드 업로드 전, 폴더 소유자와 사용권한 변경 (이미지로 생성됨)
        - $ chown -R django:www-data /var/www/django
        - $ chmod -R g+w /var/www/django
    - 소스코드 폴더에서 code 폴더 추가 생성 (이미지로 생성됨)
        - $ mkdir /var/www/django/code
        - var/www/django에 소스코드 직접 업로드하게 되면, 기존 폴더가 삭제될 수 있다.
        - 이를 방지하기 위해, code 폴더 생성하여 소스코드 옮겨놓고 연동시키는 방법이 있다. 
    (django_test 폴더의 code 폴더 내 소스코드와 연동된다. --> uwsgi.ini파일에 chdir %(base)/code 작성한 이유) 
    - 가상환경에 패키지 설치하기 위해 소스코드 폴더로 이동
        - $ cd /var/www/django
    - 가상환경 활성화
        - $ source venv/bin/activate
    - 의존성 패키지 설치 (이미지로 생성됨)
        - $ pip install -r requierments.txt
    - uwsgi 설치 (이미지로 생성됨)
        - $ pip install uwsgi
    - uwsgi 모듈로 구동 여부 확인
        - $ uwsgi --http :8080 --home /var/www/django/venv/ --chdir /var/www/django/ --module config.wsgi
    - uwsgi.servie 파일 작성 (이미지로 생성됨)
        - $ vim /etc/systemd/system/uwsgi.service

    - Nginx의 디폴트 사이트 파일 작성 (이미지로 생성됨)
        - $ vim /etc/nginx/sites-available/default

    - uwsgi 실행
        - $ uwsgi -i /var/www/django/ini/uwsgi.ini &
            - 뒤에 '&'를 입력하면 빠져나왔을 경우에도 계속 uwsgi 실행되도록 해준다.
    - 실행되고 있는 uwsgi 확인
        - $ jobs
        - uwsgi 실행 중지
            - $ pkill -f uwsgi -9
    - Nginx 재시작
        - $ service nginx restart
    - 웹 브라우저에서 사이트 뜨는지 확인

11. supervisor 설치 및 설정 파일 복사하는 명령어 입력

- 웹 서버 배포할 시, nginx와 uwsgi 모두 동작하는 형태로 배포해야 한다.
- 도커의 특성상 하나의 프로세스만 동작하는 명령을 실행할 수 있고, 동작하는 프로세스가 없는 경우 컨테이너는 종료된다.
- 이런 문제를 해결하기 위해 supervisor라는 모듈을 사용한다.
- vim conf/supervisord.conf
1
2
3
4
5
[supervisord]
nodaemon=true

[program:nginx]
command = nginx -g "daemon off;"
- $ vim Dockerfile.base
1
2
3
4
5
...
RUN apt-get -y install supervisor
ADD ./conf/supervisord.conf /etc/supervisor/supervisord.conf

CMD ["/usr/bin/supervisord"]

12. 새로운 내용으로 이미지 생성

-$ docker image build -f Dockerfile.base -t django .
- 만약 캐시 때문에 문제가 발생한다면 --no--cacche 옵션을 더해준다.

13. 새로운 이미지로 컨테이너 실행하여 웹 브라우저에서 정상 응답이 있는지 확인

- $ docker container run -it --rm -p 8080:80 django:latest

14. 도커 허브에서 기본 이미지를 자신의 repositary에 배포

- 도커 허브로 이동하여 [Repositaries] 버튼 클릭
- [Create Repository] 버튼 클릭
- 내용 입력
- name : django
- description : for docker test
- Visibility의 경우 [Private] 선택
- [Create] 버튼 클릭

15. 터미널에서 명령 입력해 이미지의 repositary와 태그 설정

- $ docker tag django:latest positipman/django:0.1

16. 도커 이미지 업로드

- $ docker push positipman/django:0.1

17. 배포가 완료되면 도커 허브에서 이미지 확인 가능

18. 도커 로그인 정보 파일 생성

- $ docker login
- ~/.docker/config.json 파일이 생성된 것 확인
- 해당 파일을 S3 버킷을 만들어 업로드

19. eb init 명령 실행

- $ eb init

20. Dockerrun.aws.json 파일 생성하여 필요 내용 입력

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
{
"AWSEBDockerrunVersion":"1",
"Authentication": {
"Bucket": "nginx-docker",
"Key": "config.json",
},
"image": {
"Name": "positipman/django",
"Update": "true",
},
"Ports": [
{
"ContainerPort": "80",
}
],
"Logging": "/var/log",
}