DigitalOceanマネージドデータベースとスペースを使用してスケーラブルなDjangoアプリをセットアップする方法

提供:Dev Guides
移動先:案内検索

序章

Django は、PythonアプリケーションまたはWebサイトをすばやく立ち上げるのに役立つ強力なWebフレームワークです。 これには、オブジェクトリレーショナルマッパー、Python API、アプリケーション用のカスタマイズ可能な管理インターフェイスなど、いくつかの便利な機能が含まれています。 また、キャッシングフレームワークが含まれており、URLディスパッチャーおよびテンプレートシステムを通じてクリーンなアプリの設計を促進します。

箱から出してすぐに、Djangoにはテストとローカル開発用の最小限のWebサーバーが含まれていますが、本番ユースケース用のより堅牢なサービングインフラストラクチャと組み合わせる必要があります。 Djangoは、静的ファイルリクエストとHTTPSリダイレクトを処理するためのNginxウェブサーバーと、アプリを提供するための GunicornWSGIサーバーとともに展開されることがよくあります。

このガイドでは、JavascriptやCSSスタイルシートなどの静的ファイルをDigitalOcean Spacesにオフロードし、オプションでCオンテントD配信N[X208X ] etwork、またはCDN。これらのファイルをエンドユーザーの近くに保存して、転送時間を短縮します。 また、データストアとしてDigitalOcean Managed PostgreSQL database を使用して、データレイヤーを簡素化し、スケーラブルなPostgreSQLデータベースを手動で構成する必要をなくします。

前提条件

このガイドを開始する前に、次のものを利用できるようにしておく必要があります。

  • 基本的なファイアウォールとsudo権限が構成された非rootユーザーを持つ新しいUbuntu18.04サーバーインスタンス。 Ubuntu 18.04を使用した初期サーバーセットアップを実行することで、これをセットアップする方法を学ぶことができます。
  • DigitalOceanマネージドPostgreSQLクラスター。 クラスタの作成方法については、DigitalOcean管理対象データベースの製品ドキュメントを参照してください。
  • Djangoプロジェクトの静的ファイルとこのスペースのアクセスキーのセットを保存するDigitalOceanスペース。 スペースの作成方法については、スペースの作成方法の製品ドキュメントを参照してください。また、スペースのアクセスキーの作成方法については、アクセスキーを使用したスペースへのアクセスの共有を参照してください。
  • Nginxは、選択したドメイン名で動作するようにサーバーにインストール、保護、および構成されています。 Let's Encrypt を使用したAレコードの設定とNginxインストールの保護の詳細については、 Ubuntu18.04でLet'sEncryptを使用してNginxを保護する方法を参照してください。

ステップ1—Ubuntuリポジトリからパッケージをインストールする

まず、Ubuntuリポジトリから必要なすべてのアイテムをダウンロードしてインストールします。 Pythonパッケージマネージャーpipを使用して、少し後で追加のコンポーネントをインストールします。

最初にローカルのaptパッケージインデックスを更新してから、パッケージをダウンロードしてインストールする必要があります。

このガイドでは、 Python3でDjangoを使用します。 必要なライブラリをインストールするには、サーバーにログインして次のように入力します。

sudo apt update
sudo apt install python3-pip python3-dev libpq-dev curl postgresql-client

これにより、pip、Gunicornのビルドに必要なPython開発ファイル、 Pyscopg PostgreSQL Pythonアダプターのビルドに必要なlibpqヘッダーファイル、およびPostgreSQLコマンドラインクライアントがインストールされます。

パッケージのダウンロードとインストールを開始するように求められたら、Yを押してから、ENTERを押します。

次に、Djangoアプリで動作するようにデータベースを構成します。

ステップ2—PostgreSQLデータベースとユーザーを作成する

次に、Djangoアプリケーション用のデータベースとデータベースユーザーを作成します。

まず、クラウドコントロールパネルからデータベースに移動し、データベースをクリックして、クラスターの接続パラメーターを取得します。 クラスタのいくつかのパラメータを含む接続の詳細ボックスが表示されます。 これらを書き留めてください。

コマンドラインに戻り、次の資格情報とインストールしたばかりのpsqlPostgreSQLクライアントを使用してクラスターにログインします。

psql -U username -h host -p port -d database -set=sslmode=require

プロンプトが表示されたら、Postgresユーザー名の横に表示されているパスワードを入力し、ENTERを押します。

データベースを管理できるPostgreSQLプロンプトが表示されます。

まず、pollsという名前のプロジェクトのデータベースを作成します。

CREATE DATABASE polls;

注:すべてのPostgresステートメントはセミコロンで終了する必要があるため、問題が発生している場合は、コマンドがセミコロンで終了していることを確認してください。


これで、pollsデータベースに切り替えることができます。

\c polls;

次に、プロジェクトのデータベースユーザーを作成します。 安全なパスワードを選択してください。

CREATE USER myprojectuser WITH PASSWORD 'password';

次に、作成したユーザーの接続パラメーターのいくつかを変更します。 これにより、データベース操作が高速化されるため、接続が確立されるたびに正しい値を照会して設定する必要がなくなります。

デフォルトのエンコーディングをUTF-8に設定しています。これは、Djangoが期待するものです。 また、デフォルトのトランザクション分離スキームを「読み取りコミット」に設定しています。これは、コミットされていないトランザクションからの読み取りをブロックします。 最後に、タイムゾーンを設定します。 デフォルトでは、DjangoプロジェクトはUTCを使用するように設定されます。 これらはすべて、Djangoプロジェクト自体からの推奨事項です。

PostgreSQLプロンプトで次のコマンドを入力します。

ALTER ROLE myprojectuser SET client_encoding TO 'utf8';
ALTER ROLE myprojectuser SET default_transaction_isolation TO 'read committed';
ALTER ROLE myprojectuser SET timezone TO 'UTC';

これで、新しいユーザーに新しいデータベースを管理するためのアクセス権を与えることができます。

GRANT ALL PRIVILEGES ON DATABASE polls TO myprojectuser;

終了したら、次のように入力してPostgreSQLプロンプトを終了します。

\q

これで、Djangoアプリがこのデータベースに接続して管理する準備が整いました。

