- PVSM.RU - https://www.pvsm.ru -

Сервис на языке Dart: введение, инфраструктура бэкэнд

Оглавление

1. Введение
2. Backend
2.1. Инфраструктура.
2.2. Доменное имя. SSL.
2.3. Серверное приложение на Dart.

3. Web
3.1. Заглушка «Under construction»

4. Mobile

Введение

Меня, Flutter-разработчика, знакомые часто спрашивают: «Что же такое язык Dart?». Качают головой со словами: «А вот Петя серьёзные транспорты на Java пишет, а в Яндексе вообще плюсы в проде...». Ну что ж, пожалуй, действительно, Dart далёк от практик «фабрик для создания фабрик [1]» из Java. Однако если стоит задача реализовать клиентские приложения сразу для нескольких платформ, не утонув в потоке задач по синхронизации разработчиков разных целевых ОС; создать целостный UI, узнаваемый, но специфичный для Android, iOS и веб и в целом уложиться в адекватные бюджет и сроки, — здесь Flutter не имеет конкурентов. И эти вопросы стоят вдвойне если у вас… стартап.

Итак, легенда: некий стартап решил создать новый сервис… ну, например, для

обмена списками покупок

Такая себе идея для стартапа, я знаю, но если я выпущу ещё один ToDo лист в этот мир, мне будет стыдно :)

между пользователями сервиса. Цель стартапа — выпустить MVP [2]за три месяца на трех платформах (плюс четвертая — сервер, конечно).

10 лет назад я бы сказал, что этот кейс не имеет решения и постарался бы держаться от него подальше, 3 года назад решением мог стать стек ReactNative/React/NodeJs, в 2020 году для этого есть Dart. Добро пожаловать в атмосферу разработки альфа версии сервиса, я постараюсь наглядно пройти и объяснить весь процесс разработки. Код всех приложений будет выложен в паблик. Комментарии, включая набросы и холивары, приветствуются. Спросить автора «по существу» или просто посоветоваться можно в Telegram канале [3] нашего отдела.

Сервис на языке Dart: введение, инфраструктура бэкэнд - 1

Инфраструктура бекэнд

Типовым способом размещения серверного приложения является, конечно, VPS [4](виртуальный приватный сервер). Фактически — это часть физического сервера в дата центре, ресурсы которого (ядра процессора и оперативная память) разделены с помощью технологии виртуализации (о наиболее распространённых технологиях аппаратной виртуализации можно почитать здесь XEN [5], KVM [6]). Внимание: технологии программной виртуализации (OpenVZ [7], Virtuozzo [8]) для нашей задачи могут не подойти из-за конфликтов с Docker и агрессивным оверселлингом [9](зачастую, при внимательном прочтении договора аренды такого VPS [10], можно обнаружить, что провайдеры гарантируют «не менее 5%» (!) утилизации ядра арендуемого процессора. Это означает, что провайдер планирует продать наше ядро процессора 20 (!) раз).

Итак, приобретём бюджетный VPS [10] со следующими характеристиками: 1 ядро процессора, 1ГБ оперативной памяти, 10ГБ накопителя (в моём случае, это гибридный HDD). В качестве операционной системы выберем Ubuntu, желательно одной из LTS [11]версий. После чего в электронную почту придёт сообщение об активации сервера с логином и паролем доступа по SSH [12](зашифрованный доступ к консоли операционной системы нашего VPS [10]) в формате SSH:

IP-адрес: 91.230.60.120
Пользователь: root
Пароль: <Пароль>

Проверим подключение, введя в командной строке:

ssh root@91.230.60.120

и, по запросу:

password: <Пароль>

Результатом должен быть вывод сведений о виртуальном сервере и поле ввода внизу:

Server is hosted by хххххххххх

