ブログに戻る

Ubuntu上でDockerを使用してDjangoとGunicornアプリケーションを構築する

Ubuntu上でDockerを使用してDjangoとGunicornアプリケーションを構築する

Django は、高レベルのオープンソースの Python Webフレームワークであり、Pythonアプリケーションを迅速に構築するのに役立ちます。モデル・テンプレート・ビュー(model–template–views)のアーキテクチャパターンに従うことで、迅速な開発とクリーンで実用的な設計を促進します。このフレームワークには、ユーザー認証、キャッシュフレームワーク, オブジェクト関係マッパー, URLディスパッチャー, テンプレートシステム、およびカスタマイズ可能な管理インターフェースなどの必要な最新のアプリケーションコンポーネントが最初から用意されています。

Gunicorn ‘Green Unicorn’ は、UNIXシステム用のPython WSGI HTTPサーバーです。GunicornサーバーはさまざまなWebフレームワークと互換性があり、優れたパフォーマンスを提供し、サーバーリソースをほとんど消費しません。 Docker は、以前から存在するオープンソースのコンテナプラットフォームであり、アプリケーション開発を迅速、効率的、かつ予測可能にします。

このチュートリアルでは、スケーラブルなコンテナ化されたDjango Webアプリの開発とデプロイのスキルを習得します。ここでは、Djangoの導入ガイド「Djangoを始める」に従って作成されたDjangoのPolls アプリを使用します。このチュートリアルの執筆時点では、Django 3.2(サポート対象:Python 3.6 以降)に基づいています。このアプリをDockerでコンテナとしてデプロイし、Gunicornサーバーで提供します。もちろん、Djangoアプリをコンテナにデプロイする前に、標準出力ストリームへのロギングや環境変数の処理などを行うために、プロジェクトコードにいくつかの変更を加える必要があります。CSSやJavaScript、画像などの静的ファイルは、マルチコンテナ環境において1つの場所からファイルを簡単に管理できるように、オブジェクトストレージサービスにオフロードできます。

スケーラブルなWebアプリケーションを構築するための、明確に定義された twelve-factor 手法に基づいて、これらの変更を実装する方法を説明します。変更が完了したら、アプリケーションのDockerイメージをビルドし、コンテナ化されたアプリをDockerでデプロイします。チュートリアルを完全に理解するために、チュートリアルに示されている手順に沿って進めることをお勧めします。

前提条件

これは実践的なチュートリアルであるため、手順に沿って進められるよう、以下のセットアップを用意することをお勧めします。

  • Ubuntu 20.04サーバー。このUbuntuサーバーのセットアップに役立つステップバイステップのチュートリアル(CloudSigma上)のステップ1から4に従ってください。

  • 上記のチュートリアルで説明されているコマンドを実行するために使用する両方のノードに、sudo権限を持つユーザーを追加してください。

  • サーバーにDockerをインストールします。当社のDockerのインストールと操作に関するチュートリアルのステップ1、2、3に従ってください。上記で作成したsudoユーザーをDockerグループに追加することを忘れないでください。

  • 互換性のあるオブジェクトストレージスペース。Djangoは、django-storagesのドキュメントに記載されているいくつかのストレージサービスをサポートしています。お好みのものを選択し、ドキュメントに従ってセットアップしてください。このチュートリアルでは、MinIO(S3互換のクラウドストレージサービス)を使用します。

  • SQLデータベースインスタンス。DjangoはいくつかのSQLデータベースをサポートしており、自由に選択できます。このチュートリアルでは、PostgreSQLを使用します。PostgreSQLデータベースはコンテナ内にはデプロイされません。マルチコンテナのセットアップとデータの永続性を確実に実現するために、PostgreSQLインスタンスをホストする別のUbuntuサーバーをセットアップします。必要に応じて、別のUbuntu 20.04インスタンスを作成し、このチュートリアルに従ってUbuntuでPostgreSQLデータベースインスタンスをセットアップしてください。ステップ 2および3で説明されているように、sudoユーザー用のロールをPostgreSQLデータベースに追加することを忘れないでください。このロールにより、コンテナをホストしている他のサーバーからデータベースに接続できるようになります。

これらの前提条件に従って、2つのUbuntuサーバーインスタンスを用意する必要があります。一方のインスタンスではDockerコンテナを実行し、もう一方のインスタンスではPostgreSQLインスタンスを実行します。始めましょう!

ステップ1:PostgreSQLデータベースインスタンスの構成

このセクションでは、Postgresインスタンスが実行されているUbuntuサーバー上のPostgres設定を変更します。これにより、外部IPアドレスからの接続が可能になります。接続されたら、デプロイするDjango Pollsアプリ専用のデータベースとユーザーロールを作成できます。

まず、前提条件に従って環境をセットアップしている場合、PostgreSQLデータベースにsudoユーザー用のロールが存在するはずです。次に、このロールのパスワードを設定する必要があります。PostgreSQLが実行されているサーバー上で、次のコマンドを使用してPostgresターミナルにログインします。

Postgresターミナルに入ったら、次のコマンドを実行します。 \password コマンドを使用してユーザーのパスワードを変更します。 \passwordコマンドは \password <username> です。今回の場合は、次のコマンドになります。

パスワードを入力し、確認します。このパスワードは、後で別のUbuntuサーバーから認証する際に使用するため、安全な場所に保存してください。その後、 exit と入力してEnterキーを押し、Postgresターミナルを終了します。

