Как создать бота в Telegram с помощью Serverless и Terraform
Важно
Часть ресурсов, необходимых для прохождения практического руководства, доступны только в регионе Россия.
Чтобы создать бота в Telegram с помощью Serverless и Terraform:
- Подготовьте облако к работе.
- Зарегистрируйте Telegram-бота.
- Создайте инфраструктуру.
- Проверьте работу Telegram-бота.
Если созданные ресурсы вам больше не нужны, удалите их.
Подготовьте облако к работе
Зарегистрируйтесь в Yandex Cloud и создайте платежный аккаунт:
- Перейдите в консоль управления
, затем войдите в Yandex Cloud или зарегистрируйтесь. - На странице Yandex Cloud Billing
убедитесь, что у вас подключен платежный аккаунт, и он находится в статусеACTIVEилиTRIAL_ACTIVE. Если платежного аккаунта нет, создайте его и привяжите к нему облако.
Если у вас есть активный платежный аккаунт, вы можете создать или выбрать каталог, в котором будет работать ваша инфраструктура, на странице облака
Подробнее об облаках и каталогах.
Необходимые платные ресурсы
В стоимость поддержки инфраструктуры Telegram-бота входят:
- плата за вызовы функции, вычислительные ресурсы, выделенные для выполнения функции, и исходящий трафик (см. тарифы Cloud Functions);
- плата за хранение данных в Object Storage, операции с ними и исходящий трафик (см. тарифы Object Storage);
- плата за количество запросов к созданному API-шлюзу и исходящий трафик (см. тарифы Yandex API Gateway).
Зарегистрируйте Telegram-бота
Зарегистрируйте вашего бота в Telegram и получите токен.
-
Для регистрации нового бота запустите бота BotFather
и отправьте команду./newbot -
В поле
nameукажите имя создаваемого бота, напримерServerless Hello Telegram Bot. Это имя увидят пользователи при общении с ботом. -
В поле
usernameукажите имя пользователя создаваемого бота, напримерServerlessHelloTelegramBot. По имени пользователя можно будет найти бота в Telegram. Имя пользователя должно оканчиваться на...Botили..._bot.В результате вы получите токен. Сохраните его, он потребуется в дальнейшем.
-
Установите иконку для бота — файл
sayhello.pngиз сохраненного архива. Отправьте боту BotFather команду:/setuserpic
Создайте инфраструктуру
Terraform
Terraform распространяется под лицензией Business Source License
Подробную информацию о ресурсах провайдера смотрите в документации на сайте Terraform
Для создания инфраструктуры с помощью Terraform:
-
Установите Terraform, получите данные для аутентификации и укажите источник для установки провайдера Yandex Cloud (раздел Настройте провайдер, шаг 1).
-
Подготовьте файлы с описанием инфраструктуры:
Готовая конфигурацияВручную-
Клонируйте репозиторий
с конфигурационными файлами, необходимым для создания бота, для этого в терминале выполните команду git :git clone https://git@git.sourcecraft.dev/yandex-cloud-examples/yc-telegram-bot-serverless.git -
Перейдите в директорию с репозиторием. В ней должны появиться файлы:
telegram-bot.tf— конфигурация создаваемой инфраструктуры;telegram-bot.auto.tfvars— файл с пользовательскими данными;telegram-bot-function.tpl— шаблон для создания функции Yandex Cloud Functions;telegram-bot-gw-spec.tpl— шаблон спецификации API-шлюза;sayhello.png— изображение для бота;package.json— манифест для функции Node.js.
-
Создайте папку для конфигурационных файлов.
-
Создайте в папке:
-
Конфигурационный файл
telegram-bot.tf:telegram-bot.tf
# Объявление переменных для конфиденциальных параметров variable "cloud_id" { type = string } variable "folder_id" { type = string } variable "bucket_name" { type = string } variable "bot_token" { type = string sensitive = true } # Настройка провайдера terraform { required_providers { yandex = { source = "yandex-cloud/yandex" } } } provider "yandex" { cloud_id = var.cloud_id folder_id = var.folder_id } # Создание сервисного аккаунта resource "yandex_iam_service_account" "bot_sa" { name = "telegram-bot-sa" description = "Service Account for Telegram bot" } # Назначение роли сервисному аккаунту resource "yandex_resourcemanager_folder_iam_member" "sa_editor" { folder_id = var.folder_id role = "editor" member = "serviceAccount:${yandex_iam_service_account.bot_sa.id}" depends_on = [yandex_iam_service_account.bot_sa] } resource "yandex_resourcemanager_folder_iam_member" "sa_invoker" { folder_id = var.folder_id role = "functions.functionInvoker" member = "serviceAccount:${yandex_iam_service_account.bot_sa.id}" depends_on = [yandex_iam_service_account.bot_sa] } # Создание статических ключей доступа resource "yandex_iam_service_account_static_access_key" "bot_sa_key" { service_account_id = yandex_iam_service_account.bot_sa.id description = "Static key for bot service account" depends_on = [ yandex_resourcemanager_folder_iam_member.sa_editor ] } # Создание бакета resource "yandex_storage_bucket" "bot_bucket" { bucket = var.bucket_name access_key = yandex_iam_service_account_static_access_key.bot_sa_key.access_key secret_key = yandex_iam_service_account_static_access_key.bot_sa_key.secret_key anonymous_access_flags { read = true } depends_on = [ yandex_iam_service_account_static_access_key.bot_sa_key ] } # Загрузка картинки в бакет resource "yandex_storage_object" "sayhello_png" { bucket = yandex_storage_bucket.bot_bucket.bucket key = "sayhello.png" source = "sayhello.png" acl = "public-read" access_key = yandex_iam_service_account_static_access_key.bot_sa_key.access_key secret_key = yandex_iam_service_account_static_access_key.bot_sa_key.secret_key content_type = "image/png" depends_on = [yandex_storage_bucket.bot_bucket] } # Создание zip-архива для функции data "archive_file" "function" { type = "zip" source { content = templatefile("telegram-bot-function.tpl", { API_GW_URL = yandex_api_gateway.bot_gateway.domain }) filename = "index.js" } source { content = "${file("package.json")}" filename = "package.json" } output_path = "function.zip" depends_on = [yandex_api_gateway.bot_gateway] } # Создание публичной функции resource "yandex_function" "telegram_bot_function" { name = "fshtb-function" description = "Serverless Telegram bot on Node.js" runtime = "nodejs22" entrypoint = "index.handler" memory = 256 execution_timeout = 5 service_account_id = yandex_iam_service_account.bot_sa.id environment = { BOT_TOKEN = var.bot_token } content { zip_filename = "function.zip" } user_hash = filesha256("telegram-bot-function.tpl") depends_on = [ yandex_resourcemanager_folder_iam_member.sa_editor, yandex_resourcemanager_folder_iam_member.sa_invoker, data.archive_file.function ] } resource "yandex_function_iam_binding" "public_invoker" { function_id = yandex_function.telegram_bot_function.id role = "functions.functionInvoker" members = ["system:allUsers"] } # Создание API-шлюза resource "yandex_api_gateway" "bot_gateway" { name = "forserverless-hello-telegram-bot" description = "API gateway for telegram bot" spec = templatefile("telegram-bot-gw-spec.tpl", { BUCKET_NAME = yandex_storage_bucket.bot_bucket.id OBJECT_NAME = yandex_storage_object.sayhello_png.key SA_ID = yandex_iam_service_account.bot_sa.id }) } -
Шаблон для создания функции Yandex Cloud Functions
telegram-bot-function.tpl:telegram-bot-function.tpl
const { Telegraf } = require('telegraf'); const bot = new Telegraf(process.env.BOT_TOKEN); bot.start((ctx) => ctx.reply(`Hello. \nMy name Serverless Hello Telegram Bot \nI'm working on Cloud Function in the Yandex.Cloud.`)) bot.help((ctx) => ctx.reply(`Hello, ${ctx.message.from.username}.\nI can say Hello and nothing more`)) bot.on('text', (ctx) => { ctx.replyWithPhoto({url: 'https://${API_GW_URL}/sayhello.png'}); ctx.reply(`Hello, ${ctx.message.from.username}`); }); module.exports.handler = async function (event, context) { const message = JSON.parse(event.body); await bot.handleUpdate(message); return { statusCode: 200, body: '', }; }; -
Шаблон спецификации API-шлюза
telegram-bot-gw-spec.tpl:telegram-bot-gw-spec.tpl
openapi: 3.0.0 info: title: for-serverless-hello-telegram-bot version: 1.0.0 paths: /sayhello.png: get: x-yc-apigateway-integration: type: object-storage bucket: ${BUCKET_NAME} object: ${OBJECT_NAME} presigned_redirect: false service_account: ${SA_ID} operationId: static -
Файл с пользовательскими данными
telegram-bot.auto.tfvars:bot_token = "<токен_Telegram-бота>" bucket_name = "<имя_бакета>" cloud_id = "<идентификатор_облака>" folder_id = "<идентификатор_каталога>" -
Манифест для функции Node.js
package.json:{ "name": "ycf-telegram-example", "version": "1.0.0", "description": "", "main": "index.js", "scripts": { "test": "echo \"Error: no test specified\" && exit 1" }, "author": "", "license": "MIT", "dependencies": { "telegraf": "^4.12.0" } }
-
Более подробную информацию о параметрах используемых ресурсов в Terraform см. в документации провайдера:
- Сервисный аккаунт — yandex_iam_service_account.
- Назначение роли сервисному аккаунту — yandex_resourcemanager_folder_iam_member.
- Статический ключ доступа — yandex_iam_service_account_static_access_key.
- Бакет — yandex_storage_bucket.
- Объект — yandex_storage_object.
- API-шлюз — yandex_api_gateway.
- Функция — yandex_function.
- Назначение роли на функцию — yandex_function_iam_binding.
-
-
В файле
telegram-bot.auto.tfvarsзадайте пользовательские параметры:bot_token— токен Telegram-бота.bucket_name— имя бакета.cloud_id— идентификатор облака.folder_id— идентификатор каталога.
-
Создайте ресурсы:
-
В терминале перейдите в директорию с конфигурационным файлом.
-
Проверьте корректность конфигурации с помощью команды:
terraform validateЕсли конфигурация является корректной, появится сообщение:
Success! The configuration is valid. -
Выполните команду:
terraform planВ терминале будет выведен список ресурсов с параметрами. На этом этапе изменения не будут внесены. Если в конфигурации есть ошибки, Terraform на них укажет.
-
Примените изменения конфигурации:
terraform apply -
Подтвердите изменения: введите в терминале слово
yesи нажмите Enter.
-
-
Настройте связь между функцией и Telegram-ботом.
-
Измените спецификацию API-шлюза — после имеющихся строчек кода добавьте секцию
fshtb-function:/fshtb-function: post: x-yc-apigateway-integration: type: cloud_functions function_id: <идентификатор_функции> operationId: fshtb-functionГде
function_id— идентификатор функцииfshtb-function. -
Примените изменения конфигурации:
terraform apply -
Подтвердите изменения: введите в терминале слово
yesи нажмите Enter. -
В терминале выполните следующую команду: вместо
<токен_бота>укажите токен Telegram-бота, вместо<домен_API-шлюза>— служебный домен API-шлюза:-
Linux, macOS:
curl \ --request POST \ --url https://api.telegram.org/bot<токен_бота>/setWebhook \ --header 'content-type: application/json' \ --data '{"url": "<домен_API-шлюза>/fshtb-function"}' -
Windows (cmd):
curl ^ --request POST ^ --url https://api.telegram.org/bot<токен_бота>/setWebhook ^ --header "content-type: application/json" ^ --data "{\"url\": \"<домен_API-шлюза>/fshtb-function\"}" -
Windows (PowerShell):
curl.exe ` --request POST ` --url https://api.telegram.org/bot<токен_бота>/setWebhook ` --header '"content-type: application/json"' ` --data '"{ \"url\": \"<домен_API-шлюза>/fshtb-function\" }"'
Результат:
{"ok":true,"result":true,"description":"Webhook was set"} -
-
Проверьте работу Telegram-бота
Поговорите с ботом:
-
Откройте Telegram и найдите бота по имени пользователя
username, созданному ранее. -
Отправьте в чат сообщение
/start.Бот должен ответить:
Hello. My name Serverless Hello Telegram Bot I'm working on Cloud Function in the Yandex Cloud. -
Отправьте в чат сообщение
/help.Бот должен ответить:
Hello, <username>. I can say Hello and nothing more -
Отправьте в чат любое текстовое сообщение. Бот должен в ответ прислать изображение и сообщение:
Hello, <username>.
Как удалить созданные ресурсы
Чтобы перестать платить за созданные ресурсы:
-
Откройте конфигурационный файл
telegram-bot.tfи удалите описание создаваемой инфраструктуры из файла. -
Примените изменения:
-
В терминале перейдите в директорию с конфигурационным файлом.
-
Проверьте корректность конфигурации с помощью команды:
terraform validateЕсли конфигурация является корректной, появится сообщение:
Success! The configuration is valid. -
Выполните команду:
terraform planВ терминале будет выведен список ресурсов с параметрами. На этом этапе изменения не будут внесены. Если в конфигурации есть ошибки, Terraform на них укажет.
-
Примените изменения конфигурации:
terraform apply -
Подтвердите изменения: введите в терминале слово
yesи нажмите Enter.
-