Tutorial

Развертывание масштабируемого и защищенного приложения Django с помощью Kubernetes

DigitalOceanDockerPostgreSQLDjangoPython FrameworksKubernetes

Введение

В этом учебном модуле мы развернем контейнеризованное приложение Django polls в кластере Kubernetes.

Django — это мощная веб-структура, позволяющая быстро развернуть ваше приложение Python с нуля. Она включает ряд удобных функций, в том числе реляционную карту объектов, аутентификацию пользователей и настраиваемый административный интерфейс для вашего приложения. Также она включает систему кэширования и помогает проектировать оптимизированные приложения с помощью диспетчера URL и системы шаблонов.

В учебном модуле Создание приложения Django и Gunicorn с помощью Docker мы изменили приложение Polls из учебного модуля Django согласно методологии Двенадцать факторов, предназначенной для построения масштабируемых веб-приложений, оптимизированных для работы в облаке. Для масштабирования и защиты контейнера использовался обратный прокси-сервер Nginx и подписанный Let’s Encrypt сертификат TLS (см. описание в учебном модуле Масштабирование и защита приложения Django с помощью Docker, Nginx и Let’s Encrypt). В этом последнем учебном модуле из серии От контейнеров к Kubernetes с Django мы покажем, как развернуть модернизированное приложение Django polls в кластере Kubernetes.

Kubernetes — мощная система оркестрации контейнеров с открытым исходным кодом, помогающая автоматизировать развертывание, масштабирование и управление контейнеризованными приложениями. Такие объекты Kubernetes как ConfigMaps и Secrets позволяют централизовать конфигурацию и отсоединить ее от контейнеров, а такие контроллеры как Deployments автоматически перезагружают неработающие контейнеры и позволяют быстро масштабировать реплики контейнеров. Шифрование TLS активируется с помощью объекта Ingress и контроллера ingress-nginx с открытым исходным кодом. Надстройка Kubernetes cert-manager проверяет и выпускает сертификаты, используя бесплатный центр сертификации Let’s Encrypt.

Предварительные требования

Для данного обучающего модуля вам потребуется следующее:

  • Кластер Kubernetes версии 1.15 или выше с включенным контролем доступа на основе ролей (RBAC). В нашем примере будет использоваться кластер DigitalOcean Kubernetes, но вы можете создать кластер с помощью другого метода.
  • Инструмент командной строки kubectl, установленный на локальном компьютере и настроенный для подключения к вашему кластеру. Дополнительную информацию об установке kubectl можно найти в официальной документации. Если вы используете кластер DigitalOcean Kubernetes, ознакомьтесь с руководством Подключение к кластеру DigitalOcean Kubernetes, чтобы узнать, как подключиться к кластеру с помощью kubectl.
  • Зарегистрированное доменное имя. В этом учебном модуле мы будем использовать имя your_domain.com. Вы можете получить бесплатный домен на Freenom или зарегистрировать доменное имя по вашему выбору.
  • Контроллер ingress-nginx и диспетчер сертификатов TLS cert-manager должны быть установлены в вашем кластере и настроены на использование сертификатов TLS. Чтобы узнать, как установить и настроить Ingress с помощью cert-manager, воспользуйтесь руководством Настройка Nginx Ingress с помощью Cert-Manager в кластере DigitalOcean Kubernetes.
  • Запись DNS A для your_domain.com, указывающая на публичный IP-адрес балансировщика нагрузки Ingress. Если вы используете DigitalOcean для управления записями DNS вашего домена, руководство Управление записями DNS поможет вам научиться создавать записи класса A.
  • Хранилище объектов S3, например пространство DigitalOcean, для хранения статических файлов проекта Django и набор ключей доступа к этому пространству. Чтобы узнать, как создать пространство, ознакомьтесь с документом Как создавать пространства. Чтобы узнать, как создать ключи доступа, ознакомьтесь со статьей Предоставление доступа к пространству с помощью ключей доступа. Внеся незначительные изменения, вы можете использовать любой сервис хранения, который поддерживает плагин django-storages.
  • Экземпляр сервера PostgreSQL, база данных и пользователь для приложения Django. Внеся незначительные изменения, вы можете использовать любую базу данных, которую поддерживает Django.
  • Учетная запись Docker Hub и публичный репозиторий. Более подробную информацию по их созданию можно найти в разделе Repositories (Репозитории) в документации по Docker.
  • Система Docker, установленная на локальном компьютере. Более подробную информацию можно найти в руководстве Установка и использование Docker в Ubuntu 18.04.

