Перейти к содержанию

Развертывание и мониторинг процессов для здорового приложения

Мы создаем новый и блестящий Fastify API и хотим выложить его в интернет, чтобы собрать отзывы перед официальным запуском. Когда мы смотрим в интернете, то видим множество вариантов... но что же нам использовать? После этого нам нужно будет понять, как следить за состоянием нашего сервера (ведь мы всегда следим за своими приложениями, верно?).

В этой главе мы рассмотрим основы развертывания монолита с использованием Docker, MongoDB и Fly.io. Мы также рассмотрим ключевые метрики Node.js, как извлечь их из нашего приложения с помощью Prometheus, а затем как легко просмотреть их в Grafana.

Именно этот путь обучения мы рассмотрим в данной главе:

  • Тестирование нашего образа Docker для развертывания
  • Размещение нашей БД на MongoDB Atlas
  • Выбор облачного провайдера
  • Развертывание на Fly.io
  • Настройка непрерывного развертывания
  • Сбор данных о процессах приложения

Технические требования

Как уже упоминалось в предыдущих главах, вам понадобится следующее:

  • Работающая установка Node.js 18
  • Текстовый редактор для работы с кодом примера
  • докер
  • HTTP-клиент для тестирования кода, например cURL или Postman
  • Аккаунт на GitHub

Все фрагменты в этой главе находятся на GitHub.

Тестирование нашего образа Docker с локальным развертыванием

В Главе 6 мы настроили наше приложение для использования с Docker. Это очень важный шаг для нашего приложения TODO List. Теперь пришло время протестировать образ с помощью Docker Compose, чтобы убедиться, что все работает так, как ожидалось.

Давайте повторим наш DockerFile с небольшими изменениями:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
FROM node:18-alpine as builder
WORKDIR /build
COPY package.json ./
COPY package-lock.json ./
ARG NPM_TOKEN
ENV NPM_TOKEN $NPM_TOKEN
RUN npm ci --only=production --ignore-scripts
FROM node:18-alpine
RUN apk update && apk add --no-cache dumb-init
ENV HOME=/home/app
ENV APP_HOME=$HOME/node/
ENV NODE_ENV=production
WORKDIR $APP_HOME
COPY --chown=node:node . $APP_HOME
COPY --chown=node:node --from=builder /build $APP_HOME
USER node
EXPOSE 3000
ENTRYPOINT ["dumb-init"]
CMD ["./node_modules/.bin/fastify", "start", "-a", "0.0.0.0", "-l",
"info", "--options", "app.js"]

Как видите, мы изменили CMD, чтобы напрямую вызывать команду fastify со следующими параметрами:

  • -a 0.0.0.0 — это важно для того, чтобы контейнер мог прослушивать все адреса.
  • --options обеспечивает загрузку опций из app.js.
  • -l info настраивает уровень протоколирования.

Теперь мы можем протестировать это развертывание с помощью локального docker-compose, что полезно для проверки того, что все работает хорошо локально, так как это проще для отладки, чем в облаке. В частности, мы собираемся подключить наше приложение к экземпляру MongoDB, запущенному также в Docker.

Сохраним следующий файл под именем docker-compose-test.yml:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
version: '3.7'
services:
    mongo:
        image: mongo:5
        volumes:
            - data:/data/db
    app:
        build:
            context: ./
            dockerfile: Dockerfile
        ports:
            - '3042:3000'
        environment:
            JWT_SECRET: changethis
            MONGO_URL: mongodb://mongo:27017/todo
volumes:
    data:

Давайте пройдемся построчно по содержимому этого файла. Во-первых, мы определяем версию файла docker-compose, так как разные версии имеют разный синтаксис. Во-вторых, мы определяем два сервиса: один из них — mongo, наша база данных, а другой — app, который мы собираем из текущей папки. Обратите внимание, что в определении app мы указываем переменные окружения, которые нужны нашему приложению:

  • JWT_SECRET, которую следует изменить для обеспечения безопасности вашего приложения.
  • MONGO_URL, которая определяет, как мы подключаемся к нашей базе данных. Обратите внимание, что мы используем mongo в качестве доменного имени — Docker автоматически преобразует его в хост, на котором работает наша MongoDB!

