base.py 

"""
Django settings for polalis project.

Generated by 'django-admin startproject' using Django 1.8.6.

For more information on this file, see
https://docs.djangoproject.com/en/1.8/topics/settings/

For the full list of settings and their values, see
https://docs.djangoproject.com/en/1.8/ref/settings/
"""

# Build paths inside the project like this: os.path.join(BASE_DIR, ...)
import os

BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))


# Quick-start development settings - unsuitable for production
# See https://docs.djangoproject.com/en/1.8/howto/deployment/checklist/

# SECURITY WARNING: keep the secret key used in production secret!
SECRET_KEY = 'p5^ykf!%2(8q3lxqfi_+&ivv*xy7!77bcjc9-9^uw#eopu6e7o'

# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = True

ALLOWED_HOSTS = []


PROJECT_APPS = (
    'account',
    'bankbook',
    'cashbook',
    'cashreceipt',
    'credit',
    'ebill',
    'etaxbill',
    'finment',
    'library',
    'login',
    'polalis',
    'process',
    'scrapping',
    'situation',
    'slipfix',
    'statement',
    'trade',
    'trialbalance',

)

# Application definition

INSTALLED_APPS = (
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.sites',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'django_jenkins',
    'rest_framework',
    'rest_framework_swagger',
    'django_crontab',
    'account',
    'bankbook',
    'cashbook',
    'cashreceipt',
    'credit',
    'ebill',
    'etaxbill',
    'finment',
    'library',
    'login',
    'polalis',
    'process',
    'scrapping',
    'situation',
    'slipfix',
    'statement',
    'trade',
    'trialbalance',
)

JENKINS_TASKS = (
    'django_jenkins.tasks.run_pylint',
)

PYLINT_LOAD_PLUGIN = (
    'pylint_django',
)
'''
REST_FRAMEWORK = {
    # Use Django's standard `django.contrib.auth` permissions,
    # or allow read-only access for unauthenticated users.
    'DEFAULT_PERMISSION_CLASSES': [
        'rest_framework.permissions.DjangoModelPermissionsOrAnonReadOnly'
    ]
}
'''

MIDDLEWARE_CLASSES = (
    'django.middleware.cache.UpdateCacheMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.common.CommonMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.auth.middleware.SessionAuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    'django.middleware.clickjacking.XFrameOptionsMiddleware',
    'django.middleware.security.SecurityMiddleware',
)

ROOT_URLCONF = 'polalis.urls'

TEMPLATES = [
    {
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
        'DIRS': [os.path.join(BASE_DIR, '../templates')],
        'APP_DIRS': True,
        'OPTIONS': {
            'context_processors': [
                'django.template.context_processors.debug',
                'django.template.context_processors.request',
                'django.contrib.auth.context_processors.auth',
                'django.contrib.messages.context_processors.messages',
            ],
        },
    },
]

CRONJOBS = [
    ('*/10 * * * *', 'scrapping.cron.scrapping_cron', '>> /tmp/scrapping_cron.log')
]

WSGI_APPLICATION = 'polalis.wsgi.application'



SWAGGER_SETTINGS = {
    'exclude_namespaces': [],
    'api_version': '0.1',
    'api_path': '/',
    'enabled_methods': [
        'get',
        'post',
        'put',
        'patch',
        'delete'
    ],
    'is_authenticated': False,
    'is_superuser': False,
    'unauthenticated_user': 'django.contrib.auth.models.AnonymousUser',
    'permission_denied_handler': None,
    'info': {
        'title': 'Polaris API',
    },
    'doc_expansion': 'none',
}

# Internationalization
# https://docs.djangoproject.com/en/1.8/topics/i18n/

LANGUAGE_CODE = 'en-us'

TIME_ZONE = 'Asia/Seoul'

USE_I18N = True

USE_L10N = True

USE_TZ = True



# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/1.8/howto/static-files/

STATIC_URL = '/static/'
STATICFILES_DIRS = (
    os.path.join(BASE_DIR, '../static'),
    './static/',
)


dev.py

from polalis.settings.base import *

