Blog project - 4

[ Blog project ]

  • 멀티데이터베이스 만들기

    • 데이터베이스도 스케일링을 고려해야 함
    • 마스터 + 슬레이브(읽기 전용)의 형태
    1. 마스터로 사용할 데이터베이스를 생성한다.

      • Amazon AWS에서 데이터베이스/RDS를 누른다.
      • 데이터베이스 생성을 누른다.
      • PostgreSQL 선택 및 화면 하단의 RDS 프리티어에 적용되는 옵션만 사용에 체크한다.
      • DB 엔진 버전은 PostgreSQL 10.6-R1 선택한다.
        • PostgreSQL 9.3.5 이상부터 일기 전용 복제본을 사용할 수 있다.
      • 용량은 20Gib로 설정하고 관리자 정보를 입력한다.
      • 퍼블릭 엑세스 가능성은 ‘예’를 선택한다.
        • 실습 환경에서는 [예]를 선택하고, 프로덕션 환경에서는 꼭 [아니오]로 변경한다.
      • 데이터베이스 이름을 입력하고 백업 보존 기간은 1일로 설정한다.
        • 읽기 전용 복제본을 만들려면 백업 기능이 활성화되어 있어야 한다.
      • 성능 개선 도우미는 비활성화하고 데이터베이스 생성을 누른다.
      • 인스턴스 생성이 완료되면 settings.py의 DATABESES 부분을 수정한다.

        1
        2
        3
        4
        5
        6
        7
        8
        9
        10
        11
        12
         # pip install psycopg2-binary를 설치하자.

        DATABASES = {
        'default': {
        'ENGINE': 'django.db.backends.postgresql_psycopg2',
        'NAME': '데이터베이스 이름',
        'USER':'마스터 사용자 이름',
        'PASSWORD':'마스터 사용자 비밀번호',
        'HOST':'아마존 RDS의 엔드포인트',
        'POST':'데이터베이스 접속 포트번호',
        },
        }
      • 수정이 완료되면 migrate한다.

        1
        $ python manage.py migrate
    2. 슬레이브(읽기 전용)로 사용할 데이터베이스를 생성한다.

      • 마스터로 사용할 데이터베이스를 누른 후, 상단 메뉴의 작업에서 읽기 복제본 생성을 누른다.
      • 생성 창이 나타나면 퍼블릭 엑세스 가능 부분에서 예를 누른다.
      • 데이터베이스 식별자를 입력한다.
      • 읽기 전용 복제본 생성을 누른다.
      • 위와 같은 방법으로 하나를 더 생성한다.

        1
        2
        3
        - 퍼블릭 엑세스 가능과 데이터베이스 식별자를 잘 설정한다.
        - 복제본을 생성하는 것이기 때문에 옵션을 모두 건드릴 필요가 없다.
        - 읽기 데이터베이스인 경우, 높은 사양을 원한다면 인스턴스 사양을 올릴 수 있다.
      • settings.py의 DATABESES 정보를 추가한다.

        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
        DATABASES = {
        'default': {
        'ENGINE': 'django.db.backends.postgresql_psycopg2',
        'NAME': 'multi',
        'USER':'마스터 사용자 이름',
        'PASSWORD':'마스터 사용자 비밀번호',
        'HOST':'마스터 전용 데이터베이스의 엔드포인트',
        'POST':'5432',
        },
        # 복제했기 때문에 다른 것은 모두 같으나, HOST만 달라지게 된다.
        # 엔드 포인트 주소를 잘 확인하자.
        # 식별자가 다를 뿐 데이터베이스의 이름은 모두 같다.
        'read1': {
        'ENGINE': 'django.db.backends.postgresql_psycopg2',
        'NAME': 'multi',
        'USER':'마스터 사용자 이름',
        'PASSWORD':'마스터 사용자 비밀번호',
        'HOST':'첫 번째 읽기 전용 데이터베이스의 엔드포인트',
        'POST':'5432',
        },
        'read2': {
        'ENGINE': 'django.db.backends.postgresql_psycopg2',
        'NAME': 'multi',
        'USER':'마스터 사용자 이름',
        'PASSWORD':'마스터 사용자 비밀번호',
        'HOST':'두 번째 읽기 전용 데이터베이스의 엔드포인트',
        'POST':'5432',
        }
        }
      • 라우터 클래스를 만들어서 추가한다.

        1
        2
        3
        4
        5
        6
        7
        8
        9
        10
        11
        12
        13
        14
        15
        16
        17
        18
        19
        20
        21
        22
        23
        # config/master_slave_router.py
        # 자동으로 쓰기, 읽기 데이터베이스를 분기해서 사용하는 것이 아니기 때문이다.

        import random

        class MasterSlaveRouter:
        def db_for_read(self, model, **hints):
        return random.choice(['read1', 'read2'])

        def db_for_write(self, model, **hints):
        return 'default' # return None으로 대체 가능

        def allow_relation(self, obj1, obj2, **hints):
        db_list = ('default', 'read1', 'read2')
        if obj1._state.db in db_list and obj2.state_db in db_list:
        return True
        return None
        # return None의 의미
        # 다음 라우터에게 물어보겠다
        # 전부 default에 넣겠다

        def allow_migrate(self, db, app_label, model_name=None, **hints):
        return True
      • settings.py에 만든 라우터를 추가한다.

        1
        DATABASE_ROUTERS = ['config.master_slave_router.MasterSlaveRouter']
      • debug toolbar를 설치한다.

        1
        2
        # debug toolbar
        $ pip install django-debug-toolbar
        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
        # settings.py
        # INSTALLED_APPS에 항목 추가
        INSTALLED_APPS = [
        #...
        'debug_toolbar',
        ]

        # MIDDLEWARE에 항목 추가
        MIDDLEWARE = [
        #...
        'debug_toolbar.middleware.DebugToolbarMiddleware',
        ]

        # debug = True, internal_ips
        INTERNAL_IPS = ['127.0.0.1']

        DEBUG_TOOLBAR_PANELS = [
        'debug_toolbar.panels.versions.VersionsPanel',
        'debug_toolbar.panels.timer.TimerPanel',
        'debug_toolbar.panels.settings.SettingsPanel',
        'debug_toolbar.panels.headers.HeadersPanel',
        'debug_toolbar.panels.request.RequestPanel',
        'debug_toolbar.panels.sql.SQLPanel',
        'debug_toolbar.panels.staticfiles.StaticFilesPanel',
        'debug_toolbar.panels.templates.TemplatesPanel',
        'debug_toolbar.panels.cache.CachePanel',
        'debug_toolbar.panels.signals.SignalsPanel',
        'debug_toolbar.panels.logging.LoggingPanel',
        'debug_toolbar.panels.redirects.RedirectsPanel',
        ]
        1
        2
        3
        4
        5
        6
        7
        8
        9
        # config.urls.py
        from django.urls import path, include
        from django.conf import settings

        if settings.DEBUG:
        import debug_toolbar
        urlpatterns = [
        path('debug/', include(debug_toolbar.urls)),
        ] + urlpatterns
      • 관리자 페이지로 접속하여 debug toolbar를 이용하여 데이터베이스를 확인한다.

      • 유저 정보를 공유하기 위해 다른 프로젝트를 생성한다.
        • Amazon AWS에서 RDS를 새로 생성하여 migrate까지 진행한다.
      • 멀티데이터베이스를 진행한 프로젝트에서 settings.py의 DATABASES 정보를 추가한다.

        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
         DATABASES = {
        'default': {
        'ENGINE': 'django.db.backends.postgresql_psycopg2',
        'NAME': 'multi',
        'USER':'마스터 사용자 이름',
        'PASSWORD':'마스터 사용자 비밀번호',
        'HOST':'마스터 전용 데이터베이스의 엔드포인트',
        'POST':'5432',
        },
        'read1': {
        'ENGINE': 'django.db.backends.postgresql_psycopg2',
        'NAME': 'multi',
        'USER':'마스터 사용자 이름',
        'PASSWORD':'마스터 사용자 비밀번호',
        'HOST':'첫 번째 읽기 전용 데이터베이스의 엔드포인트',
        'POST':'5432',
        },
        'read2': {
        'ENGINE': 'django.db.backends.postgresql_psycopg2',
        'NAME': 'multi',
        'USER':'마스터 사용자 이름',
        'PASSWORD':'마스터 사용자 비밀번호',
        'HOST':'두 번째 읽기 전용 데이터베이스의 엔드포인트',
        'POST':'5432',
        },
        # 유저의 정보를 공유하기 위해 다른 프로젝트를 생성
        # 다른 프로젝트에서 생성한 데이터베이스의 정보
        'user': {
        'ENGINE': 'django.db.backends.postgresql_psycopg2',
        'NAME': 'base_user',
        'USER':'마스터 사용자 이름',
        'PASSWORD':'마스터 사용자 비밀번호',
        'HOST': '추가로 생성한 데이터베이스의 엔드포인트',
        'PORT': '5432',
        }
        }
      • 유저의 정보 데이터베이스를 위한 라우터를 추가한다.

        1
        2
        3
        4
        5
        6
        7
        8
        9
        10
        11
        12
        13
        14
        15
        16
        17
        18
        19
        20
        21
        22
        23
        # config/user_router.py

        from django.conf import settings

        class UserRouter:
        def db_for_read(self, model, **hints):
        if model._meta.model_name == 'user':
        return 'user'
        return None

        def db_for_write(self, model, **hints):
        if model._meta.model_name == 'user':
        return 'user'
        return None

        def allow_relation(self, obj1, obj2, **hints):
        db_list = settings.DATABASES.keys() # settings에서 불러다가 사용할 수도 있다.
        if obj1._state.db in db_list and obj2._state.db in db_list:
        return True
        return None

        def allow_migrate(self, db, app_label, model_name=None, **hints):
        return True
      • settings.py에 라우터를 추가한다.

        1
        2
        DATABASE_ROUTERS = ['config.user_router.UserRouter',
        'config.master_slave_router.MasterSlaveRouter']
      • 관리자 페이지로 접속하여 멀티데이터베이스 프로젝트에서 로그인해본다.

        • 유저 정보를 위한 프로젝트 관리자의 아이디로 접속이 된다.
        • 멀티데이터베이스 프로젝트에서 유저를 생성해본다.
        • 유저 정보 프로젝트에서 관리자 접속 후, 유저 정보를 확인해본다.
        • 두 프로젝트의 유저 정보가 공유되는 것을 확인할 수 있다.
  • EC2에 장고 배포하기(정리)

    1. 인스턴스를 생성한다.
      • Amazon AWS에서 컴퓨팅/EC2로 이동한다.
      • 인스턴스 시작을 누른다.
      • Ubuntu server 18.04를 선택한다.
      • 인스턴스 타입은 t2.micro를 선택한다.
        • 서비스 상황에 따라 더 높은 사양을 선택하는 것도 생각하도록 하자.
      • 인스턴스 세부 구성에서는 설정하지 않고 넘어간다.
      • 스토리지 크기는 20Gib로, 볼륨 유형은 범용 SSD를 선택하고 넘어간다.
      • 태그 추가에서는 설정하지 않고 넘어간다.
      • 보안 그룹 구성에서는 새 보안 그룹을 선택하고 이름과 설명을 입력한다.
        • ELB에 넣을 인스턴스를 생성하는 경우엔 기존 인스턴스와 같은 그룹을 선택하도록 한다,
      • 검토 및 시작에서는 정보를 검토하고 시작하기를 누른다.
      • 인스턴스에 접속하기 위해 새 키 파일 생성을 누른다.
      • 키 페어 이름을 입력 후, 다운로드를 누르고 인스턴스를 시작한다.
      • 인스턴스 보기를 누르고 목록을 확인 후, 생성한 인스턴스의 이름을 설정해둔다.
    2. 터미널에서 명령어를 입력한다.

      • 다운로드 받은 키 페어 파일의 권한을 400으로 변경한다.

        1
        2
        # 키 페어 파일 경로도 가능
        $ chmod 400 [키 페어 파일 이름]
      • 키 페어 파일을 .ssh 폴더로 이동시킨다.

        1
        $ mv [키 페어 파일 이름] ~/.ssh/
      • 키 페어 파일을 이용하여 EC2 인스턴스에 ssh 접속을 한다.

        1
        $ ssh -i [키 페어 파일 경로] [계정]@[EC2 접속 주소]
      • 서버에 접속 후, 기존 패키지를 업데이트한다.

        1
        $ sudo apt-get update
      • Nginx를 설치한다.

        1
        $ sudo apt-get install nginx
      • vim을 설치한다.

        1
        $ sudo apt-get install vim
      • 파이썬 관련 패키지를 설치한다.

        1
        $ sudo apt-get install python3-dev python3-venv python3-pip
      • django 앱 구동용 계정을 생성한다.

        1
        $ sudo useradd -b /home -m -s /bin/bash django
      • www-data 그룹에 django 유저를 추가한다.

        1
        $ sudo usermod -a -G www-data django
      • www-data 그룹에 ubuntu 유저를 추가한다.

        1
        2
        # FTP로 업로드 시, ubuntu 계정을 사용하므로, 앱 소스 코드 폴더에 쓰기 권한을 얻기 위함
        $ sudo usermod -a -G Www-data ubuntu
      • 소스 코드를 업로드하기 위한 폴더를 만든다.

        1
        2
        # -p는 중간 폴더가 없다면 자동 생성하게 해준다.
        $ sudo mkdir -p /var/www/django
      • uswgi 모듈을 위해 폴더를 만든다.

        1
        2
        3
        $ sudo mkdir /var/www/django/run
        $ sudo mkdir /var/www/django/logs
        $ sudo mkdir /var/www/django/ini
      • uwsgi 설정 파일을 만든다.

        1
        2
        3
        4
        5
        6
        7
        8
        9
        10
        11
        12
        13
        14
        15
        16
        17
        18
        19
        20
        $ sudo vim /var/www/django/ini/uwsgi.ini

        # uwsgi.ini 내용
        [uwsgi]
        uid = django
        base = /var/www/django

        home = %(base)/venv
        chdir = %(base)
        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
      • 가상 환경을 소스 코드 폴더 밑에 만든다.

        1
        $ sudo python3 -m venv /var/www/django/venv
      • 소스 코드를 업로드하기 전에 폴더의 소유자와 사용 권한을 변경한다.

        1
        2
        $ sudo chown -R django:www-data /var/www/django
        $ sudo chmod -R g+w /var/www/django
      • 파일질라를 실행하여 왼쪽 상단 탭에서 사이트 관리자로 들어간다.

      • 새로운 사이트를 추가하고 접속 정보를 설정한다.

        1
        2
        3
        4
        5
        - 프로토콜 : SFTP
        - 호스트 : EC2의 접속 주소
        - 로그온 유형 : 키 파일
        - 사용자 : ubuntu
        - 키 파일 : 키 페어 파일 경로 지정
      • 고급 탭에서 기본 로컬 디렉터리와 기본 리모트 디렉터리를 지정한다.

        1
        2
        기본 로컬 디렉터리 = pycharm으로 만든 프로젝트 폴더
        기본 리모트 디렉터리 = 소스 코드를 업로드할 폴더
      • 설정이 완료되었다면 연결을 누른다.

      • 처음 접속 시, 알 수 없는 호스트 창이 나타나면 캐시에 등록을 체크하고 확인을 누른다.
      • 접속이 성공했다면, 소스 코드를 업로드한다.
      • 가상 환경에 패키지를 설치하기 위해 소스 코드 폴더로 이동한다.

        1
        $ cd /var/www/django
      • 관리자 모드로 변경하고 가상 환경을 활성화시킨다.

        1
        2
        $ sudo -s
        $ source venv/bin/activate
      • 의존성 리스트를 설치한다.

        1
        $ pip install -r requirements.txt
      • uwsgi를 설치한다.

        1
        $ pip install uwsgi
      • runserver 명령어를 통해 django project의 구동 여부를 확인한다.

        1
        $ python manage.py runserver 0:8000
      • 구동이 된다면 runserver를 종료하고, uwsgi 모듈로 구동 여부를 확인한다.

        1
        $ uwsgi --http :8000 --home /var/www/django/venv/ --chdir /var/www/django/ --module config.wsgi
      • 웹 브라우저를 통해 접속하여 구동이 된다면 uwsgi.service 파일을 작성한다.

        1
        2
        3
        4
        5
        6
        7
        8
        9
        10
        11
        12
        13
        14
        15
        16
        17
        18
        $ sudo vim /etc/systemed/system/uwsgi.service

        # uwsgi.service 내용
        [Unit]
        Description=uWSGI Emperor service

        [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
      • uwsgi의 서비스를 시작하고 시작 서비스로 등록한다.

        1
        2
        $ sudo systemctl start uwsgi
        $ sudo systemctl enable uwsgi
      • 서비스 상태를 확인한다.

        1
        2
        # active 상태인지 확인하자.
        $ sudo systemctl status uwsgi
      • Nginx의 default 파일을 수정한다.

        1
        2
        3
        4
        5
        6
        7
        8
        9
        10
        11
        12
        13
        14
        15
        16
        17
        18
        19
        20
        $ sudo vim /etc/nginx/sites-available/default

        # default 내용
        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;
        }
        }
      • Nginx를 재시작한다.

        1
        $ sudo systemctl restart nginx
      • 웹 브라우저에 퍼블릭 DNS를 입력하고 구동 여부를 확인한다.

      • 소스 코드의 업데이트를 위해서 아래 명령어를 실행해두자.

        1
        $ sudo chmod -R g+w /var/www/django
      • django와 관련된 부분이 수정이 된다면 uwsgi 서비스를 재시작해야 한다.

        1
        $ sudo systemctl restart uwsgi
  • 로드밸런서 설정하기

    • EC2 왼쪽 메뉴에서 로드 밸런서를 누른다.
    • 로드밸런서 생성을 누르고 Application Load Balancer의 생성을 누른다.
    • 다음으로, 로드밸런스의 이름을 입력하고 리스너를 만들어준다.
      • HTTPS의 443을 추가한다.
    • 가용 영역에서는 모두 체크하고 보안 설정 구성으로 넘어간다.
    • 보안 설정 구성에서는 다음과 같이 설정한다.
      • 인증서 유형은 ACM에서 인증서 선택을 누른다.
      • 인증서 이름에는 기존에 생성한 인증서가 나타난다.
      • 보안 정책은 ELBSecurityPolicy-2016-08을 선택한다.
        • 보안 정책이 너무 최신일 경우, 폭넓게 지원하지 않는 문제가 있다.
      • 보안 그룹 구성에서는 새 보안 그룹 생성을 누르고 이름과 설명을 입력한다.
      • 라우팅 구성에서는 그룹의 이름을 입력하고 대상 등록으로 넘어간다.
        • 프로토콜은 https(443)이 아닌 http(80)가 맞으므로 바꾸지 않아도 된다.
      • 대상 등록에서는 미리 생성해둔 인스턴스를 추가하고 검토로 넘어간다.
      • 검토 화면에서 내용을 확인하고 생성을 누른다.
      • 생성이 완료되면 닫기를 누른다.
      • 생성된 로드밸런서의 DNS 이름으로 웹 브라우저에 접속해보자.
        1
        2
        3
        4
        5
        6
        - https로만  접속하게 하고 싶을 경우
        1. 해당 로드밸런서에서 리스너에 http(80)을 편집으로 들어간다.
        2. 기본 작업에 다음으로 전달하는 값을 제거한다.
        3. 다음으로 리디렉션을 누르고 포트 번호를 443으로 설정한다.
        4. 체크를 누르고 업데이트를 누른다.
        5. 이제 https로만 접속되는지 확인한다.
  • Route53을 통해 로드밸런서 등록하기

    • 네트워킹 및 콘텐츠 전송/Route53으로 이동한다.
    • 호스팅 영역에 등록한 도메인을 누르고 레코드 세트 생성을 누른다.
    • 원하는 이름을 입력하고 별칭에서 예를 선택한다.
    • 등록한 로드밸런서를 선택하고 생성한다.
    • 웹 브라우저에서 https를 붙인 도메인 주소로 접속해본다.
Share