Наконец, важно рассказать о концепции портов в Docker. В файле docker-compose-test.yml мы указываем "3042:3000": мы сопоставляем TCP-порт 3042 хоста с портом 3000 контейнера. Таким образом, теперь мы можем перейти по адресу http://localhost:3042/ и увидеть, что наше приложение запущено.

При такой настройке сохраняйте базу данных в томе данных, чтобы избежать потери данных при удалении контейнера (например, при его обновлении).

Благодаря docker-compose мы можем проверить и протестировать, что наш DockerFile работает так, как ожидалось. Итак, выполните следующее:

1
docker-compose -f docker-compose-test.yml up

Docker загрузит базовые образы, соберет наш образ, а затем выполнит наше приложение (если у вас в папке нет package-lock.json, запустите npm i для его создания, иначе docker build выдаст ошибку). Теперь мы можем curl http://localhost:3042/, чтобы убедиться, что все работает так, как ожидалось.

Кластер MongoDB

В документации MongoDB рекомендуется использовать не менее трех узлов MongoDB, поскольку в производстве мы хотим иметь не менее двух копий данных, чтобы выдержать отказ одного узла. В нашем «локальном» развертывании мы используем только одну — это небезопасно, но для наших целей вполне подходит.

Теперь мы хотим перенести нашу установку в облако. Для этого сначала мы воспользуемся MongoDB Atlas для создания кластера MongoDB из трех узлов.

Хостинг нашей БД на MongoDB Atlas

Как мы уже писали, самый простой способ создать кластер MongoDB — это использовать MongoDB Atlas, который предоставляет 512 МБ хранилища бесплатно. Чтобы воспользоваться этим способом, следуйте руководству по настройке MongoDB Atlas — хотя мы приводим здесь скриншот, процесс может отличаться.

Первым шагом будет регистрация на MongoDB Atlas. После завершения процесса регистрации и проверки электронной почты вы можете выбрать уровень, на котором будет создана ваша новая база данных. Мы выберем вариант Shared, который является бесплатным. После выбора уровня мы выбираем, где будет расположен наш экземпляр MongoDB. Выбирайте то место, которое находится рядом с вами!

Теперь пришло время добавить механизм безопасности для нашей базы данных. Убедитесь, что вы находитесь на вкладке Quickstart под SECURITY, как показано на Рисунке 10.1. Для этой книги выберите метод аутентификации Имя пользователя и пароль.

Рисунок 10.1: Как настроена наша база данных в MongoDB Atlas

Рисунок 10.1: Как настроена наша база данных в MongoDB Atlas

Самая важная настройка для этой книги — разрешить соединения со всех IP-адресов. Это можно сделать в поле IP Address на предыдущем рисунке; введите 0.0.0.0/0, что позволит определить все IP-адреса. Хотя это очень небезопасно, надежного пароля более чем достаточно для простых приложений.

Другие способы подключения

Обратитесь к документации MongoDB Atlas для настройки дополнительных безопасных методов подключения.

Теперь вам нужно скопировать строку подключения к вашей базе данных MongoDB. Это должно быть сделано в опции, похожей на Подключиться к вашей базе данных (мы говорим «похожей», так как не можем назвать точную опцию, потому что она, вероятно, устарела к моменту прочтения).

Теперь мы можем запустить строку подключения в нашем терминале:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
$ mongosh
"mongodb+srv://fastifytodolist.ypq0399.mongodb.net/myFirst
Database" --apiVersion 1 --username fastify
Enter password: ****************
Current Mongosh Log ID: XXXXXXXXXXX
Connecting
to:          mongodb+srv://<credentials>@fastifytodolist
.ypq0399.mongodb.net/myFirstDatabase?appName=mongosh+1.5.1
Using MongoDB:          5.0.9 (API Version 1)
Using Mongosh:          1.5.1
For mongosh info see: https://docs.mongodb.com/mongodb-shell/
To help improve our products, anonymous usage data is collected and
sent to MongoDB periodically (https://www.mongodb.com/legal/privacy-
policy).
You can opt-out by running the disableTelemetry() command.
Atlas atlas-lk17c9-shard-0 [primary] myFirstDatabase>

