ProHoster > blog > amministrazione > Un esempio di un'applicazione basata su eventi basata su webhook nello storage di oggetti S3 Mail.ru Cloud Solutions
Un esempio di un'applicazione basata su eventi basata su webhook nello storage di oggetti S3 Mail.ru Cloud Solutions
L'architettura basata sugli eventi aumenta l'efficienza in termini di costi delle risorse utilizzate perché vengono utilizzate solo nel momento in cui sono necessarie. Esistono molte opzioni su come implementarlo e su come non creare entità cloud aggiuntive come applicazioni di lavoro. E oggi non parlerò di FaaS, ma di webhook. Mostrerò un esempio tutorial sulla gestione degli eventi utilizzando i webhook di archiviazione di oggetti.
Qualche parola sull'archiviazione di oggetti e sui webhook. Lo storage degli oggetti consente di archiviare qualsiasi dato nel cloud sotto forma di oggetti, accessibili tramite S3 o un'altra API (a seconda dell'implementazione) tramite HTTP/HTTPS. I webhook sono generalmente callback HTTP personalizzati. In genere vengono attivati da un evento, ad esempio il codice inviato a un repository o un commento pubblicato su un blog. Quando si verifica un evento, il sito di origine invia una richiesta HTTP all'URL specificato per il webhook. Di conseguenza, puoi fare in modo che gli eventi su un sito attivino azioni su un altro (wiki). Nel caso in cui il sito di origine sia un oggetto di archiviazione, gli eventi agiscono come modifiche al suo contenuto.
Esempi di casi semplici in cui è possibile utilizzare tale automazione:
Creazione di copie di tutti gli oggetti in un altro archivio cloud. Le copie devono essere create al volo ogni volta che i file vengono aggiunti o modificati.
Creazione automatica di una serie di miniature di file grafici, aggiunta di filigrane alle fotografie e altre modifiche alle immagini.
Notifica sull'arrivo di nuovi documenti (ad esempio, un servizio di contabilità distribuita carica i report nel cloud e il monitoraggio finanziario riceve notifiche sui nuovi report, li controlla e li analizza).
Casi leggermente più complessi riguardano, ad esempio, la generazione di una richiesta a Kubernetes, che crea un pod con i contenitori necessari, gli passa i parametri dell'attività e, dopo l'elaborazione, comprime il contenitore.
Ad esempio, creeremo una variante dell'attività 1, quando le modifiche nel bucket di storage di oggetti Mail.ru Cloud Solutions (MCS) vengono sincronizzate nello storage di oggetti AWS utilizzando webhook. In un caso di caricamento reale, il lavoro asincrono dovrebbe essere fornito registrando i webhook in coda, ma per l'attività di training eseguiremo l'implementazione senza di ciò.
Schema di lavoro
Il protocollo di interazione è descritto in dettaglio in Guida ai webhook S3 su MCS. Lo schema di lavoro contiene i seguenti elementi:
Servizio editoriale, che si trova sul lato storage S3 e pubblica richieste HTTP quando viene attivato il webnhook.
Server di ricezione del webhook, che ascolta le richieste dal servizio di pubblicazione HTTP ed esegue le azioni appropriate. Il server può essere scritto in qualsiasi lingua; nel nostro esempio scriveremo il server in Go.
Una particolarità dell'implementazione dei webhook nell'API S3 è la registrazione del server di ricezione del webhook sul servizio di pubblicazione. In particolare, il server ricevente del webhook deve confermare l'iscrizione ai messaggi dal servizio di pubblicazione (in altre implementazioni del webhook, solitamente non è richiesta la conferma dell'iscrizione).
Di conseguenza, il server di ricezione del webhook deve supportare due operazioni principali:
rispondere alla richiesta del servizio editoriale di confermare la registrazione,
elaborare gli eventi in arrivo.
Installazione di un server di ricezione webhook
Per eseguire il server di ricezione del webhook, è necessario un server Linux. In questo articolo, ad esempio, utilizziamo un'istanza virtuale che distribuiamo su MCS.
Installiamo il software necessario e avviamo il server di ricezione del webhook.
ubuntu@ubuntu-basic-1-2-10gb:~$ sudo apt-get install git
Reading package lists... Done
Building dependency tree
Reading state information... Done
The following packages were automatically installed and are no longer required:
bc dns-root-data dnsmasq-base ebtables landscape-common liblxc-common
liblxc1 libuv1 lxcfs lxd lxd-client python3-attr python3-automat
python3-click python3-constantly python3-hyperlink
python3-incremental python3-pam python3-pyasn1-modules
python3-service-identity python3-twisted python3-twisted-bin
python3-zope.interface uidmap xdelta3
Use 'sudo apt autoremove' to remove them.
Suggested packages:
git-daemon-run | git-daemon-sysvinit git-doc git-el git-email git-gui
gitk gitweb git-cvs git-mediawiki git-svn
The following NEW packages will be installed:
git
0 upgraded, 1 newly installed, 0 to remove and 46 not upgraded.
Need to get 3915 kB of archives.
After this operation, 32.3 MB of additional disk space will be used.
Get:1 http://MS1.clouds.archive.ubuntu.com/ubuntu bionic-updates/main
amd64 git amd64 1:2.17.1-1ubuntu0.7 [3915 kB]
Fetched 3915 kB in 1s (5639 kB/s)
Selecting previously unselected package git.
(Reading database ... 53932 files and directories currently installed.)
Preparing to unpack .../git_1%3a2.17.1-1ubuntu0.7_amd64.deb ...
Unpacking git (1:2.17.1-1ubuntu0.7) ...
Setting up git (1:2.17.1-1ubuntu0.7) ...
Clona la cartella con il server di ricezione del webhook:
Vai al bucket per il quale configureremo i webhook e fai clic sull'ingranaggio:
Vai alla scheda Webhook e fai clic su Aggiungi:
Compila i campi:
ID: il nome del webhook.
Evento - quali eventi trasmettere. Abbiamo impostato la trasmissione di tutti gli eventi che si verificano quando si lavora con i file (aggiunta ed eliminazione).
URL: indirizzo del server di ricezione del webhook.
Il prefisso/suffisso del filtro è un filtro che consente di generare webhook solo per oggetti i cui nomi corrispondono a determinate regole. Ad esempio, affinché il webhook attivi solo i file con estensione .png, in Suffisso del filtro devi scrivere "png".
Attualmente, solo le porte 80 e 443 sono supportate per l'accesso al server di ricezione del webhook.
Facciamo clic Aggiungi gancio e vedremo quanto segue:
Gancio aggiunto.
Il server di ricezione del webhook mostra nei suoi log l'avanzamento del processo di registrazione del webhook:
La registrazione è completata. Nella sezione successiva, daremo uno sguardo più da vicino all'algoritmo di funzionamento del server di ricezione del webhook.
Descrizione del server di ricezione del webhook
Nel nostro esempio, il server è scritto in Go. Diamo un'occhiata ai principi di base del suo funzionamento.
conferma l'iscrizione al servizio editoriale (vai alla funzione Conferma Iscrizione),
elabora i webhook in entrata (funzione Gorecords).
Le funzioni HmacSha256 e HmacSha256hex sono implementazioni degli algoritmi di crittografia HMAC-SHA256 e HMAC-SHA256 con output come stringa di numeri esadecimali per il calcolo della firma.
main è la funzione principale, elabora i parametri della riga di comando e registra i gestori URL.
Parametri della riga di comando accettati dal server:
-port è la porta su cui il server ascolterà.
-address - Indirizzo IP che il server ascolterà.
-script è un programma esterno che viene chiamato per ogni hook in entrata.
Diamo uno sguardo più da vicino ad alcune delle funzioni:
//Webhook
func Webhook(w http.ResponseWriter, req *http.Request) {
// Read body
body, err := ioutil.ReadAll(req.Body)
defer req.Body.Close()
if err != nil {
http.Error(w, err.Error(), 500)
return
}
// log request
log.Printf("[%s] incoming HTTP request from %sn", req.Method, req.RemoteAddr)
// check if we got subscription confirmation request
if strings.Contains(string(body),
""Type":"SubscriptionConfirmation"") {
SubscriptionConfirmation(w, req, body)
} else {
GotRecords(w, req, body)
}
}
Questa funzione determina se è arrivata una richiesta di conferma della registrazione oppure un webhook. Come segue da documentazione, se la registrazione viene confermata, nella richiesta Post viene ricevuta la seguente struttura Json:
POST http://test.com HTTP/1.1
x-amz-sns-messages-type: SubscriptionConfirmation
content-type: application/json
{
"Timestamp":"2019-12-26T19:29:12+03:00",
"Type":"SubscriptionConfirmation",
"Message":"You have chosen to subscribe to the topic $topic. To confirm the subscription you need to response with calculated signature",
"TopicArn":"mcs2883541269|bucketA|s3:ObjectCreated:Put",
"SignatureVersion":1,
"Token":«RPE5UuG94rGgBH6kHXN9FUPugFxj1hs2aUQc99btJp3E49tA»
}
Di conseguenza, a seconda della richiesta, è necessario capire come trattare i dati. Ho scelto la voce come indicatore "Type":"SubscriptionConfirmation", poiché è presente nella richiesta di conferma della sottoscrizione e non è presente nel webhook. In base alla presenza/assenza di questa voce nella richiesta POST, l'ulteriore esecuzione del programma va alla funzione SubscriptionConfirmationo in una funzione GotRecords.
Non considereremo nel dettaglio la funzione SubscriptionConfirmation; essa è implementata secondo i principi enunciati nell'art documentazione. È possibile visualizzare il codice sorgente per questa funzione su repository git del progetto.
La funzione GotRecords analizza una richiesta in arrivo e per ogni oggetto Record chiama uno script esterno (il cui nome è stato passato nel parametro -script) con i parametri:
nome del secchio
chiave dell'oggetto
azione:
copia - se nella richiesta originale EventName = ObjectCreated | MettiOggetto | PutObjectCopy
elimina - se nella richiesta originale EventName = ObjectRemoved | Eliminaoggetto
Pertanto, se arriva un hook con una richiesta Post, come descritto soprae il parametro -script=script.sh, lo script verrà chiamato come segue:
script.sh bucketA some-file-to-bucket copy
Dovrebbe essere chiaro che questo server di ricezione webhook non è una soluzione di produzione completa, ma un esempio semplificato di una possibile implementazione.
Esempio di lavoro
Sincronizziamo i file dal bucket principale in MCS al bucket di backup in AWS. Il bucket principale si chiama myfiles-ash, quello di backup si chiama myfiles-backup (la configurazione del bucket in AWS va oltre lo scopo di questo articolo). Di conseguenza, quando un file viene inserito nel bucket principale, la sua copia dovrebbe apparire in quello di backup e quando viene eliminato da quello principale, dovrebbe essere eliminato in quello di backup.
Lavoreremo con i bucket utilizzando l'utilità awscli, che è compatibile sia con lo storage cloud MCS che con lo storage cloud AWS.
ubuntu@ubuntu-basic-1-2-10gb:~$ sudo apt-get install awscli
Reading package lists... Done
Building dependency tree
Reading state information... Done
After this operation, 34.4 MB of additional disk space will be used.
Unpacking awscli (1.14.44-1ubuntu1) ...
Setting up awscli (1.14.44-1ubuntu1) ...
Configuriamo l'accesso all'API S3 MCS:
ubuntu@ubuntu-basic-1-2-10gb:~$ aws configure --profile mcs
AWS Access Key ID [None]: hdywEPtuuJTExxxxxxxxxxxxxx
AWS Secret Access Key [None]: hDz3SgxKwXoxxxxxxxxxxxxxxxxxx
Default region name [None]:
Default output format [None]:
Configuriamo l'accesso all'API AWS S3:
ubuntu@ubuntu-basic-1-2-10gb:~$ aws configure --profile aws
AWS Access Key ID [None]: AKIAJXXXXXXXXXXXX
AWS Secret Access Key [None]: dfuerphOLQwu0CreP5Z8l5fuXXXXXXXXXXXXXXXX
Default region name [None]:
Default output format [None]:
Verifichiamo gli accessi:
Ad AWS:
ubuntu@ubuntu-basic-1-2-10gb:~$ aws s3 ls --profile aws
2020-07-06 08:44:11 myfiles-backup
Per MCS, quando si esegue il comando è necessario aggiungere —endpoint-url:
Vediamo come funziona. Attraverso Interfaccia web MCS aggiungi il file test.txt al bucket myfiles-ash. I log della console mostrano che è stata effettuata una richiesta al server webhook:
2020/07/06 09:43:08 [POST] incoming HTTP request from
95.163.216.92:56612
download: s3://myfiles-ash/test.txt to ../../../tmp/myfiles-ash/test.txt
upload: ../../../tmp/myfiles-ash/test.txt to
s3://myfiles-backup/test.txt
Controlliamo il contenuto del bucket myfiles-backup in AWS:
Ora, tramite l'interfaccia web, elimineremo il file dal bucket myfiles-ash.
Registri del server:
2020/07/06 09:44:46 [POST] incoming HTTP request from
95.163.216.92:58224
delete: s3://myfiles-backup/test.txt
Contenuto del secchio:
ubuntu@ubuntu-basic-1-2-10gb:~/s3-webhook$ aws s3 --profile aws ls
myfiles-backup
ubuntu@ubuntu-basic-1-2-10gb:~$
Il file viene eliminato, il problema è risolto.
Conclusione e cose da fare
Tutto il codice utilizzato in questo articolo è nel mio archivio. Sono inoltre disponibili esempi di script ed esempi di conteggio delle firme per la registrazione dei webhook.
Questo codice non è altro che un esempio di come puoi utilizzare i webhook S3 nelle tue attività. Come ho detto all'inizio, se prevedi di utilizzare un server di questo tipo in produzione, devi almeno riscrivere il server per il lavoro asincrono: registrare i webhook in entrata in una coda (RabbitMQ o NATS), e da lì analizzarli ed elaborarli con le domande dei lavoratori. Altrimenti, quando i webhook arrivano in massa, potresti riscontrare una mancanza di risorse del server per completare le attività. La presenza di code consente di distribuire server e lavoratori, nonché di risolvere problemi con la ripetizione delle attività in caso di guasti. Si consiglia inoltre di modificare la registrazione in una più dettagliata e standardizzata.