Проверив наличие этих компонентов, вы можете начать прохождение этого обучающего модуля.

Шаг 1 — Клонирование и настройка приложения

На этом шаге мы клонируем код приложения с GitHub и настроим такие параметры, как учетные данные БД и ключи хранения объектов.

Код приложения и файл Dockerfile можно найти в ветви polls-docker репозитория Django Tutorial Polls App на GitHub. Этот репозиторий содержит код приложения Polls, используемого в документации по Django в качестве образца, на примере которого показывается, как создать приложение для опросов с нуля.

Ветвь polls-docker содержит размещенную в контейнере Docker версию приложения Polls. Более подробную информацию об изменениях, внесенных в приложение Polls для эффективной работы в контейнеризированной среде, можно найти в руководстве Создание приложения Django и Gunicorn с помощью Docker.

Для начала используйте git, чтобы клонировать ветвь polls-docker репозитория Django Tutorial Polls App на GitHub на локальном компьютере:

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

Перейдите в каталог django-polls:

  • cd django-polls

В этом каталоге содержится код Python приложения Django, файл Dockerfile, который Docker будет использовать для построения образа контейнера, а также файл env, содержащий список переменных среды для передачи в рабочую среду контейнера. Проверьте файл Dockerfile:

  • cat Dockerfile
Output
FROM 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 используется официальный образ Docker Python 3.7.4, который устанавливает требуемые пакеты Python для Django и Gunicorn в соответствии с файлом django-polls/requirements.txt. Затем он удаляет некоторые ненужные файлы сборки, копирует код приложения в образ и устанавливает параметр выполнения PATH. И в заключение заявляет, что порт 8000 будет использоваться для принятия входящих подключений контейнера, и запускает gunicorn с тремя рабочими элементами, прослушивающими порт 8000.

Дополнительную информацию о каждом этапе в Dockerfile см. в шаге 6 руководства Создание приложения Django и Gunicorn с помощью Docker.

Теперь создайте образ с помощью docker build:

  • docker build -t polls .

Назовем образ polls, используя флаг -t, и передадим в текущий каталог как контекст сборки набор файлов для справки при построении образа.

После того как 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_KEY: задает уникальное, непрогнозируемое значение, как описано в документации Django. Один метод генерирования этого ключа представлен в разделе Изменение настроек приложения руководства Масштабируемое приложение Django.
  • DJANGO_ALLOWED_HOSTS: эта переменная защищает приложение и предотвращает атаки через заголовки хоста HTTP. С целью тестирования установите * как подстановочный символ, подходящий для всех хостов. В производственной среде следует использовать значение your_domain.com. Дополнительную информацию об этой настройке Django см. в разделе Core Settings (Базовые настройки) документации Django.
  • DATABASE_USERNAME: задает пользователя базы данных PostgreSQL, созданного на предварительных этапах.
  • DATABASE_NAME: задает polls или имя базы данных, созданной на предварительных этапах.
  • DATABASE_PASSWORD: задает пароль пользователя базы данных PostgreSQL, созданного на предварительных этапах.
  • DATABASE_HOST: задает имя хоста базы данных.
  • DATABASE_PORT: укажите порт вашей базы данных.
  • STATIC_ACCESS_KEY_ID: укажите ключ доступа своего пространства или хранилища объектов.
  • STATIC_SECRET_KEY: укажите секретный ключ своего пространства или хранилища объектов.
  • STATIC_BUCKET_NAME: укажите имя своего пространства или корзину хранилища объектов.
  • STATIC_ENDPOINT_URL: укажите URL соответствующего пространства или конечного пункта хранилища объектов, например https://your_space_name.nyc3.digitaloceanspaces.com, если ваше пространство находится в области nyc3.

