Aws Serverless를 이용한 Telegram Bot 만들기
Serverless Telegram Bot 만들기
최근 서버 설계의 한 축을 담당하고 있는 핫한 serverless 기반으로 텔레그램 봇을 만들어보자.
Serverless 란?
서버리스하면 서버가 없다 는 것인가? 생각을 할 수 있는데, 서버는 있다. 전통적인 서버-클라이언트 구조에서는 서버는 하나의 물리적 장비 를 쓰거나 대여하여 24시간 돌아가는 데몬을 기반으로 서버-클라이언트 구조를 구현했다. 서버리스는 이러한 전통적인 구조를 완전 깼다. 하나의 서비스를 제공하기 위해 굳이 하나의 서버를 잡고 데몬이 돌아가는 것이 아니고, 함수 단위 로 잘게 나눠서 임의의 서버에서 이 작업을 수행하는 것을 뜻한다. 주로 유명한 서버리스 프레임워크는 firebase, aws.lambda 가 있다. 여러가지 많지만 저는 꼬꼬마라 다 알지는 못함.
써야 하는 aws 서비스들
aws.lambda, aws.cloudwatch, aws.dynamodb, aws.apigateway
비용은?
비용이 또 ㅁㅊㄸ.
월 200만건에 각 실행시간 100ms 에 대해서 월 0.2$ 라고 나온다.
개인이나 스타트업입장의 개발에서는 공짜나 다름없다.
개발 환경 꾸리기
nodejs & npm 설치
https://nodejs.org/ko/download/package-manager/
AWS Cli 설치
https://aws.amazon.com/ko/cli/
Serverless framework 설치하기
$ sudo npm install -g serverless
aws IAM 사용자 추가
- AWS 메뉴 중, Identity and Access Management(IAM) 들어가서 사용자 추가 를 한다.
- AWS 액세스 유형 선택 액세스 유형: 프로그래밍 방식 액세스
- 엑세스 그룹 admin: AdministratorAccess
$ aws configure
AWS Access Key ID[]: _______
AWS Secret Access Key ID[]: _________
프로젝트 생성
$ mkdir telegram-echo
$ cd telegram-echo
$ serverless create --template hello-world
Serverless: Generating boilerplate...
_______ __
| _ .-----.----.--.--.-----.----| .-----.-----.-----.
| |___| -__| _| | | -__| _| | -__|__ --|__ --|
|____ |_____|__| \___/|_____|__| |__|_____|_____|_____|
| | | The Serverless Application Framework
| | serverless.com, v1.79.0
-------'
Serverless: Successfully generated boilerplate for template: "hello-world"
Serverless: NOTE: Please update the "service" property in serverless.yml with your service name
╭─dire@dire-81w4 ~/workspace/telegram-echo
╰─$ ls
handler.js serverless.yml
handler.js, serverless.yml 이 생성된 모습이 보인다.
╭─dire@dire-81w4 ~/workspace/telegram-echo
╰─$ cat handler.js
'use strict';
module.exports.helloWorld = (event, context, callback) => {
const response = {
statusCode: 200,
headers: {
'Access-Control-Allow-Origin': '*', // Required for CORS support to work
},
body: JSON.stringify({
message: 'Go Serverless v1.0! Your function executed successfully!',
input: event,
}),
};
callback(null, response);
};
╭─dire@dire-81w4 ~/workspace/telegram-echo
╰─$ cat serverless.yml
# Welcome to serverless. Read the docs
# https://serverless.com/framework/docs/
# Serverless.yml is the configuration the CLI
# uses to deploy your code to your provider of choice
# The `service` block is the name of the service
service: telegram-echo
# The `provider` block defines where your service will be deployed
provider:
name: aws
runtime: nodejs12.x
# The `functions` block defines what code to deploy
functions:
helloWorld:
handler: handler.helloWorld
# The `events` block defines how to trigger the handler.helloWorld code
events:
- http:
path: hello-world
method: get
cors: true
별거 없고, helloWorld 를 핸들러로 하는 프로젝트 하나가 세팅된 모습이다.
provider: 항목에 region 을 넣을 수 있는데, 기본 region 은 east 어딘가로 설정이 되는데, 우리는 한국인이니 다음 줄을 추가하자. region: ap-northeast-2
그리고 게이트웨이는 직접 세팅할 것이므로
provider:
name: aws
runtime: nodejs12.x
region: ap-northeast-2
이런 모양이 될거다.
이제 드디어
╭─dire@dire-81w4 ~/workspace/telegram-echo
╰─$ serverless deploy
Serverless: Packaging service...
Serverless: Excluding development dependencies...
Serverless: Uploading CloudFormation file to S3...
Serverless: Uploading artifacts...
Serverless: Uploading service telegram-echo.zip file to S3 (740 B)...
Serverless: Validating template...
Serverless: Updating Stack...
Serverless: Checking Stack update progress...
...............
Serverless: Stack update finished...
Service Information
service: telegram-echo
stage: dev
region: ap-northeast-2
stack: telegram-echo-dev
resources: 6
api keys:
None
endpoints:
None
functions:
helloWorld: telegram-echo-dev-helloWorld
layers:
None
***********************************************************************
Serverless: Announcing an enhanced experience for running Express.js apps: https://github.com/serverless-components/express.
***********************************************************************
우리의 aws console 들어가서 뭐가 어떻게 됐나 확인해볼까?
외부 url 를 호출하면 우리 람다를 호출할 http api 가 필요하다. 트리거 추가를 누른다.
- API Gateway
- Create an API
- HTTP API
- 보안: 열기
아래에 보면 API endpoint 가 있다. 이 url 에 접근을 하게 되면 telegram-echo-dev-helloWorld 함수를 실행한다는 의미다.
함수를 실행하는 방법은 크게 두 가지. api gateway 를 통해 호출하거나 테스트 버튼을 이용해 테스트를 하거나.
handler.js 에 한줄 추가해서 다시 deploy 해보자.
console.log("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@KSOO@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@");
추가 후, serverless deploy
그러고 url 호출해본다. 로그는 어디서 확인하나?
cloudwatch.loggroup./aws/lambda/telegram-echo-dev-helloWorld
GET 변수를 넘길 수도 있다.
https://xxxxxxxxx.execute-api.ap-northeast-2.amazonaws.com/dev/hello-world?var=KSOOKSOOKSOO
..."queryStringParameters":{"var":"KSOOKSOOKSOO"},...
텔레그램과 연동
먼저 봇을 하나 만들어야 한다.
텔레그램앱에서 BotFather 를 친구 추가한다.
/newbot
BotFather, [10.09.20 17:41]
Alright, a new bot. How are we going to call it? Please choose a name for your bot.
input: telegless_bot
BotFather, [10.09.20 17:42]
Good. Now let's choose a username for your bot. It must end in `bot`. Like this, for example: TetrisBot or tetris_bot.
input: teleless_bot
BotFather, [10.09.20 17:42]
Done! Congratulations on your new bot. You will find it at t.me/teleless_bot. You can now add a description, about section and profile picture for your bot, see /help for a list of commands. By the way, when you've finished creating your cool bot, ping our Bot Support if you want a better username for it. Just make sure the bot is fully operational before you do this.
Use this token to access the HTTP API:
1349292513:AAEyIjGis0AHzrEuP4uFkRl4AvgLM*********
Keep your token secure and store it safely, it can be used by anyone to control your bot.
For a description of the Bot API, see this page: https://core.telegram.org/bots/api
여기 나온 API 는 잘 기억하거나 기록 해둬야 한다. 만든 봇에 접근할 수 있는 키의 역할을 한다.
Telegram Webhook
우리의 목표는 지금 하나다. 텔레그램 봇에 타자를 치면 이 정보를 우리의 aws.lambda 로 전달하는 것.
텔레그램에서는 webhook 를 지원한다. webhook 을 걸게 되면 텔레그램 봇으로 들어오는 정보를 어떤 url 로 포워딩 시켜줄 수가 있다.
https://core.telegram.org/bots/api#setwebhook
문서를 보면
https://api.telegram.org/bot${telegram_token}/setWebhook?url=${callback_url}
이에 맞춰서 웹브라우저에서 호출해보자.
https://api.telegram.org/*********/setWebhook?url=https://**************.com/default/telegram-echo-dev-helloWorld
이렇게 호출을 하면 웹훅이 등록된다고 되어있다. 등록해보자. Webhook was set. 과 같은 문구가 뜨면 성공. 우리 telegless_bot 을 친구 추가하고 말 걸어보자.
CloudWatch 에 우리가 추가한 로그가 찍혀있는지 확인해보자. @@@@@@@@@@ 가 많아서 확인하기 쉬울 거다.
Echo Bot
간단하게 에코봇을 만들어보자.
handler.js
'use strict';
const AWS = require('aws-sdk');
const TOKEN = '{telegram_api_token}'; // YOUR TOKEN
const https = require('https');
const util = require('util');
AWS.config.update({region: 'ap-northeast-2'})
const docClient = new AWS.DynamoDB.DocumentClient();
module.exports.helloWorld = async (event, context, callback) => {
const response = {
statusCode: 200,
headers: {
'Access-Control-Allow-Origin': '*', // Required for CORS support to work
},
body: JSON.stringify({
message: 'test message',
input: event,
}),
};
callback(null, response);
let telegramCall = typeof(event.body) !== 'undefined';
if(telegramCall) {
const obj = JSON.parse(event.body);
console.info("telegram obj: ", obj);
let chatId = (obj.message.chat.id).toString();
const requestText = obj.message.text;
console.info("chatId: ", chatId, ", requestText: ", requestText);
var splits = requestText.split(" ");
if (splits[0] == "/start") {
const postData = {
"chat_id": chatId,
"text": "따라쟁이 봇 시작합니다."
};
sendMessage(context, postData);
} else {
const postData = {
"chat_id": chatId,
"text": requestText
};
sendMessage(context, postData);
}
}
};
function sendMessage(context, content) {
const options = {
method: 'POST',
hostname: 'api.telegram.org',
port: 443,
headers: {"Content-Type": "application/json"},
path: "/bot" + TOKEN + "/sendMessage"
};
const req = https.request(options, (res) => {
res.setEncoding('utf8');
res.on('data', (chunk) => {
context.done(null);
});
});
req.on('error', function (e) {
console.log('problem with request: ' + e.message);
});
req.write(util.format("%j", content));
req.end();
}
dynamodb
따라하는건 된다. 그리고 하나의 의문이 들거다. 만약 문맥(Context)이 있는 봇을 만들고 싶다면? 즉, 입력되는 데이터를 저장하고 싶을 때는?
이 때 사용하는 것이 dynamodb 다. 다이나모디비 이름 참 이쁘다.