Hostname: 91.230.60.120
Kernel: 3.19.0-22-generic (Ubuntu хх.хх LTS)
Uptime: 09:07:06 up 3 days, 17:17, 1 user, load average: 0.00, 0.01, 0.05
CPU: Intel® Xeon® CPU 0 @ 2.00GHz (1 cores)
Memory: 989 MB total / 723 MB free

root@91.230.60.120:~$

Поздравляю, наш виртуальный сервер создан и доступен для работы.

Теперь определимся со структурой бекэнд. Нам понадобится HTTP сервер. Мы будем использовать NGINX [13]. Его задачами будут:

  1. Раздача статических файлов (файлы веб приложения).
  2. Раздача служебных ресурсов, например, файлов подтверждения владения доменом для мобильных приложений, сведений о владельце для получения SSL сертификатов Let’s encrypt и пр.
  3. Reverse proxy [14] для доступа к серверным приложениям.
  4. Шифрование соединений — https.

Два серверных приложения:

  1. Приложение регистрации и авторизации пользователей. Назовём его auth_app.
  2. Приложение с данными. Назовём его app.
  3. Для каждого из приложений п.2 нам понадобится отдельная база данных PostgreSQL.
  4. Приложение для автоматического получения и обновления сертификатов шифрования SSL (в следующей статье).

Очевидно, что такой «зоопарк» приложений необходимо изолировать друг от друга, а также заблокировать доступ извне. Для этого мы будем использовать технологию контейнеризации Docker [15]и менеджер контейнеров Docker compose [16]. В виде схемы это можно представить так:

image

Разработку будем вести в IDE Visual Studio Code [17] от Microsoft, которая, благодаря множеству доступных плагинов, позволит работать со всеми необходимыми технологиями. Также необходимо установить следующие расширения:

После перезапуска VScode подключимся к нашему VPS [10]. Нажимаем F1 и начнем вводить команду:

Remote-SSH: connect to  Host…

далее новое подключение:

+ Add New Ssh Host

затем:

ssh root@<ip-адрес сервера>

Откроем окно терминала VScode (Menu/Terminal/New terminal) и проверим системные ресурсы командой:

top

Готово, доступ к консоли и файловой системе VPS [10] получен:

Сервис на языке Dart: введение, инфраструктура бэкэнд - 3

Сервис на языке Dart: введение, инфраструктура бэкэнд - 4

Утилита top будет использоваться довольно часто, поэтому установим её псевдографическую версию htop:

Ctrl-C #Завершаем выполнение утилиты top

apt-get update #Обновляем установленные пакеты

apt-get install htop #Устанавливаем htop 

htop #Запускаем 

image

Теперь необходимо установить Docker и Docker compose:

Ctrl-C #Завершаем выполнение утилиты htop

Поскольку docker отсутствует в официальном репозитории Ubuntu, установим дополнительный репозиторий

apt-get install apt-transport-https ca-certificates curl gnupg-agent software-properties-common #Устанавливаем необходимые утилиты 

curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add - #Устанавливаем ключ репозитория docker 

add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" #Добавляем репозиторий 

apt-get install docker-ce docker-ce-cli containerd.io #Устанавливаем

curl -L "https://github.com/docker/compose/releases/download/1.26.1/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose #Скачиваем менеджер Docker compose 

chmod +x /usr/local/bin/docker-compose #Устанавливаем разрешение для загруженного файла «исполняемый файл»

ln -s /usr/local/bin/docker-compose /usr/bin/docker-compose #Добавляем символьную ссылку в директорию исполняемых файлов 

 docker  --version #Проверяем

docker-compose --version

Отлично, сервер готов к тестовому развёртыванию сервиса.

Теперь установим Docker desktop на нашем локальном ПК для разработки. Установщик для Windows 10 [21], версия для MacOS здесь [22]. Будет установлен не только Docker, но и Docker toolbox, в который входят Docker compose и графические утилиты для работы с контейнерами.

Откроем новое окно VScode, Menu/File/Open folder… Создадим новую папку нашего проекта, например, Srv и откроем её. В этой папке создадим файл docker-compose.yaml:

image

В этом файле описывается сценарий запуска контейнеров сервиса, их зависимости, переменные, команды, сети, хранилища и пр.

Здесь необходимо остановиться и уточнить разницу между образом и контейнером Docker. Контейнер — это приложение + его зависимости (например, пакеты и библиотеки) + операционная система, которую можно с помощью Docker запустить как обычное приложение. А образ — это подготовленный к запуску и упакованный в архив контейнер. Таким образом, весь наш бекэнд будет представлять собой набор контейнеров с описанием сценария их запуска.

Первым контейнером, который мы запланировали станет HTTP сервер NGINX. И давайте подготовим необходимый образ… или нет? Дело в том, что для очень многих веб приложений и сред исполнения их разработчиками или комьюнити уже собраны необходимые образы и размещены в публичном реестре DockerHub [23]. Разумеется такой широко используемый образ уже собран и ожидает нас по этой ссылке [24].

Обратите внимание на список — это различные версии, они отличаются и версиями самого NGINX и дополнительными инструментами (например, установленным PERL). Для разработки можно использовать тэг «latest» (последняя стабильная версия на момент запроса образа), но для развёртывания на сервере, конечно, стоит использовать конкретную версию. В данный момент это образ nginx:1.19.0 [25].

Здесь и далее необходимые пояснения к содержимому docker-compose.yaml я буду указывать в комментариях в самом листинге файла:

Сервис на языке Dart: введение, инфраструктура бэкэнд - 7

Сохраним изменения в файле, откроем консоль VScode и выполним команду запуска сценария

docker-compose up

Этой командой был не только запущен сценарий, но и вывод консоли контейнера был направлен в консоль хоста. Теперь, если в адресной строке браузера обратиться к локальному хосту на порте 8081 будет получена стандартный ответ NGINX:

Сервис на языке Dart: введение, инфраструктура бэкэнд - 8

Наш первый контейнер уже работает. Обычно запуск сценария выполняется командой:

docker-compose up -d

это позволяет запустить контейнеры в режиме сервиса (без вывода в консоль). Остановка контейнеров сценария выполняется командой:

docker-compose down

Для тестирования http запросов в VScode есть удобное расширение REST client [26].

Установим его и напишем первый отладочный тест нашего сервиса. Для этого создадим файл client.http в папке test/http_dev/:

Сервис на языке Dart: введение, инфраструктура бэкэнд - 9

Сервис на языке Dart: введение, инфраструктура бэкэнд - 10

Таким образом можно выполнять тестовые запросы, просматривая подробную информацию об ответах сервера.

Теперь давайте заглянем внутрь контейнера. Остановим выполнение сценария в консоли:

Ctrl-C

и запустим с флагом:

docker-compose up -d

Теперь запросим список выполняемых в данный момент контейнеров (процессов):

docker-compose ps

Сервис на языке Dart: введение, инфраструктура бэкэнд - 11

В списке выполняемых только один контейнер. Давайте откроем его:

docker exec -it srv_web_1 bash

Эта команда выполняет (exec) приложение bash (командная оболочка Linux) в контейнере srv_web_1 и не дает закрываться консоли (флаги -it):

Сервис на языке Dart: введение, инфраструктура бэкэнд - 12

Команда ls покажет стандартную структуру папок Linux:

Сервис на языке Dart: введение, инфраструктура бэкэнд - 13

Нас интересует файл /etc/nginx/conf.d/default.conf — настройки NGINX, для просмотра можно использовать утилиту cat

cat /etc/nginx/conf.d/default.conf

Сервис на языке Dart: введение, инфраструктура бэкэнд - 14

В настройках NGINX один блок (так называемый location), в котором включено прослушивание порта 80 и раздача статических файлов из папки контейнера /usr/share/nginx/html. Можно попробовать внести изменения в файл настройки NGINX и перезапустить его, применив изменения, но при перезапуске сценария контейнер будет восстановлен из образа и никакие наши изменения не сохранятся. Это неправильный путь.