CRONTAB_DJANGO_SETTINGS_MODULE = 'polalis.settings.dev'

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.postgresql_psycopg2',
        'NAME': 'polaris',
        'USER': 'sunrise',
        'PASSWORD': '1234',
        'HOST': 'postgres',
        'PORT': '5432'
    },
    'trialbalance': {
        'ENGINE': 'django.db.backends.postgresql_psycopg2',
        'NAME': 'polaris_0108',
        'USER': 'sunrise',
        'PASSWORD': '1234',
        'HOST': 'postgres',
        'PORT': '5432'
    },
    'cashbook': {
        'ENGINE': 'django.db.backends.postgresql_psycopg2',
        'NAME': 'cashbook',
        'USER': 'sunrise',
        'PASSWORD': '123',
        'HOST': 'postgres',
        'PORT': '5432'
    },
    'papyrus': {
        'ENGINE': 'django.db.backends.postgresql_psycopg2',
        'NAME': 'polaris_papyrus',
        'USER': 'sunrise',
        'PASSWORD': '1234',
        'HOST': 'postgres',
        'PORT': '5432'
    },
    'polaris_0108': {
        'ENGINE': 'django.db.backends.postgresql_psycopg2',
        'NAME': 'polaris_0108',
        'USER': 'sunrise',
        'PASSWORD': '1234',
        'HOST': 'postgres',
        'PORT': '5432'
    }
}


base.py는 공통적으로 사용하는 부분을 작성하는 파일입니다.

local.py, dev.py 등 세팅환경을 분리하여 작성할 때 사용되며 from polalis.settings.base import * 와 같이 base.py를 참조합니다.

파일경로

SUNRISE(프로젝트) / SUNRISE (앱) / settings(폴더) / base.py, server.py, __init__.py (빨간색 부분은 생성해야함)

세팅

  1. 기존에 사용하던 settings.py 안의 코드를 local.py에 전부 복사/붙여넣기합니다.
  2. TEMPLATES =[  { ... 'DIRS': [os.path.join(BASE_DIR'../../templates')] ... } ] 이와 같이 구성되어 있다면 DIRS를 다음과 같이 변경합니다.
    1. -> 'DIRS': [os.path.join(BASE_DIR'../templates')]
  3. STATICFILES_DIRS = ( os.path.join(BASE_DIR"../static"), ... 이와 같이 구성되어 있다면 os.path.join의 경로를 다음과 같이 변경합니다.

    1. -> os.path.join(BASE_DIR"../static")

  4. local.py는 로컬에서 실행하기 위해 설정한 파일이고, dev.py는 서버에서 실행시키기 위해 만든 파일입니다. 현재 server에서 변경할 부분은 databases의 속성밖에 없으므로, databases의 속성만 변경합니다. (위 코드 참조)
  5. /SUNRISE 앱 내의 wsgi.py 폴더를 살펴보면 os.environ.setdefault("DJANGO_SETTINGS_MODULE""SUNRISE.settings") 이렇게 실행 시, default로 참조할 settings 파일 경로 부분을 다음과 같이 변경합니다.
    1. -> os.environ.setdefault("DJANGO_SETTINGS_MODULE""SUNRISE.settings.local") - 서버일 경우 local 대신 dev를 입력합니다.

실행법

  • 파이참에서 실행할 경우

    1. 상단 메뉴 탭의 Run - Run - Edit Configrations... - Environment - Environment variables: 우측의 ... 버튼 클릭 - DJANGO_SETTINGS_MODULE의 Value값을 SUNRISE.settings.local로 변경


  • 터미널에서 실행할 경우

    • 터미널 창에서 python manage.py runserver (호출할 URL) -- settings파일이 존재하는 폴더=project.폴더.실행시킬 파일
      • e.g,) python manage.py runserver ip주소:80 -- settings=SUNRISE.settings.server


이전 장고의 settings.py 파일을 분리했던 것과 같은 이유로 환경변수를 분리하는 방법을 설명하겠습니다.


코드

import sys


def get(func):
    try:
        for i in range(1, len(sys.argv)):
            settings_str = "--settings="
            settings_index = sys.argv[i].find(settings_str)
            # 받은 argument 중 좌변이 환경변수 분리 키 값일 경우, 우변의 값을 경로를 저장합니다.
            if settings_index != -1:
                # 입력받은 값을 변수에 저장
                actions = sys.argv[i][settings_index + len(settings_str):]

        # 받은 값으로 import로 선언
        tmp = __import__(actions)
        # 선택할 settings 파일명만 선택
        env_name = actions[actions.rfind(".") + 1:]
        # 위에서 구한 함수이름으로 호출
        instance = getattr(tmp, env_name)

    except Exception as e:
        # 아무 입력안될 시, 에러를 내고 프로그램 종료
        print(e)
        print("입력한 파라미터를 확인해주세요")
        exit()

    try:
        # 파라미터로 받은 값을 사용해 동적으로 함수 및 변수들을 호출
        return getattr(instance, func)

    except Exception as e:
        raise e