Все сработало, как и ожидалось! Теперь мы можем попробовать подключить наше приложение с нашей машины разработки к нашей новой базе данных в облаке следующим образом:

1
2
MONGO_URL="mongodb+srv://USERNAME:PASSWORD@YOURDBDOMAIN/
myFirstDatabase" JWT_SECRET=supsersecret npm start

В качестве альтернативы можно добавить следующее и заменить значение MONGO_URL в файле .env:

1
2
3
MONGO_URL="mongodb+srv://USERNAME:PASSWORD@YOURDBDOMAIN/
myFirstDatabase"
JWT_SECRET=supsersecret

Затем в терминале выполните команду npm start.

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

Выбор облачного провайдера

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

Вот список провайдеров, на которых стоит обратить внимание:

  • Heroku — он начал поддерживать Node.js в 2011 году и на сегодняшний день является одним из самых зрелых и стабильных продуктов.
  • Google Cloud Run — основан на Knative и стеке Kubernetes.
  • AWS Lambda — это оригинальная «бессерверная» среда исполнения, позволяющая выполнять «функции», которые могут эластично масштабироваться. Каждая функция обрабатывает только один запрос за раз: хотя это упрощает масштабирование и эксплуатацию, приложения с большим объемом ввода-вывода оказываются в невыгодном положении. AWS Lambda основана на Firecracker.
  • Vercel — платформа развертывания для фронтенд-команд, основанная на AWS Lambda.
  • Fly.io — основана на Firecracker и, как таковая, обеспечивает чрезвычайно быстрый перезапуск процессов и возможность «масштабирования до нуля».

Вы можете найти список других serverless deployments.

Node.js и Fastify выигрывают, когда используются для обслуживания множества параллельных запросов. Это позволяет максимально использовать время простоя в цикле событий для обработки других запросов. Поэтому лучше всего использовать «полные» серверы, которые можно динамически масштабировать в зависимости от нагрузки.

Развертывание на AWS Lambda

Если вы хотите развернуть приложение на AWS Lambda, это возможно использовать. Преимущество нативной разработки в Lambda заключается в том, что вы можете разрабатывать свое приложение так же, как если бы оно было развернуто в стандартном процессе Node.js.

В этой книге мы рассмотрим Fly.io, поскольку он выглядит наиболее инновационным решением и обеспечивает простую автоматизацию непрерывного развертывания.

Развертывание на Fly.io

Основной интерфейс Fly.io — это инструмент командной строки под названием flyctl, который мы можем установить следующим образом:

  • iwr https://fly.io/install.ps1 -useb | iex в Windows PowerShell.
  • curl -L https://fly.io/install.sh | sh в Linux и macOS.
  • Вы также можете использовать brew install flyctl на macOS.

Зарегистрироваться на Fly.io очень просто: выполните команду flyctl auth signup. Мы рекомендуем подключить ваш аккаунт GitHub, так как он понадобится вам позже.

Теперь мы можем развернуть Fly.io, выполнив команду flyctl launch в текущей рабочей директории (убедитесь, что в ней нет файлов fly.toml) и ответив на следующие вопросы:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
$ flyctl launch
Creating app in /path/to/Chapter 10
Scanning source code
Detected a Dockerfile app
? App Name (leave blank to use an auto-generated name):
? Select organization: Matteo Collina (personal)
? Select region: fra (Frankfurt, Germany)
Created app shy-fog-346 in organization personal
Wrote config file fly.toml
? Would you like to setup a Postgresql database now? No
? Would you like to deploy now? Yes
Deploying shy-fog-346
...

Первые вопросы, которые задает flyctl, касаются нашего приложения: какой аккаунт использовать, где его запустить и нужна ли нам база данных PostgreSQL. Затем он создает наш контейнер и развертывает наше приложение на Fly.io.

