Kubernetesを使用してスケーラブルで安全なDjangoアプリケーションをデプロイする方法

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

序章

このチュートリアルでは、コンテナ化されたDjangoポーリングアプリケーションをKubernetesクラスターにデプロイします。

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

Docker を使用してDjangoおよびGunicornアプリケーションを構築する方法では、 Django Tutorial Pollsアプリケーションが、スケーラブルなクラウドを構築するためのTwelve-Factor方法論に従って変更されました。ネイティブWebアプリ。 このコンテナ化されたセットアップは、 Docker、Nginx、およびLet's Encrypt を使用してDjangoアプリケーションをスケーリングおよび保護する方法で、NginxリバースプロキシおよびLet'sEncryptで署名されたTLS証明書を使用してスケーリングおよび保護されました。 コンテナからDjangoを使用したKubernetesへシリーズのこの最後のチュートリアルでは、最新のDjangoポーリングアプリケーションがKubernetesクラスターにデプロイされます。

Kubernetes は、コンテナー化されたアプリケーションのデプロイ、スケーリング、管理を自動化する強力なオープンソースのコンテナーオーケストレーターです。 ConfigMapsやSecretsなどのKubernetesオブジェクトを使用すると、構成を一元化してコンテナから切り離すことができます。一方、Deploymentsなどのコントローラは、失敗したコンテナを自動的に再起動し、コンテナレプリカの迅速なスケーリングを可能にします。 TLS暗号化は、Ingressオブジェクトとingress-nginxオープンソースのIngressコントローラーで有効になります。 cert-manager Kubernetesアドオンは、無料の Let'sEncrypt認証局を使用して証明書を更新および発行します。

前提条件

このチュートリアルに従うには、次のものが必要です。

  • ロールベースのアクセス制御(RBAC)が有効になっているKubernetes1.15+クラスター。 このセットアップではDigitalOceanKubernetes クラスターを使用しますが、別の方法を使用してクラスターを自由に作成できます。
  • kubectlコマンドラインツールがローカルマシンにインストールされ、クラスターに接続するように構成されています。 kubectl のインストールについて詳しくは、公式ドキュメントをご覧ください。 DigitalOcean Kubernetesクラスターを使用している場合は、 DigitalOcean Kubernetesクラスターへの接続方法を参照して、kubectlを使用してクラスターに接続する方法を確認してください。
  • 登録されたドメイン名。 このチュートリアルでは、全体を通してyour_domain.comを使用します。 Freenom で無料で入手するか、選択したドメインレジストラを使用できます。
  • ingress-nginx IngressControllerとcert-manager TLS証明書マネージャーがクラスターにインストールされ、TLS証明書を発行するように構成されています。 cert-managerを使用してIngressをインストールおよび構成する方法については、 DigitalOceanKubernetesでCert-Managerを使用してNginxIngressを設定する方法を参照してください。
  • ADNSレコード。your_domain.comはIngressロードバランサーのパブリックIPアドレスを指しています。 DigitalOceanを使用してドメインのDNSレコードを管理している場合は、 DNSレコードの管理方法を参照して、Aレコードの作成方法を確認してください。
  • DigitalOcean Space などのS3オブジェクトストレージバケット。Djangoプロジェクトの静的ファイルと、このスペースのアクセスキーのセットを保存します。 スペースの作成方法については、スペースの作成方法の製品ドキュメントを参照してください。 スペースのアクセスキーを作成する方法については、アクセスキーを使用したスペースへのアクセスの共有を参照してください。 マイナーな変更により、django-storagesプラグインがサポートする任意のオブジェクトストレージサービスを使用できます。
  • DjangoアプリのPostgreSQLサーバーインスタンス、データベース、およびユーザー。 小さな変更を加えるだけで、Djangoがサポートするのデータベースを使用できます。 PostgreSQLデータベースはpolls(または以下の構成ファイルに入力する別の覚えやすい名前)と呼ばれる必要があり、このチュートリアルでは、Djangoデータベースユーザーの名前はsammyになります。 これらを作成するためのガイダンスについては、Dockerを使用してDjangoおよびGunicornアプリケーションを構築する方法のステップ1に従ってください。 これらの手順は、ローカルマシンから実行する必要があります。 このチュートリアルでは、DigitalOceanマネージドPostgreSQLクラスターを使用します。 クラスタの作成方法については、DigitalOceanManagedDatabasesの製品ドキュメントを参照してください。 独自のPostgreSQLインスタンスをインストールして実行することもできます。 UbuntuサーバーにPostgreSQLをインストールして管理するためのガイダンスについては、Ubuntu18.04にPostgreSQLをインストールして使用する方法を参照してください。
  • DockerHubアカウントとパブリックリポジトリ。 これらの作成の詳細については、Dockerドキュメントのリポジトリを参照してください。
  • ローカルマシンにインストールされているDockerエンジン。 詳細については、 Ubuntu18.04にDockerをインストールして使用する方法を参照してください。

これらのコンポーネントを設定したら、このガイドを開始する準備が整います。

ステップ1—アプリケーションのクローン作成と構成

このステップでは、GitHubからアプリケーションコードを複製し、データベースのクレデンシャルやオブジェクトストレージキーなどの設定を構成します。

