django channels on ec2
django channels
를 ec2
에 올려 노티 기능을 만들어 보기 위한 프로젝트
프로젝트 셋팅
mkdir django-channels-on-ec2
cd django-channels-on-ec2
git init
touch .gitignore
https://www.gitignore.io/에서git,linux,macos,python,django,pycharm+all
검색후 복사
1..secrets
를.gitignore
에 추가pyenv virtualenv 3.6.5 ec2
pyenv local ec2
pip install django
django-admin startproject config
mv config app
pip freeze > requirements.txt
settings.py
수정BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) ROOT_DIR = os.path.dirname(BASE_DIR) TEMPLATES_DIR = os.path.join(BASE_DIR, 'templates') SECRETS_DIR = os.path.join(ROOT_DIR, '.secrets') SECRETS_BASE = os.path.join(SECRETS_DIR, 'base.json') secrets = json.loads(open(SECRETS_BASE, 'rt').read()) SECRET_KEY = secrets['SECRET_KEY'] ALLOWED_HOSTS = [ '.amazonaws.com', ]
.secret/base.json
파일 추가{ "SECRET_KEY": "<django secret key>" }
git hub
설정
1.git hub
->new repository
->django-channels-on-ec2
2.git remote add origin git@github.com:himanmenGit/django-channels-on-ec2.git
3.git push -u origin master
git add -A && git commit -m 'first commit'
ec2 셋팅
ec2 instance 생성
ubuntu 16.04
선택t2.micro
프리티어 선택- 다음,다음,다음 6단계 보안 그룹 구성
- 새 보안 그룹 생성
1. 보안 그룹 이름 -EC2 Security Group
2. 보안 그룹 설명 -Ec2 Deploy Security Group
3. 소스 -내 IP
, 설명 -ssh
4. 규칙 추가 -사용자 지정 TCP
, 포트 번호8000
, 소스내 IP
, 설명web
- 검토 및 시작 - 시작
- 키페어를 저장 후 인스턴스 시작 (
permission
에러 나면chmod 400 <key pair>.pem
) 'ssh -i <key path>ex)~/key.pem ubuntu@<ec2 ip4 퍼블릭 IP>',
YES
-Welcome to Ubuntu 16.04
linux setting
1.sudo vi /etc/default/locale
2.locale
수정 후 재 접속LC_CTYPE="en_US.UTF-8" LC_ALL="en_US.UTF-8" LANG="en_US.UTF-8"
linux update
1.sudo apt-get update
2.sudo apt-get dist upgrade
마지막에 엔터
3.sudo apt-get install -y make build-essential libssl-dev zlib1g-dev libbz2-dev libreadline-dev libsqlite3-dev wget curl llvm libncurses5-dev libncursesw5-dev xz-utils tk-dev
pyenv
설치
1.curl -L https://github.com/pyenv/pyenv-installer/raw/master/bin/pyenv-installer | bash
2.vi ~/.bash_profile
에 마지막 설정 복사
3.source ~/.bash_profile
적용
4.pyenv
명령 확인export PATH="/home/ubuntu/.pyenv/bin:$PATH" eval "$(pyenv init -)" eval "$(pyenv virtualenv-init -)"
-
git
설치
1.sudo apt-get install libcurl4-gnutls-dev libexpat1-dev gettext libz-dev libssl-dev
2.git
확인 srv
폴더 유저 변경
1.sudo chown -R ubuntu:ubuntu /srv/
- 프로젝트
clone
및pyenv
설정
1.git clone <django-channels-on-ec2 repository url>.git
2.cd django-channels-on-ec2
3.pyenv install 3.6.5
4.pyenv virtualenv 3.6.5 ec2
5.pyenv local ec2
.secrets
폴더 업로드
1.scp -ri <key_path>.pem .secrets ubuntu@<public ipv4>:/srv/django-channels-on-ec2/
runserver
1.pip install -r requirements.txt
2../manage.py runserver 0:8000
-
브라우저 확인
1. 브라우저에<public dns주소>:8000
으로 접속
2. 로켓 발싸! -
redis-server
설치redis-channel-layer
를 사용하려면 필요.sudo apt-get install redis-server
-
tmux
설치sudo apt-get install tmux
tmux
키고redis-server
켬tmux new
(ctrl+b) + %
후 창이 나뉘어 지면(ctrl+b) + q
를 사용하여 창 이동후redis-server
작동시킴
chat 설정
django-admin startapp chat
model
from django.db import models class Room(models.Model): name = models.CharField(verbose_name='채팅방 이름', max_length=255) group_name = models.SlugField(verbose_name='채팅방 그룹 이름', unique=True) def __str__(self): return self.name class RoomMessage(models.Model): room = models.ForeignKey(Room, related_name='messages', on_delete=models.CASCADE) message = models.TextField(verbose_name='메세지') created = models.DateTimeField(verbose_name='생성 날짜', auto_now_add=True, db_index=True) def __str__(self): return self.message def get_created(self): return self.created.strftime('%p %I:%M')
routing.py
from django.urls import path from . import consumers websocket_urlpatterns = [ path('ws/main/', consumers.ChatConsumer), ]
consumers.py
import json from channels.generic.websocket import AsyncJsonWebsocketConsumer class ChatConsumer(AsyncJsonWebsocketConsumer): async def connect(self): self.noti_group_name = 'main' await self.channel_layer.group_add( self.noti_group_name, self.channel_name ) await self.accept() async def disconnect(self, code): await self.channel_layer.group_discard( self.noti_group_name, self.channel_name ) async def chat_message(self, event): message = event['message'] created = event['created'] await self.send(text_data=json.dumps({ 'message': message, 'created': created }))
config
에asgi.py
추가""" ASGI entrypoint. Configures Django and then runs the application defined in the ASGI_APPLICATION setting. """ import os import django from channels.routing import get_default_application os.environ.setdefault("DJANGO_SETTINGS_MODULE", "config.settings") django.setup() application = get_default_application()
config
routing.py
추가from channels.auth import AuthMiddlewareStack from channels.routing import ProtocolTypeRouter, URLRouter from chat.routing import websocket_urlpatterns application = ProtocolTypeRouter({ 'websocket': AuthMiddlewareStack( URLRouter( websocket_urlpatterns ) ) })
templatestags
폴더 추가 및 코드 추가# chat app ├── templatetags │ ├── __init__.py │ └── chat_extra_tags.py
# chat_extra_tags.py from django import template from chat.models import Room register = template.Library() @register.simple_tag def get_main_message(): room = Room.objects.get(group_name='main') old_messages = room.messages.order_by('-created')[:50] return old_messages
# settings.py TEMPLATES = [ { 'BACKEND': 'django.template.backends.django.DjangoTemplates', 'DIRS': [ # 추가 'templates' ], ...
settings.py
INSTALLED_APPS = [ 'channels', ... 'chat', ] ... ASGI_APPLICATION = 'config.routing.application' CHANNEL_LAYERS = { 'default': { 'BACKEND': 'channels_redis.core.RedisChannelLayer', 'CONFIG': { "hosts": [('127.0.0.1', 6379)], }, }, }
channels
,channels-redis
설치
1.pip install channels
2.pip install channels-redis
3.pip freeze > requirements.txt
4.git commit and push
ec2 에서 pull받아 작업
git pull origin master
pip install -r requirements.txt
./manage.py makemigraions && migrate
실행후 다음 메시지로 변경System check identified no issues (0 silenced). January 04, 2019 - 09:00:48 Django version 2.1.4, using settings 'config.settings' Starting development server at http://127.0.0.1:8000/ Quit the server with CONTROL-C. 에서 System check identified no issues (0 silenced). January 04, 2019 - 08:59:23 Django version 2.1.4, using settings 'config.settings' # 아래 부분에 development server 가 ASGI로 바뀜 Starting ASGI/Channels version 2.1.6 development server at http://0:8000/ Quit the server with CONTROL-C.
view에 index.html 추가
#chat/views.py
from django.views.generic import TemplateView
from chat.models import Room
class Home(TemplateView):
template_name = 'index.html'
def get(self, request, *args, **kwargs):
# 단순히 시작히 룸을 만들기 위한 장치
Room.objects.get_or_create(name='노티룸', group_name='main')
return super().get(request, *args, **kwargs)
# index.html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8"/>
<title>Chat Room</title>
</head>
<body>
<textarea id="chat-log" cols="100" rows="20"></textarea><br/>
</body>
{% load chat_extra_tags %}
<script src="//cdnjs.cloudflare.com/ajax/libs/reconnecting-websocket/1.0.0/reconnecting-websocket.min.js"></script>
<script>
{% get_main_message as old_messages %}
let chat_log = document.querySelector("#chat-log");
(function () {
let messages = [{% for message in old_messages %}'{{ message }}',{% endfor %}];
let creaties = [{% for message in old_messages %}'{{ message.get_created }}',{% endfor %}];
for (i = messages.length; i > 0; i--) {
chat_log.value += ('message:[' + messages[i - 1] +']-- created:[' + creaties[i - 1] + ']\n');
}
})();
let chatSocket = new ReconnectingWebSocket('ws://' + window.location.host + '/ws/main/');
chatSocket.onmessage = function (e) {
let data = JSON.parse(e.data);
let message = data['message'];
let created = data['created'];
chat_log.value += ('message:[' + message +']-- created:[' + created + ']\n');
};
chatSocket.onclose = function (e) {
console.error('Chat socket closed unexpectedly', e);
};
</script>
</html>
서버에서 redis-server
가 켜진 상태로 runserver
를 해서 접속하면
HTTP GET / 200
WebSocket DISCONNECT /ws/main/
WebSocket HANDSHAKING /ws/main/
WebSocket CONNECT /ws/main/
이런 로그가 나오면 성공.
api를 하나 열어서 메세지를 웹 소켓으로 전달
-
django-rest-framework
설치pip install djangorestframework
chat/views.py
에API
추가from rest_framework.response import Response from rest_framework.views import APIView from channels.layers import get_channel_layer from asgiref.sync import async_to_sync ... class Notification(APIView): def post(self, request, *args, **kwargs): room = Room.objects.get(group_name='main') message = room.messages.create(message=request.data.get('message')) channel_layer = get_channel_layer() async_to_sync(channel_layer.group_send)( 'main', { 'type': 'chat_message', 'message': str(message), 'created': message.created.strftime('%p %I:%M') } ) return Response({'status': 200, 'meesage': '{} send success'.format(message)})
urls.py
에api
용url
추가# urls.py ... urlpatterns = [ ... path('notification/', Notification.as_view()) ]
pip freeze > requirements.txt
git commit and push
확인
- 서버에 가서
git pull origin master
를 한후 pip install -r requirements.txt
로drf
를 설치 한다음- 서버를 다시 실행
./manage.py runserver 0:8000
ec2
의public dns
의url
을 기준으로한api
주소를requests
를 이용하여post
import requests res = requests.post('http://123.456.789.0.ap-northeast-2.compute.amazonaws.com:8000/notification/', data={'message':'hello'}) print(res) >>> <Response [200]> print(res.content) >>> b'{"status":200,"meesage":"hello send success"}'
localhost:8000
aws public dns
다음편 에서는 ssl
을 통해 웹소켓을 wss
로 암호화하여 통신하는 법에 대해 알아 보자.
참고 사이트
victolee님의 블로그
darkblank님의 블로그
readthedocs
Comments