PostgreSQLサーバーインスタンスでファイアウォール(ufw)を有効にしている場合は、Postgresのデフォルトポートへのトラフィックを許可する必要があります。 5432。Dockerコンテナを実行するもう一方のUbuntuサーバーの特定のIPアドレスからのみトラフィックを制限することができます。以下のコマンドを実行してufwルールを追加し、ハイライトされた部分をご自身のIPアドレスに置き換えてください。

これにより、ご自身のサーバーのみがPostgreSQLインスタンスに接続できるようになります。ファイアウォールを通過するトラフィックを許可する一方で、リモートIPアドレスからの接続を許可するようにPostgreSQL設定ファイルも変更する必要があります。デフォルトでは、設定はlocalhostからの接続のみを許可しています。PostgreSQLの設定ファイルは、 /etc/postgresql/12/main ディレクトリにあります。 12は、このチュートリアルでインストールしたPostgreSQLのバージョンです。異なるバージョンをインストールしている場合もあります。そのため、 /etc/postgresql/ ディレクトリに移動し、コンテンツをリストして、インストールしたPostgreSQLのバージョン番号を確認してください。

nanoを使用して設定ファイルを変更します。

以下の行を見つけてコメントアウトを解除し、すべてのIPからの接続を許可するように設定します。

ファイルを保存して閉じます。次に、 pg_hba.conf ファイルも編集する必要があります。これは postgresql.conf と同じディレクトリにあります。 pg_hba.conf を使用すると、どのコンピュータからPostgreSQLインスタンスに接続できるか、および認証方法を定義できます。nanoでファイルを開きます。

キーワードを理解するために、このファイル内のコメントをお読みください。探しているセクションは次のとおりです。

Building a Django and Gunicorn Application with Docker on Ubuntu 1

2行目に注目します。コメントアウトを解除した後、以下の行のようになるようにします。

ハイライトされた部分をご自身のUbuntuサーバーのIPアドレスに置き換えて、PostgreSQLインスタンスへの接続を許可してください。準備ができたらファイルを保存します。変更を有効にするためにPostgreSQLデータベースを再起動します。

指定されたIPアドレスを持つもう一方のUbuntuサーバーが、Postgresインスタンスに接続できるようになるはずです。

ステップ2:PostgreSQLサーバーインスタンスへの接続とデータベースおよびユーザーの作成

このステップでは、Dockerコンテナを提供するUbuntuインスタンスが、PostgreSQLインスタンスを実行しているもう一方のサーバーに接続できることを確認します。DockerがインストールされているUbuntuインスタンスにログインし、Ubuntuホストマシン内(まだコンテナ内ではありません)に postgresql-clientパッケージをインストールします。

通常通り、まずaptパッケージを更新し、次に以下のコマンドでパッケージをインストールします。

上記でインストールしたパッケージは、アプリケーション用のデータベースとユーザーを作成するのに役立ちます。次に、PostgreSQLクライアントに接続パラメータを渡して、PostgreSQLインスタンスに接続する必要があります。

接続パラメータは次の構文に従います。

このコマンドでは、 username は、PostgreSQLデータベースに追加したユーザー/ロールです。 host は、PostgreSQLデータベースを実行しているUbuntuインスタンスのIPアドレスです。 port は、Postgresが着信接続をリッスンするデフォルトのポート(すなわち、5432)です。 database の部分には、PostgreSQLのインストール時にデフォルトで用意されている postgres というデータベースを使用します。ハイライトされた部分をご自身の値に適切に置き換えて、Enterキーを押してください。プロンプトが表示されたら、設定したパスワードを入力します。これにより、データベースを管理できるPostgresプロンプトにログインします。

PostgreSQLインスタンスへの接続に成功しました。これで、Django pollsアプリ用のデータベースを作成できます。名前は django_polls:

エラーを避けるために、ステートメントの最後がセミコロンで終わっていることを確認してください。次に、コマンドを使用して django_polls データベースに切り替えます。

次に、このプロジェクト専用のデータベースユーザーを作成します。ユーザー名を django_user:

ユーザーに安全なパスワードを設定してください。完了したら、作成したばかりのユーザーの接続パラメータを変更する必要があります。これにより、接続が確立されるたびに正しい値が照会および設定されるのを防ぎ、データベース操作を高速化できます。

Djangoが期待するデフォルトのエンコーディングをUTF-8に設定します。

次に、デフォルトのトランザクション分離レベルを「 read committed」に設定します。これにより、未コミットのトランザクションからの読み取りがブロックされます。

タイムゾーンを設定します。チュートリアルを汎用的なものにするため、UTC:

最後に、新しいユーザーにデータベースの管理権限を付与します。

準備ができたら、PostgreSQLプロンプトを終了します。

このステップは以上です。Djangoアプリを適切に設定すれば、データベースを管理できるようになります。

ステップ 3: Gitリポジトリからのアプリのプルと依存関係の定義

このステップでは、Django-polls アプリのリポジトリをクローンします。このリポジトリには、Djangoの 「はじめてのDjangoアプリ作成」チュートリアルのコードが含まれています。.

Dockerを実行しているUbuntuサーバーにログインし、 django_project というディレクトリを作成して、その中に移動します。

次に、以下のコマンドを使用して、リポジトリをディレクトリにクローンします。

ディレクトリに移動し、中身を一覧表示します。

ディレクトリの内容を一覧表示します。

Building a Django and Gunicorn Application with Docker on Ubuntu 2