После этого скрипт пытается развернуть наше приложение до тех пор, пока не потерпит неудачу:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
...
Preparing to run: `dumb-init ./node_modules/.bin/fastify start -l info
--options app.js` as node
2022/07/28 12:54:40 listening on [fdaa:0:582d:a7b:c07e:2d5f:9db0:2]:22
(DNS: [fdaa::3]:53)
Error: env must have required property 'MONGO_URL', env must have
required property 'JWT_SECRET'
    at loadAndValidateEnvironment (/home/app/node/node_modules/@
fastify/env/node_modules/env-schema/index.js:93:19)
    at loadAndValidateEnvironment (/home/app/node/node_modules/@
fastify/env/index.js:8:20)
    at Plugin.exec (/home/app/node/node_modules/avvio/plugin.
js:131:19)
    at Boot.loadPlugin (/home/app/node/node_modules/avvio/plugin.
js:273:10)
    at process.processTicksAndRejections (node:internal/process/task_
queues:82:21) {
  errors: [
    {
      instancePath: '',
      schemaPath: '#/required',
      keyword: 'required',
      params: [Object],
      message: "must have required property 'MONGO_URL'"
    },
    {
      instancePath: '',
      schemaPath: '#/required',
      keyword: 'required',
      params: [Object],
      message: "must have required property 'JWT_SECRET'"
    }
  ]
}2022-07-28T12:54:42.000 [info] Main child exited normally with code:
1
2022-07-28T12:54:42.000 [info] Starting clean up.
***v2 failed - Failed due to unhealthy allocations - no
   stable job version to auto revert to and deploying as v3
Troubleshooting guide at https://fly.io/docs/getting-started/
troubleshooting/
Error abort