databases = {
    'default': {
        'DBNAME': 'postgres',
        'USER': 'postgres',
        'PASSWORD': '1234',
        'HOST': '127.0.0.1',
        'PORT': '5432'
    },
	'other': {
		'DBNAME': 'postgres2',
        'USER': 'postgres',
        'PASSWORD': '1234',
        'HOST': '127.0.0.1',
        'PORT': '5432'
    }
} 


from env import get

# default로 정의되어 있는 데이터베이스 정보를 호출하고 싶은 경우,
get('databases')['default']

파일경로

untitled(패키지) / settings(폴더) / base.py, local.py, ...  (빨간색 부분은 생성해야함)


세팅

직접 파일생성하여 실행할 경우

  1. env.py를 생성하여 위에 작성된 코드를 넣습니다.
  2. main이나 데이터베이스를 호출하는 파일에서 from env import get를 넣어줍니다.
  3. get() 함수를 사용

pip로 다운로드받아서 사용할 경우

virtualenv를 사용하는데 터미널에서 그냥 해당 명령어를 실행시켜 다운로드 받을 경우, 파이썬의 인터프리터는 virtualenv를 바라보고 있는데 설치는 virtualenv가 아닌 파이썬 자체에 모듈이 설치되기 때문에 인식을 할 수 없습니다.

virtualenv를 사용할 경우

  1. 터미널 실행
  2. 사용하고 있는 virtualenv 폴더로 이동
  3. source bin/activate 명령어 실행
  4. pip3 install --trusted-host ip주소 --index-url http://ip주소/simple/ env 명령어 실행

  5. from env import get를 추가하여 get()함수를 사용

virtualenv를 사용하지 않는 경우

  1. 터미널 실행
  2. pip3 install --trusted-host ip주소 --index-url http://ip주소/simple/ env 명령어 실행
  3. from env import get를 추가하여 get()함수를 사용

실행법

파이참에서 실행할 경우

상단 메뉴 탭의 Run - Run... - Edit Configrations... Script parameters에 환경변수가 들어있는 폴더 및 파일명을 작성합니다.

예) 

현재버전은 Script Parameters 부분에 --settings=settings.base 로 입력해야 합니다.


터미널에서 실행할 경우

python 실행파이썬파일 폴더.파일 과 같은 형식으로 호출합니다.

예) python main.py --settings=settings.base

사용법

settings

  • local.py

main.py

databases = {
    'default': {
        'DBNAME': 'postgres',
        'USER': 'postgres',
        'PASSWORD': '1234',
        'HOST': '127.0.0.1',
        'PORT': '5432'
    },
	'other': {
		'DBNAME': 'postgres2',
        'USER': 'postgres',
        'PASSWORD': '1234',
        'HOST': '127.0.0.1',
        'PORT': '5432'
    }
} 


from env import get
 
print(env('databases')['default'])


와 같이 폴더 구조와 local.py, main.py의 코드가 잡혀있다고 가정합니다.

위 세팅법을 통해 먼저 설치를 한 후, main.py에 from env import get를 추가합니다.

다음 터미널에서 python main.py --settings=settings.local을 입력하여 main.py를 실행시킵니다.

실행결과는 local.py 파일의 databases라는 dict 변수를 읽고 그 중, default에 정의되어 있는 DB 정보를 출력하게 됩니다.

privated pypi 서버

privated pypi서버에 올라온 패키지들의 목록이 궁금하면 등록ip주소/simple url을 입력하면 올라와있는 서버의 패키지를 확인할 수 있습니다.



아래와 같은 dict 타입의 변수가 존재한다고 할 때, 첫 번째와 두 번쨰의 차이점은 무엇일까?

dict_test={"a":"1","b":"2"}
#1
dict_test.clear()
#2
dict_test={}


두 코드 기능은 "지운다" 라는 점에 있어 동일합니다. 하지만 dict_test라는 변수를 재사용할 때, 큰 차이점이 있습니다.


#1의 경우입니다.

dict_test={"a":"1","b":"2"}
 
temp_dict=dict_test
 
dict_test.clear()
print(temp_dict)
 
결과: {}


#2의 경우입니다.

dict_test={"a":"1","b":"2"}
 
