Разворачиваем Graphcool Prisma на голом железе

В последнее время я много пишу про GraphQL и т.п., потому что тема действительно очень интересная, технологии очень важные и перспективные, а так же все это отлично состыкуется с MODX, дабы придать жизни внешней части сайта и получить более гибкое API для взаимодействия фронта с бэком. Сегодня я расскажу про graphcool-prisma. Вообще еще недавно они были просто graphcool (и устанавливались в систему именно как graphcool), затем они внезапно стали graphcool-framework (и еще так они вчера мне были известны, и устанавливались как graphcool-framework, хотя и во всех подсказках выводилось как graphcool, что доставляло много путаницы при наличии в системе и graphcool и graphcool-framework). А сегодня, когда я сел написать статью, они вдруг стали просто Prisma. Ну ппц... (хотя prisma, конечно же, проще запомнить и пишется проще). При этом нпм-страница prisma предлагает устанавливать prisma-cli, а там в свою очередь речь идет о graphcool. Короче, еще раз, ппц... Но это они не со зла. Проект очень быстро развивается и видимо какие-то внутренние архитектурные вещи заставляют так делать, типа, выбирайте: или название будет без изменений, или новые современные фишки. Я за современные фишки, а с названием потерплю... Уточнение к стилю изложения: я пишу по мере работы с сервером. Однозначно буду сталкиваться с какими-то подводными камнями и т.п., где-то в процессе находить ответы, поэтому в статье будет много уточнений, метаний по поверхности и т.п. Извиняюсь, если где-то запутано будет и не конкретно. Внимание! Если вы планируете просто запускать свою копию призма-сайта, внизу есть инструкция по быстрой установке одним скриптом. Итак, что же такое Prisma? Это готовое решение для создания своего собственного API на базе GraphQL+ Apollo и еще много все. Главная задача - быстро развернуть основу под то, чтобы принимать внешние запросы, выполнять операции с хранилищем данных, отдавать ответы и т.п. Отдельная строчка - готовая система авторизации и политик безопасности. В общем, там практически все есть для настройки полноценного бэкэнда. И в процессе мы рассмотрим много классных фишек. И, скорее всего, именно эта платформа послужит основой для обновленной версии ShopModxBox. К концу статьи вы поймете почему. А теперь от слов к делу. Сегодня мы развернем призму на сервере с нуля. В качестве хостинг-площадки предлагаю flops.ru (ссылка реферальная). Я не первый год с ними работаю и хотя там есть ограничения на дисковые операции, о которых они не говорят (что очень некрасиво), в целом они очень неплохи и для средних проектов годятся очень даже (под блокчейн не годятся точно, я проверял))). А еще там было 500 рублей на счет при регистрации (надо только карту по-моему указать, но с нее ничего не списывается без вас). Этого вполне достаточно на тесты. Для начала я взял 1Gb памяти, но в процессе работы ожидаемо выяснилось, что этого мало. Поднял до двух (плановая стоимость 700 руб/месяц). Но скорее всего для комфортной работы надо 3Gb (1000 рублей). Разворачиваем чистый сервер. Я работаю в основном только с ubuntu, на других версиях linux не проверял, на windows тоже. В данном случае я развернул ubuntu-16 x64. Первым же делом выполняем apt update и apt upgrade, дабы актуализировать OS. Устанавливаем nginx sudo apt install nginx Устанавливаем прочее ПО - Текстовый редактор. Необязательный шаг. Мне нравится mc, поэтому я его ставлю. Но каждый выбирает для себя свое (может даже vim). sudo apt install mc - sudo apt install git (контроль версий файлов, без него никуда). Создаем нового sudo-пользователя. Некоторые программы выполняются именно от sudo-пользователей (не обязательно root, просто с правами sudo), например docker. useradd USERNAME -d /home/USERNAME -G sudo,www-data -s /bin/bash (USERNAME конечно же заменить на свое, здесь и далее). passwd USERNAME (здесь запросит ввести и подтвердить пароль для пользователя). mkdir /home/USERNAME Чтобы у пользователя работала история команд, подсветка в консоли и т.п., надо создать заготовленный .bashrc cd /home/USERNAME wget https://gist.githubusercontent.com/Fi1osof/2f8ea23f5411c5c7a0e0025f04941aee/raw/.bashrc Установим нового пользователя владельцем своей директории со всем содержимым chown USERNAME: /home/USERNAME -R Чтобы каждый раз при вызове sudo на новом пользователе не приходилось вводить пароль, разрешим ему sudo без пароля. Открываем для редактирования файл mcedit /etc/sudoers Находим %sudo ALL=(ALL:ALL) ALL и переписываем на %sudo ALL=(ALL:ALL) NOPASSWD: ALL Все, теперь можно авторизовываться этим пользователем и продолжать работу от его имени. Устанавливаем docker sudo apt-get install software-properties-common python-software-properties sudo apt-key adv --keyserver hkp://p80.pool.sks-keyservers.net:80 --recv-keys 58118E89F3A912897C070ADBF76221572C52609D sudo apt-add-repository 'deb https://apt.dockerproject.org/repo ubuntu-xenial main' sudo apt-get update Убедимся, что мы собираемся установить Docker из репозитория Docker, а не из репозитория по умолчанию Ubuntu 16.04: apt-cache policy docker-engine В списке должен быть apt.dockerproject.org Если да, то выполняем непосредственно установку. sudo apt-get install -y docker-engine Проверяем docker -v Docker version 17.05.0-ce, build 89658be По умолчанию, запуск команды docker требует привилегий root, что означает, что вы должны использовать sudo. Также эта команда может запускаться пользователем, включённым в группу docker, которая автоматически создаётся при установке Docker. При попытке использования команды docker пользователем без привилегий sudo или пользователем, не входящим в группу docker, вы получите такой результат: docker: Cannot connect to the Docker daemon. Is the docker daemon running on this host?. See 'docker run --help'. Для того, чтобы не вводить sudo каждый раз при запуске docker, добавьте имя своего пользователя в группу docker: sudo usermod -aG docker $(whoami) (добавляет именно текущего пользователя, поэтому убедитесь, что вы авторизованы нужным пользователем). Для добавления произвольного пользователя sudo usermod -aG docker USERNAME После этого желательно перелогиниться. Источник: https://www.digitalocean.com/community/tutorials/docker-ubuntu-16-04-ru Устанавливаем docker-compose Важно! Обратите внимание на версию в ссылке. Прежде чем качать, лучше проверить какая актуальная версия сейчас и нужную подставить в адрес. sudo curl -L https://github.com/docker/compose/releases/download/1.18.0/docker-compose-`uname -s-uname -m` -o /usr/local/bin/docker-compose sudo chmod +x /usr/local/bin/docker-compose Источник: https://docs.docker.com/compose/install/#install-compose Устанавливаем node-js После того, как все обновится, устанавливаем node-js (с чем и npm установится). curl -sL https://deb.nodesource.com/setup_10.x | sudo -E bash - sudo apt-get install -y nodejs Проверяем node -v Должно быть типа v10.15.3 Устанавливаем yarn Yarn - совместный фейсбука с гуглом менеджер пакетов типа npm. Он здесь тоже понадобится. Способ проще: sudo npm i -g yarn Способ сложнее: curl -sS https://dl.yarnpkg.com/debian/pubkey.gpg | sudo apt-key add - echo "deb https://dl.yarnpkg.com/debian/ stable main" | sudo tee /etc/apt/sources.list.d/yarn.list sudo apt-get update && sudo apt-get install yarn Проверяем yarn -v 1.3.2 Устанавливаем призму глобально. sudo npm install -g prisma Проверяем prisma -v Должно быть типа prisma/1.0.4 (linux-x64) node-v9.4.0 Запускаем локальную службу. Выше я писал инструкцию про установку докера. Здесь докер обязателен, так что если не установили, обязательно надо установить. Локальная служба призмы - это линукс-сервер внутри нашего линукс-сервера (благодаря использованию докера). То есть призма устанавливает под себя отдельно MySQL и прочее ПО в контейнерах с минимальными рисками конфликтов с уже установленным ПО. Выполняем sudo prisma local start Запускаться будет некоторое время, так как это docker, будет установлена mysql и прочие зависимости. Если все ОК, получите типа Booting local development cluster 31.6s Вот теперь, когда локальный сервер призмы запущен, можно создавать и деплоить непосредственно проекты. Уточню, что эта служба единая и может обслуживать сразу несколько отдельных проектов. Ниже я немного раскрою эту кухню. Создаем Prisma-проект. sudo chown USERNAME /var/www -R Неоднозначный шаг, так как веб-проекты должны выполняться от имени веб-сервера и права на файлы должны быть для веб-сервера, но у нас не обычный веб-проект, да и вопросы тонкой настройки прав на веб-сервере мы сейчас не рассматриваем, но этот счет может будет отдельная статья (а может и нет, так как в сети полно материала от более опытных админов). Сейчас в этой папке ничего нет, так что я просто ее под себя резервирую, хотя npm-проект не привязывается к конкретной папке и может быть где угодно. Просто мне /var/www привычней. cd /var/www/ prisma init Выбираем GraphQL server/fullstack boilerplate (recommended) Directory for new GraphQL project (.) если папка пустая, то можно оставить так (будет создан новый проект в текущей папке). Если нет, то не позволит этого, надо указать название проекта, например, hello-world (как это принято в начале Пути делать). Далее, чтобы интересней было, выбираем react-fullstack-basic React app + GraphQL server (incl. database ), будет создан не только GraphQL-проект с АПИ, но и небольшая веб-морда на реакте. Последний шаг: выбираем local Local cluster (requires Docker), то есть полный стек будет работать на нашем сервере, а не использовать сторонние сервера graph.cool Если все прошло успешно, вы получите сообщение типа Чуть распишу указанные пять шагов со своими комментариями. 1,2. Переходим в папку hello-world/dev и запускаем API-сервер командой yarn start. Если все ОК, увидите Server is running on http://localhost:4000 Для выполнения 3-го шага придется открыть еще одну консоль, так как в текущей выполняется yarn start, и если вы закроете ее, то API-сервер остановится. 3. Открыли новую консоль и переходим в /var/www/hello-world 4,5. Запускаем веб-сервер yarn start. Этот сервер будет отвечать за пользовательский интерфейс. Если все ОК, увидите типа Local: http://localhost:3000/ On Your Network: http://10.7.112.123:3000/ В моем случае призма допустила ошибку из-за своеобразной настройки сервера хостинг-провайдером, и показала внутренний ip-адрес, а не внешний. В любом случае, если вы на localhost запускаете, то можете и указывать localhost. Если нет, то еще немного нам придется повоевать. Для это открываем файл /www/hello-world/src/index.js, находим в нем localhost и меняет на реальный ip сервера или доменное имя. После этого уже запускаем веб-сервер командой yarn start Если все у вас заработало как надо, API-консоль вы увидите в браузере на 4000 порту, например http://prismagraphql.ru:4000/ , веб-морду на 3000-ом, к примеру http://prismagraphql.ru:3000/ Веб-морда тестовая, можно перейти на вкладку http://prismagraphql.ru:3000/drafts (черновики), создать запись и, перейдя в нее, опубликовать. В API-консоли можно сформировать нужный вам запрос и выполнить, получив информацию. Пара примеров: Список опубликованных топиков: Список черновиков: Отдельная мега-фича: генерация CURL-строки для API-запросов. Кликаем кнопочку CURL и в буфер обмена попадает строка типа Эту строку можно выполнить просто в консоли на любом сервере и получить JSON-ответ с данными. Запуск демона и мониторинг. Выше я писал: Для выполнения 3-го шага придется открыть еще одну консоль, так как в текущей выполняется yarn start, и если вы закроете ее, то API-сервер остановится. Конечно же для боевого режима это совсем не годится. Надо иметь возможность запускать процесс так, чтобы он уже жил своей жизнью и можно было спокойно закрывать все консоли. В этом нам поможет очень крутая утилита pm2. Устанавливаем ее тоже глобально. sudo npm i -g pm2 Теперь запустим api-сервер через него. Переходим в server/ и выполняем pm2 --name server start npm -- start После этого посмотрим список всех запущенных процессов на pm2. pm2 list. Должна вывестись табличка со списком процессов (сейчас скорее всего только один процесс server) и если с ним все хорошо, то статус online и uptime больше нуля. Там же информация об использовании процессора и оперативки. После этого зайдите в API-консоль на 4000-ом порту и если все ОК, она работает. Чтобы остановить службу, выполняем pm2 stop server. Веб-консоль перестанет быть доступной. При этом если вы выполните pm2 list, процесс server в нем по прежнему будет, просто со статусом stopped. Если надо, можно опять его запустить уже через сам pm2 командой pm2 start server Согласитесь, так гораздо удобней :) А теперь через него же запустим и веб-морду. Для этого переходим в корень проекта cd /var/www/hello-world/, но теперь выполним еще один предварительный шаг, а именно сборку конечных скриптов, выполнив команду yarn build После выполнения этой команды у нас появится папка build со всеми готовыми скриптами. Теперь надо эти скрипты запустить. В призме пока не указана команда для запуска сервера со сжатыми скриптами, поэтому используем для запуска программу serve. Устанавливаем serve глобально. sudo npm i -g serve И запускаем server через pm2. PORT=3000 pm2 --name front start serve -- -s build Выполняем pm2 и смотрим список процессор. Теперь у нас там есть server и front. Открываем браузер на 3000 порту и должно работать. У меня работает http://prismagraphql.ru:3000/ Вот теперь мы можем закрыть все свои консоли, а веб-сервер продолжит работать :) А где же обещанный мониторинг? ОК, будет вам и мониторинг :) Для этого опять подключимся к серверу и выполним pm2 monit Вот теперь откроется более подробная информация о выполняемых процессах (в нашем случае это front и server). Но такой вид не очень радует глаз (хотя и определенно несет свою пользу). Сделаем теперь все гораздо красивее. Прервем выполнение мониторинга Ctrl+C и выполним pm2 register. В ответ вы получите вопрос есть у вас аккаунт на https://keymetrics.io/ или нет. Выберите свой ответ. Если n, вероятней всего там же будет предложена регистрация (но я не знаю, у меня уже был аккаунт). Так или иначе, дойдите до окончательной регистрации и будете вознаграждены вот таким интерфейсом мониторинга: Согласитесь, так гораздо красивее :) Плюс к этому не требуется постоянно сидеть в консоли, а можно в любое время зайти в браузер и посмотреть что у вас на сервере творится. И можно даже оттуда перезагружать службы на своем сервере И напоследок еще один момент: как я и говорил выше, призма запускает под себя мускул в контейнере докер. И вот достучаться до этого контейнера не очень-то и просто, то есть если мы хотим запустить phpMyAdmin и заглянуть в БД, то придется изрядно попотеть (точнее мне пришлось, а далее будет зависеть от того, что и где они еще поменяют, так как вчера еще одно было и все работало, а сегодня уже вчерашние примеры не работают и пришлось покопаться поглубже в поисках точек входа). Вот строка для установки докер-контейнера phpmyadmin с коннектом в нужный нам докер: sudo docker run -d --link prisma-db:db --network local_prisma -p 8080:80 phpmyadmin/phpmyadmin В версии prisma-1.15+ чуть другая строка: docker run -d -e UPLOAD_LIMIT=100M --name pma --link prisma_mysql_1:db --network prisma_default -p 8090:80 phpmyadmin/phpmyadmin Здесь две нужные нам переменные: prisma-db:db и local_prisma. UPLOAD_LIMIT=100M - задает лимит размера импортируемых файлов. Чтобы найти первую, выполняем prisma local eject В результате в домашнюю папку пользователя будут записаны два файла docker-compose.yml и env. В env мы найдем export SQL_CLIENT_HOST="prisma-db". Вот этот хост нам и нужен для формирования переменной prisma-db:db. Там же указаны и другие полезные для нас переменные типа логина и пароля для доступа к БД. Для поиска второй переменной выполняем sudo docker network ls Будет выведена таблица запущенных процессор. Там надо типа a66536c90365 local_prisma bridge local Вот local_prisma отсюда нам и нужна. Выполняем вышеуказанную команду и если все ок, на порту 8080 будет запущен phpMyAdmin (порт конечно же можно указать другой). Указываем логин и пароль из env и все, мы в БД. Структуру БД нет смысла приводить, так как вчера она еще была одна, сегодня другая, а завтра может будет третья. Единственное отмечу, что под каждый проект создается отдельная БД (все их видно в списке через phpMyAdmin). На сегодня, думаю, хватит. Впереди будет еще много сопутствующего материала типа как создавать свои типы и обработчики для API, примеры авторизации, интеграции с MODX и т.д. и т.п. Пока что осваивайте это. очень советую не пропускать этот материал, так как это отправная точка. UPD: локально у меня на имеющейся системе призма не запускалась. Долго воевал, но победил. Проблему и решение описал здесь: https://www.graph.cool/forum/t/cannot-start-prisma-local-mysql-error-0-0-0-0-3306-bind-address-already-in-use/2190 UPD2: Крайне полезная статья в плане понимания как в призме webpack устроен: https://habrahabr.ru/company/plarium/blog/326520/ А то запускаешь yarn start, дев-сервер работает, а откуда ноги растут - не понятно. UPD3: Быстрая установка одним скриптом. Если вы планируете в ознакомительных целях запустить призма-сайт, можно воспользоваться скриптом быстрой установки. Сайт будет в итоге запущен от рута, но для тестов это не страшно.