После завершения редактирования сохраните и закройте файл.

На следующем шаге мы запустим настроенный контейнер в локальной среде и создадим схему базы данных. Также мы выгрузим в хранилище объектов статические ресурсы, такие как таблицы стилей и изображения.

Шаг 2 — Создание схемы базы данных и выгрузка ресурсов в хранилище объектов

После построения и настройки контейнера используйте docker run, чтобы заменить заданную команду CMD в файле Dockerfile и создайте схему базы данных, используя команды 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", которая создаст схему базы данных, определяемую кодом приложения.

Если запускаете эти команды впервые, вы должны увидеть следующее:

Output
No 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 не будет выполнять никаких операций, если схема базы данных не изменилась.

Затем мы запустим еще один экземпляр контейнера приложения и используем внутри него интерактивную оболочку для создания административного пользователя проекта Django.

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

Вы получите строку оболочки внутри работающего контейнера, которую сможете использовать для создания пользователя Django:

  • python manage.py createsuperuser

Введите имя пользователя, адрес электронной почты и пароль для пользователя, а после создания пользователя нажмите CTRL+D для выхода из контейнера и его удаления.

В заключение мы создадим статические файлы приложения и загрузим их в пространство DigitalOcean с помощью collectstatic. Обратите внимание, что для завершения процесса может потребоваться время.

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

После создания и загрузки файлов вы получите следующий вывод.

Output
121 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 на локальном компьютере и порта 8000 контейнера polls.

Теперь у вас должна появиться возможность открыть приложение polls в браузере, для чего нужно ввести http://localhost в адресную строку. Поскольку маршрут для пути / не определен, скорее всего, вы получите ошибку 404 Страница не найдена.

Введите в адресную строку http://localhost/polls, чтобы увидеть интерфейс приложения Polls:

Интерфейс приложения «Опросы»

Чтобы открыть интерфейс администрирования, введите адрес http://localhost/admin. Вы должны увидеть окно аутентификации администратора приложения «Опросы»:

Страница аутентификации администратора приложения

Введите имя администратора и пароль, которые вы создали с помощью команды createsuperuser.

После аутентификации вы сможете получить доступ к административному интерфейсу приложения «Опросы»:

Основной интерфейс администратора приложения

Обратите внимание, что статические активы приложений admin и polls поступают напрямую из хранилища объекта. Чтобы убедиться в этом, ознакомьтесь с материалами Тестирование доставки статических файлов пространства.

После завершения изучения данных нажмите CTRL+C в окне терминала, где запущен контейнер Docker, чтобы удалить контейнер.

Когда образ Docker приложения Django будет протестирован, статичные ресурсы будут выгружены в хранилище объектов, а схема базы данных будет настроена и готова к выгрузке образа приложения Django в реестр образов, например в Docker Hub.

Шаг 3 — Размещение образа приложения Django в Docker Hub

Чтобы развернуть приложение в Kubernetes, необходимо будет выгрузить образ приложения в реестр, например, в Docker Hub. Kubernetes извлечет образ приложения из репозитория, а затем развернет его в кластере.

Вы можете использовать частный реестр Docker, например, реестр контейнеров DigitalOcean Container Registry, предварительная версия которого в настоящее время предоставляется бесплатно, или публичный реестр Docker, такой как Docker Hub. Docker Hub также позволяет создавать частные репозитории Docker. Публичный репозиторий позволяет любому пользователю видеть и извлекать образы контейнеров, а в частном репозитории доступ имеется только у вас и у членов вашей команды.