Выйдем из консоли контейнера:

Ctrl-D

Мы напишем свой файл настройки и разместим свои статические файлы, а при запуске будем их монтировать в контейнер NGINX. Создадим файл default.conf в папке /conf.d нашего проекта:

Сервис на языке Dart: введение, инфраструктура бэкэнд - 15

Сервис на языке Dart: введение, инфраструктура бэкэнд - 16

Создадим заглушку статического файла /public/index.html:

Сервис на языке Dart: введение, инфраструктура бэкэнд - 17

Теперь в сценарии запуска docker-compose.yaml смонтируем наши папки в файловую систему контейнера:

Сервис на языке Dart: введение, инфраструктура бэкэнд - 18

Обратите внимание, что содержимое папки проекта ./conf.d заменит содержимое контейнера в /etc/nginx/conf.d/, а в корневую папку папку контейнера будет смонтирована папка ./public.

Перезапустим сценарий:

docker-compose restart

Тестовый запрос:

Сервис на языке Dart: введение, инфраструктура бэкэнд - 19

Давайте посмотрим на файл default.conf. Обратите внимание, что мы отключили логирование доступа к статическим файлам access_log off. Это хорошее решение для прода, но очень неудобное при тестировании и разработке. Давайте создадим тестовые файл конфигурации NGINX /conf.dev.d/default.conf и сценарий docker-compose.dev.yaml.

Сервис на языке Dart: введение, инфраструктура бэкэнд - 20

Сервис на языке Dart: введение, инфраструктура бэкэнд - 21

Сервис на языке Dart: введение, инфраструктура бэкэнд - 22

Остановим сценарий:

docker-compose down

и запустим уже с флагами имен файлов:

docker-compose -f docker-compose.yaml -f docker-compose.dev.yaml up

При таком запуске сценария сначала будет прочитаны настройки из файла docker-compose.yaml, а затем будут добавлены или заменены совпадающие поля из docker-compose.dev.yaml (ports, volumes). Проверим логирование повторив запрос:

Сервис на языке Dart: введение, инфраструктура бэкэнд - 23

Сервис на языке Dart: введение, инфраструктура бэкэнд - 24

Итак, нам осталось выполнить копирование и запуск на сервере. Создадим на сервере папку /opt/srv_0/ (мы ведь ещё не закрыли окно VScode c SSH соединением к VPS [10]) и скопируем в неё всё содержимое нашего проекта командой:

scp scp -r ./* root@91.230.60.120:/opt/srv_0/ 

Сервис на языке Dart: введение, инфраструктура бэкэнд - 25

Теперь на сервере в папке проекта /opt/srv_0/ выполним команду:

docker-compose up -d

Напишем ещё один http тест, теперь уже для VPS [10]:

Сервис на языке Dart: введение, инфраструктура бэкэнд - 26

Ну или откройте в браузере ссылка [27].

→ Исходный код github [28]

Вместо заключения

Итак, сделан первый шаг. Мы успешно раскатили на боевой сервер приложение. Во второй статье мы продолжим настройку сервера: назначим доменное имя и установим сертификат шифрования SSL. В третьей статье напишем flutter web приложение с обратным отсчётом времени до запуска нашего сервиса, соберём его и разместим на нашем сервере. В четвертой статье напишем и соберём нативный сервер под Linux на языке Дарт, который станет основой для приложений авторизации и данных нашего сервиса.

Комментарии и предложения приветствуются. Пообщаться с автором можно в Telegram-канале [3].

Автор: Andrew

Источник [29]


Сайт-источник PVSM.RU: https://www.pvsm.ru

Путь до страницы источника: https://www.pvsm.ru/dart/355247

Ссылки в тексте:

[1] фабрик для создания фабрик: https://youtu.be/0ZQk2SKDlYY?t=110

[2] MVP : https://ru.wikipedia.org/wiki/%D0%9C%D0%B8%D0%BD%D0%B8%D0%BC%D0%B0%D0%BB%D1%8C%D0%BD%D0%BE_%D0%B6%D0%B8%D0%B7%D0%BD%D0%B5%D1%81%D0%BF%D0%BE%D1%81%D0%BE%D0%B1%D0%BD%D1%8B%D0%B9_%D0%BF%D1%80%D0%BE%D0%B4%D1%83%D0%BA%D1%82

[3] Telegram канале: https://t.me/SurfGear

[4] VPS : https://ru.wikipedia.org/wiki/VPS

[5] XEN: https://ru.wikipedia.org/wiki/Xen

[6] KVM: https://ru.wikipedia.org/wiki/KVM

[7] OpenVZ: https://ru.wikipedia.org/wiki/OpenVZ

[8] Virtuozzo: https://ru.wikipedia.org/wiki/Parallels_Virtuozzo_Containers

[9] оверселлингом : https://ru.wikipedia.org/wiki/%D0%9E%D0%B2%D0%B5%D1%80%D1%81%D0%B5%D0%BB%D0%BB%D0%B8%D0%BD%D0%B3

[10] VPS: https://www.reg.ru/?rlink=reflink-717

[11] LTS : https://ru.wikipedia.org/wiki/%D0%94%D0%BE%D0%BB%D0%B3%D0%BE%D1%81%D1%80%D0%BE%D1%87%D0%BD%D0%B0%D1%8F_%D0%BF%D0%BE%D0%B4%D0%B4%D0%B5%D1%80%D0%B6%D0%BA%D0%B0_%D0%BF%D1%80%D0%BE%D0%B3%D1%80%D0%B0%D0%BC%D0%BC%D0%BD%D0%BE%D0%B3%D0%BE_%D0%BE%D0%B1%D0%B5%D1%81%D0%BF%D0%B5%D1%87%D0%B5%D0%BD%D0%B8%D1%8F

[12] SSH : https://ru.wikipedia.org/wiki/SSH

[13] NGINX: https://nginx.org/ru/

[14] Reverse proxy: https://ru.wikipedia.org/wiki/%D0%9E%D0%B1%D1%80%D0%B0%D1%82%D0%BD%D1%8B%D0%B9_%D0%BF%D1%80%D0%BE%D0%BA%D1%81%D0%B8

[15] Docker : https://ru.wikipedia.org/wiki/Docker

[16] Docker compose: https://docs.docker.com/compose/

[17] Visual Studio Code: https://code.visualstudio.com/

[18] Docker: https://marketplace.visualstudio.com/items?itemName=ms-azuretools.vscode-docker

[19] Remote-SSH: https://marketplace.visualstudio.com/items?itemName=ms-vscode-remote.remote-ssh

[20] YAML: https://marketplace.visualstudio.com/items?itemName=redhat.vscode-yaml

[21] Windows 10: https://download.docker.com/win/stable/Docker%20Desktop%20Installer.exe

[22] здесь: https://docs.docker.com/docker-for-mac/install/

[23] DockerHub: https://hub.docker.com/

[24] ссылке: https://hub.docker.com/_/nginx?tab=tags

[25] nginx:1.19.0: https://hub.docker.com/layers/nginx/library/nginx/1.19.0/images/sha256-f50820bdc7060dd598dc1125e8b307ec155f8224f5f72848c0f29c0ba82b06ce?context=explore

[26] REST client: https://marketplace.visualstudio.com/items?itemName=humao.rest-client

[27] ссылка: http://91.230.60.120/

[28] github: https://github.com/AndX2/dart_server/tree/v0.2.1-pre

[29] Источник: https://habr.com/ru/post/511880/?utm_source=habrahabr&utm_medium=rss&utm_campaign=511880