以下の項目に注目してください。

  • manage.py: このファイルは、Djangoがアプリを管理するために提供するコマンドラインユーティリティへのエントリです。

  • mysite: Djangoプロジェクトのスコープとコード設定を含むディレクトリです。

  • polls: polls アプリケーションコードを含むディレクトリです。

  • templates: 管理ページのカスタムテンプレートファイルが含まれています。

プロジェクトの実際の作成方法の詳細については、公式ドキュメントのWriting your first Django app を参照してください。 django-polls ディレクトリに、Pythonの依存関係をテキストファイルで定義したいと思います。名前は requirements.txt とします。お好みのエディタでファイルを開いてください:

依存関係を宣言するために、ファイル内に次の行を貼り付けます:

このファイルでは、アプリをビルドするときにインストールする必要があるPythonの依存関係を、正確なバージョンとともに定義しました。これらには、 Django, django-storages(オブジェクトストレージバケットとやり取りするため)、 psycopg2(PostgreSQL用アダプター)、 gunicorn(WSGIサーバー)、およびその他の追加の依存関係が含まれています。完了したら、ファイルを保存して閉じます。

ステップ 4: Djangoアプリの環境変数の設定

twelve-factor app」の手法では、ハードコードされた設定をアプリケーションのコードベースから抽出することを推奨しています。そうすることで、コードベースに触れることなく環境変数を変更するだけで、実行時にアプリケーションの動作を自由に変更できるようになります。Dockerはこのセットアップに対応しているため、環境変数で動作するように設定ファイルを変更します。Kubernetesもこの設定セットアップに対応しています。Kubernetesを使用したデプロイに関する別のチュートリアルを、CloudSigma blog.

で公開する予定です。 settings.pyは、Djangoプロジェクトのメインの設定ファイルです。これは、ネイティブのデータ構造を使用してアプリケーションを設定するPythonモジュールです。私たちのアプリケーションでは、ファイルは次の場所にあります: django-polls/mysite/settings.py。その値のほとんどはハードコードされています。そのため、アプリケーションの動作を変更する場合、コードベース内の設定ファイルを変更する必要があります。私たちはそれを変更したいと考えています。幸いなことに、Pythonには getenv 関数が os モジュールに用意されています。これを使用して、ローカルの環境変数から設定パラメータを読み取るようにDjangoを設定できます。

続けて、 django-polls/mysite/settings.py ファイルを変更して、変数のハードコードされた値を置き換えましょう。実行時に os.getenv を呼び出して更新できるようにします。この関数は、指定された環境変数名に設定されている値を読み取ります。オプションとして、環境変数が設定されていない場合に使用されるデフォルト値である2番目のパラメータを指定することもできます。

以下に例を示します:

上の行では、環境変数からシークレットキーを取得するようにDjangoに指示しています。キーは外部から提供するため、フォールバック値は提供していません。キーが存在しない場合、アプリケーションの起動は失敗するはずです。シークレットキーを外部から提供する一方で、コンテナ化されたアプリのすべてのコピーが、さまざまなサーバー間で同じキーを使用していることを確認する必要もあります。これにより、アプリのさまざまなコピーが異なるキーを使用するときに発生する潜在的な問題を回避できます。

デフォルトオプションを使用した別の例を以下に示します:

この行では、読み取る必要のある環境変数 DEBUG を定義しています。ただし、設定されていない場合に DEBUG 設定変数に渡される2番目のパラメータを指定しています。 DEBUGFalse に設定され、アプリケーションに問題が発生した場合に機密情報がフロントエンドに渡されないようにします。ただし、開発モードの場合は、エラー情報を表示してエラーの修正を容易にするために、 True に設定したいと考えています。

環境変数の重要性がわかったところで、エディタで django_project/django-polls/settings.py を開きます。まず、 os モジュールをインポートするために、 settings.py ファイルの先頭に次の行を追加します:

次に、これらの変数を見つけて、以下のように更新します:

In the ALLOWED_HOSTS setting, we specify that it should get the value from the DJANGO_ALLOWED_HOSTS environment variable, and split it into a Python list using comma ( ,) as a separator. If the variable is missing, ALLOWED_HOSTS is set to 127.0.0.1.

次に、ファイルをスクロールして DATABASES セクションを見つけ、環境変数からも読み取るように設定します:

ここでは、 json.loads モジュールを追加したことに注目してください。また、 settings.py ファイルの先頭でこのモジュールをインポートする必要があります:

The json.loads function deserializes a JSON object passed into the DATABASES['default']['OPTIONS'] from the DB_OPTIONS environment variable. Specifying this option allows us to pass in an arbitrary data structure to define the database configuration. A database engine includes a set of valid options applicable to it. The JSON option gives us the flexibility to encode a JSON object with the appropriate parameters for the database engine we are using at the time.

The DATABASES['default']['NAME'] specifies the database name in the relational database management system we have set up. In the case of using an SQLite database, you should specify the path to the database file.

Pythonには、外部環境変数を読み取るための方法がいくつか用意されています。ここではそのうちの1つだけを使用しました。他の方法を調べて使用することも自由です。このステップでは、外部環境変数の操作方法を学びました。これにより、変数を変更してコンテナで実行されているアプリの動作を変更する柔軟性が得られます。次のステップでは、オブジェクトストレージサービスを操作する方法を学びます。

ステップ 5: 外部オブジェクトストレージサービスの操作