次のステップでは、virtualenvをインストールし、Djangoプロジェクト用のPython仮想環境を作成します。

ステップ3—プロジェクト用のPython仮想環境を作成する

アプリケーションで動作するようにデータベースを設定したので、このプロジェクトの依存関係をシステムのグローバルPythonインストールから分離するPython仮想環境を作成します。

これを行うには、最初にvirtualenvコマンドにアクセスする必要があります。 これはpipでインストールできます。

pipをアップグレードし、次のように入力してパッケージをインストールします。

sudo -H pip3 install --upgrade pip
sudo -H pip3 install virtualenv

virtualenvをインストールすると、Python仮想環境を保存するディレクトリを作成し、Djangopollsアプリで使用できるようになります。

envsというディレクトリを作成し、そのディレクトリに移動します。

mkdir envs
cd envs

このディレクトリ内に、次のように入力してpollsというPython仮想環境を作成します。

virtualenv polls

これにより、envsディレクトリ内にpollsというディレクトリが作成されます。 内部には、Pythonのローカルバージョンとpipのローカルバージョンがインストールされます。 これを使用して、プロジェクト用に分離されたPython環境をインストールおよび構成できます。

プロジェクトのPython要件をインストールする前に、仮想環境をアクティブ化する必要があります。 次のように入力すると、次のように入力できます。

source polls/bin/activate

プロンプトが変化して、Python仮想環境内で操作していることを示します。 (polls)user@host:~/envs$のようになります。

仮想環境をアクティブにして、Django、Gunicorn、およびpsycopg2PostgreSQLアダプターをpipのローカルインスタンスとともにインストールします。

注:仮想環境がアクティブ化されている場合(プロンプトの前に(polls)がある場合)、使用している場合でも、pip3の代わりにpipを使用してくださいPython3。 仮想環境のツールのコピーには、Pythonのバージョンに関係なく、常にpipという名前が付けられます。


pip install django gunicorn psycopg2-binary

これで、Djangopollsアプリを実行するために必要なすべてのソフトウェアが揃いました。 次のステップでは、Djangoプロジェクトを作成し、このアプリをインストールします。

ステップ4—PollsDjangoアプリケーションを作成する

これで、サンプルアプリケーションを設定できます。 このチュートリアルでは、DjangoドキュメントのPollsデモアプリケーションを使用します。 これは、ユーザーが投票を表示して投票できる公開サイトと、管理者が投票を変更、作成、および削除できる管理コントロールパネルで構成されています。

このガイドでは、チュートリアルの手順をスキップし、DigitalOceanコミュニティ django-pollsrepoから最終的なアプリケーションのクローンを作成します。

手順を手動で完了する場合は、ホームディレクトリにdjango-pollsというディレクトリを作成し、次の場所に移動します。

cd
mkdir django-polls
cd django-polls

そこから、公式のDjangoドキュメントから最初のDjangoアプリの作成チュートリアルに従うことができます。 完了したら、ステップ5にスキップします。

完成したアプリのクローンを作成するだけの場合は、ホームディレクトリに移動し、gitを使用してdjango-pollsリポジトリのクローンを作成します。

cd
git clone https://github.com/do-community/django-polls.git

cdをその中に入れ、ディレクトリの内容を一覧表示します。

cd django-polls
ls

次のオブジェクトが表示されます。

OutputLICENSE  README.md  manage.py  mysite  polls  templates

manage.pyは、アプリの操作に使用されるメインのコマンドラインユーティリティです。 pollsにはpollsアプリコードが含まれ、mysiteにはプロジェクトスコープコードと設定が含まれます。 templatesには、管理インターフェース用のカスタムテンプレートファイルが含まれています。 プロジェクトの構造とファイルの詳細については、Djangoの公式ドキュメントからプロジェクトの作成を参照してください。

アプリを実行する前に、デフォルト設定を調整してデータベースに接続する必要があります。

ステップ5—アプリの設定を調整する

このステップでは、Djangoプロジェクトのデフォルト構成を変更してセキュリティを強化し、Djangoをデータベースに接続して、静的ファイルをローカルディレクトリに収集します。

テキストエディタで設定ファイルを開くことから始めます。

nano ~/django-polls/mysite/settings.py

ALLOWED_HOSTSディレクティブを見つけることから始めます。 これは、Djangoインスタンスへの接続に使用するアドレスまたはドメイン名のリストを定義します。 このリストにないHostヘッダーを持つ着信要求は、例外を発生させます。 Djangoでは、特定のクラスのセキュリティ脆弱性を防ぐために、これを設定する必要があります。

角かっこ内に、Djangoサーバーに関連付けられているIPアドレスまたはドメイン名をリストします。 各項目は、エントリをコンマで区切って引用符で囲む必要があります。 ローカルのNginxインスタンスを介して接続をプロキシするため、リストにはlocalhostも含まれます。 ドメイン全体とサブドメインのリクエストを含める場合は、エントリの先頭にピリオドを追加します。

以下のスニペットには、これらのエントリがどのように表示されるかを示すコメントアウトされた例がいくつかあります。

〜/ django-polls / mysite / settings.py

. . .

# The simplest case: just add the domain name(s) and IP addresses of your Django server
# ALLOWED_HOSTS = [ 'example.com', '203.0.113.5']
# To respond to 'example.com' and any subdomains, start the domain with a dot
# ALLOWED_HOSTS = ['.example.com', '203.0.113.5']
ALLOWED_HOSTS = ['your_server_domain_or_IP', 'second_domain_or_IP', . . ., 'localhost']

. . . 

次に、データベースアクセスを構成するファイルのセクションを見つけます。 DATABASESで始まります。 ファイル内の構成はSQLiteデータベース用です。 プロジェクト用にPostgreSQLデータベースをすでに作成しているため、これらの設定を調整する必要があります。

デフォルトのSQLiteエンジンの代わりに、pipでインストールしたpsycopg2データベースアダプターを使用するようにDjangoに指示します。 また、ステップ2で参照されている接続パラメータを再利用します。 この情報は、DigitalOceanクラウドコントロールパネルの管理対象データベースセクションからいつでも見つけることができます。