Отличная статья, спасибо! Не могу войти в phpMyAdmin. Указываю пароль по умолчанию из env SQL_CLIENT_USER="root" SQL_LOGS_PASSWORD="graphcool" Не входит. Других логинов и паролей не нашел. Где ошибаюсь?

Попробуйте prisma:prisma или root:prisma, они писали о планах теперь такой использовать

Классное пособие, было бы здорово его обновить и добавить поддержку https. Сам не могу разобраться)

Читайте документацию по react-scripts, для фронта он используется. Если просто тестовый сертификат сгенерировать, то запускаете HTTPS=true yarn start. Если использовать сторонний рабочий сертификат, то я лично настраиваю его на уровне nginx.

Также настраиваю его на уровне Nginx для сайтов по этому учебнику https://blog.ssdnodes.com/blog/tutorial-extending-docker-nginx-host-multiple-websites-ssl/ , но к сожалению не смог настроить его для сервера Prisma. Будет здорово, если вы продолжите цикл своих познавательных статей по интеграции с Prisma.

Вам не надо настраивать ssl на уровне призмы, если вы настраиваете ssl на уровне nginx. На nginx вы принимаете шифрованный трафик, и с него проксируете на призму (уже дешифрованный). Призма, в свою очередь, работает по обычному протоколу, но при этом напрямую не доступна извне, только через nginx.

Спасибо! В теории все понятно, но на практике не хватает опыта без учебника, так как я больше фронт =)

Сайт все =(?

@edit, сайт не "все". Просто пользователи не хотят ничего писать и спрашивать, видимо.