temp_dict=dict_test
 
dict_test={}
print(temp_dict)
 
결과: {"a":"1","b":"2"}


#2의 경우, dict_test={}를 할 때, 새로운 {} (비어있는 dict 타입)을 새로 생성하고 dict_test의 값을 {}에 할당합니다. 이 때, temp_dict는 값이 할당되어 있는 예전 변수의 값인 {"a":"1","b":"2"}를 가리키고 있기 때문에, dict_test를 추가하거나 삭제해도 그대로 값이 존재합니다.

반면 #1의 경우, dict_test.clear()를 할 경우, dict_test와 temp_dict 둘 다 가리키고 있는 point의 값을 지워버리기 때문에 temp_dict에 값을 할당하고 clear()를 해도 가리키고 있는 point의 값이 존재하지 않게 됩니다.



"2016-01-01" 이라는 문자열을 아래와 같이 사용하면 datetime 객체로 변환 가능

1
2
3
4
import date
 
test_date="2016-01-01"
convert_date = datetime.datetime.strptime(test_date, "%Y-%m-%d").date()
cs

"20160101"이라는 문자열을 아래와 같이 사용하면 역시 변환 가능

1
2
3
4
import date
 
test_date="20140206"
convert_date = datetime.datetime.strptime(test_date, "%Y%m%d").date()
cs

결과 값은 전부 "2016-01-01"의 datetime 객체 형태로 반환된다.


아래와 같이 strftime을 사용하여 현재일의 년월일을 문자열로 구할 수 있다.

1
today = datetime.datetime.today().strftime("%Y-%m-%d").split('-')
cs



Django는 파이썬에서 제공하는 웹프레임워크입니다. Django에는 코드를 자체적으로 테스트하기 위한 간단한 웹서버를 가지고 있고, 이를 실행하는 명령어는 runserver입니다. 

제품출시를 할 때에는 Django에서 제공하는 간단한 웹서버를 사용하는 것이 아닌, 보안이 더 좋고 강력한 웹서버가 필요합니다. 지금부터는 runserver로 Django 자체 웹서버를 실행하는 것이 아닌, uWSGI를 사용하여 Nginx와 연동하는 법을 설명하겠습니다.


사양

VIRTUAL BOXUbuntu-64bit 14.04 LTS
RAM2GB
HDD8GB
pythonpython 3.4.3
djangodjango 1.8.7


uWSGI 지원 플랫폼/시스템


개발에 앞서, uWSGI는 전 OS에 지원하는 것이 아닌, 특정 OS/System에만 지원을 합니다. 윈도우의 경우, uWSGI를 지원하지 않아서 pip로 다운로드가 불가능하며 동작하지 않습니다. 따라서 Virtual Box에 우분투 14.04를 설치하여 테스트 하였습니다. 

Platforms/Systems

Linux 2.6/3.x

FreeBSD >= 7

NetBSD

OpenBSD

DragonFlyBSD

Windows Cygwin

Mac OSX

Solaris >= 10

NexentaOS

SmartOS

OpenSolaris

OpenIndiana

OmniOS

Debian/kFreeBSD

GNU/Hurd


virtualenv 세팅


먼저 virtualenv를 설정해야 합니다. virtualenv를 사용하는 이유는 각 프로젝트 별로 필요로 하는 개발 환경이 다르기 때문입니다. 만약 이를 나누지 않고 하나로 사용하게 되면 전체 시스템에 패키지가 전체 설치가 되어 새로운 프로젝트에선 사용하지 않는 패키지가 존재하는 모습이 됩니다.


아래 명령어를 실행시켜 pip을 설치합니다.

$ sudo apt-get update
$ sudo apt-get install python3-pip

(본 가이드는 파이썬 3.4.3 버전을 사용하기 때문에 python3-pip를 다운받아 pip가 아닌, pip3 명령어를 사용합니다.)


pip3이 설치가 되었으면 virtualenv를 설치할 수 있습니다.

$ sudo pip3 install virtualenv


설치가 완료된 다음, 다음과 같이 명령어를 작성하여 'uwsgi-tutorial'란 이름으로 virtualenv를 생성한 뒤, 해당 폴더로 들어가 활성화 시킵니다.

$ virtualenv uwsgi-tutorial
$ cd uwsgi-tutorial
$ source bin/activate

활성화가 제대로 되었을 경우, hostname@server:~/uwsgi-tutorial에서 (uwsgi-tutorial)hostname@server:~/uwsgi-tutorial 이렇게 바뀝니다.