В этом учебном модуле мы разместим образ Django в публичном репозитории Docker Hub, созданном на этапе предварительных требований. Также вы можете перенести образ в частный репозиторий, однако извлечение образов из частного репозитория в этой статье не описывается. Чтобы получить более подробную информацию об аутентификации Kubernetes с Docker Hub и извлечении образов из частного репозитория, ознакомьтесь со статьей Pull an Image from a Private Registry (Извлечение образа из частного реестра) в документации по Kubernetes.

Для начала выполните вход в Docker Hub на локальном компьютере:

  • docker login
Output
Login 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:

Введите имя пользователя и пароль Docker Hub для входа в систему.

Образ Django сейчас помечен тегом polls:latest. Чтобы поместить его в ваш репозиторий Docker Hub, измените теги образа, указав свое имя пользователя Docker Hub и имя репозитория:

  • docker tag polls:latest your_dockerhub_username/your_dockerhub_repo_name:latest

Разместите образ в репозитории:

  • docker push sammy/sammy-django:latest

В этом учебном модуле мы используем имя пользователя Docker Hub sammy и имя репозитория sammy-django. Вам следует заменить эти значения своим именем пользователя Docker Hub и именем репозитория.

По мере размещения слоев образа в Docker Hub вы будете видеть на экране определенные сообщения.

Теперь ваш образ доступен Kubernetes в репозитории Docker Hub, и вы можете начать его развертывание в своем кластере.

Шаг 4 — Настройка ConfigMap

При локальном запуске контейнера Django мы передали файл env в docker run для вставки переменных конфигурации в среду исполнения. Для вставки переменных конфигурации в Kubernetes используются элементы ConfigMap и Secret.

Элементы ConfigMap следует использовать для сохранения неконфиденциальной информации о конфигурации, такой как параметры приложения, а элементы Secret следует использовать для хранения важной информации, такой как ключи API и учетные данные для входа в базу данных. Они вставляются в контейнеры примерно одинаково, но у элементов Secret имеются дополнительные функции контроля доступа и безопасности, такие как шифрование в состоянии покоя. Элементы Secret хранят данные в формате base64, а элементы ConfigMap хранят данные в формате обычного текста.

Для начала необходимо создать каталог yaml, где мы будем хранить наши манифесты Kubernetes. Перейдите в каталог.

  • mkdir yaml
  • cd

Откройте файл polls-configmap.yaml в nano или в другом предпочитаемом текстовом редакторе:

  • 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"

Мы извлекли неконфиденциальные данные конфигурации из файла env, измененного на шаге 1, и передали их в манифест ConfigMap. Объект ConfigMap носит имя polls-config. Скопируйте те же самые значения, введенные в файл env на предыдущем шаге.

Для тестирования оставьте для DJANGO_ALLOWED_HOSTS значение *, чтобы отключить фильтрацию на основе заголовков хоста. В производственной среде здесь следует указать домен вашего приложения.

Когда вы завершите редактирование файла, сохраните и закройте его.

Создайте в своем кластере элемент ConfigMap, используя kubectl apply:

  • kubectl apply -f polls-configmap.yaml
Output
configmap/polls-config created

Мы создали элемент ConfigMap, а на следующем шаге мы создадим элемент Secret, который будет использоваться нашим приложением.

Шаг 5 — Настройка элемента Secret

Значения Secret должны иметь кодировку base64, то есть создавать объекты Secret в кластере немного сложнее, чем объекты ConfigMaps. Вы можете повторить описанную на предыдущем шаге процедуру, выполнив кодирование значений Secret в формате base64 вручную и вставив их в файл манифеста. Также вы можете создавать их, используя файл переменных среды, kubectl create и флаг --from-env-file, что мы и сделаем на этом шаге.