アプリケーションコードとDockerfileは、Django Tutorial Polls AppGitHubリポジトリpolls-dockerブランチにあります。 このリポジトリには、Djangoドキュメントのサンプルポーリングアプリケーションのコードが含まれています。このコードは、ポーリングアプリケーションを最初から作成する方法を示しています。

polls-dockerブランチには、このPollsアプリのDocker化バージョンが含まれています。 コンテナ化された環境で効果的に機能するようにPollsアプリがどのように変更されたかについては、Dockerを使用してDjangoおよびGunicornアプリケーションを構築する方法を参照してください。

gitを使用して、Django Tutorial Polls AppGitHubリポジトリpolls-dockerブランチをローカルマシンに複製することから始めます。

git clone --single-branch --branch polls-docker https://github.com/do-community/django-polls.git

django-pollsディレクトリに移動します。

cd django-polls

このディレクトリには、DjangoアプリケーションのPythonコード、Dockerがコンテナイメージのビルドに使用するDockerfile、およびコンテナに渡される環境変数のリストを含むenvファイルが含まれています。実行環境。 Dockerfileを調べます。

cat Dockerfile
OutputFROM python:3.7.4-alpine3.10

ADD django-polls/requirements.txt /app/requirements.txt

RUN set -ex \
    && apk add --no-cache --virtual .build-deps postgresql-dev build-base \
    && python -m venv /env \
    && /env/bin/pip install --upgrade pip \
    && /env/bin/pip install --no-cache-dir -r /app/requirements.txt \
    && runDeps="$(scanelf --needed --nobanner --recursive /env \
        | awk '{ gsub(/,/, "\nso:", $2); print "so:" $2 }' \
        | sort -u \
        | xargs -r apk info --installed \
        | sort -u)" \
    && apk add --virtual rundeps $runDeps \
    && apk del .build-deps

ADD django-polls /app
WORKDIR /app

ENV VIRTUAL_ENV /env
ENV PATH /env/bin:$PATH

EXPOSE 8000

CMD ["gunicorn", "--bind", ":8000", "--workers", "3", "mysite.wsgi"]

このDockerfileは、公式のPython 3.7.4 Docker image をベースとして使用し、django-polls/requirements.txtファイルで定義されているDjangoおよびGunicornのPythonパッケージ要件をインストールします。 次に、不要なビルドファイルをいくつか削除し、アプリケーションコードをイメージにコピーして、実行を設定しますPATH。 最後に、ポート8000を使用して着信コンテナー接続を受け入れることを宣言し、ポート8000でリッスンする3人のワーカーでgunicornを実行します。

このDockerfileの各ステップの詳細については、Dockerを使用してDjangoおよびGunicornアプリケーションを構築する方法のステップ6を参照してください。

次に、docker buildを使用してイメージをビルドします。

docker build -t polls .

-tフラグを使用してイメージにpollsという名前を付け、現在のディレクトリをビルドコンテキストとして渡します。これは、イメージを構築するときに参照するファイルのセットです。

Dockerがイメージをビルドしてタグ付けした後、docker imagesを使用して使用可能なイメージを一覧表示します。

docker images

pollsの画像が表示されます。

OutputREPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
polls               latest              80ec4f33aae1        2 weeks ago         197MB
python              3.7.4-alpine3.10    f309434dea3a        8 months ago        98.7MB

Djangoコンテナを実行する前に、現在のディレクトリにあるenvファイルを使用して実行環境を構成する必要があります。 このファイルは、コンテナーの実行に使用されるdocker runコマンドに渡され、Dockerは構成された環境変数をコンテナーの実行環境に挿入します。

envファイルをnanoまたはお気に入りのエディターで開きます。

nano env

django-polls / env

DJANGO_SECRET_KEY=
DEBUG=True
DJANGO_ALLOWED_HOSTS=
DATABASE_ENGINE=postgresql_psycopg2
DATABASE_NAME=polls
DATABASE_USERNAME=
DATABASE_PASSWORD=
DATABASE_HOST=
DATABASE_PORT=
STATIC_ACCESS_KEY_ID=
STATIC_SECRET_KEY=
STATIC_BUCKET_NAME=
STATIC_ENDPOINT_URL=
DJANGO_LOGLEVEL=info

