Перемещение приложения Parse на Parse Server в Ubuntu 14.04

Parse – это платформа «мобильный сервер как услуга», которая с 2013 года принадлежит Facebook. В январе 2016 Parse анонсировал, что полностью прекратит поддержку сервисов внешнего размещения 28 января 2017 года.

К счастью, Parse также выпустил сервер API с открытым исходным кодом, совместимый с API-интерфейсом хостинга, называемым Parse Server. Parse Server находится в активной разработке и, вероятно, привлечет большое сообщество разработчиков. Его можно развернуть в различных средах с Node.js и MongoDB.

В этом руководстве основное внимание уделяется миграции готового рабочего приложения Parse на автономный экземпляр Parse Server, работающий на Ubuntu 14.04. Он поддерживает шифрование TLS/SSL для всех подключений, используя бесплатный сертификат Let’s Encrypt. В целом этот мануал подходит всем пользователям, которые работают с Debian-подобными дистрибутивами GNU/Linux.

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

Требования

Данный мануал основан на руководстве Запуск Parse Server на Ubuntu 14.04.

Для работы вам понадобится:

На целевом сервере должно быть достаточно места для обработки всех данных вашего приложения. Поскольку Parse сжимает данные, разработчики проекта официально рекомендуют предоставить как минимум в 10 раз больше места, чем нужно вашему приложению.

1: Подготовка MongoDB к миграции данных

Parse предоставляет инструмент для перемещения готовых приложений. Для этого нужно открыть MongoDB для внешних подключений и защитить БД копией сертификата TLS/SSL от Let’s Encrypt. Для начала объедините fullchain1.pem и privkey1.pem в новый файл /etc/ssl:

sudo cat /etc/letsencrypt/archive/domain_name/{fullchain1.pem,privkey1.pem} | sudo tee /etc/ssl/mongo.pem

Примечание: Вам нужно будет повторить вышеуказанную команду после обновления сертификата Let’s Encrypt. Если вы настроили автоматическое обновление сертификата Let’s Encrypt, не забудьте включить эту операцию.

Передайте права на mongo.pem пользователю mongodb:

sudo chown mongodb:mongodb /etc/ssl/mongo.pem
sudo chmod 600 /etc/ssl/mongo.pem

Откройте /etc/mongod.conf в nano или другом текстовом редакторе:

sudo nano /etc/mongod.conf

Здесь нужно внести несколько важных изменений.

Сначала найдите строку bindIp в разделе net: и настройте MongoDB для прослушивания всех адресов, изменив 127.0.0.1 на 0.0.0.0. Ниже в тот же раздел вы можете добавить конфигурацию SSL:

# network interfaces
net:
port: 27017
bindIp: 0.0.0.0
ssl:
mode: requireSSL
PEMKeyFile: /etc/ssl/mongo.pem

Включите авторизацию клиентов в разделе # security:

# security
security:
authorization: enabled

Также инструмент миграции данных требует, чтобы у параметра failIndexKeyTooLong было значение false:

setParameter:
failIndexKeyTooLong: false

Примечание: В конфигурационных файлах MongoDB, которые основаны на YAML, все пробелы и отступы важны. При копировании конфигурации убедитесь, что вы сохранили отступы.

Сохраните и закройте файл.

Прежде чем перезапустить сервис mongod, нужно добавить пользователя с ролью admin. Подключитесь к текущему экземпляру MongoDB:

mongo --port 27017

Создайте админа и выйдите. Вместо 8host укажите имя вашего пользователя, а вместо password – свой надежный пароль.

use admin
db.createUser({
user: "8host",
pwd: "password",
roles: [ { role: "userAdminAnyDatabase", db: "admin" } ]
})
exit

Перезапустите сервис:

sudo service mongod restart

2: Миграция данных приложения с Parse

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

Учетные данные MongoDB для инструмента миграции данных

Создайте локальное подключение с помощью аккаунта админа:

mongo --port 27017 --ssl --sslAllowInvalidCertificates --authenticationDatabase admin --username 8host --password

Вам будет предложено ввести пароль, который вы установили ранее.

После подключения выберите имя базы данных для хранения данных приложения. Например, если вы переносите приложение под названием Todo, вы можете использовать БД todo. Вам также потребуется выбрать еще один надежный пароль для пользователя, который называется parse.

В оболочке mongo передайте этому пользователю доступ к database_name:

use database_name
db.createUser({ user: "parse", pwd: "password", roles: [ "readWrite", "dbAdmin" ] })

Запуск процесса переноса данных