Мы снова используем файл env из шага 1, удалив переменные, вставленные в ConfigMap. Создайте копию файла env с именем polls-secrets в каталоге yaml:

  • cp ../env ./polls-secrets

Отредактируйте файл в предпочитаемом редакторе:

  • nano polls-secrets
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. Когда вы закончите, содержимое файла должно выглядеть следующим образом:

polls-secrets
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. Закончив, сохраните и закройте файл.

Создайте в кластере объект Secret, используя kubectl create secret:

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

Здесь мы создадим объект Secret с именем polls-secret и передадим в него созданный нами файл secrets.

Вы можете проинспектировать объект Secret, используя kubectl describe:

  • kubectl describe secret polls-secret
Output
Name: 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

Мы сохранили конфигурацию вашего приложения в кластере Kubernetes, используя типы объектов Secret и ConfigMap. Мы готовы развернуть приложение в кластере.

Шаг 6 — Развертывание приложения Django с помощью контроллера Deployment

На этом шаге мы создадим Deployment для вашего приложения Django. Kubernetes Deployment — контроллер, который можно использовать для управления приложениями без состояния в вашем кластере. Контроллер — это контур управления, регулирующий рабочие задачи посредством вертикального масштабирования. Контроллеры также перезапускают и очищают неисправные контейнеры.

Контроллеры Deployment контролируют один или несколько подов. Под — это наименьшая развертываемая единица в кластере Kubernetes. Поды содержат один или несколько контейнеров. Чтобы узнать о различных типах рабочих задач, ознакомьтесь с учебным модулем Введение в Kubernetes.

Для начала откройте файл polls-deployment.yaml в предпочитаемом текстовом редакторе:

  • nano polls-deployment.yaml

Вставьте в него следующий манифест Deployment:

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

Введите соответствующее имя образа контейнера, ссылаясь на образ Django Polls, который вы разместили в Docker Hub на шаге 2.

Здесь мы определяем контроллер Kubernetes Deployment с именем polls-app и присваиваем ему пару ключ-значение app: polls. Мы указываем, что хотим запустить две реплики пода, определенного под полем template.

Используя envFrom с secretRef и configMapRef, мы указываем, что все данные из объектов polls-secret и polls-config следует вставить в контейнеры как переменные среды. Ключи ConfigMap и Secret становятся именами переменных среды.

В заключение мы откроем порт containerPort 8000 и назовем его gunicorn.

Чтобы узнать больше о настройке контроллеров Kubernetes Deployment, ознакомьтесь с разделом Deployments в документации по Kubernetes.

Когда вы завершите редактирование файла, сохраните и закройте его.

Создайте в кластере контроллер Deployment, используя kubectl apply -f:

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

Убедитесь, что контроллер Deployment развернут правильно, используя kubectl get:

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

Если вы столкнетесь с ошибкой или что-то не будет работать, вы можете использовать kubectl describe для проверки неработающего контроллера Deployment:

  • kubectl describe deploy

Чтобы проинспектировать два пода, используйте kubectl get pod:

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

В кластеры запущены и работают две реплики вашего приложения Django. Чтобы получить доступ к приложению, вам нужно создать Kubernetes Service, и мы сделаем это на следующем шаге.

Шаг 7 — Предоставление внешнего доступа с использованием Service

На этом шаге мы создаем Service для нашего приложения Django. Kubernetes Service — это абстракция, позволяющая предоставить доступ к набору работающих подов как к сетевой службе. Используя Service, вы можете создать для вашего приложения стабильный конечный пункт, который не будет изменяться по мере уничтожения и воссоздания подов.

Существует несколько типов служб Service, в том числе службы ClusterIP, открывающие доступ к Service через внутренний IP-адрес кластера, службы NodePort, открывающие доступ к Service на каждом узле статического порта NodePort, и службы LoadBalancer, предоставляющие облачный балансировщик нагрузки для управления внешним трафиком подов вашего кластера (через порты NodePort, которые он создает автоматически). Чтобы узнать больше об этом, ознакомьтесь с разделом Service в документации по Kubernetes.