アプリケーションをコンテナ化する大きなメリットは、ポータビリティが向上し、トラフィックが増加したときにアプリの複数のコピーを簡単にデプロイできることです。これにより、スケーリングの余地が生まれます。しかし、これによって、さまざまなコンテナ間で静的ファイルやアセットのバージョンを維持するという問題が生じます。クラウド技術の進歩のおかげで、これらの共有静的要素を外部ストレージにオフロードできます。そして、実行中のすべてのコンテナからネットワーク経由でファイルにアクセスできるようにすることができます。実行中のさまざまなコンテナ間でファイルを同期しようとする代わりに、それらを管理する1つの中心的な場所を持つことができます。

上記で説明しようとしている概念は、クラウドオブジェクトストレージサービス、またはSimple Storage Service(S3)の使用です。Djangoには、django-storages を使用すると、リモートストレージバックエンドを操作できるようになります。 Django-storages は、FTP、SFTP、AmazonのAWS S3、Google Cloud Storage、Dropbox、Azure Storageなど、ほとんどのS3互換オブジェクトストレージサービスに対応しています。このチュートリアルでは、MinIO。他の任意のS3互換オブジェクトストレージサービス. MinIO は、高性能なS3互換オブジェクトストレージを提供します。MinIOを使用すると、任意のクラウド上にS3互換のデータインフラストラクチャを構築できます。

CloudSigmaプラットフォーム上でMinIOストレージサービスをセットアップする方法を説明します。次の手順に従ってください:

  • まず、CloudSigmaでアカウントを作成することから始めます。 MinIOストレージの作成中に問題が発生した場合は、CloudSigma’sの無料24時間年中無休ライブチャットサポートにお問い合わせください。サポートスタッフが対応いたします。

  • お支払い情報を追加します。

  • 次に、こちらから公開アクセス可能なバケットをリクエストしてください: https://blog.cloudsigma.com/xxxx。アカウントのアクセス資格情報を取得するには、ライブチャットサポートに連絡する必要があります。

  • MinIOオブジェクトストレージ環境が作成されると、アクセス資格情報とアクセスに関するその他の手順が提供されます。資格情報には、以下のものが含まれている必要があります。 MINI_ACCESS_KEY, MINIO_SECRET_KEY, および MINIO_URL。これらのキーは、以下の手順で使用します。

前のステップで変更した mysite/settings.py ファイルにさらに変更を加えましょう。ファイル内で、 storages アプリをDjangoの INSTALLED_APPS:

INSTALLED_APPS

この storages アプリは、 django-storages を介してインストールされます。これは、 requirements.txt で定義されています。ファイルの最下部までスクロールし、 STATIC_URL 変数を次のコードスニペットに置き換えます。

一部の設定変数がハードコードされていることに注意してください。

  • STATICFILES_STORAGE: Djangoが静的ファイルを処理するために使用するストレージバックエンドを定義します。このガイドではMinIOストレージを使用していますが、任意のDjango Storagesのドキュメントで説明されているS3互換バックエンドを使用できます。.

  • AWS_S3_OBJECT_PARAMETERS: cache-controlヘッダーを定義します。

  • AWS_LOCATION: これを使用して、すべての静的ファイルが保存されるストレージバケット内のディレクトリを設定します。別の名前を自由に選択できます。

  • AWS_DEFAULT_ACL: 静的ファイルのアクセス制御リスト(ACL)を設定します。値を ‘ public-Read’ に設定すると、すべての一般ユーザーがファイルにアクセスできるようになります。

  • STATIC_URL: Djangoは、この変数に設定されたベースURLを使用して静的ファイルのURLを生成します。この場合のベースURLは、エンドポイントURLと静的ファイルのサブディレクトリを組み合わせることで取得されます。

  • STATIC_ROOT: リモートオブジェクトストレージにコピーする前に、静的ファイルをローカルに収集する場所を定義します。

柔軟性と移植性を維持するために、外部で定義された環境変数もいくつか用意されています。

  • AWS_STORAGE_BUCKET_NAME: Djangoがアセットをアップロードするストレージバケットの名前を定義します。

  • AWS_S3_ENDPOINT_URL: オブジェクトストレージサービスへのアクセスに使用されるエンドポイントURLを定義します。これは、MinIOサービスをホストしているサーバーにマッピングされたURLになります。

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

これらの設定を行い、宣言されたPythonの依存関係をインストールしたら、いつでもDjangoコマンドの manage.py collectstaticを実行して、プロジェクトの静的ファイルを収集し、リモートオブジェクトストレージバックエンドにアップロードできます。

ただし、まだ envファイルの設定を行っていないため、おそらく失敗します。

コマンドを実行すると、アセットのサイズやインターネットの速度によっては、MinIOクラウドストレージへのアセットのコピーに少し時間がかかります。

このステップは以上です。次のステップでは、DjangoのログをDocker Engineにプッシュして、 docker logsコマンドを使用して表示できるようにする方法を見てみましょう。

ステップ 6: Djangoアプリでのロギングの設定

デバッグモード中、 DEBUGオプションが Trueに設定されている場合、Djangoは標準出力と標準エラーに情報をログ出力します。ログ情報は通常、開発用HTTPサーバーを起動したターミナルに表示されます。

本番環境では、別のHTTPサーバーを使用している可能性が高く、 DEBUGオプションは Falseに設定されます。この場合、Djangoは異なるロギング方法を使用します。Djangoは、優先度が ERRORまたは CRITICALのログを、定義した管理者用メールアカウントに送信します。これは多くの状況で非常にうまく機能します。