次のキーの不足している値を入力します。

  • DJANGO_SECRET_KEYDjango docs で詳しく説明されているように、これを一意の予測できない値に設定します。 このキーを生成する1つの方法は、 Scalable DjangoAppチュートリアルのAppSettingsの調整にあります。
  • DJANGO_ALLOWED_HOSTS:この変数はアプリを保護し、HTTPホストヘッダー攻撃を防ぎます。 テストのために、これを*に設定します。これは、すべてのホストに一致するワイルドカードです。 本番環境では、これをyour_domain.comに設定する必要があります。 このDjango設定の詳細については、Djangoドキュメントのコア設定を参照してください。
  • DATABASE_USERNAME:前提条件の手順で作成したPostgreSQLデータベースユーザーに設定します。
  • DATABASE_NAME:これをpollsまたは前提条件の手順で作成したPostgreSQLデータベースの名前に設定します。
  • DATABASE_PASSWORD:これを前提条件の手順で作成したPostgreSQLユーザーパスワードに設定します。
  • DATABASE_HOST:これをデータベースのホスト名に設定します。
  • DATABASE_PORT:これをデータベースのポートに設定します。
  • STATIC_ACCESS_KEY_ID:これをスペースまたはオブジェクトストレージのアクセスキーに設定します。
  • STATIC_SECRET_KEY:これをスペースまたはオブジェクトストレージのアクセスキーシークレットに設定します。
  • STATIC_BUCKET_NAME:これをスペース名またはオブジェクトストレージバケットに設定します。
  • STATIC_ENDPOINT_URL:これを適切なスペースまたはオブジェクトストレージエンドポイントURLに設定します。たとえば、スペースがnyc3リージョンにある場合は、https://your_space_name.nyc3.digitaloceanspaces.comに設定します。

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

次のステップでは、構成されたコンテナーをローカルで実行し、データベーススキーマを作成します。 また、スタイルシートや画像などの静的アセットをオブジェクトストレージにアップロードします。

ステップ2—データベーススキーマの作成とオブジェクトストレージへのアセットのアップロード

コンテナを構築および構成したら、docker runを使用してDockerfileに設定されているCMDをオーバーライドし、manage.py makemigrationsおよびmanage.py migrateコマンドを使用してデータベーススキーマを作成します。

docker run --env-file env polls sh -c "python manage.py makemigrations && python manage.py migrate"

polls:latestコンテナイメージを実行し、変更したばかりの環境変数ファイルを渡し、Dockerfileコマンドをsh -c "python manage.py makemigrations && python manage.py migrate"でオーバーライドします。これにより、アプリコードで定義されたデータベーススキーマが作成されます。

これを初めて実行する場合は、次のように表示されます。

OutputNo changes detected
Operations to perform:
  Apply all migrations: admin, auth, contenttypes, polls, sessions
Running migrations:
  Applying contenttypes.0001_initial... OK
  Applying auth.0001_initial... OK
  Applying admin.0001_initial... OK
  Applying admin.0002_logentry_remove_auto_add... OK
  Applying admin.0003_logentry_add_action_flag_choices... OK
  Applying contenttypes.0002_remove_content_type_name... OK
  Applying auth.0002_alter_permission_name_max_length... OK
  Applying auth.0003_alter_user_email_max_length... OK
  Applying auth.0004_alter_user_username_opts... OK
  Applying auth.0005_alter_user_last_login_null... OK
  Applying auth.0006_require_contenttypes_0002... OK
  Applying auth.0007_alter_validators_add_error_messages... OK
  Applying auth.0008_alter_user_username_max_length... OK
  Applying auth.0009_alter_user_last_name_max_length... OK
  Applying auth.0010_alter_group_name_max_length... OK
  Applying auth.0011_update_proxy_permissions... OK
  Applying polls.0001_initial... OK
  Applying sessions.0001_initial... OK

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

後でmigrateを実行している場合、データベーススキーマが変更されていない限り、Djangoはno-opを実行します。

次に、アプリコンテナーの別のインスタンスを実行し、その中のインタラクティブシェルを使用して、Djangoプロジェクトの管理ユーザーを作成します。

docker run -i -t --env-file env polls sh

これにより、実行中のコンテナ内にシェルプロンプトが表示され、Djangoユーザーの作成に使用できます。

python manage.py createsuperuser

ユーザーのユーザー名、メールアドレス、パスワードを入力し、ユーザーを作成したら、CTRL+Dを押してコンテナーを終了して強制終了します。

最後に、アプリの静的ファイルを生成し、collectstaticを使用してDigitalOceanSpaceにアップロードします。 これが完了するまでに少し時間がかかる場合があることに注意してください。

docker run --env-file env polls sh -c "python manage.py collectstatic --noinput"

これらのファイルが生成およびアップロードされると、次の出力が表示されます。

Output121 static files copied.

これでアプリを実行できます。

docker run --env-file env -p 80:8000 polls
Output[2019-10-17 21:23:36 +0000] [1] [INFO] Starting gunicorn 19.9.0
[2019-10-17 21:23:36 +0000] [1] [INFO] Listening at: http://0.0.0.0:8000 (1)
[2019-10-17 21:23:36 +0000] [1] [INFO] Using worker: sync
[2019-10-17 21:23:36 +0000] [7] [INFO] Booting worker with pid: 7
[2019-10-17 21:23:36 +0000] [8] [INFO] Booting worker with pid: 8
[2019-10-17 21:23:36 +0000] [9] [INFO] Booting worker with pid: 9

ここでは、Dockerfileで定義されているデフォルトのコマンドgunicorn --bind :8000 --workers 3 mysite.wsgi:applicationを実行し、コンテナポート8000を公開して、ローカルマシンのポート80がポート[にマップされるようにします。 pollsコンテナのX176X]。

これで、URLバーにhttp://localhostと入力して、Webブラウザーを使用してpollsアプリに移動できるようになります。 /パスにルートが定義されていないため、404 Page Not Foundエラーが発生する可能性があります。これは予想どおりです。

