Benvenuti in questo terzo tutorial sui bot di Telegram. Abbiamo imparato a creare semplici bot col modulo telepot e ci siamo sbizzarriti per renderli sempre più raffinati. Finora abbiamo utilizzato le nostre macchine di sviluppo con accesso ad internet, ma non potremo sempre farci affidamento per mantenere attivi i nostri bot.
In questo veloce tutorial vedremo come creare una immagine Docker del bot presentato da Andrea nella seconda parte di questa serie e come deployarla in un container sul servizio di hosting Heroku.
Requisiti
- Tutti i concetti spiegati nella parte 1 e 2 di questa serie
- Concetti base di Docker
- Un account Heroku
Modifiche al bot
Prima di procedere, mi sono permesso di fare una piccola modifica al codice del bot presentato da Andrea:
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 42 43 44 45 46 47 |
import telepot from telepot.loop import MessageLoop from telepot.namedtuple import InlineKeyboardMarkup, InlineKeyboardButton from pprint import pprint import time import datetime import json from urllib2 import urlopen import os TOKEN = os.environ.get('API_TOKEN', None) def on_chat_message(msg): content_type, chat_type, chat_id = telepot.glance(msg) keyboard = InlineKeyboardMarkup(inline_keyboard=[ [InlineKeyboardButton(text='IP', callback_data='ip'), InlineKeyboardButton(text='Info', callback_data='info')], [InlineKeyboardButton(text='Time', callback_data='time')], ]) bot.sendMessage(chat_id, 'Use inline keyboard', reply_markup=keyboard) def on_callback_query(msg): query_id, chat_id, query_data = telepot.glance(msg, flavor='callback_query') print('Callback Query:', query_id, chat_id, query_data) if query_data=='ip': my_ip = urlopen('http://ip.42.pl/raw').read() bot.sendMessage(chat_id, my_ip) elif query_data=='info': info=json.dumps(bot.getUpdates(),sort_keys=True, indent=4) bot.sendMessage(chat_id, info) elif query_data=='time': ts = time.time() bot.answerCallbackQuery(query_id, text=datetime.datetime.fromtimestamp(ts).strftime('%H:%M:%S')) #messaggio a comparsa bot = telepot.Bot(TOKEN) MessageLoop(bot, {'chat': on_chat_message, 'callback_query': on_callback_query}).run_as_thread() print('Listening ...') while 1: time.sleep(10) |
Per rendere il codice più sicuro e modularizzabile, ho impostato la lettura da variabile d'ambiente del token che ci ha restituito BotFather quando abbiamo creato il nostro bot. Nel seguito del tutorial vedremo come impostare il token tra le variabili d'ambiente del container.
Per pulizia, nella cartella di progetto contenente il file bot.py
aggiungiamo un file requirements.txt
. In questo caso, l'unico modulo python esterno alle librerie base di cui abbiamo bisogno è telepot
, quindi il file requirements.txt
conterrà una sola riga con scritto "telepot
".
Creazione del Dockerfile
Abbiamo già parlato di Docker nell'articolo di Valentina che vi invito a rileggere per avere una infarinatura di base del framework.
Nella cartella del progetto andiamo ad aggiunge un Dockerfile
così definito:
1 2 3 4 5 6 7 8 9 |
FROM debian:stretch RUN apt-get update RUN apt-get install -y python-pip WORKDIR /app COPY requirements.txt /app/ COPY bot.py /app/ RUN pip install --upgrade pip RUN pip install -r requirements.txt CMD python bot.py |
Dal file si nota che partiamo dall'immagine debian:stretch
e andiamo ad installarci pip
per gestire i moduli python
. Avviato il container, sarà eseguito il comando python bot.py
. Per provare il Dockerfile
, possiamo creare l'immagine e successivamente avviare un container che la contenga:
docker build -t NOME_IMMAGINE:TAG .
docker run -d NOME_IMMAGINE:TAG
Se tutto è andato a buon fine digitiamo docker ps
per controllare lo stato dei container attivi. Se è presente il container appena creato, il bot dovrebbe rispondere alle nostre richieste.
Per vedere i log del container, digitiamo il comando:
docker logs -f CONTAINER_ID
Deploy del container su Heroku
Procediamo adesso a crearci un account su Heroku seguendo le istruzioni sul sito ufficiale.
Una volta fatto, installiamo sulla nostra macchina Debian/Ubuntu la Command Line Interface di Heroku digitando il seguente comando:
sudo wget -qO- https://toolbelt.heroku.com/install-ubuntu.sh | sh
In alternativa, per gli altri sistemi operativi, seguite le istruzioni ufficiali.
DISCLAIMER: ciò che segue della procedura presentata nel tutorial è tratto dalla guida ufficiale di Heroku per la gestione dei container Docker. Vi invito perciò a dargli un'occhiata prima di proseguire, così da avere un'idea generale delle operazioni che andremo ad eseguire.
Spostiamoci nella cartella contenente il Dockerfile
ed eseguiamo i seguenti comandi
heroku login
heroku:container login
Col primo comando ci siamo loggati tramite la CLI al nostro account di Heroku, mentre col secondo comando ci siamo collegati al Container Registry di Heroku dove andremo a caricare il nostro container Docker.
Adesso siamo pronti a creare la nostra app:
heroku create
La CLI di Heroku ci risponderà con il nome casualmente generato per la nostra app. Solitamente il nome è formato da un aggettivo in inglese, un nome comune in inglese ed una sequenza numerica, separati da dei trattini.
Prima di andare avanti sul terminale, colleghiamoci alla dashboard di Heroku accedendo sul sito ufficiale.
Nella pagina personale troveremo l'elenco delle nostre app, tra cui quella appena creata.
Clicchiamo sulla nuova app e andiamo su Settings. Nella sezione Config Vars andiamo ad aggiungere la variabile d'ambiente contenente il token delle api di Telegram:
KEY=API_TOKEN
VALUE=token
Dopo aver salvato, torniamo sul terminale e digitiamo:
heroku container:push worker --app APP_NAME
Con questo comando, abbiamo fatto il push del container nel registry di Heroku. La parola chiave worker
si riferisce al Process Type scelto per la nostra applicazione. Poichè abbiamo utilizzato MessageLoop
al posto dei WebHooks
forniti da telepot
, la nostra app non necessita di essere esposta ad alcuna porta. Per questo motivo, non è stato utilizzato il Process Type web
Effettuiamo adesso il vero e proprio deploy della applicazione:
heroku container:release worker --app APP_NAME
heroku ps:scale worker=1 --app APP_NAME
Per controllare lo stato della nostra app, digitiamo:
heroku ps --app APP_NAME
Per dare un'occhiata ai log della nostra app, digitimo:
heroku logs --tail --app APP_NAME
Se l'app non fosse partita, proviamo a digitare:
heroku restart --app APP_NAME
Possiamo modificare il nome della nostra app con uno sperabilmente più parlante accedendo alla pagina Settings della dashboard di Heroku.
Conclusioni
Ora che la nostra applicazione è attiva su Heroku, possiamo provare ad interrogare il bot da Telegram e vedere che tutto funzioni correttamente.
Come sempre, vi invito a lasciare un commento in coda all'articolo per qualsiasi domanda, richiesta di chiarimento, appunto o preciazione da utenti più esperti di Python, Docker o Heroku.