env가 활성화 되어있는 상태에서 django를 설치해줍니다. 

$ pip3 install django==1.8.7


설치가 완료된 후, 프로젝트를 생성한 다음, 해당 프로젝트로 이동합니다.

$ django-admin.py startproject testproject
$ cd uwsgi


여기까지 정상적으로 진행했을 시, 파일은 다음과 같습니다.


uWSGI 세팅


먼저 uWSGI를 설치합니다. 이때, source bin/activate된 상태를 유지해야 됩니다.

$ pip3 install uwsgi


다음 test.py를 ~/uwsgi-tutorial에 생성합니다.

#sudo vi test.py
def application(env, start_response):
    start_response('200 OK', [('Content-Type','text/html')])
    return [b"Hello World"] # python3


uwsgi로 test.py을 실행시켜 작동하는지 확인합니다.


$ uwsgi --http :8000 --wsgi-file test.py


127.0.0.1:8000을 접속하면 hello world가 생성되어 아래와 같은 구조로 통신하는 것을 확인할 수 있습니다.

Web Client <-> uWSGI <-> Python


testproject 프로젝트로 들어가 아래의 명령어를 실행시킨 후, 웹에서 확인을 해보면 It works라는 문구가 나오는 것을 알 수 있습니다.

$ cd testproject
$ python3 manage.py runserver 0.0.0.0:8000


runserver로 실행시킨 것을 중지한 후, 이를 uWSGI로 변경해 실행시켜봅니다.

$ uwsgi --http :8000 --module testproject.wsgi

runserver로 실행시킨 것과 같이 웹에서 확인해보면 같은 문구가 나오는 것과 아래와 같은 구조로 통신하는 것을 알 수 있습니다.

Web Client <-> uWSGI <-> Django


Nginx 세팅


이 가이드에서는 웹서버를 Nginx를 선택하였습니다.

Nginx설치 후, virtualenv 폴더로 이동해 testproject_nginx.conf를 작성합니다.

$ cd ~/uwsgi-tutorial
$ sudo vi testproject_nginx.conf


생성한 .conf파일에 필요한 부분을 고쳐줍니다.

 # testproject_nginx.conf
# the upstream component nginx needs to connect to
upstream django {
    # server unix:///path/to/your/mysite/mysite.sock; # for a file socket
    server 127.0.0.1:8001; # for a web port socket (we'll use this first)
}
# configuration of the server
server {
    # the port your site will be served on
    listen      8000;
    # the domain name it will serve for
    server_name .jinhwan.com; # substitute your machine's IP address or FQDN
    charset     utf-8;
    # max upload size
    client_max_body_size 75M;   # adjust to taste
    # Django media
    location /media  {
        alias /home/jinhwan/uwsgi-tutorial/testproject/media;  # your Django project's media files - amend as required
    }
    location /static {
        alias /home/jinhwan/uwsgi-tutorial/testproject/static; # your Django project's static files - amend as required
    }
    # Finally, send all non-media requests to the Django server.
    location / {
        uwsgi_pass  django;
        include     /home/jinhwan/uwsgi-tutorial/testproject/uwsgi_params; # the uwsgi_params file you installed
    }
}



다음 심볼릭 링크를 생성합니다.

$ cd /etc/nginx/sites-enabled
$ sudo ln -s /home/jinhwan/uwsgi-tutorial/testproject_nginx.conf /etc/nginx/sites-enabled/


다음 프로젝트 폴더로 이동한 다음 settings.py 파일을 아래와 같이 추가하고

STATIC_ROOT = os.path.join(BASE_DIR, "static/")

아래 명령어를 실행시킵니다.

$ python3 manage.py collectstatic

실행시킨 후, yes를 입력하면 static 폴더가 생성됩니다.

해당 프로젝트 내에 uwsgi_params 파일을 만든 다음, https://github.com/nginx/nginx/blob/master/conf/uwsgi_params이 안에 있는 데이터를 넣고 저장합니다.

Port을 사용한 uWSGI


앞서 만들어 놓은 test.py로 nginx와 uWSGI 연동을 확인하는 명령어입니다. 

$ uwsgi --socket :8001 --wsgi-file test.py