データベース設定(データベース名(polls)、データベースユーザー名、データベースユーザーのパスワード、およびデータベースhostport)でファイルを更新します。 データベース固有の値を独自の情報に置き換えてください。

〜/ django-polls / mysite / settings.py

. . .

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.postgresql_psycopg2',
        'NAME': 'polls',
        'USER': 'myprojectuser',
        'PASSWORD': 'password',
        'HOST': 'managed_db_host',
        'PORT': 'managed_db_port',
    }
}

. . .

次に、ファイルの一番下に移動し、静的ファイルを配置する場所を示す設定を追加します。 これは、Nginxがこれらのアイテムのリクエストを処理できるようにするために必要です。 次の行は、ベースプロジェクトディレクトリのstaticというディレクトリにそれらを配置するようにDjangoに指示しています。

〜/ django-polls / mysite / settings.py

. . .

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

終了したら、ファイルを保存して閉じます。

この時点で、Djangoプロジェクトのデータベース、セキュリティ、静的ファイルの設定を構成しました。 最初からpollsチュートリアルに従い、GitHubリポジトリのクローンを作成しなかった場合は、ステップ6に進むことができます。 GitHubリポジトリのクローンを作成した場合、追加の手順が1つ残っています。

Django設定ファイルには、さまざまなDjangoオブジェクトのハッシュを作成するために使用されるSECRET_KEY変数が含まれています。 一意の予測できない値に設定することが重要です。 SECRET_KEY変数はGitHubリポジトリからスクラブされているため、djangoPythonパッケージに組み込まれているget_random_secret_key()という関数を使用して新しい変数を作成します。 コマンドラインから、Pythonインタープリターを開きます。

python

次の出力とプロンプトが表示されます。