コンテナ化された環境やKubernetesのセットアップでは、標準出力および標準エラーへのロギングが強く推奨されます。ログメッセージはノードのファイルシステム上の単一のディレクトリに収集され、 kubectlおよび dockerコマンドを使用して簡単にアクセスできます。ノードのファイルシステム上にログの集中管理ポイントがあるため、運用チームは各ノードでプロセスを簡単に実行してログを監視および転送できます。したがって、この標準的なセットアップにログを書き込むようにアプリケーションを構成する必要があります。

DjangoがPython標準ライブラリの高度にカスタマイズ可能な loggingモジュールを活用していることを知ると嬉しくなるでしょう。これにより、logging.config.dictConfigに渡す辞書を定義して、目的の出力とフォーマットを定義できます。Djangoのロギング技術を習得するのに役立つ、Django Logging, The Right Wayに関する素晴らしい記事があります。

エディタで django-polls/mysite/settings.py ファイルを開きます。ファイルの先頭にPythonの logging.configライブラリのインポートを追加します。

これまでに追加したすべてのインポートを含めると、 settings.pyのインポートセクションは次のようになります。

Building a Django and Gunicorn Application with Docker on Ubuntu 3

この logging.configライブラリは、 dictConfig関数を介して新しいロギング設定の辞書を受け取り、Djangoのデフォルトのロギング動作を上書きします。

ファイルの末尾までスクロールし、次のロギング設定コードスニペットを追加します。

LOGGING_CONFIG は None に設定され、Djangoが定義するデフォルトのロギング設定を無効化またはクリアします。 LOGLEVELDJANGO_LOGLEVEL 環境変数によって設定されます。ただし、存在しない場合は、‘ info’.

上部でインポートした logging.config モジュールは、新しい設定辞書を設定するために使用される関数 dictConfig を提供します。この辞書は、 formatters キーを使用してテキストのフォーマットを定義します。出力は handlers キーで設定され、最後に loggers キーが、どのメッセージをどのハンドラーに送るかを定義します。

これらの設定を定義すると、Dockerdocker logs コマンドを介してログを公開します。同様に、Kubernetes向けに行う別のチュートリアルでは、 kubectl logs コマンドでログを表示できます。それでは、次のステップでコンテナ化プロセスを開始しましょう。

ステップ 7: アプリケーションの Dockerfile の定義

このステップでは、Gunicorn WSGIサーバーによって提供されるDjangoアプリを実行するコンテナイメージを起動するための設定を定義します。コンテナイメージをビルドするためのランタイム環境を定義し、アプリケーションとその依存関係をインストールし、いくつかの最終設定を行います。

  • Djangoアプリの親イメージ

コンテナ化されたデプロイを扱う際、ベースとなる基盤イメージを決定することは、最初に行う決定です。もちろん、コンテナイメージをSCRATCH(つまり空のファイルシステム)からビルドすることも、既存 of 既存のコンテナイメージをベースにすることも可能です。車輪の再発明は避けたいため、今回はベースイメージからイメージをビルドします。オープンソースのコンテナイメージは、Docker’s official container image repository から多数提供されています。イメージをスクラッチからビルドする場合を除き、Dockerの公式ハブのイメージを使用することを強くお勧めします。これは、Dockerがベストプラクティスに従っていることを検証し、定期的なアップデートやセキュリティパッチが適用されていることを保証しているためです。

DjangoはPythonフレームワークであるため、必要なツールやライブラリがすでにインストールされている標準的なPython環境のイメージを利用します。公式の Python images on Docker hub ページから、さまざまなバージョンのPythonに対応したPythonベースのイメージを見つけることができます。

当サイトのさまざまな Docker-based tutorials, をご覧いただくと、Alpine Linux に基づくイメージを使用していることにお気づきでしょう。Alpine Linuxは、コンテナ化されたアプリケーションを実行するための、堅牢でありながらスリムなオペレーティングシステム環境を提供します。ファイルシステムは小さいですが、拡張性があり、機能を追加できる完全なパッケージ管理システムが付属しています。

Dockerハブでベースイメージを選択する際、各イメージに複数のタグが用意されていることに気づくかもしれません。For the sake of Python の場合、3-alpine があります。これは、最新のAlpineバージョンの最新のPython 3バージョンイメージを指します。つまり、プロジェクトが古いイメージバージョンで動作している場合、Dockerイメージのメンテナがアップデートを行った際に動作しなくなる可能性があります。将来このようなシナリオを避けるために、使用したいイメージに対して常に最も具体的なタグを選択することをお勧めします。

このチュートリアルでは、 3.8.12-alpine3.15 イメージを、Djangoアプリケーションのベースイメージとして使用します。この特定のタグは、 Dockerfile 内で、 FROM 命令を使用して指定されます。Dockerfileは、メインのプロジェクトディレクトリである django_project.

まず、 Django-polls ディレクトリから、 django_project ディレクトリに戻ります。

ディレクトリに移動したら、お好みのエディタを使用して、 Dockerfile :

次に、以下の行を貼り付けて、イメージのベースを設定します。

この FROM  キーワードは、カスタムDockerイメージの開始点を定義します。これが定義されたら、アプリケーションをセットアップするための命令の追加を続けることができます。これらの命令は、必要な依存関係をインストールし、アプリケーションファイルをコピーし、実行環境をセットアップします。

Dockerfile内に以下のコードスニペットを追加します。