웹에서 확인하기 위해선 URL:8001로 확인하는 것이 아닌, 8000 포트로 확인합니다. 아래와 같은 구조로 되어 있으면서 사용자가 8000번 포트로 접속하면 작성한 testproject_nginx.conf 파일 내용과 같이 소켓을 통해 8001번을 호출하게 됩니다. 8001번은 위 uWSGI에서 사용한 포트이므로 test.py을 실행하여 클라이언트에게 보여주게 됩니다.  

the web client <-> the web server <-> the socket <-> uWSGI <-> Python

Unix socket을 사용한 uWSGI


앞서 uWSGI를 사용한 방법은 TCP port socket을 사용한 방법이였습니다. 이 방법을 사용하는 이유는 간단하기 때문입이다. 하지만 포트를 사용하는 것보단 유닉스 소켓을 사용하는 것이 오버헤드가 더 적기 때문에 좋습니다.

앞에서 작성한 testproject_nginx.conf를 수정합니다.

server unix:///tmp/testproject.sock; # for a file socket
# server 127.0.0.1:8001; # for a web port socket (we'll use this first)

nginx를 재시작 한 다음, 아래의 명령어를 실행합니다.

$ uwsgi --socket /tmp/testproject.sock --wsgi-file test.py --chmod-socket=666

--chmod-socket=666을 사용하는 이유는 권한이 없어 Permission Denied를 방지하기 위해 모든 사용자가 해당 파일에 대해 쓰기, 읽기 권한을 줍니다.

(666 대신 664를 입력해도 되지만 664를 입력해도 에러가 나서 666밖에 사용하지 않았습니다.)


만약 에러코드에 대해 확인해 보고 싶은 경우 /var/log/nginx/error.log 에서 확인할 수 있습니다.


Unix Socket을 사용해 Django 실행


먼저 프로젝트로 이동한 후, 해당 명령어를 입력, 웹에서 8000포트를 입력하면 It worked라는 문구가 나옵니다.

$ cd testproject
$  uwsgi --socket /tmp/testproject.sock --module testproject.wsgi --chmod-socket=666

.ini파일을 사용하여 uWSGI 실행


.ini파일을 설정하여 사용하는 이유는 uWSGI를 실행시키기 위해  공통적으로 사용되는 옵션들을 정리하여 보다 쉽게 구성하기 위함입니다.

또한 매번 긴 파일 경로를 사용하지 않아도 됩니다.


먼저 testproject_uwsgi.ini를 생성한 다음, 내부를 아래와 같이 작성합니다.

# mysite_uwsgi.ini file
[uwsgi]
# Django-related settings
# the base directory (full path)
chdir           = /home/jinhwan/uwsgi-tutorial/testproject/
# Django's wsgi file
module          = testproject.wsgi
# the virtualenv (full path)
home            = /home/jinhwan/uwsgi-tutorial
# process-related settings
# master
master          = true
# maximum number of worker processes
processes       = 1
# the socket (use the full path to be safe
socket          = /tmp/testproject.sock
# ... with appropriate permissions - may be needed
 chmod-socket    = 666
# clear environment on exit
vacuum          = true


다음, 아래의 명령어를 실행시켜 확인합니다.

$ uwsgi --ini testproject_uwsgi.ini


worker processes의 갯수는 어느정도가 적당할까?

프로세스나 쓰레드의 갯수를 설정하기위한 규칙이나 제한은 없습니다. 해당 갯수는 시스템이나 응용 프로그램에 매우 의존적입니다. 이것의 갯수를 정하는 것은 processes = 2 * cpucores와 같은 단순한 수식으로는 적합하지 않습니다.

항상 해당 app에 대해 다양한 설정과 끊임없는 모니터링을 하여 실험을 할 필요가 있습니다. uwsgitop은 이러한 것들을 도와주는 좋은 도구가 될 수 있습니다.

시스템 전체에 uWSGI 설치


시스템이 부팅되었을 때, 자동으로 uWSGI를 시작하기 위해선 virtualenv만 아닌, 시스템 전체에 설치가 되어야 합니다.


아래 명령어로 virtualenv를 나간 후, 설치합니다.

$ deactivate
$ sudo pip3 install uwsgi


다음 uWSGI사용방법은 동일합니다.

Emperor mode


uWSGI는 'emperor' 모드를 실행할 수 있습니다. 이 모드는 uWSGI config files들의 directory를 감시하고 설정 파일을 발견했을 때, 각각 ('vassals')이라는 인스턴스를 생성합니다.

config file들이 수정될 때마다, emperor는 vassal을 자동적으로 재시작 합니다. emperor mode를 사용하기 위해선 .ini파일을 생성해야 합니다.