http://localhost/pollsに移動して、Pollsアプリのインターフェイスを確認します。

管理インターフェースを表示するには、http://localhost/adminにアクセスしてください。 Pollsアプリの管理者認証ウィンドウが表示されます。

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

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

adminおよびpollsアプリの静的アセットは、オブジェクトストレージから直接配信されていることに注意してください。 これを確認するには、テストスペースの静的ファイル配信を参照してください。

探索が終了したら、Dockerコンテナを実行しているターミナルウィンドウでCTRL+Cを押して、コンテナを強制終了します。

DjangoアプリのDockerイメージをテストし、静的アセットをオブジェクトストレージにアップロードし、データベーススキーマを構成してアプリで使用できるようになったら、DjangoアプリのイメージをDockerHubなどのイメージレジストリにアップロードする準備が整います。

ステップ3—DjangoアプリイメージをDockerHubにプッシュする

Kubernetesでアプリをロールアウトするには、アプリの画像を DockerHubなどのレジストリにアップロードする必要があります。 Kubernetesは、リポジトリからアプリイメージをプルしてから、クラスターにデプロイします。

DigitalOcean Container Registry のようなプライベートDockerレジストリを使用できます。これは、現在早期アクセスで無料です。または、DockerHubのようなパブリックDockerレジストリを使用できます。 Docker Hubでは、プライベートDockerリポジトリを作成することもできます。 パブリックリポジトリを使用すると、誰でもコンテナイメージを表示およびプルできますが、プライベートリポジトリを使用すると、自分とチームメンバーへのアクセスを制限できます。

このチュートリアルでは、前提条件で作成されたパブリックDockerHubリポジトリにDjangoイメージをプッシュします。 イメージをプライベートリポジトリにプッシュすることもできますが、プライベートリポジトリからイメージをプルすることはこの記事の範囲を超えています。 Docker Hubを使用したKubernetesの認証とプライベートイメージのプルについて詳しくは、Kubernetesドキュメントのプライベートレジストリからイメージをプルするをご覧ください。

まず、ローカルマシンのDockerHubにログインします。

docker login
OutputLogin with your Docker ID to push and pull images from Docker Hub. If you don't have a Docker ID, head over to https://hub.docker.com to create one.
Username:

DockerHubのユーザー名とパスワードを入力してログインします。

Djangoイメージには、現在polls:latestタグが付いています。 Docker Hubリポジトリにプッシュするには、DockerHubのユーザー名とリポジトリ名でイメージにタグを付け直します。

docker tag polls:latest your_dockerhub_username/your_dockerhub_repo_name:latest

画像をリポジトリにプッシュします。

docker push sammy/sammy-django:latest

このチュートリアルでは、DockerHubのユーザー名はsammy で、リポジトリ名はsammy-djangoです。 これらの値を独自のDockerHubユーザー名とリポジトリ名に置き換える必要があります。

画像レイヤーがDockerHubにプッシュされると更新される出力が表示されます。

これで、Docker Hub上のKubernetesでイメージを利用できるようになったので、クラスターでイメージのロールアウトを開始できます。

ステップ4—ConfigMapを設定する

Djangoコンテナーをローカルで実行するときに、envファイルをdocker runに渡して、構成変数をランタイム環境に挿入しました。 Kubernetesでは、ConfigMapsおよびSecretsを使用して構成変数を挿入できます。

ConfigMapsは、アプリ設定などの機密でない構成情報を格納するために使用する必要があり、Secretsは、APIキーやデータベースクレデンシャルなどの機密情報に使用する必要があります。 どちらも同様の方法でコンテナに挿入されますが、シークレットには、保存時の暗号化などの追加のアクセス制御とセキュリティ機能があります。 シークレットはbase64にもデータを保存しますが、ConfigMapsはデータをプレーンテキストで保存します。

まず、Kubernetesマニフェストを保存するyamlというディレクトリを作成します。 ディレクトリに移動します。

mkdir yaml
cd

nanoまたはお好みのテキストエディタでpolls-configmap.yamlというファイルを開きます。

nano polls-configmap.yaml

次のConfigMapマニフェストに貼り付けます。

polls-configmap.yaml

apiVersion: v1
kind: ConfigMap
metadata:
  name: polls-config
data:
  DJANGO_ALLOWED_HOSTS: "*"
  STATIC_ENDPOINT_URL: "https://your_space_name.space_region.digitaloceanspaces.com"
  STATIC_BUCKET_NAME: "your_space_name"
  DJANGO_LOGLEVEL: "info"
  DEBUG: "True"
  DATABASE_ENGINE: "postgresql_psycopg2"

ステップ1で変更されたenvファイルから機密性の低い構成を抽出し、ConfigMapマニフェストに貼り付けました。 ConfigMapオブジェクトはpolls-configと呼ばれます。 前の手順でenvファイルに入力したのと同じ値をコピーします。

テストのために、DJANGO_ALLOWED_HOSTS*のままにして、ホストヘッダーベースのフィルタリングを無効にします。 本番環境では、これをアプリのドメインに設定する必要があります。

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

kubectl applyを使用して、クラスターにConfigMapを作成します。