В браузере войдите в Parse и откройте настройки своего приложения. В разделе General найдите кнопку Migrate и нажмите ее.

Вам будет предложено ввести строку подключения MongoDB. Используйте следующий формат:

mongodb://parse:password@your_domain_name:27017/database_name?ssl=true

Например, если вы используете домен example.com, пользователя parse, пароль foo и БД todo, ваша строка подключения будет выглядеть так:

mongodb://parse:foo@example.com:27017/todo?ssl=true

Не забудьте указать ?ssl=true в конце, иначе соединение не будет выполнено. Введите строку подключения в диалоговое окно.

Нажмите Begin the migration. Вы должны увидеть прогресс копирования снапшота базы данных Parse на ваш сервер, а затем синхронизации новых данных со снапшотом. Продолжительность этого процесса будет зависеть от количества передаваемых данных и может занять много времени.

Проверка перемещенных данных

По завершении процесса миграции будет запущен этап проверки. Сейчас важно убедиться, что данные действительно переданы, и протестировать локальный экземпляр Parse Server.

Вернитесь к своей оболочке mongo и изучите локальную базу данных. Получите доступ к БД и просмотрите содержащиеся в ней коллекции:

use database_name
show collections
Sample Output for Todo App
Todo
_Index
_SCHEMA
_Session
_User
_dummy
system.indexes

Также можно изучить контент с помощью метода .find():

db.ApplicationName.find()
Sample Output for Todo App
> db.Todo.find()
{ "_id" : "hhbrhmBrs0", "order" : NumberLong(1), "_p_user" : "_User$dceklyR50A", "done" : false, "_acl" : { "dceklyR50A" : { "r" : true, "w" : true } }, "_rperm" : [ "dceklyR50A" ], "content" : "Migrate this app to my own server.", "_updated_at" : ISODate("2016-02-08T20:44:26.157Z"), "_wperm" : [ "dceklyR50A" ], "_created_at" : ISODate("2016-02-08T20:44:26.157Z") }

Ваш результат, конечно, будет другим, вы должны увидеть данные своего приложения. Убедившись, что все данные на месте, выйдите из mongo и вернитесь в оболочку:

exit

3: Установка и настройка Parse Server и PM2

Теперь можно перейти к установке самого Parse Server и интеграции с остальной частью системы. Предоставьте Parse Server выделенного пользователя и используйте утилиту PM2 для его настройки.

Глобальная установка Parse Server и PM2

Используйте npm для глобальной установки утилиты parse-server, диспетчера процессов pm2 и их зависимостей:

sudo npm install -g parse-server pm2

Создание выделенного пользователя и домашнего каталога

Вместо пользователя root или sudo для запуска parse-server используйте специального системного пользователя, который называется parse:

sudo useradd --create-home --system parse

Установите для него пароль:

sudo passwd parse

Вам будет предложено ввести пароль дважды.

Теперь используйте команду su, чтобы стать пользователем parse:

sudo su parse

Перейдите в его домашний каталог:

cd ~

Запись или миграция файла cloud code

Создайте каталог для cloud code:

mkdir -p ~/cloud

Отредактируйте /home/parse/cloud/main.js:

nano ~/cloud/main.js

Для тестирования можно вставить такие строки:

Parse.Cloud.define('hello', function(req, res) {
res.success('Hi');
});

Кроме того, вы можете перенести любой cloud code вашего приложения, скопировав его из раздела Cloud Code в настройках вашего приложения в панели Parse Dashboard.

Выйдите и сохраните файл.

Извлечение ключей и настройка /home/parse/ecosystem.json

PM2 – многофункциональный менеджер процессов, популярный у разработчиков Node.js. Мы будем использовать утилиту pm2 для настройки экземпляра parse-server и управления его работой в дальнейшем.

Вам нужно извлечь некоторые из ключей вашего приложения. На панели инструментов Parse нажмите App Settings, затем Security & Keys.

Здесь вам нужны идентификатор приложения и главный ключ (Application ID и Master Key). Другие ключи (ключи клиента, JavaScript, .NET и REST API) могут потребоваться для поддержки старых сборок клиента, но если они установлены, они требуются во всех запросах. Если у вас нет оснований использовать другие ключи, вы должны извлечь только Application ID и Master Key.

Затем отредактируйте файл /home/parse/ecosystem.json:

nano ecosystem.json

Вставьте следующие строки, указав свою строку подключения MongoDB, Application ID и Master Key:

{
"apps" : [{
"name"        : "parse-wrapper",
"script"      : "/usr/bin/parse-server",
"watch"       : true,
"merge_logs"  : true,
"cwd"         : "/home/parse",
"env": {
"PARSE_SERVER_CLOUD_CODE_MAIN": "/home/parse/cloud/main.js",
"PARSE_SERVER_DATABASE_URI": "mongodb://parse:password@your_domain_name:27017/database_name?ssl=true",
"PARSE_SERVER_APPLICATION_ID": "your_application_id",
"PARSE_SERVER_MASTER_KEY": "your_master_key",
}
}]
}

Объект env используется для установки переменных среды. Если вам нужно настроить дополнительные ключи, parse-сервер также распознает следующие переменные:

  • PARSE_SERVER_COLLECTION_PREFIX
  • PARSE_SERVER_CLIENT_KEY
  • PARSE_SERVER_REST_API_KEY
  • PARSE_SERVER_DOTNET_KEY
  • PARSE_SERVER_JAVASCRIPT_KEY
  • PARSE_SERVER_DOTNET_KEY
  • PARSE_SERVER_FILE_KEY
  • PARSE_SERVER_FACEBOOK_APP_IDS

Сохраните и закройте ecosystem.json.

Запустите сценарий с помощью pm2:

pm2 start ecosystem.json
...
[PM2] Spawning PM2 daemon
[PM2] PM2 Successfully daemonized
[PM2] Process launched
┌───────────────┬────┬──────┬──────┬────────┬─────────┬────────┬─────────────┬──────────┐
│ App name      │ id │ mode │ pid  │ status │ restart │ uptime │ memory      │ watching │
├───────────────┼────┼──────┼──────┼────────┼─────────┼────────┼─────────────┼──────────┤
│ parse-wrapper │ 0  │ fork │ 3499 │ online │ 0       │ 0s     │ 13.680 MB   │  enabled │
└───────────────┴────┴──────┴──────┴────────┴─────────┴────────┴─────────────┴──────────┘
Use `pm2 show <id|name>` to get more details about an app

Теперь нужно сохранить этот список процессов:

pm2 save
[PM2] Dumping processes

Список процессов pm2, выполняющийся для пользователя parse, теперь должен быть сохранен в /home/parse/.pm2.

Теперь нужно убедиться, что процесс parse-wrapper, который вы определили ранее в ecosystem.json, восстанавливается при каждом перезапуске сервера. К счастью, pm2 может генерировать и устанавливать сценарий самостоятельно.

Выйдите в сессию обычного пользователя sudo:

exit

С помощью pm2 можно определить, какие скрипты инициализации для Ubuntu будут выполняться как пользователь parse, используя /home/parse как домашний каталог:

sudo pm2 startup ubuntu -u parse --hp /home/parse/
[PM2] Spawning PM2 daemon
[PM2] PM2 Successfully daemonized
[PM2] Generating system init script in /etc/init.d/pm2-init.sh
[PM2] Making script booting at startup...
[PM2] -ubuntu- Using the command:
su -c "chmod +x /etc/init.d/pm2-init.sh && update-rc.d pm2-init.sh defaults"
System start/stop links for /etc/init.d/pm2-init.sh already exist.
[PM2] Done.

4: Установка и настройка Nginx

Мы будем использовать веб-сервер Nginx в качестве обратного прокси-сервера для parse-server, чтобы безопасно обслуживать Parse API через TLS/SSL.

Согласно требованиям мануала вы настроили сервер по умолчанию отвечать на ваше доменное имя с помощью SSL-сертификата Let’s Encrypt. Сейчас нужно обновить этот файл конфигурации, добавив туда информацию прокси.

Откройте /etc/nginx/sites-enabled/default:

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

Внутри основного блока server (он должен уже содержать блок location) нужно добавить еще один элемент location для обработки проксирования URL-адресов /parse/:

. . .
# Pass requests for /parse/ to Parse Server instance at localhost:1337
location /parse/ {
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-NginX-Proxy true;
proxy_pass http://localhost:1337/;
proxy_ssl_session_reuse off;
proxy_set_header Host $http_host;
proxy_redirect off;
}

Сохраните и закройте файл. Перезапустите Nginx:

sudo service nginx restart
* Restarting nginx nginx
...done.

5: Тестирование Parse Server

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

  • Сертификат TLS/SSL, предоставленный Let’s Encrypt
  • Экземпляр MongoDB, защищенный сертификатом Let’s Encrypt
  • parse-server, запущенный как пользователь parse по порту 1337, настроенный с помощью ключей приложения
  • pm2, управляющий процессом parse-server пользователя parse и запускающий сценарий для перезапуска pm2 во время загрузки
  • сервер nginx, защищенный сертификатом Let’s Encrypt и настроенный на проксирование соединений с https://your_domain_name/parse на экземпляр parse-server.