아래와 같이 명령어를 실행시킵니다. (실행 위치 상관 X) 마지막 명령어를 실행시키면 /etc/uwsgi/vassals/ 안에 심볼릭 링크가 생성된 것을 볼 수 있습니다.

$ sudo mkdir /etc/uwsgi
$ sudo mkdir /etc/uwsgi/vassals
$  sudo ln -s /home/jinhwan/uwsgi-tutorial/testproject_uwsgi.ini /etc/uwsgi/vassals/


다음 아래 명령어로 웹서버를 실행시킵니다.

uwsgi --emperor /etc/uwsgi/vassals --uid www-data --gid www-data

문서에서는 sudo를 사용해야 할지도 모른다고 나와있지만 직접 사용했을 때, sudo가 없어도 되는 것을 알 수 있습니다.

위 명령어의 옵션:

emperor : vassals(config files)가 어디에 있는지 

uid: 시작하고 난 뒤, 프로세스의 유저 id

gid: 시작하고 난 뒤, 프로세스의 그룹 id

시스템 부팅될 때, uWSGI 자동 실행


이를 사용하기 위해선,  virtualenv에 uwsgi만 깔려 있어야 하는 것이 아닌, 시스템 전체에 uwsgi가 깔려 있어야 합니다. 


/etc 폴더 안의 rc.local에 다음과 같이 경로를 작성합니다.

 #!/bin/sh -e
#
# rc.local
#
# This script is executed at the end of each multiuser runlevel.
# Make sure that the script will "exit 0" on success or any other
# value on error.
#
# In order to enable or disable this script just change the execution
# bits.
#
# By default this script does nothing.
/usr/local/bin/uwsgi --emperor /etc/uwsgi/vassals --uid www-data --gid www-data daemonize /var/log/uwsgi-emperor.log
exit 0