kubectl apply -f polls-configmap.yaml
Outputconfigmap/polls-config created

ConfigMapを作成したら、次のステップでアプリが使用するシークレットを作成します。

ステップ5—秘密を設定する

シークレット値はbase64エンコードである必要があります。つまり、クラスターでのシークレットオブジェクトの作成は、ConfigMapの作成よりも少し複雑です。 シークレット値を手動でbase64エンコードし、マニフェストファイルに貼り付けることで、前の手順からプロセスを繰り返すことができます。 また、環境変数ファイルkubectl create、および--from-env-fileフラグを使用して作成することもできます。これは、このステップで行います。

ステップ1envファイルをもう一度使用して、ConfigMapに挿入された変数を削除します。 yamlディレクトリにpolls-secretsという名前のenvファイルのコピーを作成します。

cp ../env ./polls-secrets

お好みのエディタでファイルを編集します。

nano polls-secrets

世論調査-秘密

DJANGO_SECRET_KEY=
DEBUG=True
DJANGO_ALLOWED_HOSTS=
DATABASE_ENGINE=postgresql_psycopg2
DATABASE_NAME=polls
DATABASE_USERNAME=
DATABASE_PASSWORD=
DATABASE_HOST=
DATABASE_PORT=
STATIC_ACCESS_KEY_ID=
STATIC_SECRET_KEY=
STATIC_BUCKET_NAME=
STATIC_ENDPOINT_URL=
DJANGO_LOGLEVEL=info

ConfigMapマニフェストに挿入されたすべての変数を削除します。 完了すると、次のようになります。

世論調査-秘密

DJANGO_SECRET_KEY=your_secret_key
DATABASE_NAME=polls
DATABASE_USERNAME=your_django_db_user
DATABASE_PASSWORD=your_django_db_user_password
DATABASE_HOST=your_db_host
DATABASE_PORT=your_db_port
STATIC_ACCESS_KEY_ID=your_space_access_key
STATIC_SECRET_KEY=your_space_access_key_secret

ステップ1で使用したのと同じ値を使用してください。 完了したら、ファイルを保存して閉じます。

kubectl create secretを使用して、クラスターにシークレットを作成します。

kubectl create secret generic polls-secret --from-env-file=poll-secrets
Outputsecret/polls-secret created

ここでは、polls-secretというシークレットオブジェクトを作成し、作成したシークレットファイルを渡します。

kubectl describeを使用してシークレットを検査できます。

kubectl describe secret polls-secret
OutputName:         polls-secret
Namespace:    default
Labels:       <none>
Annotations:  <none>

Type:  Opaque

Data
====
DATABASE_PASSWORD:     8 bytes
DATABASE_PORT:         5 bytes
DATABASE_USERNAME:     5 bytes
DJANGO_SECRET_KEY:     14 bytes
STATIC_ACCESS_KEY_ID:  20 bytes
STATIC_SECRET_KEY:     43 bytes
DATABASE_HOST:         47 bytes
DATABASE_NAME:         5 bytes

この時点で、SecretオブジェクトタイプとConfigMapオブジェクトタイプを使用して、アプリの構成をKubernetesクラスターに保存しました。 これで、アプリをクラスターにデプロイする準備が整いました。

ステップ6—デプロイメントを使用してDjangoアプリをロールアウトする

このステップでは、Djangoアプリのデプロイを作成します。 Kubernetes Deploymentは、クラスター内のステートレスアプリケーションを管理するために使用できるコントローラーです。 コントローラは、ワークロードをスケールアップまたはスケールダウンすることによってワークロードを調整する制御ループです。 コントローラも再起動し、障害が発生したコンテナをクリアします。

デプロイは、Kubernetesクラスター内のデプロイ可能な最小ユニットである1つ以上のポッドを制御します。 ポッドは1つ以上のコンテナを囲みます。 起動できるさまざまなタイプのワークロードの詳細については、Kubernetesの概要をご覧ください。

お気に入りのエディターでpolls-deployment.yamlというファイルを開くことから始めます。

nano polls-deployment.yaml

次のデプロイメントマニフェストに貼り付けます。

polls-deployment.yaml

apiVersion: apps/v1
kind: Deployment
metadata:
  name: polls-app
  labels:
    app: polls
spec:
    replicas: 2
  selector:
    matchLabels:
      app: polls
  template:
    metadata:
      labels:
        app: polls
    spec:
      containers:
        - image: your_dockerhub_username/app_repo_name:latest
          name: polls
          envFrom:
          - secretRef:
              name: polls-secret
          - configMapRef:
              name: polls-config
          ports:
            - containerPort: 8000
              name: gunicorn

ステップ2でDockerHubにプッシュしたDjangoPollsイメージを参照して、適切なコンテナーイメージ名を入力します。

ここでは、polls-appというKubernetesデプロイメントを定義し、キーと値のペアapp: pollsでラベルを付けます。 templateフィールドの下に定義されたポッドの2つのレプリカを実行することを指定します。

envFromsecretRefおよびconfigMapRefを使用して、polls-secretシークレットおよびpolls-configConfigMapからのすべてのデータを環境変数としてのコンテナ。 ConfigMapキーとSecretキーが環境変数名になります。