このコードスニペットでは、Dockerに対して、 requirements.txt  ファイルを /app/requirements.txt にコピーするように指示し、アプリケーションの依存関係がイメージのファイルシステム上で利用可能であることを保証します。要件には、アプリケーションの実行に必要なすべてのPythonパッケージが含まれています。Dockerがイメージレイヤーをキャッシュできるように、依存関係が最初にコピーされます。これは、DockerがDockerfile内のすべてのステップをキャッシュするためです。イメージの最初のビルドは通常、より時間がかかります。Dockerは依存関係をダウンロードし、それをキャッシュします。もし requirements.txt ファイルが変更されない場合、Dockerはキャッシュからビルドするため、その後のビルドが高速になります。

次のステップには、 RUN 命令があり、一連のLinuxコマンドを実行します。これらはLinuxの && 演算子でチェーンされています。コマンドは以下を実行します:

  • Alpineの apk パッケージマネージャーツールを使用して、PostgreSQLの開発ファイルと基本的なビルド依存関係をインストールします。

  • Pythonの仮想環境を作成します。

  • に定義されているPythonの依存関係を、 requirements.txt ファイルから、 pip を使用してインストールします。.

  • インストールされたPythonパッケージの要件を分析して、必要なランタイムパッケージをコンパイルします。

  • 不要になったビルド依存関係を削除します。

コマンドを RUN ステップでチェーンする理由は、イメージレイヤーを削減するためです。Dockerは、 ADD, COPY、または RUN に遭遇するたびに、既存のファイルシステムの上に新しいイメージレイヤーを作成します。命令をDockerfileに記述します。適用可能な箇所でコマンドを圧縮することで、作成されるイメージレイヤーの数を最小限に抑えることができます。

イメージレイヤーに追加されたアイテムは、後続のレイヤーで削除することはできません。次の命令に進む前に、不要なアイテムを削除する命令を宣言する必要があります。これはイメージサイズを削減するために必要です。最後に次のコマンドを追加したことにお気づきでしょう。 apk delコマンドを、 RUN コマンドの末尾に追加しました。これは、アプリのパッケージをビルドするために使用したビルド依存関係を、ビルド後に削除するために行われました。

次に、もう1つの ADD命令があり、これを使用してアプリケーションコードを /appディレクトリにコピーします。次に、 WORKDIR命令を使用して、イメージの作業ディレクトリを /app ディレクトリ(アプリケーションのコードが含まれているディレクトリ)に設定します。

次に、 ENV命令があり、これを使用して、実行中のコンテナでイメージが利用できるようにする2つの環境変数を設定します。まず、 VIRTUAL_ENV変数を /envに設定します。次に、 PATH変数を設定して、 /env/binディレクトリを含めます。これら2行では、 /env/bin/activateスクリプトを読み込んでいます。これはLinux環境で仮想環境をアクティベートする方法です。他のオペレーティングシステムにおけるPythonの仮想環境の操作について詳しく読むことができます。最後の命令は、 EXPOSEコマンドで、コンテナが実行時にリッスンするポート 8000を設定します。

これで、コンテナの起動時に実行されるデフォルトのコマンドを除いて、Dockerfileはほぼ完成しました。次のセクションでそれを定義しましょう。

  • デフォルトのDockerイメージコマンドについて理解する

Dockerコンテナを起動するときに、実行するコマンドを指定できます。ただし、コマンドを指定しない場合は、Dockerイメージのデフォルトコマンドによって、コンテナの起動時に何が起こるかが決定されます。Dockerfile内でデフォルトコマンドを定義するには、 ENTRYPOINTまたは CMD命令を単独で、または組み合わせて使用します。

両方の ENTRYPOINTCMDを定義する場合、 ENTRYPOINT命令でコンテナによって実行される実行可能ファイルを定義します。 CMD命令では、実行可能コマンドのデフォルトの引数リストを定義します。コンテナを起動するときに、コマンドラインで次の形式で別の引数を追加することにより、デフォルトの引数リストをオーバーライドできます。

この形式により、開発者が ENTRYPOINTコマンドを簡単にオーバーライドするのを防ぎます。 ENTRYPOINTコマンドは、環境をセットアップし、提供された引数リストに基づいて異なるアクションを実行するスクリプトを呼び出すように定義されます。

You can use the ENTRYPOINT命令のみを使用してコンテナの実行可能ファイルを構成できます。ただし、この形式ではデフォルトの引数リストを定義できません。コンテナを実行するときに、 docker runコマンドで引数を指定できます。

If you choose to go with CMD のみを使用することを選択した場合、Dockerはそれをデフォルトのコマンドおよび引数リストとして解釈し、実行時にオーバーライドできます。詳細については、公式のDockerfileリファレンスドキュメント.

を参照してください。デフォルトコマンドについて学んだ情報を、コンテナの例にどのように適用できるかを見てみましょう。デフォルトでは、 gunicornサーバーを使用してアプリケーションを提供したいと考えています。 gunicornサーバーに渡される引数リストを実行時に設定可能にする必要はありませんが、デバッグや設定管理(データベースの初期化、静的アセットの収集など)の目的で他のコマンドを実行できる柔軟性を持たせたいと考えています。ご覧のとおり、必要に応じてオーバーライドできるように、 CMDを使用してデフォルトコマンドを定義するのが最善です。

