В этой статье я хочу поделиться своим опытом создания Telegram-бота написанного на Dart и запущенного через Docker на VDS.

Оригинал статьи размещён тут.

В конце у вас будет работающий Telegram-бот, написанный на Dart, запущенный в контейнере Docker и размещенный на VDS. Вы сможете отправлять сообщения боту и получать ответы, а также отправлять фотографии, хранить их на VDS и удалять, при необходимости.

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


И так, для того, чтобы все это сделать, нам нужно следующее:

  • Создать нового бота с помощью BotFather;

  • Создать новый dart-проект и написать код бота;

  • Настроить все необходимые пакеты и плагины на VDS;

  • Запустить контейнер Docker и протестировать бота.

Telegram-бот и VDS, которые использовались для этой статьи, удалены, поэтому все данные, такие как токен Telegram API или IP-адрес VDS, должны быть заменены.

1. Новый бот

Это самая простая часть, все, что нам нужно сделать, это перейти к BotFather, нажав на эту ссылку, и создать нового бота.

Выберите в меню «Создать нового бота» или введите команду /newbot в текстовом поле.

Вас попросят указать имя бота (оно может быть не уникальным) и имя пользователя бота, которые должны быть уникальными и содержать «_bot» в конце.

Для этой статьи я выбрал имя пользователя ak_medium_bot. BotFather дал мне токен для доступа к Telegram API (пример на скриншоте). Вы всегда можете получить его или сбросить с помощью BotFather.

С этим всё!

2. Проект Dart

Сначала установите Dart на вашу машину. Все шаги описаны на официальном сайте, и это довольно просто, поэтому у вас не должно быть никаких проблем.

После установки Dart откройте терминал на компьютере Mac или Linux, перейдите в папку в которой вы хотите сохранить проект и выполните следующую команду (у вас должны быть права администратора):

dart create -t console-full bot_medium

(для получения дополнительной информации о создании проектов Dart посетите этот сайт).

Теперь откройте созданную папку в любой IDE, которой вам нравится. Например, я использую VS Code.

В терминале вашей IDE (или просто в терминале) выполните следующую команду для установки пакета Teledart:

dart pub add teledart

Перейдите в папку bin, откройте bot_medium.dart и замените его содержимое следующим:

Код bot_medium.dart

Важно! Не храните ключи API, как это было сделано в этой статье! Всегда держите их в секрете и подальше от гита!

Приведенный выше код запускает Telegram-бота и ждет, когда пользователь введет определенные ключевые слова. Если какое-либо ключевое слово будет отправлено боту, он запускает соответствующие действие.

Далее создадим новый файл в корне папки проекта и присвоим ему имя Dockerfile, без какого-либо типа или точки в конце. Заполните его следующим:

Dockerfile

Dockerfile создает образ Docker из нашего проекта Dart.

Теперь пришло время создать новый репозиторий, например, на GitHub. Перейдите в терминале в папку проекта и выполните следующие действия:

git init
git add -A
git commit -m "first commit"
git branch -M main
git remote add origin https://github.com/kharitonovAL/bot_medium.git
git push -u origin main

Обратите внимание! Ваш git remote add origin https://github.com/kharitonovAL/bot_medium.git будет отличаться.

Отлично! Двигаемся дальше!

3. VDS

Чтобы бот был доступен 24/7, мы должны запустить его на сервере. Вы можете использовать любого поставщика услуг VDS, которого хотите. Что касается меня — я использую сервис reg.ru, он не дорогой, стабильный и имеет предварительно настроенные образы операционной системы.

Если вы используете другого поставщика услуг VDS, я рекомендую вам установить Ubuntu с версией 18.04 или 20.04, как показано на скриншоте:

Я выбираю версию 20.04 для этой статьи.

Так, теперь у нас есть VDS, работающие на Ubuntu со следующими параметрами:

Пароль root пользователя был отправлен на мою электронную почту.

Теперь нам нужно подключиться к нашему серверу и установить Dart и Docker.

Используйте любой ssh-клиент или терминал для подключения к серверу. Если вы используете терминал, запустите следующее: ssh root@89.108.70.91. Вас попросят ввести пароль пользователя root.

Если вы все сделали правильно, вы будете подключены к серверу:

Теперь давайте установим Dart на ваш VDS. Все шаги описаны на официальном сайте.

После установки вы можете ввести в терминале dart --version, чтобы проверить, что Dart установлен:

root@89–108–70–91:~# dart — version

Dart SDK version: 2.14.4 (stable) (Unknown timestamp) on “linux_x64"

Далее установим Docker, как описано на официальном сайте.

Убедитесь, что Docker Engine установлен правильно, запустив образ hello-world:

sudo docker run hello-world

Эта команда загружает тестовый образ и запускает его в контейнере. Когда контейнер запускается, он печатает сообщение и выходит.

Теперь давайте установим официальный контейнер Dart, как описано здесь.

И еще нам нужно создать нового пользователя для Ubuntu, чтобы позже собрать и запустить бота в контейнере Docker. Для этого запустите в терминале следующее:

adduser duser

// (вы можете выбрать любое другое имя)

Выходные данные будут похожи на то, что показано на скриншоте:

Важно! Добавьте нового пользователя в группу Docker, как описано здесь. Там описано всего два шага:

1. Создайте группу docker:

sudo groupadd docker

2. Добавьте своего пользователя в группу docker:

// (duser в моем случае)
sudo usermod -aG docker duser

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

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

  • Перейдите в корневой каталог, когда вы сделаете путь в терминале, он должен выглядеть следующим образом: root@89–108–70–91:/# (начинается с /);

  • Перейдите в каталог var, выполнив cd var;

  • Создать новую папку с загрузкой имени, выполнив mkdir upload в терминале;

  • Введите ls и нажмите Enter.

Вы должны увидеть что-то подобное в терминале:

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

Если вы видите папку загрузки, вы можете двигаться вперед.

Хорошо, теперь давайте клонируем наш репозиторий из GiHub. Перейдите в папку home и выполните следующее:

git clone https://github.com/kharitonovAL/bot_medium.git

Отлично, следующий шаг!

4. Сборка и запуск контейнера Docker

Итак, теперь вы все настроили.

Теперь войдите в систему со своим новым пользователем (в моем случае duser). Перейдите в папку вашего бота-проекта (в моем случае он находится по пути /home/bot_medium) и создайте образ Docker следующей командой:

docker build -t dart-server .

// (да, в конце есть пробел и точка)

Выходные данные будут аналогичны следующему:

Данные
duser@89-108-70-91:~$ cd ..
duser@89-108-70-91:/home$ cd bot_medium
duser@89-108-70-91:/home/bot_medium$ docker build -t dart-server .
Sending build context to Docker daemon  100.9kB
Step 1/12 : FROM dart:stable AS build
 ---> 91437c5c4a32
Step 2/12 : WORKDIR /app
 ---> Using cache
 ---> d9119631358f
Step 3/12 : COPY pubspec.* ./
 ---> Using cache
 ---> 2c5d1335e912
Step 4/12 : RUN dart pub get
 ---> Using cache
 ---> 0a673e765734
Step 5/12 : COPY . .
 ---> 7c7f640d4fa1
Step 6/12 : RUN dart pub get --offline
 ---> Running in 40222d0387df
Resolving dependencies...
Got dependencies!
Removing intermediate container 40222d0387df
 ---> ef8bfd2f84b3
Step 7/12 : RUN dart compile exe bin/bot_medium.dart -o bin/server
 ---> Running in ab4c98041acc
Info: Compiling with sound null safety
Generated: /app/bin/server
Removing intermediate container ab4c98041acc
 ---> bbb20f1d1a4e
Step 8/12 : FROM scratch
 ---> 
Step 9/12 : COPY --from=build /runtime/ /
 ---> c4a23b9f77c4
Step 10/12 : COPY --from=build /app/bin/server /app/bin/
 ---> 4b9c61aa381b
Step 11/12 : EXPOSE 8080
 ---> Running in 1a434ab35272
Removing intermediate container 1a434ab35272
 ---> e47cf083a71f
Step 12/12 : CMD ["/app/bin/server"]
 ---> Running in 761123b25035
Removing intermediate container 761123b25035
 ---> 98ba199f8aca
Successfully built 98ba199f8aca
Successfully tagged dart-server:latest

Важно! Если вы попытаетесь запустить docker build -t dart-server. с правами root пользователя, вы получите AOT ошибку компиляции.

Хорошо, теперь нужно сообщить системе, что бот должен быть онлайн 24/7. Для этого выполните следующее в терминале (сделать это нужно root пользователем):

systemctl enable docker.service
systemctl enable containerd.service

Теперь давайте запустим наш контейнер! Выполните следующее (сделайте это с помощью duser):