最後に、containerPort 8000を公開し、gunicornという名前を付けます。

Kubernetesデプロイの設定の詳細については、Kubernetesドキュメントのデプロイを参照してください。

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

kubectl apply -fを使用して、クラスターにデプロイメントを作成します。

kubectl apply -f polls-deployment.yaml
deployment.apps/polls-app created

kubectl getを使用して、展開が正しく展開されたことを確認します。

kubectl get deploy polls-app
OutputNAME        READY   UP-TO-DATE   AVAILABLE   AGE
polls-app   2/2     2            2           6m38s

エラーが発生した場合、または何かがうまく機能していない場合は、kubectl describeを使用して、失敗したデプロイメントを検査できます。

kubectl describe deploy

kubectl get podを使用して2つのポッドを検査できます。

kubectl get pod
OutputNAME                         READY   STATUS    RESTARTS   AGE
polls-app-847f8ccbf4-2stf7   1/1     Running   0          6m42s
polls-app-847f8ccbf4-tqpwm   1/1     Running   0          6m57s

これで、Djangoアプリの2つのレプリカがクラスターで稼働しています。 アプリにアクセスするには、Kubernetesサービスを作成する必要があります。これを次に行います。

ステップ7—サービスを使用した外部アクセスの許可

このステップでは、Djangoアプリのサービスを作成します。 Kubernetesサービスは、実行中のポッドのセットをネットワークサービスとして公開できるようにする抽象化です。 サービスを使用すると、ポッドが停止して再作成されても変更されない、アプリの安定したエンドポイントを作成できます。

クラスター内部IPでサービスを公開するClusterIPサービス、NodePortと呼ばれる静的ポートで各ノードのサービスを公開するNodePortサービス、クラウドロードバランサーをプロビジョニングするLoadBalancerサービスなど、複数のサービスタイプがあります。外部トラフィックをクラスター内のポッドに転送します(NodePortsを介して自動的に作成されます)。 これらの詳細については、Kubernetesドキュメントのサービスをご覧ください。

最終的なセットアップでは、このガイドの前提条件でセットアップされたIngressとIngressControllerを使用して公開されるClusterIPサービスを使用します。 今のところ、すべてが正しく機能していることをテストするために、Djangoアプリにアクセスするための一時的なNodePortサービスを作成します。

お気に入りのエディターを使用して、polls-svc.yamlというファイルを作成することから始めます。

nano polls-svc.yaml

次のサービスマニフェストに貼り付けます。

polls-svc.yaml

apiVersion: v1
kind: Service
metadata:
  name: polls
  labels:
    app: polls
spec:
  type: NodePort
  selector:
    app: polls
  ports:
    - port: 8000
      targetPort: 8000

ここでは、pollsというNodePortサービスを作成し、それにapp: pollsラベルを付けます。 次に、app: pollsラベルの付いたバックエンドポッドを選択し、それらの8000ポートをターゲットにします。

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

kubectl applyを使用してサービスを展開します。

kubectl apply -f polls-svc.yaml
Outputservice/polls created

kubectl get svcを使用してサービスが作成されたことを確認します。

kubectl get svc polls
OutputNAME    TYPE       CLUSTER-IP       EXTERNAL-IP   PORT(S)          AGE
polls   NodePort   10.245.197.189   <none>        8000:32654/TCP   59s

この出力は、サービスのクラスター内部IPおよびNodePort(32654)を示しています。 サービスに接続するには、クラスターノードの外部IPアドレスが必要です。

kubectl get node -o wide
OutputNAME                   STATUS   ROLES    AGE   VERSION   INTERNAL-IP   EXTERNAL-IP      OS-IMAGE                       KERNEL-VERSION          CONTAINER-RUNTIME
pool-7no0qd9e0-364fd   Ready    <none>   27h   v1.18.8   10.118.0.5    203.0.113.1   Debian GNU/Linux 10 (buster)   4.19.0-10-cloud-amd64   docker://18.9.9
pool-7no0qd9e0-364fi   Ready    <none>   27h   v1.18.8   10.118.0.4    203.0.113.2    Debian GNU/Linux 10 (buster)   4.19.0-10-cloud-amd64   docker://18.9.9
pool-7no0qd9e0-364fv   Ready    <none>   27h   v1.18.8   10.118.0.3    203.0.113.3   Debian GNU/Linux 10 (buster)   4.19.0-10-cloud-amd64   docker://18.9.9

Webブラウザーで、任意のノードの外部IPアドレスとNodePortを使用してPollsアプリにアクセスします。 上記の出力を考えると、アプリのURLはhttp://203.0.113.1:32654/pollsになります。

手順1でローカルにアクセスしたものと同じPollsアプリのインターフェースが表示されます。

/adminルートhttp://203.0.113.1:32654/adminを使用して同じテストを繰り返すことができます。 以前と同じ管理インターフェースが表示されます。

この段階で、Deploymentを使用してDjangoPollsアプリコンテナーの2つのレプリカをロールアウトしました。 また、これら2つのレプリカ用の安定したネットワークエンドポイントを作成し、NodePortサービスを使用して外部からアクセスできるようにしました。