Теперь вы можете выполнить тестовые операции записи, чтения и выполнения cloud code с помощью curl.

Примечание: Команда curl не повредит тестовое приложение или версию, которая находится в разработке. Будьте осторожны при использовании curl с версией в производстве.

Запись данных с помощью POST

Вы должны передать curl несколько важных опций:

Опция Описание
-X POST Устанавливает тип запроса (в противном случае по умолчанию был бы GET)
-H «X-Parse-Application-Id:your_application_id» Отправляет заголовок, который идентифицирует ваше приложение на parse-server
-H «Content-Type: application/json» Отправляет заголовок, который помогает parse-server обнаружить данные в формате JSON
-d ‘{json_data} Отправляет сами данные

В результате будет такая команда:

curl -X POST \
-H "X-Parse-Application-Id: your_application_id" \
-H "Content-Type: application/json" \
-d '{"score":1337,"playerName":"8host","cheatMode":false}' \
https://your_domain_name/parse/classes/GameScore
{"objectId":"YpxFdzox3u","createdAt":"2016-02-18T18:03:43.188Z"}

Чтение данных с помощью GET

Поскольку curl отправляет запросы GET по умолчанию и вам не нужно добавлять какие-либо данные, теперь достаточно отправить Application ID:

curl -H "X-Parse-Application-Id: your_application_id" https://your_domain_name/parse/classes/GameScore
{"results":[{"objectId":"BNGLzgF6KB","score":1337,"playerName":"8host","cheatMode":false,"updatedAt":"2016-02-17T20:53:59.947Z","createdAt":"2016-02-17T20:53:59.947Z"},{"objectId":"0l1yE3ivB6","score":1337,"playerName":"Sean Plott","cheatMode":false,"updatedAt":"2016-02-18T03:57:00.932Z","createdAt":"2016-02-18T03:57:00.932Z"},{"objectId":"aKgvFqDkXh","score":1337,"playerName":"Sean Plott","cheatMode":false,"updatedAt":"2016-02-18T04:44:01.275Z","createdAt":"2016-02-18T04:44:01.275Z"},{"objectId":"zCKTgKzCRH","score":1337,"playerName":"Sean Plott","cheatMode":false,"updatedAt":"2016-02-18T16:56:51.245Z","createdAt":"2016-02-18T16:56:51.245Z"},{"objectId":"YpxFdzox3u","score":1337,"playerName":"Sean Plott","cheatMode":false,"updatedAt":"2016-02-18T18:03:43.188Z","createdAt":"2016-02-18T18:03:43.188Z"}]}

Выполнение тестового cloud code

Простой POST-запрос без реальных данных для https://your_domain_name/parse/functions/hello запустит функцию hello(), определенную в /home/parse/cloud/main.js:

curl -X POST \
-H "X-Parse-Application-Id: your_application_id" \
-H "Content-Type: application/json" \
-d '{}' \
https://your_domain_name/parse/functions/hello
{"result":"Hi"}

Если вы вместо этого перенесли свой собственный cloud code, вы можете протестировать его с помощью функции из main.js.

6: Настройка приложения на Parse Server и завершение миграции

Следующим шагом будет изменение самого клиентского приложения для использования конечной точки API Parse Server. Обратитесь к официальной документации по использованию Parse SDK с Parse Server. Вам понадобится последняя версия SDK для вашей платформы. Как и в вышеописанных тестах с curl, используйте эту строку для URL-адреса сервера:

https://your_domain_name/parse

Вернитесь на панель инструментов Parse в браузере откройте вкладку Migration. Нажмите кнопку Finalize.

Теперь ваше приложение должно быть перенесено.

Заключение

Данный мануал предлагает базовые шаги для переноса приложения Parse и установки Parse Server в единой системе Ubuntu. Конфигурация, которую мы описали здесь, подходит для приложения с низким трафиком и скромной пользовательской базой. Для хостинга большего приложения может потребоваться несколько серверов (для обеспечения избыточного хранения данных и балансировки нагрузки между конечными точками API). Даже небольшие проекты, вероятно, могут потребовать настройки инфраструктуры, о которой здесь не рассказывается.

В дополнение к официальной документации Parse Server и отслеживанию проблем проекта на GitHub при устранении неполадок вы можете изучить следующие темы:

Tags: , , , ,