Как видно из сообщения об ошибке, сервер не может найти переменные окружения JWT_SECRET и MONGO_URL. Давайте добавим их в качестве секретов Fly.io:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
$ flyctl secrets set MONGO_URL="mongodb+srv://
YOURUSERNAME:[email protected]/myFirstDatabase"
...
$ fly secrets set JWT_SECRET="ALONGRANDOMSTRING"
Release v4 created
==> Monitoring deployment
...
./node_modules/.bin/fastify start -l info --options app.js` as node
[info]2022/07/28 13:19:02 listening on [fdaa:0:582d:a7b:66:b7
3e:6147:2]:22 (DNS: [fdaa::3]:53)
[info]
{"level":30,"time":1659014344254,"pid":517,"hostname":"b73e6147",
"msg":"Server listening at http://[::1]:3000"}
[info]
{"level":30,"time":1659014344262,"pid":517,"hostname":"b73e6147",
"msg":"Server listening at http://127.0.0.1:3000"}
--> v4 failed - Failed due to unhealthy allocations - no stable job
version to auto revert to and deploying as v5
--> Troubleshooting guide at https://fly.io/docs/getting-started/
troubleshooting/

О нет! Он все еще не работает. Что случилось? Давайте откроем файл fly.toml (файл конфигурации Fly.io): там есть строка internal_port = 8080, которая предписывает Fly.io направлять все входящие запросы на порт 8080 нашего контейнера. Однако наше приложение запускается на порту 3000! Давайте изменим строку на internal_port = 3000 и запустим flyctl launch.

Ура! Наше приложение теперь развернуто по адресу https://shy-fog-346.fly.dev/ (замените на свой URL).

В этом разделе мы настроили Fly.io и установили два секрета приложения на Fly.io.

Настройка непрерывного развертывания

Мы настраиваем систему непрерывного развертывания, чтобы каждый коммит, добавленный в основную ветку вашего репозитория на GitHub, автоматически разворачивался на Fly.io.

Автоматизация проекта с помощью GitHub Actions

Мы рекомендуем автоматизировать процесс разработки с помощью GitHub Actions. С их помощью можно автоматически запускать автоматизированные тесты, развертывать проект и даже синхронизировать проблемы с другими программами управления.

Для начала давайте создадим репозиторий на GitHub, клонируем его локально и загрузим туда наш код! Чтобы загрузить наш код на GitHub, выполним в терминале команды git clone, git add, git commit и git push.

Использование Git и GitHub

Если вы не знакомы с Git и GitHub, мы рекомендуем вам следовать руководству GitImmersion tutorial, а также https://docs.github.com/en/get-started/quickstart/create-a-repo, чтобы создать репозиторий на GitHub, клонировать его и развернуть наше приложение.

Чтобы развертывание на Fly.io происходило автоматически, мы должны установить и настроить клиент flyctl. Нам нужно будет аутентифицировать наш GitHub Action на Fly.io, и для этого нам нужен токен авторизации Fly.io. Его можно сгенерировать, выполнив команду fly auth token в терминале.

После этого скопируйте это значение и откройте наш репозиторий GitHub. Внутри Settings | Secrets | Actions откройте New Repository Secret. Затем задайте FLY_API_TOKEN в качестве имени и наш токен в качестве значения, и нажмите на Add secret.

Рисунок 10.2: Добавление FLY_API_TOKEN в качестве секрета действия GitHub

Рисунок 10.2: Добавление FLY_API_TOKEN в качестве секрета действия GitHub

После настройки нашего секрета пришло время использовать GitHub Actions для автоматического развертывания нашего приложения. Для этого в нашей рабочей директории создайте файл .github/workflows/fly.yml со следующим содержимым:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
name: Fly Deploy
on:
    push:
        branches:
            - main
env:
    FLY_API_TOKEN: ${{ secrets.FLY_API_TOKEN }}
jobs:
    deploy:
        name: Deploy app
        runs-on: ubuntu-latest
        steps:
            - uses: actions/checkout@v3
            - uses: superfly/flyctl-actions/setup-flyctl@master
            - run: flyctl deploy –remote-only

Этот GitHub Action использует действие setup-flyctl для настройки клиента Fly.io, а затем использует flyctl для развертывания нашего кода. Чтобы выполнить развертывание, ему нужна переменная окружения FLY_API_TOKEN, которую мы задаем в секции env определения действия (взяв значение из секрета, который мы ранее настроили в настройках репозитория).

Затем мы добавляем этот файл в Git-репозиторий, фиксируем его и отправляем на выполнение. В результате действие должно запуститься и развернуть наше приложение:

Рисунок 10.3: Успешное развертывание на Fly.io с помощью GitHub Action

Рисунок 10.3: Успешное развертывание на Fly.io с помощью GitHub Action

Далее мы хотим настроить мониторинг нашего развернутого приложения, чтобы держать его под контролем!

Сбор данных о процессах приложения

Отрывок из выступления «Мой процесс Node.js горит»

В 10 утра в «черную пятницу» у вас звонит телефон: новое JS-приложение, которое вы развернули, подверглось слишком большой нагрузке, и сайт упал! Ваш работодатель теряет возможности для продаж... Ваш работодатель теряет деньги! Но вы не теряете самообладания. Вы заходите в облако провайдера и изменяете настройки автомасштабирования. Теперь развертывание может справиться со скачком нагрузки, но с использованием в четыре раза большего количества серверов, что в четыре раза дороже. На следующий день вы пытаетесь проанализировать, что произошло, и начинаете оптимизировать свое приложение, чтобы подготовиться к будущим скачкам нагрузки».

Этот полный доклад был сделан Маттео Коллиной на JSConf Asia 2018.

Основная причина, по которой мы хотим собирать метрики нашего работающего процесса Node.js, — это возможность диагностировать и отлаживать проблемы спустя часы, дни или даже недели после их возникновения. Поток диагностики производственных проблем описан на следующем рисунке:

Рисунок 10.4: Путь к решению производственной проблемы

Рисунок 10.4: Путь к решению производственной проблемы

Нам нужно собрать данные, чтобы понять, что произошло, и воспроизвести проблему в неживой среде — иначе мы не сможем понять, устранили ли мы проблему! После этого мы используем более тонкие инструменты для локального воспроизведения и разработки исправления. Какие инструменты мы будем использовать? Мы рассмотрим их в главе 13.

Сбор данных о процессе приложения с помощью Prometheus

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

Архитектура Prometheus разделена на различные компоненты: в ее основе лежит сервер Prometheus, который получает метрики от каждой цели через точные интервалы времени (несколько раз в минуту). Для короткоживущих заданий существует Pushgateway, который позволяет Prometheus получать эти метрики. Клиенты визуализации — такие как Grafana — запрашивают Prometheus с помощью PromQL.

Рисунок 10.5: Архитектура Prometheus

Рисунок 10.5: Архитектура Prometheus

Эта книга не посвящена Prometheus и всем его возможностям; однако мы расскажем о том, как настроить наше приложение Fastify на предоставление данных для сбора Prometheus. Мы также расскажем о встроенной поддержке Fly.io для Prometheus и о возможностях сбора данных.

Prometheus

За дополнительной информацией о Prometheus обращайтесь к документации Prometheus.

Основной библиотекой Node.js, которая создает метрики в нужном формате для извлечения Prometheus, является prom-client. fastify- metrics использует ее и интегрирует с Fastify.

Prometheus и Fly.io рекомендуют выставлять метрики на TCP-порт, отличный от порта нашего основного сервиса, который обычно равен 9001. Поэтому мы хотим собирать метрики для нашего основного процесса и запустить отдельный сервер Fastify для передачи этих метрик скребку. Поэтому мы создаем файл plugins/metrics.js со следующим содержимым:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
'use strict';
const fp = require('fastify-plugin');
const Fastify = require('fastify');
module.exports = fp(
    async function (app) {
        app.register(require('fastify-metrics'), {
            defaultMetrics: { enabled: true },
            endpoint: null,
            name: 'metrics',
            routeMetrics: { enabled: true },
        });
        const promServer = Fastify({ logger: app.log });
        promServer.route({
            url: '/metrics',
            method: 'GET',
            logLevel: 'info',
            handler: (_, reply) => {
                reply.type('text/plain');
                return app.metrics.client.register.metrics();
            },
        });
        app.addHook('onClose', async (instance) => {
            await promServer.close();
        });
        await promServer.listen({
            port: 9001,
            host: '0.0.0.0',
        });
    },
    { name: 'prom' }
);

Затем нам нужно настроить Fly.io на получение наших пользовательских метрик в своем решении для мониторинга. Таким образом, мы добавляем следующее в fly.toml:

1
2
3
[metrics]
  port = 9001
  path = "/metrics"

Далее мы запускаем в терминале нашу обычную тройку команд: git add ., git commit и git push. После того как GitHub Action развернет наш код, мы можем протестировать его, используя следующее:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
$ curl https://api.fly.io/prometheus/personal/api/v1/query_
range\?step\=30 \
    --data-urlencode 'query=sum(rate(nodejs_active_handles{app="shy-
fog-346"}[5m])) by (status)' \
    -H "Authorization: Bearer YOURFLYTOKEN"
{"status":"success","isPartial":false,"data":{"resultType":
"matrix","result":[{"metric":{},"values":[[1659088433,"0"],
[1659088463,"0"],[1659088493,"0"],[1659088523,"0"],[1659088553,"0"],
[1659088583,"0"],[1659088613,"0"],[1659088643,"0"],[1659088673,"0"],
[1659088703,"0"],[1659088733,"0"]]}]}}

Команда curl проверяет, что Fly.io теперь следит за нашим приложением — в частности, она проверяет количество активных хендлов (сокетов и т. д.) в Node.js. Команда использует схему авторизации с использованием токена на предъявителя (т.е. заголовок Authorization), поэтому нам понадобится токен авторизации Fly.io, который мы сгенерировали ранее. Если вы не скопировали токен авторизации, вы можете получить его с помощью команды fly auth token. При выполнении этого кода не забудьте также обновить название приложения на свое.

Grafana будет использовать эту конечную точку для получения данных для своих визуализаций.

Исследование метрик с помощью Grafana

В этой книге мы будем использовать Grafana Cloud, хостинговую версию проекта Grafana с открытым исходным кодом. Чтобы начать работу, перейдите по адресу https://grafana.com/ и зарегистрируйте новый бесплатный аккаунт. В итоге вы окажетесь на следующем экране:

Рисунок 10.6: Первый экран Grafana Cloud

Рисунок 10.6: Первый экран Grafana Cloud

Нажмите на Подключить данные (или в меню нажмите на Подключения), а затем выполните поиск Prometheus:

Рисунок 10.7: Интеграции и подключения в облаке Grafana

Рисунок 10.7: Интеграции и подключения в облаке Grafana

Далее нажмите на Источник данных Prometheus, затем Создать источник данных Prometheus:

Рисунок 10.8: Создание интеграции Prometheus в Grafana Cloud

Рисунок 10.8: Создание интеграции Prometheus в Grafana Cloud

Теперь мы можем настроить наш источник данных Prometheus. Мы используем подход, аналогичный команде curl в предыдущем разделе: мы должны авторизовать Grafana для получения данных с Fly.io. Для этого мы задаем в заголовке Authorization значение Bearer TOKEN, где TOKEN — это вывод fly auth token. На следующем рисунке показана окончательная конфигурация.

Рисунок 10.9: Настройки интеграции Prometheus в Grafana Cloud

Рисунок 10.9: Настройки интеграции Prometheus в Grafana Cloud

Grafana и Fly.io

Вы можете найти дополнительную информацию о [том, как Fly.io может интегрироваться с Grafana] (https://fly.io/docs/reference/metrics/#grafana).

Теперь нажмите Save & test, затем Explore. В следующем окне выберите fly_instance_memory_mem_total в качестве метрики, примените app = shy-fog-346 в качестве метки (используйте собственное имя приложения) и нажмите Run query. Окончательная настройка будет выглядеть следующим образом:

Рисунок 10.10: Изучение метрик, предоставляемых Fly.io, в Grafana Cloud

Рисунок 10.10: Изучение метрик, предоставляемых Fly.io, в Grafana Cloud

Здесь мы видим, как Fly.io следит за памятью нашего приложения.

Модуль fastify-metrics предоставляет несколько интересных метрик, касающихся Fastify:

  • http_request_duration_seconds_count — общее количество HTTP-запросов в интервале
  • http_request_summary_seconds — длительность запроса, разделенная на проценты

Prom-client предоставляет метрики для экземпляра Node.js. Вы можете обратиться к https://github.com/siimon/prom-client/tree/721829cc593bb7da28ae009985caeeacb4b59e05/lib/metrics за полным списком доступных метрик, но я рекомендую вам построить график следующих:

  • nodejs_event_loop_lag_p99_seconds — для отслеживания того, насыщается ли наш цикл событий и нужно ли дальше оптимизировать наше приложение
  • nodejs_heap_space_used_bytes — чтобы отслеживать, сколько памяти использует наше приложение, и выявлять проблемы с памятью на ранней стадии.

В качестве другого примера мы можем построить график максимальной задержки по всем маршрутам для каждого экземпляра нашего приложения:

Рисунок 10.11: График задержки нашего сервера при различных квантилях в Grafana Cloud

Рисунок 10.11: График задержки нашего сервера при различных квантилях в Grafana Cloud

На предыдущей диаграмме показана задержка всех маршрутов нашего сервера при различных квантилях. Нас интересуют квантили 0,95 и 0,99, поскольку они учитывают большинство запросов, исключая при этом провалы. Это полезно для того, чтобы понять, как работает наше приложение для большинства пользователей.

Квантиль или перцентиль

В статистике и теории вероятностей квантили — это точки среза, делящие диапазон распределения вероятностей на непрерывные интервалы с равными вероятностями, или делящие наблюдения в выборке таким же образом. Количество квантилей на один меньше, чем количество созданных групп. Общие квантили имеют специальные названия, например, квартили (четыре группы), децили (десять групп) и перцентили (100 групп). Созданные группы называются половинами, третями, четвертями и т. д., хотя иногда термины для квантилей используются для созданных групп, а не для точек отсечения."_ — https:// en.wikipedia.org/wiki/Quantile.

Мы узнали, как интегрировать Fly.io с Grafana Cloud, и теперь у нас есть мощный сайт мониторинга, который мы можем настроить по своему вкусу. В качестве упражнения мы рекомендуем изучить все метрики, доступные в Grafana, и создать полноценный дашборд!

Grafana

Чтобы узнать больше о Grafana, прочитайте статью Learn Grafana 7.0, написанную Эриком Салитуро.

Резюме

В этой главе мы развернули наше приложение Fastify на Fly.io с базой данных, размещенной в MongoDB Atlas. Затем мы добавили мониторинг с помощью экземпляра Prometheus, размещенного на Fly.io. Наконец, мы подключили Prometheus к Grafana Cloud.

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

Комментарии