このチュートリアルの最後のステップは、HTTPSを使用してアプリへの外部トラフィックを保護することです。 これを行うには、前提条件にインストールされているingress-nginx Ingress Controllerを使用し、Ingressオブジェクトを作成して外部トラフィックをpollsKubernetesサービスにルーティングします。

ステップ8—NginxIngressとcert-managerを使用したHTTPSの構成

Kubernetes Ingresses を使用すると、Kubernetesクラスターの外部からクラスター内のサービスにトラフィックを柔軟にルーティングできます。 これは、HTTPおよびHTTPSトラフィックをKubernetesサービスにルーティングするためのルールを定義するIngressオブジェクトと、トラフィックを負荷分散して適切なバックエンドサービスにルーティングすることでルールを実装するIngress Controllersを使用して実現されます。

前提条件で、 ingress-nginx IngressControllerとcert-managerTLS証明書自動化アドオンをインストールしました。 また、Let's Encrypt認証局を使用して、ドメインのステージングおよび本番ClusterIssuersを設定し、2つのダミーバックエンドサービスへの証明書発行とTLS暗号化をテストするためのIngressを作成しました。 この手順を続行する前に、前提条件のチュートリアルで作成されたecho-ingress入力を削除する必要があります。

kubectl delete ingress echo-ingress

必要に応じて、kubectl delete svcおよびkubectl delete deployを使用してダミーのサービスとデプロイメントを削除することもできますが、これはこのチュートリアルを完了するために必須ではありません。

また、IngressLoadBalancerのパブリックIPアドレスを指すyour_domain.comを使用してDNSAレコードを作成する必要があります。 DigitalOceanロードバランサーを使用している場合、このIPアドレスはコントロールパネルのロードバランサーセクションにあります。 DigitalOceanを使用してドメインのDNSレコードも管理している場合は、 DNSレコードの管理方法を参照して、Aレコードの作成方法を確認してください。

DigitalOcean Kubernetesを使用している場合は、 DigitalOceanKubernetesでCert-Managerを使用してNginxIngressを設定する方法のステップ5で説明されている回避策を実装していることも確認してください。

Ingress Controller LoadBalancerを指すAレコードを取得したら、your_domain.comおよびpollsサービスのIngressを作成できます。

お気に入りのエディタを使用して、polls-ingress.yamlというファイルを開きます。

nano polls-ingress.yaml

次のIngressマニフェストに貼り付けます。

[polls-ingress.yaml]
apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
  name: polls-ingress
  annotations:
    kubernetes.io/ingress.class: "nginx"
    cert-manager.io/cluster-issuer: "letsencrypt-staging"
spec:
  tls:
  - hosts:
    - your_domain.com
    secretName: polls-tls
  rules:
  - host: your_domain.com
    http:
      paths:
      - backend:
          serviceName: polls
          servicePort: 8000

polls-ingressというIngressオブジェクトを作成し、それに注釈を付けて、コントロールプレーンにingress-nginxIngressControllerとステージングClusterIssuerを使用するように指示します。 また、your_domain.comのTLSを有効にし、証明書と秘密鍵をpolls-tlsという秘密に保存します。 最後に、your_domain.comホストのトラフィックをポート8000pollsサービスにルーティングするルールを定義します。

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

kubectl applyを使用して、クラスターに入力を作成します。

kubectl apply -f polls-ingress.yaml
Outputingress.networking.k8s.io/polls-ingress created

kubectl describeを使用して、作成したばかりのイングレスの状態を追跡できます。

kubectl describe ingress polls-ingress
OutputName:             polls-ingress
Namespace:        default
Address:          workaround.your_domain.com
Default backend:  default-http-backend:80 (<error: endpoints "default-http-backend" not found>)
TLS:
  polls-tls terminates your_domain.com
Rules:
  Host        Path  Backends
  ----        ----  --------
  your_domain.com
                 polls:8000 (10.244.0.207:8000,10.244.0.53:8000)
Annotations:  cert-manager.io/cluster-issuer: letsencrypt-staging
              kubernetes.io/ingress.class: nginx
Events:
  Type    Reason             Age   From                      Message
  ----    ------             ----  ----                      -------
  Normal  CREATE             51s   nginx-ingress-controller  Ingress default/polls-ingress
  Normal  CreateCertificate  51s   cert-manager              Successfully created Certificate "polls-tls"
  Normal  UPDATE             25s   nginx-ingress-controller  Ingress default/polls-ingress

polls-tls証明書でdescribeを実行して、作成が成功したことをさらに確認することもできます。

kubectl describe certificate polls-tls
Output. . .
Events:
  Type    Reason     Age    From          Message
  ----    ------     ----   ----          -------
  Normal  Issuing    3m33s  cert-manager  Issuing certificate as Secret does not exist
  Normal  Generated  3m32s  cert-manager  Stored new private key in temporary Secret resource "polls-tls-v9lv9"
  Normal  Requested  3m32s  cert-manager  Created new CertificateRequest resource "polls-tls-drx9c"
  Normal  Issuing    2m58s  cert-manager  The certificate has been successfully issued

これにより、TLS証明書が正常に発行され、your_domain.comに対してHTTPS暗号化がアクティブになったことを確認できます。