docker run -d — restart=always -p 8080:8080 \-v /var/upload:/var/upload \dart-server

Вывод будет примерно следующим:

duser@89-108-70-91:~$ cd ..
duser@89-108-70-91:/home$ cd bot_medium
duser@89-108-70-91:/home/bot_medium$ docker run -d --restart=always -p 8080:8080 \-v /var/upload:/var/upload \dart-server
2d46670198864b4adef9afa126c1e0b5c9917657b69aae7a5b01d0335700b1e2
duser@89-108-70-91:/home/bot_medium$

Чтобы убедиться, что наш контейнер запущен, выполните docker ps в терминале, и вывод будет следующим:

duser@89-108-70-91:/home/bot_medium$ docker ps
CONTAINER ID   IMAGE         COMMAND             CREATED          STATUS          PORTS                                       NAMES
2d4667019886   dart-server   "/app/bin/server"   18 seconds ago   Up 17 seconds   0.0.0.0:8080->8080/tcp, :::8080->8080/tcp   vigorous_khayyam
duser@89-108-70-91:/home/bot_medium$

Наконец-то наш бот теперь онлайн. Но это еще не конец. Выполните следующее, чтобы обновить настройки контейнера Docker:

docker update --restart=always vigorous_khayyam

Этой командой мы говорим Docker перезапускать этот контейнер каждый раз, когда он отключается.

Имя моего контейнера в данном случае — vigorous_khayyam. Имя вашего контейнера может быть другим. Выполните команду docker ps. Вы увидите список запущенных контейнеров Docker и сможете увидеть имя вашего.

5. Тестирование

Давайте протестируем нашего бота!

Мы отправили фото! Теперь давайте сделаем паузу и проверим, все ли идет как надо после того, как мы отправили фото. Перейдите в каталог /var/upload и введите команду ls, вы увидите вложенную папку с именем chat_id:

duser@89-108-70-91:/home/bot_medium$ cd ..
duser@89-108-70-91:/home$ cd ..
duser@89-108-70-91:/$ cd var/upload
duser@89-108-70-91:/var/upload$ ls
415294329
duser@89-108-70-91:/var/upload$

Круто, фото есть! Теперь давайте нажмем кнопку «Удалить изображение» в действиях бота и еще раз проверим содержимое /var/upload:

duser@89-108-70-91:/home/bot_medium$ cd ..
duser@89-108-70-91:/home$ cd ..
duser@89-108-70-91:/$ cd var/upload
duser@89-108-70-91:/var/upload$ ls
duser@89-108-70-91:/var/upload$

И теперь фото нет!


Теперь вы знаете как создать Telegram-бота с помощью Dart, Docker и VDS. Эта статья также будет полезна Flutter разработчикам.

Код bot_medium вы можете найти здесь.

Telegram-бот и VDS, которые использовались для этой статьи, удаляются, поэтому все конкретные данные, такие как токен Telegram API или IP-адрес VDS, должны быть заменены.

Спасибо за внимание!

Комментарии (5)


  1. korsetlr473
    30.12.2021 13:45

    зачем ставить дарт на виртуалку если в докере запускате ?


    1. kharitonovAL Автор
      30.12.2021 14:00
      -2

      Чтоб образ собрать


  1. OkunevPY
    30.12.2021 19:30
    +1

    Я не очень понимаю зачем эта статья?

    Копипаст кода без разбора самого кода, какой смысл.

    Копипаст команд без разбора что и зачем, зато всавка логов сборки образов. Дичь полная.

    Дальше ещё веселее, клонируйте вообще наш проект и соберите. Так с этого и надо было начать, ничего бы не изменилось.

    Ну и сборка докер образа.

    Есть два образа, один рантайм второй sdk. Как очевидно из названия один для запуска воторой с sdk. Вменяемым подходом являеться использование двух образов при сборке, в образе SDK он же build вы собираете проект и получаеться артефакты в виде бинарей, пакетов и чего бы то ни было, затем переносите артефакты в образ runtime и его используете дальше для запуска, образ будет чистенький, маленький и как у всех.


    1. kharitonovAL Автор
      30.12.2021 20:12
      +2

      Спасибо за Ваши замечания!

      Статья была написана чтоб поделиться опытом. Потому что не нашёл подобного кейса когда искал.


  1. muturgan
    30.12.2021 22:00
    +2

    Я испытываю странную слабость к дарту. Даже не знаю почему. В работе его не использую.