Nginx Uwsgi Django Docker
Background
- client - nginx - socket - uwsgi - django 연결
AWS 서버 생성
- ec2 ubuntu 생성
- python, 가상환경 생성
$ top
$ ls -rlt
$ sudo apt update
$ sudo apt install python3-pip
$ sudo apt install virtualenv
$ virtualenv venv --python=python3
$ source venv/bin/activate
- ec2 인바운드 보안설정에 TCP 8000포트, 위치무관 추가
- 장고 설치
- 'ALLOWED_HOSTS' 변경
- 런서버
filename : settings.py
ALLWED_HOSTS = ['*']
$ python manage.py runserver 127.0.0.1:8000 # 로컬만 되니 이거 말고
$ python manage.py runserver 0.0.0.0:8000 # 이것으로
- AWS DNS로 접속 확인
- 장고 런서버는 디버깅을 위한 서버 - 성능이 안 좋다, 이에 아래 구조로 구현
- 웹 클라이언트 - 웹 서버 - 소켓 - WSGI(Web server Gateway Interface) - Django - Python function
- wsgi - 서버와 프레임워크 통신
- 소켓을 쓰는 이유는 통신을 하면 헤더를 써서 과정이 하나 더 생기는데 소켓을 쓰면 그러지 않아도 되기 때문
uwsgi
$ pip install uwsgi
$ uwsgi --http :8000 --module projectname.wsgi
- uwsgi 설정파일 만들기
$ cd /etc
$ sudo mkdir uwsgi
$ cd uwsgi
$ sudo mkdir sites
$ cd sites
$ vim projectname.ini // 아래 내용 추가
[uwsgi]
base = /home/ubuntu/projectname
home = /home/ubuntu/venv # 가상환경 경로
chdir = %(base) # 프로젝트 경로
module = projectname.wsgi:application
socket = /tmp/django.sock # 장고 뒤에 이름은 임의로 가능
chmod-socket = 666 # 소켓 권한 설정, 666은 누구나 쓸 수 있다는 의미
master = true # 마스터 프로세스는 워커 프로세스들을 감시한다
enable-threads = true # 멀티 쓰레드 옵션
pidfile = /tmp/django.pid # 프로세스 kill할 때 하나씩 pid 찾아서 해야 하는 번거로움을 덜기 위해 한 개로 묶어주는 옵션
vaccum = true # uwsgi가 내려가면 자동으로 pid, socket 등을 지워주는 옵션
logger = file:/tmp/uwsgi.log # 로그 남길 경로 설정
- 실행
# 실행
$ uwsgi -i /etc/uwsgi/sites/projectname.ini --http :8000
# 실행확인
$ ps -ef | grep uwsgi
# 파일추적
# 명령 실행한 상태로 웹접속하면 곧장 로그가 뜬다
$ tail -f /tmp/uwsgi.log
nginx
- 설치
$ sudo apt-get install nginx
- 설정 폴더 자동으로 생김
/etc/nginx/
- 설정 파일 확인
$ vim /etc/nginx/nginx.conf
- 설정 파일 변수 내용 하나하나 숙지 중요
- 여기를 참고 - Nginx와 uWSGI 설치해서 연결하기 + docker로 mysql 띄우기
tcp_nopush on;
- tcp 패킷전송 시 개별이 아니라 모아서 전송하는 혼잡제어 가능하게 만듦tcp_nodelay_on;
- 작은 데이터도 기다리지 않고 바로 보내도록 만듦- nginx는 상반되는 두 옵션을 상황에 맞게 대응 가능
# 서버설정
$ sudo vim /etc/nginx/sites-enabled/projectname # 아래 내용 추가
upstream djnago {
server unix:///tmp/django.sock;
} # 서버그룹을 정의, 서버가 여러 개면 여러 개 작성 가능
server {
listen 80;
server_name localhost;
charset utf-8;
client_max_body_size 75M; # 클라이언트 요청 최대 사이즈
location / {
uwsgi_pass django; # uwsgi 요청이 오면 바로 장고로
include /etc/nginx/uwsgi_params;
}
} # 서버 정의
- aws 보안그룹 인바운드
- HTTP 80 포트
- TCP 8080 포트 위치무관 설정 추가
- nginx를 구동하면 /etc/nginx/nginx.conf에서 /etc/nginx/sites-enables/projectname을 읽어서
- 80(http) 포트로 오는 요청을 uwsgi로 보냄
- 이에 nginx listen 포트는 80이 아닌 8080으로 변경
$ sudo vim /etc/nginx/sites-enables/default
# 8080으로 변경
server {
listen 8080 default_server;
listen [::]:8080 defulat_server;
}
- 실행
# 실행
$ uwsgi -i /etc/uwsgi/sites/projectname.ini # uwsgi 먼저 실행
$ sudo systemctl start nginx # nginx start
# 확인
$ ps -ef | grep nginx
- 로그
$ vim /etc/nginx/nginx.conf # log 경로 찾을 수 있다
$ cd /var/log/nginx
$ tail -f /var/log/nginx/access.log
Docker
Mysql
- ec2에서 설치
# docker 설치
$ curl -fsSL https://get.docker.com/ | sudo sh
# 현재 접속 유저 권한 설정
$ sudo usermod -aG docker $USER
# 특정 유저 권한 설정
$ sudo uwermod -aG docker username
- MySQL docker pull
- Docker Hub
$ docker pull mysql
- Docker Hub
- 실행
$ docker run -it --rm --name mysql-db -p 3306:3306 -e MYSQL_ROOT_PASSWORD=password -e MYSQL_PASSWORD=password mysql
- 확인
$ docker ps
settings.py
변경
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql',
'HOST': '127.0.0.1',
'NAME': 'mysql-db',
'USER': 'root',
'PASSWORD': 'password',
'PORT': '3306',
'OPTIONS': {'charset': 'utf8mb4'},
}
}
Redis
$ docker run --rm --name some-redis -d -p 6379:6379 redis
settinsg.py
CACHES = {
"default": {
"BACKEND" : "django_redis.cache.RedisCache",
"LOCATION" : "redis://127.0.0.1",
"OPTIONS": {
"CLIENT_CLASS" : "django_redis.client.DefaultClient",
}
}
}
Django
- 도커서버 폴더생성, 프로젝트 이동
$ mkdir docker-server
$ mv projectname/ docker-server/
- Dockerfile 생성
$ cd docker-server
$ vim Dockerfile
# /docker-server/server_dev/Dockerfile
FROM python:3
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
RUN pip install -r ./projectname/requirements.txt
EXPOSE 8000 CMD ["python", "./projectname/manage.py", "runserver", "0.0.0.0:8000"]
requirements.txt
->pip freeze > requirements.txt
로 생성- 버전 호환 안 되는 라이브러리 있으면 수동 점검해야
- Docker 빌드
- -t는 이름 붙이는 옵션 - projectname/django
- .은 이미지를 만들 경로
$ docker build -t projectname/django .
- 이미지 확인
$ docker image list
- 도커 실행
- -p 옵션으로 서버 포트(호스트 포트)와 도커 포트를 맞춰준다.
$ docker run -p 8000:8000 projectname/django
Nginx
# ~/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;"]
- 빌드
$ docker build -t projectname/nginx .
- 실행
$ docker run -p 80:80 projectname/nginx
Docker-compose
- 여러 개의 이미지를 관리하는 툴, 두 개의 이미지를 연결
- nginx docker + 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
명령으로 실행 확인- Dokerfile처럼 docker-compose.yml을 사용해 설정
# ~/docker-server/docker-compose.yml
version: '3'
services:
nginx:
container_name: nginx
build: ./nginx
image: projectname/nginx
restart: always
ports:
- "80:80"
volumes:
- ./projectname:/srv/docker-server
- ./log:/var/log/nginx
depends_on:
- django
django:
container_name: django
build: ./projectname
image: docker-server/django
restart: always
command: uwsgi --ini uwsgi.ini
volumes:
- ./server_dev:/srv/docker-server
- ./log:/var/log/uwsgi
- 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;"]
- uwsgi.ini 파일 생성
# ~/docker-server/server_dev/uwsgi.ini
[uwsgi]
socket = /srv/docker-server/apps.sock
master = true
processes = 1
threads = 2
chdir = /srv/docker-server
module = projectname.wsgi
logto = /var/log/uwsgi/uwsgi.log
log-reopen = true
vacuum = true
- 빌드
- -d는 데몬
- run이 아닌 up/down
$ docker-compoase up -d --build
- 확인
$ docker-compose ps