На заключительном шаге настройки мы используем службу ClusterIP Service, доступ к которой открыт через Ingress и контроллер Ingress, настроенный на этапе подготовки к этому учебному модулю. Сейчас мы убедимся, что все элементы работают корректно. Для этого мы создадим временную службу NodePort Service для доступа к приложению Django.

Для начала создайте файл с именем polls-svc.yaml в предпочитаемом редакторе:

  • nano polls-svc.yaml

Вставьте в него следующий манифест Service:

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

Здесь мы создаем службу NodePort под названием polls и присваиваем ей ярлык app: polls. Мы выберем поды серверной части с ярлыком app: polls и установим в качестве цели порты 8000.

Когда вы завершите редактирование файла, сохраните и закройте его.

Разверните Service с помощью команды kubectl apply:

  • kubectl apply -f polls-svc.yaml
Output
service/polls created

Убедитесь, что служба была создана с использованием kubectl get svc:

  • kubectl get svc polls
Output
NAME 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
Output
NAME 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

Откройте в браузере приложение Polls, используя внешний IP-адрес и порт NodePort любого узла. С учетом приведенного выше вывода URL приложения будет выглядеть так: http://203.0.113.1:32654/polls.

Вы должны увидеть тот же интерфейс приложения Polls, который вы открыли локально на шаге 1:

Интерфейс приложения «Опросы»

Вы можете повторить ту же проверку, используя маршрут /admin: http://203.0.113.1:32654/admin. Вы увидите тот же интерфейс администрирования, что и раньше:

Страница аутентификации администратора приложения

Мы развернули две реплики контейнера приложения Django Polls, используя Deployment. Также мы создали стабильный конечный пункт сети для этих двух реплик и обеспечили внешний доступ к ним через службу NodePort.

Заключительный шаг этого учебного модуля заключается в том, чтобы защитить внешний трафик нашего приложения, используя HTTPS. Для этого мы используем контроллер ingress-nginx, установленный на этапе предварительных требований, и создадим объект Ingress для перенаправления внешнего трафика в службу Kubernetes polls.

Шаг 8 — Настройка HTTPS с использованием Nginx Ingress и cert-manager

Сущности Ingress в Kubernetes обеспечивают гибкую маршрутизацию внешнего трафика кластера Kubernetes среди служб внутри кластера. Это достигается с помощью ресурсов Ingress, которые определяют правила маршрутизации трафика HTTP и HTTPS для служб Kubernetes, и контроллеров Ingress, которые реализуют правила посредством балансировки нагрузки трафика и его перенаправления на соответствующие службы серверной части.

На этапе предварительных требований мы установили контроллер ingress-nginx и надстройку cert-manager для автоматизации сертификатов TLS. Также мы настроили испытательную и производственную среду ClusterIssuers для вашего домена, используя центр сертификации Let’s Encrypt, и создали объект Ingress для проверки выдачи сертификатов и шифрования TLS для двух фиктивных серверных служб. Прежде чем продолжить выполнение этого шага, удалите объект echo-ingress, созданный в подготовительном учебном модуле:

  • kubectl delete ingress echo-ingress

При желании вы также можете удалить фиктивные службы и развертывания, используя команды kubectl delete svc и kubectl delete deploy, но для прохождения этого учебного модуля это не обязательно.

Также вы должны были создать запись DNS типа A для your_domain.com, указывающую на публичный IP-адрес балансировщика нагрузки Ingress. Если вы используете балансировщик нагрузки DigitalOcean, вы можете найти этот IP-адрес в разделе Load Balancers панели управления. Если вы также используете DigitalOcean для управления записями DNS вашего домена, руководство Управление записями DNS поможет вам научиться создавать записи класса A.

