Vue Storefront: Поднимаем backend +5


Продолжаю продвигать свою реферальную ссылку на IaaS-провайдера Exostate и запиливаю вторую статью своей рекламной кампании. В первой статье я развернул и запустил приложение 'vue-storefront' как отдельный сервер, без привязки к каким-либо данным, маскируя таким нелепым образом свой коммерческий интерес в продажах сервисов Exoscale. Мои жалкие потуги были успешно вскрыты коллегой aol-nnov и я был выведен на чистую воду. Что ж, второй этап моей рекламной кампании по результату не отличается от первого — такая же страница с ошибкой:


image


Фронт теперь привязан к backend'у ('vue-storefront-api'), но в браузере клиента то же самое безрадостное сообщение "Something went wrong ...". Поэтому я, отбросив ложную скромность, вынес свою реферальную ссылку до ката, а всю маскировку поместил под кат — детали того, каким образом я совмещал "Vue Storefront" с "Vue Storefront API".


Цель


На этом этапе я поставил себе задачу поднять минимально работоспособный backend и замкнуть на него фронт.


Схемка


Чтобы было немного понятнее, привожу картинку, которая у меня сложилась по результатам анализа конфигов приложений:


image


Последовательность развёртывания vue-storefront я приводил в предыдущей статье. Таким образом, нужно поднять ещё vue-storefront-api, Elasticsearch и Redis. Судя по адресу/порту в конфигах за GraphQL отвечает само vue-storefront-api.


Рабочее окружение


Для этого этапа мне также хватило small-версии сервера Linux Ubuntu 18.04 LTS 64-bit (2x 2198 MHz CPU, 2 GB RAM, 10GB disk). Что приятно в IaaS, так это возможность раз за разом начинать с чистого листа, выкидывая предыдущие неудачные эксперименты в корзину.


Первый этап


Вот скрипт для повторения действий первого этапа:


#!/usr/bin/env/bash
set -e
sudo apt update
sleep 2 # wait 2 second before upgrade to prevent en error
sudo apt upgrade -y
sudo curl -sL https://deb.nodesource.com/setup_12.x | sudo -E bash -
sudo apt install -y nodejs
sudo curl -sL https://dl.yarnpkg.com/debian/pubkey.gpg | sudo apt-key add -
sudo echo "deb https://dl.yarnpkg.com/debian/ stable main" | sudo tee /etc/apt/sources.list.d/yarn.list
sudo apt update && sudo apt install yarn
sudo npm install pm2@latest -g
sudo npm install @vue-storefront/cli@latest -g
# interactive command below: use 'Stable versions' / 'v1.10.4' (or latest) / 'Manual installation'
vsf init

Нужно будет глянуть в сторону автоматического развёртывания vue-storefront, без участия человека. Но пока вот так, с vsf.


Установка Elasticsearch


# apt install openjdk-11-jre-headless -y
# java -version
openjdk version "11.0.4" 2019-07-16
OpenJDK Runtime Environment (build 11.0.4+11-post-Ubuntu-1ubuntu218.04.3)
OpenJDK 64-Bit Server VM (build 11.0.4+11-post-Ubuntu-1ubuntu218.04.3, mixed mode, sharing)
# apt-get install apt-transport-https
# wget -qO - https://artifacts.elastic.co/GPG-KEY-elasticsearch | sudo apt-key add -
# add-apt-repository "deb https://artifacts.elastic.co/packages/7.x/apt stable main"
# apt update
# apt install elasticsearch -y

Прежде, чем запускать сервис нужно изменить конфигурацию Elasticsearch'а, чтобы можно было достучаться до сервиса снаружи (это не обязательно, но мне так удобнее):


$ sudo nano /etc/elasticsearch/elasticsearch.yml
cluster.name: habr_demo
node.name: exo01
path.data: /var/lib/elasticsearch
path.logs: /var/log/elasticsearch
network.host: 0.0.0.0
discovery.seed_hosts: []

Запуск сервиса:


# service elasticsearch restart

И проверка его работоспособности:


$ curl -X GET "http://localhost:9200/?pretty"
{
  "name" : "exo01",
  "cluster_name" : "habr_demo",
  "cluster_uuid" : "_na_",
  "version" : {
    "number" : "7.4.2",
    "build_flavor" : "default",
    "build_type" : "deb",
    "build_hash" : "2f90bbf7b93631e52bafb59b3b049cb44ec25e96",
    "build_date" : "2019-10-28T20:40:44.881551Z",
    "build_snapshot" : false,
    "lucene_version" : "8.2.0",
    "minimum_wire_compatibility_version" : "6.8.0",
    "minimum_index_compatibility_version" : "6.0.0-beta1"
  },
  "tagline" : "You Know, for Search"
}

Установка Redis


# apt install redis-server -y

Так же, как и Elasticsearch, настраиваю Redis на доступность снаружи:


# nano /etc/redis/redis.conf
bind 0.0.0.0
# service redis-server start

Запускаю сервис и проверяю его работоспособность:


# service redis-server start
# redis-cli
> set test "It's working!"
> get test
> exit

Установка vue-storefront-api


$ cd ~
$ git clone https://github.com/DivanteLtd/vue-storefront-api.git

Связывание фронта с backend'ом


Конфигурация фронта


Доступные параметры конфигурации фронта можно посмотреть в ~/vue-storefront/config/default.json. Я переопределил некоторые параметры в ~/vue-storefront/config/local.json:


{
  "server": {
    "host": "0.0.0.0",
    "port": 3000
  },
  "redis": {
    "host": "194.182.181.149",
    "port": 6379,
    "db": 0
  },
  "graphql": {
    "host": "194.182.181.149",
    "port": 8080
  },
  "api": {
    "url": "http://194.182.181.149:8080"
  },
  "elasticsearch": {}
}

server.host|.port — привязываю nodejs-сервер, который будет выдавать контент для фронта, ко всем доступным ip-адресам на соответствующий порт.


redis и graphql — привязываю на внешний ip-адрес своего тестового сервера. Я не знаю, использует ли эти настройки nodejs-сервер, выдающий контент, или эти настройки используются на стороне клиента в браузере, поэтому ставлю внешний адрес.


api.uri — здесь точно нужно прописывать внешний ip-адрес сервера, т.к. на предыдущем этапе я видел обращения к API из браузера (PWA-приложения) в логах запросов (вкладка Network в панели инструментов). Это тот адрес-порт, на котором будет висеть nodejs-сервер из приложения vue-storefront-api.


Конфигурация backend'а


Доступные параметры конфигурации также можно посмотреть в ~/vue-storefront-api/config/default.json. Вот переопределённые параметры в ~/vue-storefront-api/config/local.json:


{
  "server": {
    "host": "0.0.0.0",
    "port": 8080
  },
  "elasticsearch": {
    "host": "localhost",
    "port": 9200
  },
  "redis": {
    "host": "localhost",
    "port": 6379
  }
}

server.host|.port — привязываю nodejs-сервер, который будет выдавать контент для API, ко всем доступным ip-адресам на соответствующий порт.


elasticsearch и redis располагаются на том же хосте, что и API-сервер, поэтому я просто повторяю default-параметры.


Сборка приложений


Фронт


$ cd ~/vue-storefront
$ yarn install
$ yarn build

Backend


$ cd ~/vue-storefront-api
$ yarn install
$ yarn build

Запуск и остановка приложений


$ cd ~/vue-storefront-api
$ yarn start
...
$ cd ~/vue-storefront
$ yarn start
...
[PM2][WARN] Applications server not running, starting...
[PM2] App [server] launched (4 instances)
┌──────────┬────┬─────────┬──────┬────────┬─────────┬────────┬───────┬───────────┬────────┬──────────┐
│ App name │ id │ mode    │ pid  │ status │ restart │ uptime │ cpu   │ mem       │ user   │ watching │
├──────────┼────┼─────────┼──────┼────────┼─────────┼────────┼───────┼───────────┼────────┼──────────┤
│ api      │ 0  │ fork    │ 3690 │ online │ 0       │ 11s    │ 0%    │ 85.2 MB   │ ubuntu │ disabled │
│ o2m      │ 1  │ fork    │ 3696 │ online │ 0       │ 11s    │ 0%    │ 48.4 MB   │ ubuntu │ disabled │
│ server   │ 2  │ cluster │ 3763 │ online │ 0       │ 0s     │ 26.7% │ 66.9 MB   │ ubuntu │ disabled │
│ server   │ 3  │ cluster │ 3770 │ online │ 0       │ 0s     │ 0%    │ 68.1 MB   │ ubuntu │ disabled │
│ server   │ 4  │ cluster │ 3785 │ online │ 0       │ 0s     │ 0%    │ 40.9 MB   │ ubuntu │ disabled │
│ server   │ 5  │ cluster │ 3796 │ online │ 0       │ 0s     │ 0%    │ 40.9 MB   │ ubuntu │ disabled │
└──────────┴────┴─────────┴──────┴────────┴─────────┴────────┴───────┴───────────┴────────┴──────────┘
 Use `pm2 show <id|name>` to get more details about an app