OutputPython 3.6.7 (default, Oct 22 2018, 11:32:17)
[GCC 8.2.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>>

Djangoパッケージからget_random_secret_key関数をインポートし、関数を呼び出します。

from django.core.management.utils import get_random_secret_key
get_random_secret_key()

結果のキーをクリップボードにコピーします。

CTRL+Dを押して、Pythonインタープリターを終了します。

次に、テキストエディタで設定ファイルをもう一度開きます。

nano ~/django-polls/mysite/settings.py

SECRET_KEY変数を見つけて、生成したキーを貼り付けます。

〜/ django-polls / mysite / settings.py

. . .

# SECURITY WARNING: keep the secret key used in production secret!
SECRET_KEY = 'your_secret_key_here'

. . .

ファイルを保存して閉じます。

次に、Django開発サーバーを使用してアプリをローカルでテストし、すべてが正しく構成されていることを確認します。

ステップ6—アプリをテストする

Django開発サーバーを実行する前に、manage.pyユーティリティを使用してデータベーススキーマを作成し、静的ファイルをSTATIC_ROOTディレクトリに収集する必要があります。

プロジェクトのベースディレクトリに移動し、makemigrationsおよびmigrateコマンドを使用してPostgreSQLデータベースに初期データベーススキーマを作成します。

cd django-polls
./manage.py makemigrations
./manage.py migrate

makemigrationsは、Djangoモデルに加えられた変更に基づいて、移行またはデータベーススキーマの変更を作成します。 migrateは、これらの移行をデータベーススキーマに適用します。 Djangoでの移行の詳細については、Djangoの公式ドキュメントのMigrationsを参照してください。

次のように入力して、プロジェクトの管理ユーザーを作成します。

./manage.py createsuperuser

ユーザー名を選択し、メールアドレスを入力し、パスワードを選択して確認する必要があります。

次のように入力して、構成したディレクトリの場所にすべての静的コンテンツを収集できます。

./manage.py collectstatic

静的ファイルは、プロジェクトディレクトリ内のstaticというディレクトリに配置されます。

サーバーの初期設定ガイドに従った場合は、サーバーを保護するUFWファイアウォールが必要です。 開発サーバーをテストするには、使用するポートへのアクセスを許可する必要があります。

次のように入力して、ポート8000の例外を作成します。

sudo ufw allow 8000

Django開発サーバーを使用したアプリのテスト

最後に、次のコマンドでDjango開発サーバーを起動して、プロジェクトをテストできます。

./manage.py runserver 0.0.0.0:8000

Webブラウザーで、サーバーのドメイン名またはIPアドレスにアクセスし、続いて:8000およびpollsパスにアクセスします。

http://server_domain_or_IP:8000/polls

Pollsアプリのインターフェースが表示されます。

管理インターフェースを確認するには、サーバーのドメイン名またはIPアドレスにアクセスし、続いて:8000と管理インターフェースのパスにアクセスします。

http://server_domain_or_IP:8000/admin

Pollsアプリの管理者認証ウィンドウが表示されます。

createsuperuserコマンドで作成した管理者のユーザー名とパスワードを入力します。

認証後、Pollsアプリの管理インターフェースにアクセスできます。

探索が終了したら、ターミナルウィンドウでCTRL-Cを押して、開発サーバーをシャットダウンします。

Gunicornを使用したアプリのテスト

静的ファイルをオフロードする前に最後に実行したいのは、Gunicornをテストして、アプリケーションにサービスを提供できることを確認することです。 これを行うには、プロジェクトディレクトリに入り、gunicornを使用してプロジェクトのWSGIモジュールをロードします。

gunicorn --bind 0.0.0.0:8000 mysite.wsgi

これにより、Django開発サーバーが実行されていたのと同じインターフェースでGunicornが起動します。 戻ってアプリをもう一度テストできます。

注: Gunicornはこれに関与する静的CSSコンテンツを見つける方法を知らないため、管理インターフェースにはスタイルが適用されません。


アプリケーションへのエントリポイントであるDjangoのwsgi.pyファイルへの相対ディレクトリパスを指定して、Gunicornにモジュールを渡しました。 このファイルは、アプリケーションと通信するapplicationと呼ばれる関数を定義します。 WSGI仕様の詳細については、ここをクリックをクリックしてください。

テストが終了したら、ターミナルウィンドウでCTRL-Cを押してGunicornを停止します。

次に、アプリケーションの静的ファイルをDigitalOceanSpacesにオフロードします。

ステップ7—静的ファイルをDigitalOceanスペースにオフロードする

この時点で、GunicornはDjangoアプリケーションを提供できますが、静的ファイルは提供できません。 通常、これらのファイルを提供するようにNginxを構成しますが、このチュートリアルでは、django-storagesプラグインを使用してそれらをDigitalOceanSpacesにオフロードします。 これにより、静的コンテンツを一元化し、サーバーリソースを解放することで、Djangoを簡単にスケーリングできます。 さらに、DigitalOceanSpacesCDNを使用してこの静的コンテンツを配信できます。

Django静的ファイルをオブジェクトストレージにオフロードするための完全なガイドについては、Djangoを使用してオブジェクトストレージをセットアップする方法を参照してください。

django-storagesのインストールと構成

まず、django-storagesPythonパッケージをインストールします。 django-storagesパッケージは、boto3ライブラリを使用してファイルをS3互換のオブジェクトストレージサービスにアップロードするS3Boto3StorageストレージバックエンドをDjangoに提供します。

開始するには、pipを使用してdjango-storagesおよびboto3Pythonパッケージをインストールします。

pip install django-storages boto3

次に、アプリのDjango設定ファイルをもう一度開きます。

nano ~/django-polls/mysite/settings.py

ファイルのINSTALLED_APPSセクションに移動し、インストールされているアプリのリストにstoragesを追加します。

〜/ django-polls / mysite / settings.py

. . .

INSTALLED_APPS = [
    . . .
    'django.contrib.staticfiles',
    'storages',
]

. . .

ファイルをさらに下にスクロールして、前に変更したSTATIC_URLまで移動します。 これらの値を上書きし、新しいS3Boto3Storageバックエンドパラメーターを追加します。 以前に入力したコードを削除し、スペースのアクセスと場所の情報を含む次のブロックを追加します。 ここで強調表示されている値を独自の情報に置き換えることを忘れないでください::

〜/ django-polls / mysite / settings.py

. . .

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

AWS_ACCESS_KEY_ID = 'your_spaces_access_key'
AWS_SECRET_ACCESS_KEY = 'your_spaces_secret_key'

AWS_STORAGE_BUCKET_NAME = 'your_space_name'
AWS_S3_ENDPOINT_URL = 'spaces_endpoint_URL'
AWS_S3_OBJECT_PARAMETERS = {
    'CacheControl': 'max-age=86400',
}
AWS_LOCATION = 'static'
AWS_DEFAULT_ACL = 'public-read'

STATICFILES_STORAGE = 'storages.backends.s3boto3.S3Boto3Storage'

STATIC_URL = '{}/{}/'.format(AWS_S3_ENDPOINT_URL, AWS_LOCATION)
STATIC_ROOT = 'static/'

次の構成項目を定義します。

  • AWS_ACCESS_KEY_ID:チュートリアルの前提条件で作成したスペースのアクセスキーID。 アクセスキーのセットを作成しなかった場合は、アクセスキーを使用したスペースへのアクセスの共有を参照してください。
  • AWS_SECRET_ACCESS_KEY:DigitalOceanSpaceの秘密鍵。
  • AWS_STORAGE_BUCKET_NAME:DigitalOceanSpaceの名前。
  • AWS_S3_ENDPOINT_URL:オブジェクトストレージサービスへのアクセスに使用されるエンドポイントURL。 DigitalOceanの場合、これはスペース領域に応じてhttps://nyc3.digitaloceanspaces.comのようになります。
  • AWS_S3_OBJECT_PARAMETERS静的ファイルにキャッシュ制御ヘッダーを設定します。
  • AWS_LOCATION:すべての静的ファイルが配置されるオブジェクトストレージバケット内のディレクトリを定義します。
  • AWS_DEFAULT_ACL:静的ファイルのアクセス制御リスト(ACL)を定義します。 public-readに設定すると、エンドユーザーがファイルにパブリックにアクセスできるようになります。
  • STATICFILES_STORAGE:Djangoが静的ファイルをオフロードするために使用するストレージバックエンドを設定します。 このバックエンドは、DigitalOceanSpacesを含むすべてのS3互換バックエンドで動作するはずです。
  • STATIC_URL:静的ファイルのURLを生成するときにDjangoが使用するベースURLを指定します。 ここでは、エンドポイントURLと静的ファイルサブディレクトリを組み合わせて、静的ファイルのベースURLを作成します。
  • STATIC_ROOT:静的ファイルをオブジェクトストレージにコピーする前にローカルで収集する場所を指定します。

編集が完了したら、ファイルを保存して閉じます。

今後、collectstaticを実行すると、Djangoはアプリの静的ファイルをSpaceにアップロードします。 Djangoを起動すると、このスペースからCSSやJavascriptなどの静的アセットの提供が開始されます。

次のセクションでは、このSpaceのCDNを有効にし、オプションでSpacesCDNのカスタムサブドメインを構成します。 これにより、地理的に分散したエッジサーバーのネットワーク全体にキャッシュすることで、Djangoプロジェクトの静的ファイルの配信が高速化されます。 CDNの詳細については、CDNを使用した静的コンテンツ配信の高速化を参照してください。 Spaces CDNを有効にしたくない場合は、CORSヘッダーの設定に進んでください。

CDNの有効化(オプション)

DigitalOcean Spaces CDNを介した静的ファイル配信をアクティブ化するには、まずDigitalOceanSpaceのCDNを有効にします。 これを行う方法については、DigitalOcean製品ドキュメントの SpacesCDNを有効にする方法を参照してください。

Spaces CDNでカスタムドメインを使用する場合は、サブドメインでSpaces CDNエンドポイントをカスタマイズする方法に従って、サブドメインCNAMEレコードと適切なSSL証明書を作成します。

SpacesCDNでカスタムドメインを使用することを強くお勧めします。 これにより、オフロードされたアセットのURLをDjangoサイトのURLと同様に保つことで、サイトの検索エンジン最適化(SEO)が大幅に向上します。 Spaces CDNでカスタムドメインを使用するには、最初にドメインをDigitalOceanアカウントに追加する必要があります。 これを行う方法については、ドメインを追加する方法を参照してください。

スペースのCDNを有効にし、オプションでそのカスタムサブドメインを作成したら、クラウドコントロールパネルを使用してスペースに移動します。 スペース名の下に新しいEndpointsリンクが表示されます。

これらのエンドポイントには、スペース名が含まれている必要があります。 Spaces CDNのカスタムサブドメインを作成した場合、このリストにはサブドメインという追加のエンドポイントが含まれます。

Edge エンドポイントは、SpacesオブジェクトのリクエストをCDN経由でルーティングし、可能な限りエッジキャッシュからそれらを提供します。 このEdgeエンドポイントは、django-storagesプラグインの構成に使用するため、メモしておいてください。 Spaces CDNのサブドメインを作成した場合、SubdomainエンドポイントはこのEdgeエンドポイントのエイリアスです。

次に、アプリのDjango設定ファイルをもう一度編集します。

nano ~/django-polls/mysite/settings.py

最近変更した[静的ファイル]セクションに移動します。 AWS_S3_CUSTOM_DOMAINパラメーターを追加してdjango-storagesプラグインCDNエンドポイントを構成し、STATIC_URLパラメーターを更新してこの新しいCDNエンドポイントを使用します。

〜/ django-polls / mysite / settings.py

. . .

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

# Moving static assets to DigitalOcean Spaces as per:
# how-to-set-up-object-storage-with-django
AWS_ACCESS_KEY_ID = 'your_spaces_access_key'
AWS_SECRET_ACCESS_KEY = 'your_spaces_secret_key'

AWS_STORAGE_BUCKET_NAME = 'your_space_name'
AWS_S3_ENDPOINT_URL = 'spaces_endpoint_URL'
AWS_S3_CUSTOM_DOMAIN = 'spaces_edge_endpoint_URL'
AWS_S3_OBJECT_PARAMETERS = {
    'CacheControl': 'max-age=86400',
}
AWS_LOCATION = 'static'
AWS_DEFAULT_ACL = 'public-read'

STATICFILES_STORAGE = 'storages.backends.s3boto3.S3Boto3Storage'

STATIC_URL = '{}/{}/'.format(AWS_S3_CUSTOM_DOMAIN, AWS_LOCATION)
STATIC_ROOT = 'static/'

ここで、spaces_edge_endpoint_URLを、メモしたばかりのEdgeエンドポイントに置き換え、https://プレフィックスを切り捨てます。 たとえば、エッジエンドポイントURLがhttps://example.sfo2.cdn.digitaloceanspaces.comの場合、AWS_S3_CUSTOM_DOMAINexample.sfo2.cdn.digitaloceanspaces.comに設定する必要があります。

カスタムサブドメインを作成した場合は、spaces_edge_endpoint_URLをカスタムサブドメインエンドポイントに置き換え、https://プレフィックスを切り捨てます。 たとえば、サブドメインのエンドポイントURLがhttps://assets.example.comの場合、AWS_S3_CUSTOM_DOMAINassets.example.comに設定する必要があります。

完了したら、ファイルを保存して閉じます。

Djangoを起動すると、DigitalOceanSpaceのCDNを使用して静的コンテンツが提供されるようになります。

これがすべて正しく機能していることをテストする前に、Spacesファイルの Cross-Origin Resource Sharing(CORS)ヘッダーを構成する必要があります。そうしないと、特定の静的アセットへのアクセスがWebブラウザーによって拒否される場合があります。 Djangoで使用されているのと同じドメインに対してSpacesCDNでカスタムサブドメインを使用している場合は、 Spaces Static FileDeliveryのテストに進んでください。

CORSヘッダーの設定

CORSヘッダーは、あるドメインで実行されているアプリケーションが別のドメインにあるスクリプトまたはリソースにアクセスできることをWebブラウザーに通知します。 この場合、スペース内の静的ファイルのリクエストがWebブラウザーによって拒否されないように、Djangoサーバーのドメインのクロスオリジンリソース共有を許可する必要があります。

注:この手順は、SpacesCDNでカスタムサブドメインを使用していない場合にのみ必要です。


まず、クラウドコントロールパネルを使用して、スペースの設定ページに移動します。

CORS構成セクションで、追加をクリックします。

ここで、 Origin の下に、ワイルドカードの原点*を入力します。

警告:アプリを本番環境にデプロイするときは、必ずこの値を正確なオリジンドメイン(http://またはhttps://プロトコルを含む)に変更してください。 ワイルドカードオリジンとしてこれを残すことは安全ではありません。オリジンをhttp://example.com:8000(非標準ポートを使用)に設定することは現在サポートされていないため、ここではテスト目的でのみこれを行います。


許可されたメソッドで、GETを選択します。

ヘッダーの追加をクリックし、表示されるテキストボックスにAccess-Control-Allow-Originと入力します。

Access Control Max Age600に設定して、作成したヘッダーが10分ごとに期限切れになるようにします。

[オプションの保存]をクリックします。

今後、Space内のオブジェクトには、適切なAccess-Control-Allow-Origin応答ヘッダーが含まれるようになり、最新の安全なWebブラウザーがドメイン間でこれらのファイルをフェッチできるようになります。

テストスペースの静的ファイル配信

ここで、DjangoがDigitalOceanSpaceから静的ファイルを正しく提供していることをテストします。

Djangoアプリディレクトリに移動します。

cd ~/django-polls

ここから、collectstaticを実行して、静的ファイルを収集し、DigitalOceanSpaceにアップロードします。

python manage.py collectstatic

次の出力が表示されます。

OutputYou have requested to collect static files at the destination
location as specified in your settings.

This will overwrite existing files!
Are you sure you want to do this?

Type 'yes' to continue, or 'no' to cancel: 

yesと入力し、ENTERを押して確認します。

次のような出力が表示されます。

Output121 static files copied.

これは、Djangoがpollsアプリの静的ファイルをSpaceに正常にアップロードしたことを確認します。 クラウドコントロールパネルを使用してスペースに移動し、staticディレクトリ内のファイルを調べることができます。

次に、Djangoが適切なURLを書き換えていることを確認します。

Gunicornサーバーを起動します。

gunicorn --bind 0.0.0.0:8000 mysite.wsgi  

Webブラウザーで、サーバーのドメイン名またはIPアドレスにアクセスし、続いて:8000および/adminにアクセスします。

http://server_domain_or_IP:8000/admin

もう一度、Pollsアプリの管理者認証ウィンドウが表示されます。今回は正しいスタイルで表示されます。

次に、ブラウザの開発者ツールを使用して、ページの内容を調べ、ソースファイルの保存場所を明らかにします。

Google Chromeを使用してこれを行うには、ページを右クリックして、検査を選択します。

次のウィンドウが表示されます。

ここから、ツールバーのソースをクリックします。 左側のペインのソースファイルのリストで、Djangoサーバーのドメインの下に/admin/loginが表示され、SpaceのCDNエンドポイントの下にstatic/adminが表示されます。 static/admin内に、cssディレクトリとfontsディレクトリの両方が表示されます。

これにより、CSSスタイルシートとフォントがSpaceのCDNから正しく提供されていることが確認されます。

テストが終了したら、ターミナルウィンドウでCTRL-Cを押してGunicornを停止します。

deactivateと入力すると、アクティブなPython仮想環境を無効にできます。

deactivate

プロンプトは通常に戻るはずです。

この時点で、Djangoサーバーから静的ファイルを正常にオフロードし、オブジェクトストレージからそれらを提供しています。 これで、システムサービスとして自動的に開始するようにGunicornを構成することに進むことができます。

ステップ8—Gunicorn用のsystemdソケットおよびサービスファイルの作成

ステップ6では、GunicornがDjangoアプリケーションと対話できることをテストしましたが、アプリケーションサーバーを起動および停止するためのより堅牢な方法を実装する必要があります。 これを実現するために、systemdサービスとソケットファイルを作成します。

Gunicornソケットは起動時に作成され、接続をリッスンします。 接続が発生すると、systemdは接続を処理するためにGunicornプロセスを自動的に開始します。

sudo権限を持つGunicornのsystemdソケットファイルを作成して開くことから始めます。

sudo nano /etc/systemd/system/gunicorn.socket

内部では、ソケットを説明する[Unit]セクション、ソケットの場所を定義する[Socket]セクション、およびソケットが確実に作成されるようにする[Install]セクションを作成します。適切なタイミング。 次のコードをファイルに追加します。

/etc/systemd/system/gunicorn.socket

[Unit]
Description=gunicorn socket

[Socket]
ListenStream=/run/gunicorn.sock

[Install]
WantedBy=sockets.target

終了したら、ファイルを保存して閉じます。

次に、テキストエディタでsudo権限を持つGunicornのsystemdサービスファイルを作成して開きます。 サービスファイル名は、拡張子を除いてソケットファイル名と一致する必要があります。

sudo nano /etc/systemd/system/gunicorn.service

メタデータと依存関係を指定する[Unit]セクションから始めます。 ここにサービスの説明を入力し、ネットワークターゲットに到達した後にのみこれを開始するようにinitシステムに指示します。 私たちのサービスはソケットファイルのソケットに依存しているため、その関係を示すためにRequiresディレクティブを含める必要があります。

/etc/systemd/system/gunicorn.service

[Unit]
Description=gunicorn daemon
Requires=gunicorn.socket
After=network.target

次に、[Service]セクションを開きます。 実行する処理を行うユーザーとグループを指定します。 プロセスは関連するすべてのファイルを所有しているため、通常のユーザーアカウントにプロセスの所有権を付与します。 NginxがGunicornと簡単に通信できるように、www-dataグループにグループ所有権を付与します。

次に、作業ディレクトリをマップし、サービスの開始に使用するコマンドを指定します。 この場合、仮想環境内にインストールされているGunicorn実行可能ファイルへのフルパスを指定する必要があります。 プロセスを/runディレクトリ内に作成したUnixソケットにバインドして、プロセスがNginxと通信できるようにします。 journaldプロセスがGunicornログを収集できるように、すべてのデータを標準出力に記録します。 ここでは、ワーカープロセスの数など、オプションのGunicornの微調整を指定することもできます。 ここでは、3つのワーカープロセスでGunicornを実行します。

次のサービスセクションをファイルに追加します。 ここにリストされているユーザー名を自分のユーザー名に置き換えてください。

/etc/systemd/system/gunicorn.service

[Unit]
Description=gunicorn daemon
Requires=gunicorn.socket
After=network.target

[Service]
User=sammy
Group=www-data
WorkingDirectory=/home/sammy/django-polls
ExecStart=/home/sammy/envs/polls/bin/gunicorn \
          --access-logfile - \
          --workers 3 \
          --bind unix:/run/gunicorn.sock \
          mysite.wsgi:application

最後に、[Install]セクションを追加します。 これにより、起動時にサービスを開始できるようにした場合に、このサービスを何にリンクするかがsystemdに通知されます。 このサービスは、通常のマルチユーザーシステムが稼働しているときに開始する必要があります。

/etc/systemd/system/gunicorn.service

[Unit]
Description=gunicorn daemon
Requires=gunicorn.socket
After=network.target

[Service]
User=sammy
Group=www-data
WorkingDirectory=/home/sammy/django-polls
ExecStart=/home/sammy/envs/polls/bin/gunicorn \
          --access-logfile - \
          --workers 3 \
          --bind unix:/run/gunicorn.sock \
          mysite.wsgi:application

[Install]
WantedBy=multi-user.target

これで、systemdサービスファイルが完成しました。 今すぐ保存して閉じます。

これで、Gunicornソケットを起動して有効にできます。 これにより、/run/gunicorn.sockで起動時にソケットファイルが作成されます。 そのソケットに接続が確立されると、systemdは自動的にgunicorn.serviceを起動してそれを処理します。

sudo systemctl start gunicorn.socket
sudo systemctl enable gunicorn.socket

ソケットファイルを確認することで、操作が成功したことを確認できます。

Gunicornソケットファイルの確認

プロセスのステータスをチェックして、プロセスが正常に開始されたかどうかを確認します。

sudo systemctl status gunicorn.socket

次の出力が表示されます。

OutputFailed to dump process list, ignoring: No such file or directory
● gunicorn.socket - gunicorn socket
   Loaded: loaded (/etc/systemd/system/gunicorn.socket; enabled; vendor preset: enabled)
   Active: active (running) since Tue 2019-03-05 19:19:16 UTC; 1h 22min ago
   Listen: /run/gunicorn.sock (Stream)
   CGroup: /system.slice/gunicorn.socket

Mar 05 19:19:16 django systemd[1]: Listening on gunicorn socket.

次に、/runディレクトリ内にgunicorn.sockファイルが存在するかどうかを確認します。

file /run/gunicorn.sock
Output/run/gunicorn.sock: socket

systemctl statusコマンドでエラーが発生したことが示された場合、またはディレクトリにgunicorn.sockファイルが見つからない場合は、Gunicornソケットが正しく作成されていないことを示しています。 次のように入力して、Gunicornソケットのログを確認します。

sudo journalctl -u gunicorn.socket

続行する前に、/etc/systemd/system/gunicorn.socketファイルをもう一度確認して、問題を修正してください。

ソケットアクティベーションのテスト

現在、gunicorn.socketユニットのみを起動した場合、ソケットはまだ接続を受信していないため、gunicorn.serviceはアクティブになりません。 次のように入力して、これを確認できます。

sudo systemctl status gunicorn
Output● gunicorn.service - gunicorn daemon
   Loaded: loaded (/etc/systemd/system/gunicorn.service; disabled; vendor preset: enabled)
   Active: inactive (dead)

ソケットアクティベーションメカニズムをテストするには、次のように入力して、curlを介してソケットへの接続を送信できます。

curl --unix-socket /run/gunicorn.sock localhost

ターミナルにアプリケーションからのHTML出力が表示されます。 これは、Gunicornが起動し、Djangoアプリケーションを提供できることを示しています。 次のように入力して、Gunicornサービスが実行されていることを確認できます。

sudo systemctl status gunicorn
Output● gunicorn.service - gunicorn daemon
   Loaded: loaded (/etc/systemd/system/gunicorn.service; disabled; vendor preset: enabled)
   Active: active (running) since Tue 2019-03-05 20:43:56 UTC; 1s ago
 Main PID: 19074 (gunicorn)
    Tasks: 4 (limit: 4915)
   CGroup: /system.slice/gunicorn.service
           ├─19074 /home/sammy/envs/polls/bin/python3 /home/sammy/envs/polls/bin/gunicorn --access-logfile - --workers 3 --bind unix:/run/gunicorn.sock mysite.wsgi:application
           ├─19098 /home/sammy/envs/polls/bin/python3 /home/sammy/envs/polls/bin/gunicorn 
. . .

Mar 05 20:43:56 django systemd[1]: Started gunicorn daemon.
Mar 05 20:43:56 django gunicorn[19074]: [2019-03-05 20:43:56 +0000] [19074] [INFO] Starting gunicorn 19.9.0
. . .
Mar 05 20:44:15 django gunicorn[19074]:  - - [05/Mar/2019:20:44:15 +0000] "GET / HTTP/1.1" 301 0 "-" "curl/7.58.0"

curlからの出力またはsystemctl statusの出力が問題が発生したことを示している場合は、ログで詳細を確認してください。

sudo journalctl -u gunicorn

/etc/systemd/system/gunicorn.serviceファイルに問題がないか確認することもできます。 このファイルに変更を加えた場合は、必ずデーモンをリロードしてサービス定義を再読み込みし、Gunicornプロセスを再起動してください。

sudo systemctl daemon-reload
sudo systemctl restart gunicorn

Nginxサーバーの構成に進む前に、問題のトラブルシューティングを必ず行ってください。

ステップ8—NginxHTTPSとGunicornプロキシパッシングの設定

Gunicornがより堅牢な方法でセットアップされたので、接続を暗号化し、トラフィックをGunicornプロセスに渡すようにNginxを構成する必要があります。

前提条件に従い、Let's Encryptを使用してNginxを設定した場合、Nginxのsites-availableディレクトリに、ドメインに対応するサーバーブロックファイルがすでに用意されているはずです。 そうでない場合は、 Ubuntu 18.04でLet'sEncryptを使用してNginxを保護する方法に従って、この手順に戻ります。

このexample.comサーバーブロックファイルを編集する前に、Nginxのインストール後にデフォルトでロールアウトされるdefaultサーバーブロックファイルを最初に削除します。

sudo rm /etc/nginx/sites-enabled/default

ここで、example.comサーバーブロックファイルを変更して、前提条件の手順で構成されたデフォルトのindex.htmlページの代わりに、トラフィックをGunicornに渡します。

ドメインに対応するサーバーブロックファイルをエディターで開きます。

sudo nano /etc/nginx/sites-available/example.com

次のようなものが表示されます。

/etc/nginx/sites-available/example.com

server {

        root /var/www/example.com/html;
        index index.html index.htm index.nginx-debian.html;

        server_name example.com www.example.com;

        location / {
                try_files $uri $uri/ =404;
        }

    listen [::]:443 ssl ipv6only=on; # managed by Certbot
    listen 443 ssl; # managed by Certbot
    ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem; # managed by Certbot
    ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem; # managed by Certbot
    include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
    ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot

}

server {
    if ($host = example.com) {
        return 301 https://$host$request_uri;
    } # managed by Certbot


        listen 80;
        listen [::]:80;

        server_name example.com www.example.com;
    return 404; # managed by Certbot


}

これは、 Ubuntu 18.04にNginxをインストールする方法で作成されたデフォルトのサーバーブロックファイルと、Let'sEncryptによって自動的に追加された追加ファイルの組み合わせです。 このファイルの内容を削除し、HTTPトラフィックをHTTPSにリダイレクトし、前の手順で作成したGunicornソケットに着信要求を転送する新しい構成を記述します。

必要に応じて、cpを使用してこのファイルのバックアップを作成できます。 テキストエディタを終了し、example.com.oldという名前のバックアップを作成します。

sudo cp /etc/nginx/sites-available/example.com /etc/nginx/sites-available/example.com.old

ここで、ファイルを再度開き、その内容を削除します。 新しい構成をブロックごとに作成します。

次のブロックに貼り付けることから始めます。これにより、ポート80のHTTPリクエストがHTTPSにリダイレクトされます。

/etc/nginx/sites-available/example.com

server {
    listen 80 default_server;
    listen [::]:80 default_server;
    server_name _;
    return 301 https://example.com$request_uri;
}

ここでは、ポート80でHTTPIPv4およびIPv6要求をリッスンし、301応答ヘッダーを送信して、example.comドメインを使用して要求をHTTPSポート443にリダイレクトします。 これにより、直接HTTPリクエストがサーバーのIPアドレスにリダイレクトされます。

このブロックの後に、example.comドメインのHTTPSリクエストを処理する構成コードの次のブロックを追加します。

/etc/nginx/sites-available/example.com

. . . 
server {
    listen [::]:443 ssl ipv6only=on;
    listen 443 ssl;
    server_name example.com www.example.com;
    
    # Let's Encrypt parameters
    ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
    include /etc/letsencrypt/options-ssl-nginx.conf;
    ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem;
    
    location = /favicon.ico { access_log off; log_not_found off; }

    location / {
        proxy_pass         http://unix:/run/gunicorn.sock;
        proxy_redirect     off;

        proxy_set_header   Host              $http_host;
        proxy_set_header   X-Real-IP         $remote_addr;
        proxy_set_header   X-Forwarded-For   $proxy_add_x_forwarded_for;
        proxy_set_header   X-Forwarded-Proto https;
    }
}

ここでは、最初にポート443で、example.comおよびwww.example.comドメインにヒットするリクエストをリッスンします。

次に、デフォルトのサーバーブロックファイルに含まれているものと同じLet's Encrypt構成を提供します。これは、SSL証明書と秘密鍵の場所、およびいくつかの追加のセキュリティパラメーターを指定します。

location = /favicon.ico行は、ファビコンの検索に関する問題を無視するようにNginxに指示します。

最後のlocation = /ブロックは、ステップ8で構成されたGunicornソケットにリクエストを渡すようにNginxに指示します。 さらに、リクエストが転送されたことをアップストリームDjangoサーバーに通知し、さまざまなリクエストプロパティを提供するヘッダーを追加します。

これらの2つの構成ブロックを貼り付けると、最終的なファイルは次のようになります。

/etc/nginx/sites-available/example.com

server {
    listen 80 default_server;
    listen [::]:80 default_server;
    server_name _;
    return 301 https://example.com$request_uri;
}
server {
        listen [::]:443 ssl ipv6only=on;
        listen 443 ssl;
        server_name example.com www.example.com;

        # Let's Encrypt parameters
        ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
        ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
        include /etc/letsencrypt/options-ssl-nginx.conf;
        ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem;

        location = /favicon.ico { access_log off; log_not_found off; }

        location / {
          proxy_pass         http://unix:/run/gunicorn.sock;
          proxy_redirect     off;

          proxy_set_header   Host              $http_host;
          proxy_set_header   X-Real-IP         $remote_addr;
          proxy_set_header   X-Forwarded-For   $proxy_add_x_forwarded_for;
          proxy_set_header   X-Forwarded-Proto https;
        }
}

終了したら、ファイルを保存して閉じます。

次のように入力して、構文エラーについてNginx構成をテストします。

sudo nginx -t

構成にエラーがない場合は、次のように入力してNginxを再起動します。

sudo systemctl restart nginx

これで、サーバーのドメインまたはIPアドレスにアクセスしてアプリケーションを表示できるようになります。 ブラウザは、安全なHTTPS接続を使用してDjangoバックエンドに接続する必要があります。

Djangoプロジェクトを完全に保護するには、settings.pyファイルにいくつかのセキュリティパラメーターを追加する必要があります。 エディターでこのファイルを再度開きます。

nano ~/django-polls/mysite/settings.py

ファイルの一番下までスクロールし、次のパラメータを追加します。

〜/ django-polls / mysite / settings.py

. . .

SECURE_PROXY_SSL_HEADER = ('HTTP_X_FORWARDED_PROTO', 'https')
SESSION_COOKIE_SECURE = True
CSRF_COOKIE_SECURE = True
SECURE_SSL_REDIRECT = True

これらの設定は、サーバーでHTTPSを有効にしていることをDjangoに通知し、「安全な」Cookieを使用するように指示します。 これらの設定の詳細については、DjangoのセキュリティのSSL/HTTPSセクションを参照してください。

完了したら、ファイルを保存して閉じます。

最後に、Gunicornを再起動します。

sudo systemctl restart gunicorn

この時点で、HTTPリクエストをリダイレクトし、これらのリクエストをGunicornに渡すようにNginxを設定しました。 これで、DjangoプロジェクトとアプリでHTTPSが完全に有効になります。 エラーが発生した場合は、NginxとGunicornのトラブルシューティングに関するこのディスカッションが役立つ場合があります。

警告: CORSヘッダーの構成で説明されているように、Spaces CDNのカスタムサブドメインを構成しなかった場合は、必ずOriginを変更してください。 ]ワイルドカード*ドメインからドメイン名(このガイドではhttps://example.com)に変更してから、エンドユーザーがアプリにアクセスできるようにします。


結論

このガイドでは、Ubuntu18.04サーバーで実行されるスケーラブルなDjangoアプリケーションをセットアップして構成しました。 この設定を複数のサーバーに複製して、高可用性アーキテクチャを作成できます。 さらに、このアプリとその構成は、 Docker または別のコンテナーランタイムを使用してコンテナー化でき、デプロイとスケーリングが容易になります。 これらのコンテナは、Kubernetesなどのコンテナクラスタにデプロイできます。 今後のチュートリアルシリーズでは、このDjango pollsアプリをコンテナ化して最新化し、Kubernetesクラスターで実行できるようにする方法について説明します。

静的ファイルに加えて、DjangoMediaファイルをオブジェクトストレージにオフロードすることもできます。 これを行う方法については、AmazonS3を使用してDjangoサイトの静的ファイルとメディアファイルを保存するを参照してください。 静的ファイルを圧縮して、エンドユーザーへの配信をさらに最適化することも検討してください。 これを行うには、DjangoコンプレッサーのようなDjangoプラグインを使用できます。