postgresql이란?
- 오픈 소스 데이터베이스로 무료로 사용 가능합니다.
- 또한 장고에서는 기본 데이터베이스로 postgresql을 사용하는 것을 권장하고 있습니다.
- docker에서 사용 가능한 이미지들은 https://hub.docker.com 에서 제공하고 있습니다.
# 백업하기
mkdir backup
sudo mv ./* ./backup/
# 전체 삭제
sudo rm -rf ./*
ls -l
sudo docker ps -a
sudo docker rm -f 24 36 #숫자는 컨테이너 id
sudo docker volume prune
# 사용되지 않는 모든 것을 삭제
sudo docker system prune -a
vi docker-compose.yml
version: '3.8'
volumes:
postgres: {} # postgresql에서 사용 할 볼륨 지정
services:
postgres:
container_name: postgres
image: postgres:14.5
volumes:
- postgres:/var/lib/postgresql/data/
environment: # postgresql 컨테이너에서 사용할 환경변수 지정해주기
- POSTGRES_USER=user # 데이터베이스 사용자 지정
- POSTGRES_PASSWORD=P@ssw0rd # 사용자 비밀번호 지정
- POSTGRES_DB=django # 데이터베이스 이름 지정
restart: always
sudo docker compose up -d
gunicorn이란?
- django 프로젝트를 실행할 때 사용되는 runserver와 같이, 사용자의 요청을 받아 django에 작성한 코드를 실행시켜 주도록 하는 역할을 해줍니다.
- 단순하게 생각해서 배포용으로 사용되는 runserver라고 생각해도 무관합니다.
- 기본적으로 runserver는 배포용이 아닌 개발용으로 사용되는 명령어이며, 공식 문서에서도 runserver로 배포하는 것을 권장하지 않고 있습니다.
- runserver는 기본적으로 싱글 스레드에서 동작하지만, gunicorn은 멀티 스레드로 동작하도록 설정할 수 있기 때문에 많은 요청을 더 효율적으로 처리할 수 있습니다.
mkdir backend
cd backend/
git clone https://github.com/sparta-course/drf-project.git ./django
# 경로 변경시 추후에 docker compose 파일에서 볼륨을 잡아줄 때 수정이 필요함
vi django/drf_project/settings.py
# 아래 코드로 변경
ALLOWED_HOSTS = ['*']
STATIC_ROOT = BASE_DIR / "static"
# timezone 변경
sudo ln -sf /usr/share/zoneinfo/Asia/Seoul /etc/localtime
date
vi Dockerfile
# python 3.10.8버전 이미지를 사용해 빌드
# 프로젝트와 일치시키는 것을 권장
FROM python:3.10.8
# .pyc 파일을 생성하지 않도록 설정합니다.
ENV PYTHONDONTWRITEBYTECODE 1
# 파이썬 로그가 버퍼링 없이 즉각적으로 출력하도록 설정합니다.
ENV PYTHONUNBUFFERED 1
# /app/ 디렉토리를 생성합니다.
RUN mkdir /app/
# /app/ 경로를 작업 디렉토리로 설정합니다.
WORKDIR /app/
# requirments.txt를 작업 디렉토리(/app/) 경로로 복사합니다.
COPY ./django/requirements.txt .
# 프로젝트 실행에 필요한 패키지들을 설치합니다.
RUN pip install --no-cache-dir -r requirements.txt
# gunicorn을 사용하기 위한 패키지를 설치합니다.
RUN pip install gunicorn
cd ..
vi docker-compose.yml
version: '3.8'
services:
backend:
container_name: backend
build: ./backend/
# drf_project.wsgi는 프로젝트 경로에 맞게 지정해야 합니다.
entrypoint: sh -c "python manage.py collectstatic --no-input && python manage.py migrate && gunicorn drf_project.wsgi --workers=5 -b 0.0.0.0:8000"
ports:
- 80:8000
volumes:
- ./backend/django/:/app/
- /etc/localtime:/etc/localtime:ro # host의 timezone 설정을 컨테이너에 적용합니다.
# ro 은 읽기 전용(read only) 속성으로 볼륨을 설정하는 것을 의미합니다.
restart: always
entrypoint의 명령어는 아래와 같이 나눠서 해석할 수 있습니다.
sh -c : 컨테이너에서 뒤에 작성한 명령어를 실행시킬 수 있도록 해줍니다.
&& : 특정 명령어를 실행한 이후 다음 명령어를 실행시켜 줍니다.
python manage.py collectstatic --no-input : 배포를 위해 static 파일을 모아줍니다. 해당 명령어를 실행시키기 위해서는 settings.py에 STATIC_ROOT가 정의되어 있어야 합니다.
python manage.py migrate : django에 연결된 db를 migrate 해줍니다.
gunicorn project_name.wsgi --workers=5 -b 0.0.0.0:8000 : gunicorn을 사용해 django 프로젝트를 실행시킵니다.
- project_name : django 프로젝트 이름을 입력합니다. 이름을 다르게 입력할 경우 에러가 발생합니다.
- --workers=5 : django를 실행시킬 process 갯수를 입력합니다. 일반적으로 cpu 코어 갯수 * 2 + 1만큼 지정해줍니다.(ex - 2코어라면 2*2+1=5)
- -b 0.0.0.0:8000 : 8000번 포트로 실행시킵니다.
sudo docker compose up -d
sudo docker compose logs -f
nginx란?
- nginx는 클라이언트의 request 요청을 처리해주는 웹 서버(web server)입니다.
- reverse proxy, 로드밸런싱, 캐싱 등의 기능을 지원하며, 클라이언트의 요청을 nginx가 받은 후 service(django) 데이터를 넘겨주는 역할을 해줍니다.
- 로드밸런싱을 활용해 트래픽을 분산할 수 있습니다.
- SSL 기능을 사용해 데이터를 안전하게 전달할 수 있습니다.
- reverse proxy 기능을 통해 client에서 서버에 직접적으로 접근하는 것을 막아줍니다.
- 콘텐츠를 캐싱하여 동일한 요청에 대해 더 빠른 속도로 처리할 수 있게 해줍니다.
vi docker-compose.yml
version: '3.8'
services:
nginx:
container_name : nginx
image: nginx:1.23.2
ports:
- "80:80" # http 포트포워딩
- "443:443" # https 포트포워딩
restart: always
sudo docker compose up -d
# 장고가 이미 80번 포트를 사용하고 있으므로 에러가 남
sudo docker ps
sudo docker rm -f c8 92 # 숫자는 본인 컨테이너 ID
sudo docker compose up -d
sudo docker compose logs -f
nginx / postgresql / django 연동하기
mkdir nginx
vi nginx/default.conf
server {
listen 80;
server_name _; # 모든 도메인 혹은 ip로 들어오는 요청에 대해 처리해 줍니다.
location / { # nginx로 요청이 들어왔을 때
proxy_pass http://backend:8000/; # backend 컨테이의 8000번 포트로 전달합니다.
}
location /static/ { # 브라우저에서 /static/ 경로로 요청이 들어왔을 때
alias /static/; # /static/ 경로에 있는 파일들을 보여줍니다.
}
location /media/ { # 브라우저에서 /media/ 경로로 요청이 들어왔을 때
alias /media/; # /media/ 경로에 있는 파일들을 보여줍니다.
}
}
vi backend/django/drf_project/settings.py
# 해당부분 수정하기
import os
# 환경변수에 따라 DEBUG모드 여부를 결정합니다.
DEBUG = os.environ.get('DEBUG', '0') == '1'
# 접속을 허용할 host를 설정합니다.
ALLOWED_HOSTS = ['backend', ]
# postgres 환경변수가 존재 할 경우에 postgres db에 연결을 시도합니다.
POSTGRES_DB = os.environ.get('POSTGRES_DB', '')
if POSTGRES_DB:
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.postgresql',
'NAME': POSTGRES_DB,
'USER': os.environ.get('POSTGRES_USER', ''),
'PASSWORD': os.environ.get('POSTGRES_PASSWORD', ''),
'HOST': os.environ.get('POSTGRES_HOST', ''),
'PORT': os.environ.get('POSTGRES_PORT', ''),
}
}
# 환경변수가 존재하지 않을 경우 sqlite3을 사용합니다.
else:
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.sqlite3',
'NAME': BASE_DIR / 'db.sqlite3',
}
}
# CORS 허용 목록에 ec2 ip를 추가합니다.
CORS_ORIGIN_WHITELIST = ['http://$ec2_public_ip']
# ex) CORS_ORIGIN_WHITELIST = ['http://43.201.72.190']
# CSRF 허용 목록을 CORS와 동일하게 설정합니다.
CSRF_TRUSTED_ORIGINS = CORS_ORIGIN_WHITELIST
sudo docker compose down
sudo docker ps -a
vi docker-compose.yml
version: '3.8'
volumes:
postgres: {}
django_media: {}
django_static: {}
services:
postgres:
container_name: postgres
image: postgres:14.5
volumes:
- postgres:/var/lib/postgresql/data/
environment:
- POSTGRES_USER=user
- POSTGRES_PASSWORD=P@ssw0rd
- POSTGRES_DB=django
restart: always
backend:
container_name: backend
build: ./backend/
entrypoint: sh -c "python manage.py collectstatic --no-input && python manage.py migrate && gunicorn drf_project.wsgi --workers=5 -b 0.0.0.0:8000"
volumes:
- ./backend/django/:/app/
- /etc/localtime:/etc/localtime:ro
- django_media:/app/media/ # nginx에서 media를 사용할 수 있도록 volume을 지정해줍니다.
- django_static:/app/static/ # nginx에서 static을 사용할 수 있도록 volume을 지정해줍니다.
environment: # django에서 사용할 설정들을 지정해줍니다.
- DEBUG=1
- POSTGRES_DB=django
- POSTGRES_USER=user
- POSTGRES_PASSWORD=P@ssw0rd
- POSTGRES_HOST=postgres
- POSTGRES_PORT=5432
depends_on:
- postgres
restart: always
nginx:
container_name : nginx
image: nginx:1.23.2
ports:
- "80:80"
- "443:443"
volumes:
- ./nginx/default.conf:/etc/nginx/conf.d/default.conf
- django_media:/media/ # django의 media를 사용할 수 있도록 volume을 지정해줍니다.
- django_static:/static/ # django의 static 사용할 수 있도록 volume을 지정해줍니다.
depends_on:
- backend
restart: always
vi backend/Dockerfile
# 수정하기
RUN pip install gunicorn psycopg2
sudo docker compose up -d --build
sudo docker compose logs -f
sudo docker exec -it backend /bin/bash
python manage.py createsuperuser
python manage.py shell
from django.db import connections
from pprint import pprint
pprint(connections.databases)
배포 환경의 통신 구조
가장 먼저 사용자는 EC2의 nginx에 request 요청을 하게 됩니다.
nginx에서는 사용자의 요청을 받아 .conf 파일에서 설정한 서버로 요청을 전달합니다.
이후 gunicorn에서는 django로, django에서는 필요에 따라 데이터베이스에 쿼리를 날려 개발자가 작성한 코드를 실행하게 됩니다.
env 작성하기
vi .env
DEBUG=1
POSTGRES_DB=django
POSTGRES_USER=user
POSTGRES_PASSWORD=P@ssw0rd
POSTGRES_HOST=postgres
POSTGRES_PORT=5432
vi docker-compose.yml
# 해당 부분의 environment만 수정하기
services:
postgres:
environment:
- POSTGRES_USER
- POSTGRES_PASSWORD
- POSTGRES_DB
backend:
environment: #
- DEBUG
- POSTGRES_DB
- POSTGRES_USER
- POSTGRES_PASSWORD
- POSTGRES_HOST
- POSTGRES_PORT
sudo docker compose up -d
vi .env
# DEBUG=0 으로 바꾸고 페이지가 달라지는지 확인하기
slim 이미지
- 이미지마다 지원하는 버전은 차이가 있습니다.
- 동일한 docker 이미지라 하더라도 태그에 따라 이미지의 용량이 달라집니다.
- 가령 python 이미지의 경우 가장 큰 이미지와 가장 작은 이미지의 용량이 300mb 이상 차이납니다.
- 용량이 작은 이미지를 사용할 때는 외부 패키지를 설치할 때 필요한 의존성 파일들이 존재하지 않아 에러가 발생할 수 있습니다.
- 내가 사용하는 이미지에 어떤 종류의 태그가 존재하는지 확인이 필요할 때는 https://hub.docker.com/ 이미지 페이지의 tags에서 확인 가능합니다.
이미지의 태그별 특징
- buster, jessie, stretch
- debian에서 만든 linux를 기반으로 만들어진 이미지입니다.
- buster, jessie, stretch는 os의 codename입니다. (링크)
- python:3.8과 python:3.8-buster는 동일합니다. (약 300~350mb)
- slim
- 실행에 필요한 환경만 만들어둔 이미지입니다.
- 이미지가 기본이미지에 비해서는 작습니다. (약 40~50mb)
- 보통 python 실행환경에서 가장 많이 쓰이는 이미지
- alpine
- 용량이 작고, 보안에 집중한 alpine-linux 기반으로 만들어진 이미지입니다.
- 보통 이미지들 중에서 가장 작다는 특징을 가지고 있습니다. (약 15~20mb)
- python기준으로 봤을 때, pip install을 할 때 불리한 점이 있습니다.
vi backend/Dockerfile
# python 3.10.8-slim버전 이미지를 사용해 빌드
FROM python:3.10.8-slim
ENV PYTHONDONTWRITEBYTECODE 1
ENV PYTHONUNBUFFERED 1
RUN mkdir /app/
WORKDIR /app/
# slim 이미지에서 postgresql 패키지를 설치하기 위해 필요 명령어 추가
RUN apt update && apt install libpq-dev gcc -y
COPY ./django/requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
RUN pip install gunicorn psycopg2
vi docker-compose.yml
services:
postgres:
image: postgres:14.5-alpine # alpine으로 수정
nginx:
image: nginx:1.23.2-alpine # alpine으로 수정
sudo docker compose up -d --build
sudo docker images
# 필요없는 이미지 삭제
sudo docker rmi aa c7 # 숫자는 none이라고 쓰인 이미지ID
sudo docker image prune -a #컨테이너에서 사용중인 이미지 이외에 모두 삭제
도메인 배포 서버에 연결
AWS, 가비아, freenom 등 마음에 드는 곳에서 구매하면 됩니다.
freenom의 경우 무료이지만 오류가 많습니다.
도메인이 등록되는데 최대 24시간까지 걸리기도 합니다.
ex) 소셜로그인 오류, xxx.tk 등 도메인 전체 주소를 입력해야 하는 오류 등
www를 강제로 붙여주는 작업
vi nginx/default.conf
server {
listen 80;
server_name www.spartacodingclub.tk; # www.spartacodingclub.tk 도메인으로 들어오는 요청을 처리해줍니다.
location / {
proxy_pass http://backend:8000/;
}
location /static/ {
alias /static/;
}
location /media/ {
alias /media/;
}
}
server {
listen 80;
server_name spartacodingclub.tk; # www가 없는 url로 요청 했을 때
return 301 http://www.spartacodingclub.tk$request_uri; # www를 붙인 url로 redirection 해줍니다.
}
sudo docker compose restart nginx
https 란?
- 웹 서버에서 데이터를 전송하기 위한 http 프로토콜에 보안을 의미하는 secure를 붙여 http 통신을 더 안전하게 할 수 있도록 해주는 프로토콜입니다.
- 보안적인 특성 때문에 배포를 하는 서비스에는 https를 필수적으로 적용하게 됩니다.
- https를 적용하기 위해서는 SSL 인증서를 발급받고 웹서버에서 인증서를 지정해주는 과정이 필요합니다.
vi backend/django/drf_project/settings.py
CORS_ORIGIN_WHITELIST = ['https://www.winterakoon.shop',]
sudo docker compose restart backend
※ '503 Service Temporarily Unavailable' 에러가 발생하는 경우 로드밸런싱 대상 그룹에 Healthy 부분을 잘 체크하자. 인스턴스 가용영역을 서브넷에서 설정하지 않은 경우 unused라고 나타나며 에러가 발생하기도 한다. 이 경우 로드벨런서 서브넷 편집에서 해당 가용영역을 추가하면 해결할 수 있다.
※ 보안 그룹 선택할 경우 생성후 인바운드 규칙을 바로 추가해주거나, 애초에 SSH, HTTPS, HTTP 포트 허용한 걸로 선택하자.
'aws' 카테고리의 다른 글
02.5 [Docker] putty (0) | 2023.05.31 |
---|---|
2주차 [Docker] docker (0) | 2023.05.31 |
1주차 [Docker] Linux (0) | 2023.05.30 |
11. [aws] EBS(Elastic Beanstalk) & http를 https로 리다이렉트 (0) | 2023.05.26 |
10. [aws] CDN (0) | 2023.05.26 |