Here are some syntaxes you can use to define the CMDコマンドを定義するために使用できるいくつかの構文を以下に示します。

  • CMD ["command", "argument 1", "argument 2", . . . ,"argument n"]: exec形式(推奨形式)は、コマンドと引数のリストを受け取ります。シェル処理を行わずにコマンドを直接実行します。
  • CMD command "argument 1" "argument 2" . . . "引数 n": シェル形式は、コマンドと引数のリストを定義します。処理のためにコマンドのリストをシェルに渡します。コマンド内で環境変数を置換したい場合に便利ですが、完全に予測可能というわけではありません。
  • CMD ["引数 1", "引数 2", . . . ,"引数 n"]: 引数リスト形式は、デフォルトの引数リストのみを定義し、以下と一緒に使用されます。 ENTRYPOINT 命令。

ここでは、以下の exec 形式を使用して、 Dockerfile 内の最終命令を定義します。お使いの Dockerfile:

これで、 Dockerfile.

を保存して閉じることができます。このイメージを使用してコンテナを起動すると、 gunicorn が localhost のポート 8000 にバインドされ、3 つのワーカーで実行され、 application 関数を呼び出します。これは、 wsgi.py ファイル( mysite ディレクトリ内)にあります。実行時にデフォルトのコマンドをオーバーライドして、gunicorn の代わりに別のプロセスを実行するために、別のコマンドを提供することもできます。詳細については、Gunicorn ワーカー.

これで Dockerfile の準備が整いました。以下のコマンドを実行して、 docker build アプリイメージをビルドできます。また、 docker run を使用して、ローカルの開発マシン上でコンテナを起動できます。

  • Docker イメージのビルド

デフォルトでは、docker build コマンドは、ビルド指示を見つけるために現在のディレクトリにある Dockerfile を探します。また、ビルドの「コンテキスト」を Docker デーモンに送信します。ビルドコンテキスト とは、ビルドプロセス中に利用可能であるべきファイル群のことです。デフォルトでは、 docker build コマンドを実行している現在のディレクトリがビルドコンテキストとして設定されます。

Dockerfile が含まれているのと同じディレクトリで、次のコマンドを実行します。 docker build。イメージとタグを -t フラグで指定し、コマンドの最後にあるドット ( .) を使用して現在のディレクトリをビルドコンテキストとして設定します。

このコマンドでは、イメージ名を django-polls 、タグを v1 と指定しています。コマンドの最後にあるドットに注目してください。これは現在のディレクトリをビルドコンテキストとして示すために使用されます。

When the docker build が完了すると、以下のような出力が表示されます。

Building a Django and Gunicorn Application with Docker on Ubuntu 4

これで Dockerイメージの準備が整いました。一部の設定を外部の環境変数にオフセットしていなければ、 docker run コマンドで簡単にコンテナを実行できたはずです。しかし、 settings.py ファイルで設定した外部環境変数をまだ設定していないため、実行は失敗します。次のステップでそれを仕上げましょう。

ステップ 8: 実行環境の設定とアプリのテスト

このチュートリアルも終わりに近づいています。このステップでは、 env ファイルで環境変数を設定します。 env ファイルの変数が設定されれば、データベーススキーマを作成し、静的ファイルを生成して外部のオブジェクトストレージサービスにアップロードし、最後にアプリをテストできます。

Docker には、コンテナに環境変数を提供するための方法がいくつか用意されています。今回のケースでは、ファイルを通じて環境変数のリストを提供したいため、 --env-file メソッドを使用します。

お好みのエディタを使用して、 env という名前のファイルを django_project ディレクトリに作成します。

以下の変数リストを貼り付けます。

リスト内の変数は、前のステップで定義したものです。

  • DJANGO_SECRET_KEY:一意で予測不可能な値を生成します。詳細は次のDjangoドキュメントを参照してください。このコマンドを使用してランダムな文字列を生成し、変数に設定できます。

  • DEBUG:この値は次のように設定されています。 True。ただし、本番環境へのデプロイでは、次のように設定することを忘れないでください。 False(空白のままにします)。

  • DJANGO_LOGLEVEL:これを次のように設定しました。 info。必要に応じてお好みのレベルに調整してください。

  • DJANGO_ALLOWED_HOSTS:この値は、Dockerコンテナを実行しているUbuntuサーバーのIPアドレスに設定します。オプションで、次のように設定することもできます。 *(開発モードの場合、すべてのホストに一致するワイルドカード)。

  • DB_DATABASE:別のデータベース名を使用した場合は、ここに適切に設定してください。

  • DB_USERNAME:データベース用に選択したユーザー名に設定します。

  • DB_PASSWORD:データベース用に選択したパスワードに設定します。

  • DB_HOST:データベースインスタンスを実行しているホストに設定します(セットアップは以下で行いました):ステップ1.

  • DB_PORT:データベースのポートに設定します。

  • STATIC_MINIO_BUCKET_NAME:MinIOクラウドストレージアカウントで作成したバケット名に設定します。

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

環境設定の準備が整いました。デフォルトのCMDコマンドをオーバーライドする引数を渡してコンテナを実行し、次のコマンドを使用してデータベーススキーマを作成する必要があります。 manage.py makemigrations および manage.py migrate コマンド。

コマンドは次のとおりです。

このコマンドでは、 django-polls:v1 コンテナイメージを実行し、 env-file フラグを使用して環境変数ファイルを渡しています。また、デフォルトのCMDコマンドを次のようにオーバーライドします。 sh -c "python manage.py makemigrations && python manage.py migrate" このコマンドを実行してコンテナを起動すると、アプリケーションコードで定義されているデータベーススキーマが作成されます。

成功すると、以下のような出力が表示されます。

Building a Django and Gunicorn Application with Docker on Ubuntu 4

出力は、データベーススキーマが正常に作成されたことを示しています。