Если вы используете DigitalOcean Kubernetes, убедитесь, что вы внедрили обходное решение, описанное в шаге 5 учебного модуля Настройка Nginx Ingress с помощью Cert-Manager в DigitalOcean Kubernetes.

Когда у вас будет запись A, указывающая на балансировщик нагрузки контроллера Ingress, вы можете создать Ingress для your_domain.com и службы polls.

Откройте файл с именем 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

Мы создаем объект Ingress под именем polls-ingress и добавляем к нему аннотацию, чтобы уровень управления использовал контроллер ingress-nginx и размещение ClusterIssuer. Также мы включаем TLS для домена your_domain.com и сохраняем сертификат и закрытый ключ в объекте Secret с именем polls-tls. В заключение мы определяем правило перенаправления трафика для хоста your_domain.com в службу polls через порт 8000.

Когда вы завершите редактирование файла, сохраните и закройте его.

Создайте в кластере объект Ingress, используя kubectl apply:

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

Вы можете использовать kubectl describe для отслеживания состояния только что созданного объекта Ingress:

  • kubectl describe ingress polls-ingress
Output
Name: 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

Также вы можете запустить команду describe для сертификата polls-tls, чтобы убедиться, что он был успешно создан:

  • 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 успешно выдан, и шифрование HTTPS для домена your_domain.com активно.

Поскольку мы использовали тестовую версию ClusterIssuer, большинство браузеров не будут доверять поддельному сертификату 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>

В этом выводе показан код HTML для страницы интерфейса /polls, а также подтверждается выдача таблицы стилей из хранилища объектов.

Мы успешно проверили выдачу сертификата с помощью тестовой версии ClusterIssuer и теперь можем изменить Ingress для использования производственной версии ClusterIssuer.

Снова откройте файл 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

Внесите необходимые изменения, после чего сохраните и закройте файл. Обновите Ingress, используя kubectl apply:

  • kubectl apply -f polls-ingress.yaml
Output
ingress.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"

Приведенный выше вывод подтверждает, что новый производственный сертификат успешно выдан и сохранен в объекте Secret polls-tls.

Откройте в браузере адрес your_domain.com/polls, чтобы убедиться, что шифрование HTTPS включено, и все работает ожидаемым образом. Вы должны увидеть интерфейс приложения Polls:

Интерфейс приложения «Опросы»

Убедитесь, что в браузере включено шифрование HTTPS. Если вы используете Google Chrome, то если вышеуказанная страница откроется без ошибок, это будет означать, что все работает правильно. Кроме того, на панели URL должно быть изображение замка. Нажав на замок, вы сможете просмотреть детали сертификата Let’s Encrypt.

Для окончательной очистки вы можете переключить тип службы polls с NodePort на внутренний тип ClusterIP.

Отредактируйте файл polls-svc.yaml в текстовом редакторе:

  • nano polls-svc.yaml

Измените type с NodePort на 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
Output
service/polls configured

Убедитесь, что служба Service была изменена, используя kubectl get svc:

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

Этот вывод показывает, что тип Service — ClusterIP. Для доступа можно использовать только домен и Ingress, созданный на этом шаге.

Заключение

В этом учебном модуле мы развернули масштабируемое приложение Django с защитой HTTPS в кластере Kubernetes. Статичный контент выдается напрямую из хранилища объектов, а количество работающих подов можно быстро увеличивать или уменьшать, используя поле replicas в манифесте Deployment polls-app.

Если вы используете пространство DigitalOcean Space, вы также можете включить доставку статичных ресурсов через сеть доставки контента и создать настраиваемый субдомен для своего пространства. Дополнительную информацию можно найти в разделе Включение CDN учебного модуля Настройка масштабируемого приложения Django с управляемыми базами данных и пространствами DigitalOcean.

С остальными частями серии можно ознакомиться на странице От контейнеров к Kubernetes с Django.

Creative Commons License