ステージングClusterIssuerを使用した場合、ほとんどのWebブラウザーは、発行した偽のLet's Encrypt証明書を信頼しないため、your_domain.comに移動するとエラーページが表示されます。

テストリクエストを送信するには、コマンドラインからwgetを使用します。

wget -O - http://your_domain.com/polls
Output. . .
ERROR: cannot verify your_domain.com's certificate, issued by ‘CN=Fake LE Intermediate X1’:
  Unable to locally verify the issuer's authority.
To connect to your_domain.com insecurely, use `--no-check-certificate'.

提案された--no-check-certificateフラグを使用して、証明書の検証をバイパスします。

wget --no-check-certificate -q -O - http://your_domain.com/polls
Output

<link rel="stylesheet" type="text/css" href="https://your_space.nyc3.digitaloceanspaces.com/django-polls/static/polls/style.css">


    <p>No polls are available.</p>

この出力には、/pollsインターフェイスページのHTMLが表示され、スタイルシートがオブジェクトストレージから提供されていることも確認されます。

ステージングClusterIssuerを使用して証明書の発行を正常にテストしたので、本番ClusterIssuerを使用するようにIngressを変更できます。

polls-ingress.yamlを開いて、もう一度編集します。

nano polls-ingress.yaml

cluster-issuer注釈を変更します。

[polls-ingress.yaml]
apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
  name: polls-ingress
  annotations:
    kubernetes.io/ingress.class: "nginx"
    cert-manager.io/cluster-issuer: "letsencrypt-prod"
spec:
  tls:
  - hosts:
    - your_domain.com
    secretName: polls-tls
  rules:
  - host: your_domain.com
    http:
      paths:
      - backend:
          serviceName: polls
          servicePort: 8000

完了したら、ファイルを保存して閉じます。 kubectl applyを使用して入力を更新します。

kubectl apply -f polls-ingress.yaml
Outputingress.networking.k8s.io/polls-ingress configured

kubectl describe certificate polls-tlsおよびkubectl describe ingress polls-ingressを使用して、証明書の発行ステータスを追跡できます。

kubectl describe ingress polls-ingress
Output. . .
Events:
  Type    Reason             Age                From                      Message
  ----    ------             ----               ----                      -------
  Normal  CREATE             23m                nginx-ingress-controller  Ingress default/polls-ingress
  Normal  CreateCertificate  23m                cert-manager              Successfully created Certificate "polls-tls"
  Normal  UPDATE             76s (x2 over 22m)  nginx-ingress-controller  Ingress default/polls-ingress
  Normal  UpdateCertificate  76s                cert-manager              Successfully updated Certificate "polls-tls"

上記の出力は、新しい本番証明書が正常に発行され、polls-tlsシークレットに保存されたことを確認します。

Webブラウザでyour_domain.com/pollsに移動して、HTTPS暗号化が有効になっていて、すべてが期待どおりに機能していることを確認します。 Pollsアプリのインターフェースが表示されます。

WebブラウザでHTTPS暗号化がアクティブになっていることを確認します。 Google Chromeを使用している場合、エラーなしで上記のページにアクセスすると、すべてが正しく機能していることが確認されます。 さらに、URLバーに南京錠が表示されます。 南京錠をクリックすると、Let'sEncrypt証明書の詳細を調べることができます。

最後のクリーンアップタスクとして、オプションでpollsサービスタイプをNodePortから内部専用のClusterIPタイプに切り替えることができます。

エディタを使用してpolls-svc.yamlを変更します。

nano polls-svc.yaml

typeNodePortからClusterIPに変更します。

polls-svc.yaml

apiVersion: v1
kind: Service
metadata:
  name: polls
  labels:
    app: polls
spec:
  type: ClusterIP
  selector:
    app: polls
  ports:
    - port: 8000
      targetPort: 8000

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

kubectl applyを使用して変更をロールアウトします。

kubectl apply -f polls-svc.yaml --force
Outputservice/polls configured

kubectl get svcを使用してサービスが変更されたことを確認します。

kubectl get svc polls
OutputNAME    TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)    AGE
polls   ClusterIP   10.245.203.186   <none>        8000/TCP   22s

この出力は、サービスタイプがClusterIPになったことを示しています。 アクセスする唯一の方法は、ドメインとこのステップで作成したIngressを経由することです。

結論

このチュートリアルでは、HTTPSで保護されたスケーラブルなDjangoアプリをKubernetesクラスターにデプロイしました。 静的コンテンツはオブジェクトストレージから直接提供され、実行中のポッドの数は、polls-appデプロイメントマニフェストのreplicasフィールドを使用してすばやくスケールアップまたはスケールダウンできます。

DigitalOcean Spaceを使用している場合は、コンテンツ配信ネットワークを介した静的アセットの配信を有効にして、Spaceのカスタムサブドメインを作成することもできます。 詳細については、 DigitalOceanマネージドデータベースとスペースを使用してスケーラブルなDjangoアプリをセットアップする方法から、CDNを有効にするを参照してください。

シリーズの残りの部分を確認するには、コンテナからKuberneteswithDjangoシリーズページにアクセスしてください。