次のステップは、Djangoアプリの管理ユーザーを作成することです。次のコマンドを使用してコンテナを起動し、内部でインタラクティブシェルを開始します。

このコマンドは、Pythonシェルと対話するために使用できるシェルプロンプトでコンテナを起動します。ユーザーを作成しましょう。

プロンプトに従って、ユーザー名、メールアドレス、パスワードを入力し、パスワードを再入力して、Enterキーを押してユーザーを作成します。シェルを終了し、次を押してコンテナを停止します。 CTRL+D.

次に、コンテナを再度実行し、デフォルトのコマンドを次のDjangoコマンドにオーバーライドして、アプリの静的ファイルを生成し、MinIOクラウドストレージサービスにアップロードする必要があります。 collectstatic(このDjangoコマンドは、アプリの静的ファイルを生成し、MinIOクラウドストレージサービスにアップロードします):

完了すると、以下のような出力が表示され、コンテナがMinIOストレージサービスに正常に接続し、静的ファイルをアップロードしたことを示します。

static files

ストレージバケットは、Djangoが作成したディレクトリを含め、次のようになります。

Building a Django and Gunicorn Application with Docker on Ubuntu 5

最後に、次のコマンドでアプリを実行できます。

出力は次のとおりです。

output

上記のコマンドを実行すると、イメージ内のデフォルトのCMDコマンドが実行され、定義されているポート 8000が公開されます。これで、ポート 80のUbuntuが、 8000ポート( django-polls:v1コンテナ)にマッピングされます。

これでブラウザでアプリケーションをテストできます。ブラウザでサーバーのパブリックIPアドレスにアクセスしてください: http://your_server_public_ip.

「404 Page Not Found」エラーが表示されるはずです。なぜなら、Djangoチュートリアルに従って、 /パスのルートを定義していないためです:

page not found

We have the DEBUG変数に Trueが設定されているため、多くの重要な情報が含まれるこのエラーページが表示されます。この DEBUG変数の設定を解除しましょう。まず、実行中のコンテナを CTRL+Cで停止する必要があります。次に、 envファイルを開きます:

次に、 DEBUG変数を見つけて設定を解除するか、空のままにします。 getenv関数は Falseを文字列として解釈し、結果としてtrueを返すため、空のままにします:

ファイルを保存し、次のコマンドでコンテナを再度実行します。

ブラウザでこのhttp://your_server_public_ipにアクセスすると、デフォルトの404ページが表示されるはずです。

not found

ソースコードを変更することなく、環境変数を使用してDjangoアプリの実行時の動作を操作する方法を確認できました。

Navigate to http://your_server_public_ip/pollsにアクセスして、Pollsのホームページを表示します:

Building a Django and Gunicorn Application with Docker on Ubuntu 6

アプリをデプロイしたばかりなので、投票(polls)はありません。

管理インターフェース(http://your_server_public_ip/admin)にアクセスして、管理者認証ウィンドウを表示します:

polls administration

Provide the credentials you had set with the createsuperuserコマンドで設定した資格情報を入力してログインします。これで管理ページのインターフェースが表示されるはずです:

site administration

すべての静的ファイルは、設定した外部ストレージサービスから提供されていることに注意してください。ブラウザウィンドウで右クリックして、「ページのソースを表示」を選択できます。:

external storage

質問と選択肢を追加して、アプリ全体のパフォーマンスをテストできます。

questions and choices

Pollsのインデックス( http://your_server_public_ip/polls)に戻り、質問に投票してみてください:

django framework

すべてが期待通りに動作することを確認したら、コンテナを終了できます。

結論

コンテナベースの環境で適切に動作するように、Djangoウェブアプリの設定に成功しました。これには、外部環境変数で動作するようにアプリを適応させること、静的ファイルにクラウドストレージサービスを使用するようにアプリを設定すること、およびコンテナイメージ用のDockerfileを作成することが含まれます。アプリをDocker化するために行った変更は、django-polls-dockerブランチ( django-polls GitHubリポジトリ)で確認できます。

ここからの可能性は、あなたの想像力次第で無限に広がります。クライアントとGunicornサーバーの間に位置するNginxリバースプロキシをセットアップできます。また、Certbotを追加してTLS証明書を取得し、Nginxサーバーを保護することもできます。低速なクライアントをバッファリングし、Gunicornサーバーをサービス拒否(DoS)攻撃から保護するために、HTTPプロキシを追加することをお勧めします。

Dockerfileの起動コマンドで3つのワーカーを定義しましたが、サーバーで利用可能なリソースに応じて、お好みの数を設定できます。詳細については、Gunicornの公式設計ドキュメントを参照してください。必要に応じて、ビルドしたDockerイメージをDocker Hubにプッシュし、Dockerがインストールされている複数の環境にデプロイしてみることもできます。さらに詳しく知りたい場合は、引き続き当社のチュートリアルブログをチェックしてください。NginxとLet's Encryptを使用してDjangoアプリを安全にするための続編チュートリアルを予定しています。

最後に、Dockerを活用するのに役立つその他のリソースを以下に示します。

ハッピーコンピューティング!

author

Shreyas Patil

著者 · CloudSigma

Preslav DobrevはCloudSigmaのクリエイティブデザイナーであり、従来型および革新的なマーケティングチャネルを活用した一貫性のあるビジネスアイデンティティに注力しています。彼は芸術的なビジョンと戦略的マーケティングを融合させ、インパクトのあるブランドナラティブを生み出すことに長けています。

コメント

コメントはまだありません。最初のコメントを投稿しましょう。