Done in 1.49s.

Останов:


$ pm2 stop all

Просмотр логов:


$ pm2 log

Подключение к приложению


Адрес приложения: http://194.182.181.149:3000/ В результате в браузере имеем сообщение об ошибке, приведённое в самом начале, но зато в логах API-сервера можем фиксировать обращения браузера к API:


$ pm2 log
3|server  | 2019-11-16 07:44:33: Error during render : /
3|server  | 2019-11-16 07:44:33: Error: FetchError in request to ES: FetchError: invalid json response body at http://194.182.181.149:8080/api/catalog/vue_storefront_catalog/product/_search?_source_exclude=%2A.msrp_display_actual_price_type%2Crequired_options%2Cupdated_at%2Ccreated_at%2Cattribute_set_id%2Coptions_container%2Cmsrp_display_actual_price_type%2Chas_options%2Cstock.manage_stock%2Cstock.use_config_min_qty%2Cstock.use_config_notify_stock_qty%2Cstock.stock_id%2Cstock.use_config_backorders%2Cstock.use_config_enable_qty_inc%2Cstock.enable_qty_increments%2Cstock.use_config_manage_stock%2Cstock.use_config_min_sale_qty%2Cstock.notify_stock_qty%2Cstock.use_config_max_sale_qty%2Cstock.use_config_max_sale_qty%2Cstock.qty_increments%2Csmall_image%2Csgn%2C%2A.sgn&from=0&request=%7B%22query%22%3A%7B%22bool%22%3A%7B%22filter%22%3A%7B%22bool%22%3A%7B%22must%22%3A%5B%7B%22terms%22%3A%7B%22category.name.keyword%22%3A%5B%22Tees%22%5D%7D%7D%2C%7B%22terms%22%3A%7B%22visibility%22%3A%5B2%2C3%2C4%5D%7D%7D%2C%7B%22terms%22%3A%7B%22status%22%3A%5B0%2C1%5D%7D%7D%5D%7D%7D%7D%7D%7D&size=8&sort=created_at%3Adesc reason: Unexpected end of JSON input
3|server  |     at w (core/server-entry.ts:23:25)
3|server  |     at server-bundle.js:1:468554
3|server  |     at processTicksAndRejections (internal/process/task_queues.js:93:5)
3|server  | 2019-11-16 07:44:33: whole request [/error]: 56ms
0|api     | 2019-11-16 07:44:34: OPTIONS /api/cart/create?token= 204 1.320 ms - 0
0|api     | 2019-11-16 07:44:34: POST /api/cart/create?token= 200 465.416 ms - 56
0|api     | 2019-11-16 07:44:34: OPTIONS /api/cart/pull?token=&cartId=35bea3b7dcf8fb841187d69489fe8c51 204 0.239 ms - 0
0|api     | 2019-11-16 07:44:34: GET /api/cart/pull?token=&cartId=35bea3b7dcf8fb841187d69489fe8c51 200 103.949 ms - 24

Заключение


Удалось продвинуться ещё на шаг вперёд — Vue Storefront PWA общается с Vue Storefront API. Далее нужно разбираться с наполнением backend'а. Какие данные индексируются в Elasticsearch, как они туда попадают и как извлекаются.


Спасибо за прочтение и кликайте по моей реферальной ссылке. Я ж, блин, ради неё тут всё это наворотил.




К сожалению, не доступен сервер mySQL