(재부팅시 에러가 납니다. - 위 코드 확인 필요)

  1. rootlee 2016.07.17 19:05

    글 정말 잘 읽었습니다. ^^ 친절하게 잘 설명해주셔서 잘따라할 수 있었습니다.

    그런데 궁금한 것이 8000번 포트로 deploy하는 경우,
    www.mydomain.com:8000 과 같이 domain 뒤에 8000을 붙여서 접속을 하게 되는데,
    일반적으로 홈페이지에 접속할 때는 8000없이 접속을 하잖아요.

    80포트로 하면 뒤에 8000을 안붙여도 접속이 될거 같아서 80포트로 옮기려 하는데, 이게 맞는 방법인지 잘 모르겠네요.
    일반적으로 deploy해서 웹사이트를 서비스 하는 경우, 어떤식으로 포트를 관리하는지 궁금합니다.

    항상 좋은 글 감사합니다 ! 그럼 좋은하루 되세요^^

    • 불곰1 2016.07.20 15:12 신고

      보통 웹사이트에서 배포를 하는 경우는 HTTP 기본포트인 80을 사용해 서비스를 합니다. 80 포트는 포트번호를 명시해주지 않아도 알기 때문이죠ㅎ

  2. haruholic 2016.10.11 20:03

    안녕하세요 ini 파일을 이용해서 시작하는 부분에서 no modue named django 라고 에러가 뜨는데 이유가 무엇인지 알 수 있을까요?

    • 불곰1 2016.10.16 14:40 신고

      혹시
      # Django's wsgi file
      module = testproject.wsgi 이 부분이 생략되어 있는게 아닐까요?
      아니면 장고 프로젝트가 아닌 파이썬 단일 파일을 ini로 실행하고자 해서 나는 에러일 수도 있을거 같네요

  3. 에리크 2016.10.13 14:32

    안녕하세요...장고를 스터디중입니다..글 잘 읽었습니다ㅣ..도움이 많이되고 있습니다
    주신자료를 참조하여 ...ubuntu+django+ngix+gunicorn으로 설정은 했는대..

    이상하게 , 소스코드를 변경(모델에 필드추가)하고 저장하면 브라우에서 바로바로 변경이 않되고..우분투를 OS를 restart 해야 변경된 사항이 브라우져에서 보입니다.

    예전에..python manage.py runserver 0:8000 할때는 바로바로 ㅂ소스코드변경을 확인가능했느데..제가 뭘 setting을 잘 못했느지 잘 모르겠습니다
    ..아니면 restart django 같은것이 혹시 있느지요?

    • 불곰1 2016.10.16 14:50 신고

      setting 파일보단 nginx만 재부팅하여 uwsgi를 재실행 해주면 될 것 같아요

      저도 해당 문제에 대해서 찾아본건 아니고 제 생각이지만 runserver는 장고에서 기본으로 제공해주기 때문에 값을 수정하고 다시 실행할 때 자동적으로 웹서버에 반영이 되는거 같아요

  4. 황영재 2017.02.14 09:43

    안녕하세요
    포스팅 따라서 django과 uwsgi 연동중에 확장자가 .wsgi 파일이 보이지 않아 문의 드려요
    python 2.7.10버전 사용중이구 우분투입니다
    근데 testproject.wsgi 파일을 modules에 지정하신다고 하셔서 그 부분 따라해 보려고 했는데
    제가 생성한 프로젝트에서는 아무리 찾아도 wsgi.py 는 있는데 확장명이 wsgi로 끝나는 파일은 찾을수가 없어서요

    • dudwo56@gmail.com 2017.02.14 09:48

      아 죄송합니다
      그게 아니였네요

  5. 80포트 2017.02.28 17:12

    80포트로 설정하는 방법이 뭔가요?ㅠㅜㅜ

    • 불곰1 2017.03.04 11:18 신고

      웹서버의 config파일에 포트를 지정할 수 있는 부분이 있습니다.
      nginx 같은 경우 xxxx.conf 파일 내의
      ...
      server { # the port your site will be served on listen 8000; # 이부분
      ...
      에서 포트를 수정할 수 있습니다!

  6. emperor mode(황제모드?)가 정확히 무엇인가요?
    저거 몰라도 장고앱 배포하는데 지장이 없나요?
    아주 소규모의 2~30명이 사용하는 정도의 웹인데 필요할까요?
    아니면 스킵해도 괜찮나요?
    저로선 무슨 소리인지 모르겠어서 말이죠....

    • 불곰1 2017.04.06 14:08 신고

      emperor mode는 한 서버 내에서 여러 uWSGI를 실행한다고 가정할 때, 관리를 위해서 사용하는 모드이기 때문에 생략하고 배포해도 무관합니다.

function sortNumber(a,b){//콜백함수

    // 위의 예제와 비교해서 a와 b의 순서를 바꾸면 정렬순서가 반대가 된다.

    return b-a;

}

var numbers = [20, 10, 9,8,7,6,5,4,3,2,1];

alert(numbers.sort(sortNumber)); // array, [20,10,9,8,7,6,5,4,3,2,1]



numbers는 객체이다. (배열객체)

sort(sortNumber()); -->sortNumber가 콜백함수이다. 


이것이 콜백이다.(콜백이 가능한 이유: 자바스크립트에서는 함수가 값이기 때문이다.)

(여기서 sort는 함수가 아닌 메소드라고 한다.), 배열이나 sort는 자바스크립가 기본적으로 가지고 있는 기능이기에 내장객체, 내장메소드, 빌트인 객체, 빌트인 메소드라 한다. 

우리가 만드는 객체, 메소드, 함수는 사용자 정의 객체, 사용자 정의 함수라 한다.


2. 비동기 처리

cf.) 글작성->이메일 발송-> 작성완료: 순차적작성을 동기식 처리라고 한다. 

글작성하고 이메일 발송 부분은 예약하고 작성완료(to do)를 하면 순식간에 일이 처리된다. 내부적으로는 예약 부분을 백그라운드에서 비동기적으로 처리

웹페이지에 표시되지않은 데이터를 화면에 표시할 수 있는 이유는 내부적으로 화면에 표시된 정보를 서버에 요청해서 화면에 표시한 것이다.(웹페이지 리로드 없이 작업한 것임)

클릭시 웹페이지가 변경되지 않고 서버와 웹브라우저가 조용히 통신하는 기법을 Ajax라고 한다.

콜백은 비동기처리에서도 유용하게 사용된다. 시간이 오래걸리는 작업이 있을 때 이 작업이 완료된 후에 처리해야 할 일을 콜백으로 지정하면 해당 작업이 끝났을 때 미리 등록한 작업을 실행하도록 할 수 있다. 

다음 코드는 일반적인 환경에서는 작동하지 않고 서버 환경에서만 동작한다. 동영상을 참고한다.




자바스크립트 콜백

http://yubylab.tistory.com/49

+ Random Posts