Едва ли в мире есть более популярный движок для создания блогов и небольших сайтов, чем WordPress — около 26% всех веб-сайтов в интернете созданы на его основе. Многие хостинги включают его в список своих сервисов, а официальный docker-образ был скачан более 10 миллионов раз и является одним из 25 самых популярных образов на Docker Hub. Запустив его не просто в докере, а в Kubernetes, мы можем создать масштабируемую платформу для блога или веб-сайта: при росте нагрузки мы просто масштабируем количество реплик приложения.
Планируем архитектуру
Теория: stateless- и stateful-приложения
Перед тем как приступить к установке WordPress, нам придется вкратце рассмотреть несколько базовых понятий, связанных с хранением данных в облаках и в Kubernetes.
Stateless-приложения. Для примера возьмем два приложения — «корзину» в интернет-магазине и наш блог на WordPress. Когда мы добавляем товары в корзину (но не переходим к оплате заказа), она сохраняет все данные в cookies на нашей стороне. По завершении сессии приложение сбрасывает все данные и не хранит ничего на сервере. Когда мы снова заходим в интернет-магазин, информация о товарах считывается из нашей системы и снова отображается в корзине. Чтобы работать с покупателем, корзине не нужно получать никакую информацию с бэкенда — роль хранилища выполняет система покупателя. Такие приложения называются stateless, поскольку они не хранят информацию о своем состоянии.
Stateful-приложения. Теперь посмотрим на наш блог. Когда мы создаем новый пост или оставляем комментарий, нужно чтобы любой пользователь в любое время мог получить к ним доступ. Поэтому все данные должны храниться на стороне сервера. Когда мы переходим на ту или иную страницу, движок блога загружает имеющуюся информацию из базы данных, а если мы что-то меняем на странице — записывает изменения на сервер. Такие приложения, которые должны хранить информацию о своем состоянии для корректной работы, называются stateful. WordPress относится именно к таким приложениям.
Как будем хранить данные?
Kubernetes поддерживает оба типа приложений, но принцип их запуска различен. Stateless-приложения не требуют выделения хранилища, но наш блог — stateful, и для него нужно выделить директорию для записи и чтения данных о состоянии. В нашей инсталляции WordPress мы будем хранить данные приложения в базе данных, конкретно — в MySQL. Для запуска WordPress и MySQL потребуется выделить две директории: одну для системных данных WordPress, другую для данных сайта и информации о пользователях, хранимых в MySQL.
С этим разобрались. Но где хранить все эти данные? Рассмотрим два варианта.
WordPress и MySQL могут хранить всю информацию внутри контейнеров, в которых они запущены. Это обеспечит сохранность данных на какое-то время, но при перезапуске пода (pod) все данные будут утеряны (по эффекту перезапустить под — это всё равно что удалить все данные на сервере). Этот вариант подходит, если вы хотите быстро протестировать работу приложений, но его точно не стоит использовать для работы в production.
Можно хранить данные приложений вне контейнера, используя внешнее хранилище на сервере. В этом случае перезапуск пода никак не повлияет на сохранность данных и, кроме того, мы сможем делать бэкапы содержимого. Именно этот вариант мы и выберем.
Что сделать, чтобы использовать внешнее хранилище?
Чтобы работать с хранилищем в Kubernetes и, в частности, смонтировать в него WordPress и MySQL, нам необходимо сделать две вещи:
настроить утилиту для управления хранилищем на сервере хранилища,
обеспечить взаимодействие между этой утилитой и приложениями в Kubernetes.
Kubernetes поддерживает множество утилит для работы с хранилищем: Ceph, GlusterFS, iSCSI, NFS и др. Список всех поддерживаемых типов можно найти в официальной документации Kubernetes. Для простоты в данной статье мы будем использовать NFS.
Для работы с хранилищем Kubernetes использует абстракции PersistentVolume и PersistentVolumeClaim. Что они из себя представляют? Объект PersistentVolume (PV) управляет постоянным хранилищем в кластере. Он поддерживает различные типы внешнего хранилища, например NFS, GlusterFS, Ceph и многие другие. PersistentVolumeClaim (PVC) — это запрос на использование хранилища для конкретного приложения. В упрощенном виде их взаимодействие можно изобразить следующим образом: приложение обращается к PersistentVolumeClaim, который запрашивает хранилище у PersistentVolume, который, в свою очередь, монтирует данные приложений в директорию на сервере хранилища. Чтобы не создавать PersistentVolume вручную, мы установим nfs-client-provisioner — приложение, которое автоматически создает PV по требованию PVC.
Как поды обращаются к физическому хранилищу
Для работы подов с хранилищами в архитектуре Kubernetes выделена абстракция Volume. Под обращается к нему как хранилищу без учёта того, как это хранилище реализовано. С помощью volume решается две проблемы:
сохранение данных при падении контейнера (пода),
возможность для двух и более подов работать с общими файлами.
PersistentVolume (PV) — это Volume для работы подов с физическим хранилищем через API. PV представляет собой объект в Kubernetes, который содержит в себе информацию, как монтировать физическое хранилище и его метаданные.
PersistentVolumeClaim (PVC) — это запрос на создание PV и предоставление Storage.
План развёртывания
В процессе подготовки NFS и установки WordPress и MySQL мы выполним следующие шаги:
Установка утилиты NFS для управления хранилищем.
Установка nfs-client-provisioner для автоматического выделения хранилища в Kubernetes.
Создание PersistentVolumeClaim для запроса места в хранилище.
Создание Secret для MySQL для доступа к MySQL.
Запуск MySQL.
Запуск WordPress.
Подготовка NFS
Для работы с NFS необходимо настроить NFS-сервер на отдельной машине и NFS-клиенты на машинах с Kubernetes.
Зайдем на машину-сервер, которую будем использовать для хранения данных, установим на нее файервол и откроем порты TCP:111, UDP: 111, TCP:2049, UDP:2049. В нашем примере мы используем CenOS 7.5. Для этого выполним команды:
Помимо этого, не забудьте дополнительно защитить внутренние ресурсы от доступа из интернета. Для этого закройте доступ к портам извне на уровне фаервола сети, в которой развёрнута ваша инсталляция.
После этого установим NFS-utils для работы с хранилищем:
sudo yum install nfs-utils
Создадим директорию для монтирования данных на диск (/nfs) и запустим nfs-server:
Чтобы не монтировать PersistentVolume к хранилищу вручную для каждого PVC, установим nfs-client provisioner на каждой машине-клиенте. Для установки будем использовать Helm. Выполним команду:
Чтобы хранить данные WordPress и MySQL в NFS, необходимо запросить часть хранилища (в данном случае по 1 GiB) для каждого приложения через PVC. Благодаря запущенному nfs-provisioner PV будут предоставлены автоматически. Создадим файлы pvc-wordpress.yaml и pvc-mysql.yaml со следующим содержанием:
Готово, теперь можно переходить к запуску MySQL и WordPress.
Создаем secret для MySQL
Secret — объект, который хранит какую-либо конфиденциальную информацию типа паролей или ключей. Данные, хранимые в Secret, должны быть закодированы по стандарту base64. Сейчас мы создадим секрет c паролем для пользователя admin в MySQL, зададим создание случайного пароля:
openssl rand -base64 32 | base64
На выходе получим зашифрованный пароль: QlFhZzlEOWF6c3JoMTU4Rjh2U3FDVUdHNE9KSm4xMVBtVDV1Rno1Szkvbz0K
Теперь нужно создать secret.yaml для MySQL и WordPress, на который будет ссылаться MYSQL_ROOT_PASSWORD в environment деплойментов:
Файл состоит из 2 файлов конфигураций: Service открывает порт 3306 для всех контейнеров, у которых прописаны лейблы app:wordpress и tier:mysql. Часть Deployment описывает параметры создания деплоймента и specs контейнера с MySQL:
используется образ mysql:5.7
указываются лейблы app:wordpress и tier:frontend, прописанные в Service для WordPress.
в качестве переменной MYSQL_ROOT_PASSWORD используется password из созданного секрета.
открывается порт 3306
Директория /var/lib/mysql внутри контейнера монтируется в Volume через PVC с названием claim-db-wordpress-one.
Создадим деплоймент и сервис из файла:
kubectl create -f mysql-deploy.yaml
Запускаем WordPress
Процесс запуска WordPress аналогичен описанному выше. Создадим wordpress-deploy.yaml:
Как и в предыдущем случае, файл состоит из 2 частей. Service пробрасывает 80-й порт контейнера на внешний IP:порт машины для всех контейнеров с лейблами app:wordpress и tier:frontend. Deployment содержит следующие specs контейнера WordPress:
запускаемый образ с DockerHub - wordpress:4.8-apache
указаны лейблы app:wordpress и tier:frontend, используемые в Service.
указаны переменные WORDPRESS_DB_HOST (внутренний hostname MySQL) и MYSQL_ROOT_PASSWORD, использующий значение из созданного секрета
открыт 80-й порт.
Директория /var/www/html внутри контейнера монтируется в Volume через PVC с названием wp-pv-claim.
Создадим Deployment и Service из файла wordpress-deploy.yaml:
kubectl create -f wordpress-deploy.yaml
Убедимся, что все работает:
kubectl get po
Откроем WordPress
Теперь откроем WordPress в браузере. Для этого получим порт приложения, выполнив команду kubectl get svc:
Перейдем по адресу: внешний_IP:порт_сервиса (в нашем случае 32095).
Перед нами появился экран выбора языка — WordPress готов к работе.
Проверка
Теперь убедимся, что мы верно настроили работу WordPress и MySQL с хранилищем. В панели управления вордпресса укажем название блога («WordPress в Kubernetes») и перейдем на главную страницу по адресу внешний IP:порт_сервиса. На странице появилось название блога.
Теперь перезапустим поды WordPress и MySQL и проверим, сохранились ли данные приложений.
kubectl get po
Удалим поды и подождем, пока будут созданы новые:
kubectl delete po название_пода1 название_пода2
Снова зайдем на главную страницу WordPress.
Картинка та же, так что при удалении и восстановлении пода всё сохранилось
После перезапуска подов оба приложения взяли сохраненные данные из NFS-хранилища — значит, мы все настроили правильно!
Заключение
С Kubernetes мы можем быстро развернуть WordPress с MySQL и смонтировать их данные в постоянное хранилище. Мы использовали NFS из-за простоты настройки, однако для более надежного production рекомендуется использовать более сложные распределенные системы хранения, например GlusterFS или Ceph.
Тем не менее, NFS отлично подходит для небольших проектов. Если в какой-то момент что-то пойдет не так и WordPress или MySQL «упадет» или перезапустится, мы не потеряем контент благодаря тому, что они хранятся не внутри контейнеров, а во внешнем хранилище. Главное — не забывать регулярно делать бэкапы.
Чтобы не тратить время на установку и настройку кластера Kubernetes, можно получить настроенный кластер в облаке в несколько кликов, с бесплатным тестированием.