Ett exempel pÄ en hÀndelsedriven applikation baserad pÄ webhooks i S3-objektlagring Mail.ru Cloud Solutions

Ett exempel pÄ en hÀndelsedriven applikation baserad pÄ webhooks i S3-objektlagring Mail.ru Cloud Solutions
Rube Goldberg kaffemaskin

HÀndelsedriven arkitektur ökar kostnadseffektiviteten för de resurser som anvÀnds eftersom de bara anvÀnds i det ögonblick dÄ de behövs. Det finns mÄnga alternativ för hur man implementerar detta och inte skapar ytterligare molnenheter som arbetarapplikationer. Och idag ska jag inte prata om FaaS, utan om webhooks. Jag ska visa ett sjÀlvstudieexempel pÄ hantering av hÀndelser med hjÀlp av webhooks för objektlagring.

NÄgra ord om objektlagring och webhooks. Objektlagring lÄter dig lagra all data i molnet i form av objekt, tillgÀngliga via S3 eller annat API (beroende pÄ implementering) via HTTP/HTTPS. Webhooks Àr i allmÀnhet anpassade HTTP-Äteruppringningar. De utlöses vanligtvis av en hÀndelse, till exempel att kod skickas till ett arkiv eller en kommentar som lÀggs upp pÄ en blogg. NÀr en hÀndelse intrÀffar skickar ursprungsplatsen en HTTP-begÀran till den URL som anges för webhook. Som ett resultat kan du fÄ hÀndelser pÄ en webbplats att utlösa ÄtgÀrder pÄ en annan (wiki). I det fall dÀr kÀllplatsen Àr en objektlagring fungerar hÀndelser som Àndringar av dess innehÄll.

Exempel pÄ enkla fall dÄ sÄdan automatisering kan anvÀndas:

  1. Skapa kopior av alla objekt i en annan molnlagring. Kopior mÄste skapas i farten nÀr filer lÀggs till eller Àndras.
  2. Automatiskt skapande av en serie miniatyrer av grafiska filer, lÀgga till vattenstÀmplar pÄ fotografier och andra bildÀndringar.
  3. Meddelande om ankomsten av nya dokument (till exempel laddar en distribuerad redovisningstjÀnst upp rapporter till molnet och finansövervakningen tar emot aviseringar om nya rapporter, kontrollerar och analyserar dem).
  4. NÄgot mer komplexa fall innebÀr till exempel att generera en begÀran till Kubernetes, som skapar en pod med nödvÀndiga behÄllare, skickar uppgiftsparametrar till den och efter bearbetning kollapsar behÄllaren.

Som ett exempel kommer vi att göra en variant av uppgift 1, nÀr Àndringar i Mail.ru Cloud Solutions (MCS) objektlagringshink synkroniseras i AWS-objektlagring med hjÀlp av webhooks. I ett riktigt laddat fall bör asynkront arbete tillhandahÄllas genom att registrera webhooks i en kö, men för utbildningsuppgiften kommer vi att göra implementeringen utan detta.

Arbetsordning

Interaktionsprotokollet beskrivs i detalj i Guide till S3 webhooks pÄ MCS. Arbetsschemat innehÄller följande element:

  • PubliceringstjĂ€nst, som finns pĂ„ S3-lagringssidan och publicerar HTTP-förfrĂ„gningar nĂ€r webnhook utlöses.
  • Webhook mottagande server, som lyssnar pĂ„ förfrĂ„gningar frĂ„n HTTP-publiceringstjĂ€nsten och utför lĂ€mpliga Ă„tgĂ€rder. Servern kan skrivas pĂ„ vilket sprĂ„k som helst, i vĂ„rt exempel kommer vi att skriva servern i Go.

En speciell egenskap för implementeringen av webhooks i S3 API Àr registreringen av webhook-mottagningsservern pÄ publiceringstjÀnsten. Speciellt mÄste den webhook-mottagande servern bekrÀfta prenumerationen pÄ meddelanden frÄn publiceringstjÀnsten (i andra webhook-implementationer krÀvs vanligtvis inte bekrÀftelse av prenumeration).

Följaktligen mÄste webhook-mottagande servern stödja tvÄ huvudoperationer:

  • svara pĂ„ förlagstjĂ€nstens begĂ€ran om att bekrĂ€fta registreringen,
  • bearbeta inkommande hĂ€ndelser.

Installation av en webhook-mottagningsserver

För att köra webhook-mottagningsservern behöver du Linux-server. I den hÀr artikeln anvÀnder vi en virtuell instans som distribuerats pÄ MCS som exempel.

LÄt oss installera den nödvÀndiga programvaran och starta webhook-mottagningsservern.

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) ...

Klona mappen med webhook-mottagningsservern:

ubuntu@ubuntu-basic-1-2-10gb:~$ git clone
https://github.com/RomanenkoDenys/s3-webhook.git
Cloning into 's3-webhook'...
remote: Enumerating objects: 48, done.
remote: Counting objects: 100% (48/48), done.
remote: Compressing objects: 100% (27/27), done.
remote: Total 114 (delta 20), reused 45 (delta 18), pack-reused 66
Receiving objects: 100% (114/114), 23.77 MiB | 20.25 MiB/s, done.
Resolving deltas: 100% (49/49), done.

LÄt oss starta servern:

ubuntu@ubuntu-basic-1-2-10gb:~$ cd s3-webhook/
ubuntu@ubuntu-basic-1-2-10gb:~/s3-webhook$ sudo ./s3-webhook -port 80

Prenumerera pÄ publiceringstjÀnst

Du kan registrera din webhook-mottagningsserver via API:et eller webbgrÀnssnittet. För enkelhetens skull kommer vi att registrera oss via webbgrÀnssnittet:

  1. LÄt oss gÄ till sektionen hinkar i kontrollrummet.
  2. GÄ till hinken som vi kommer att konfigurera webhooks för och klicka pÄ kugghjulet:

Ett exempel pÄ en hÀndelsedriven applikation baserad pÄ webhooks i S3-objektlagring Mail.ru Cloud Solutions

GÄ till fliken Webhooks och klicka pÄ LÀgg till:

Ett exempel pÄ en hÀndelsedriven applikation baserad pÄ webhooks i S3-objektlagring Mail.ru Cloud Solutions
Fyll i fÀlten:

Ett exempel pÄ en hÀndelsedriven applikation baserad pÄ webhooks i S3-objektlagring Mail.ru Cloud Solutions

ID — namnet pĂ„ webhook.

HÀndelse - vilka hÀndelser som ska överföras. Vi har stÀllt in överföringen av alla hÀndelser som intrÀffar nÀr man arbetar med filer (lÀgger till och raderar).

URL — webbhook mottagande serveradress.

Filterprefix/suffix Àr ett filter som lÄter dig generera webhooks endast för objekt vars namn matchar vissa regler. Till exempel, för att webhook endast ska trigga filer med filtillÀgget .png, in Filtersuffix du mÄste skriva "png".

För nÀrvarande stöds endast portarna 80 och 443 för Ätkomst till webhook-mottagningsservern.

LÄt oss klicka LÀgg till krok och vi kommer att se följande:

Ett exempel pÄ en hÀndelsedriven applikation baserad pÄ webhooks i S3-objektlagring Mail.ru Cloud Solutions
Krok tillagd.

Webhook-mottagningsservern visar i sina loggar förloppet för hook-registreringsprocessen:

ubuntu@ubuntu-basic-1-2-10gb:~/s3-webhook$ sudo ./s3-webhook -port 80
2020/06/15 12:01:14 [POST] incoming HTTP request from 
95.163.216.92:42530
2020/06/15 12:01:14 Got timestamp: 2020-06-15T15:01:13+03:00 TopicArn: 
mcs5259999770|myfiles-ash|s3:ObjectCreated:*,s3:ObjectRemoved:* Token: 
E2itMqAMUVVZc51pUhFWSp13DoxezvRxkUh5P7LEuk1dEe9y URL: 
http://89.208.199.220/webhook
2020/06/15 12:01:14 Generate responce signature: 
3754ce36636f80dfd606c5254d64ecb2fd8d555c27962b70b4f759f32c76b66d

Registreringen Àr klar. I nÀsta avsnitt kommer vi att titta nÀrmare pÄ algoritmen för driften av webhook-mottagningsservern.

Beskrivning av webhook-mottagande server

I vÄrt exempel Àr servern skriven i Go. LÄt oss titta pÄ de grundlÀggande principerna för dess funktion.

package main

// Generate hmac_sha256_hex
func HmacSha256hex(message string, secret string) string {
}

// Generate hmac_sha256
func HmacSha256(message string, secret string) string {
}

// Send subscription confirmation
func SubscriptionConfirmation(w http.ResponseWriter, req *http.Request, body []byte) {
}

// Send subscription confirmation
func GotRecords(w http.ResponseWriter, req *http.Request, body []byte) {
}

// Liveness probe
func Ping(w http.ResponseWriter, req *http.Request) {
    // log request
    log.Printf("[%s] incoming HTTP Ping request from %sn", req.Method, req.RemoteAddr)
    fmt.Fprintf(w, "Pongn")
}

//Webhook
func Webhook(w http.ResponseWriter, req *http.Request) {
}

func main() {

    // get command line args
    bindPort := flag.Int("port", 80, "number between 1-65535")
    bindAddr := flag.String("address", "", "ip address in dot format")
    flag.StringVar(&actionScript, "script", "", "external script to execute")
    flag.Parse()

    http.HandleFunc("/ping", Ping)
    http.HandleFunc("/webhook", Webhook)

log.Fatal(http.ListenAndServe(*bindAddr+":"+strconv.Itoa(*bindPort), nil))
}

TÀnk pÄ huvudfunktionerna:

  • Ping() - en rutt som svarar via URL/ping, den enklaste implementeringen av en liveness-prob.
  • Webhook() - huvudvĂ€g, URL/webhook-hanterare:
    • bekrĂ€ftar registreringen pĂ„ publiceringstjĂ€nsten (gĂ„ till funktionen PrenumerationsbekrĂ€ftelse),
    • bearbetar inkommande webhooks (Gorecords-funktion).
  • Funktionerna HmacSha256 och HmacSha256hex Ă€r implementeringar av krypteringsalgoritmerna HMAC-SHA256 och HMAC-SHA256 med utdata som en strĂ€ng av hexadecimala tal för berĂ€kning av signaturen.
  • main Ă€r huvudfunktionen, bearbetar kommandoradsparametrar och registrerar URL-hanterare.

Kommandoradsparametrar som accepteras av servern:

  • -port Ă€r den port som servern kommer att lyssna pĂ„.
  • -adress - IP-adress som servern kommer att lyssna pĂ„.
  • -script Ă€r ett externt program som anropas för varje inkommande hook.

LÄt oss ta en nÀrmare titt pÄ nÄgra av funktionerna:

//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)
    }

}

Denna funktion avgör om en begÀran om att bekrÀfta registrering eller en webhook har kommit in. Som följer av dokumentation, om registreringen bekrÀftas, tas följande Json-struktur emot i Post-förfrÄgan:

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»
}

Denna frÄga mÄste besvaras:

content-type: application/json

{"signature":«ea3fce4bb15c6de4fec365d36bcebbc34ccddf54616d5ca12e1972f82b6d37af»}

DÀr signaturen berÀknas som:

signature = hmac_sha256(url, hmac_sha256(TopicArn, 
hmac_sha256(Timestamp, Token)))

Om en webhook anlÀnder ser strukturen för Post-begÀran ut sÄ hÀr:

POST <url> HTTP/1.1
x-amz-sns-messages-type: SubscriptionConfirmation

{ "Records":
    [
        {
            "s3": {
                "object": {
                    "eTag":"aed563ecafb4bcc5654c597a421547b2",
                    "sequencer":1577453615,
                    "key":"some-file-to-bucket",
                    "size":100
                },
            "configurationId":"1",
            "bucket": {
                "name": "bucketA",
                "ownerIdentity": {
                    "principalId":"mcs2883541269"}
                },
                "s3SchemaVersion":"1.0"
            },
            "eventVersion":"1.0",
            "requestParameters":{
                "sourceIPAddress":"185.6.245.156"
            },
            "userIdentity": {
                "principalId":"2407013e-cbc1-415f-9102-16fb9bd6946b"
            },
            "eventName":"s3:ObjectCreated:Put",
            "awsRegion":"ru-msk",
            "eventSource":"aws:s3",
            "responseElements": {
                "x-amz-request-id":"VGJR5rtJ"
            }
        }
    ]
}

Följaktligen, beroende pÄ begÀran, mÄste du förstÄ hur du behandlar uppgifterna. Jag valde posten som en indikator "Type":"SubscriptionConfirmation", eftersom det finns i begÀran om prenumerationsbekrÀftelse och inte finns i webhook. Baserat pÄ nÀrvaron/frÄnvaron av denna post i POST-begÀran, gÄr vidare exekvering av programmet antingen till funktionen SubscriptionConfirmation, eller in i funktionen GotRecords.

Vi kommer inte att övervÀga prenumerationsbekrÀftelsefunktionen i detalj; den implementeras enligt principerna som anges i dokumentation. Du kan se kÀllkoden för denna funktion pÄ projekt git repositories.

GotRecords-funktionen analyserar en inkommande begÀran och för varje Record-objekt anropar ett externt skript (vars namn skickades i parametern -script) med parametrarna:

  • hinknamn
  • objektnyckel
  • handling:
    • copy - om i den ursprungliga begĂ€ran EventName = ObjectCreated | PutObject | PutObjectCopy
    • delete - om i den ursprungliga begĂ€ran EventName = ObjectRemoved | Ta bort objekt

AlltsÄ, om en krok kommer med en Post-förfrÄgan, enligt beskrivningen ovan, och parametern -script=script.sh sÄ kommer skriptet att anropas enligt följande:

script.sh  bucketA some-file-to-bucket copy

Det bör förstÄs att denna webhook-mottagningsserver inte Àr en komplett produktionslösning, utan ett förenklat exempel pÄ en möjlig implementering.

Exempel pÄ arbete

LÄt oss synkronisera filerna frÄn huvudbucket i MCS till backup-bucket i AWS. Den huvudsakliga hinken heter myfiles-ash, den backup som kallas myfiles-backup (hinkkonfigurationen i AWS ligger utanför ramen för denna artikel). Följaktligen, nÀr en fil placeras i huvudbehÄllaren, bör dess kopia visas i sÀkerhetskopian, och nÀr den raderas frÄn den huvudsakliga, bör den tas bort i sÀkerhetskopian.

Vi kommer att arbeta med hinkar med hjÀlp av verktyget awscli, som Àr kompatibelt med bÄde MCS molnlagring och AWS molnlagring.

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) ...

LÄt oss konfigurera Ätkomst till S3 MCS API:

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]:

LÄt oss konfigurera Ätkomst till AWS S3 API:

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]:

LÄt oss kontrollera Ätkomsterna:

Till AWS:

ubuntu@ubuntu-basic-1-2-10gb:~$ aws s3 ls --profile aws
2020-07-06 08:44:11 myfiles-backup

För MCS, nĂ€r du kör kommandot mĂ„ste du lĂ€gga till —endpoint-url:

ubuntu@ubuntu-basic-1-2-10gb:~$ aws s3 ls --profile mcs --endpoint-url 
https://hb.bizmrg.com
2020-02-04 06:38:05 databasebackups-0cdaaa6402d4424e9676c75a720afa85
2020-05-27 10:08:33 myfiles-ash

Åtkomst.

LÄt oss nu skriva ett skript för att bearbeta den inkommande kroken, lÄt oss kalla det s3_backup_mcs_aws.sh

#!/bin/bash
# Require aws cli
# if file added — copy it to backup bucket
# if file removed — remove it from backup bucket
# Variables
ENDPOINT_MCS="https://hb.bizmrg.com"
AWSCLI_MCS=`which aws`" --endpoint-url ${ENDPOINT_MCS} --profile mcs s3"
AWSCLI_AWS=`which aws`" --profile aws s3"
BACKUP_BUCKET="myfiles-backup"

SOURCE_BUCKET="${1}"
SOURCE_FILE="${2}"
ACTION="${3}"

SOURCE="s3://${SOURCE_BUCKET}/${SOURCE_FILE}"
TARGET="s3://${BACKUP_BUCKET}/${SOURCE_FILE}"
TEMP="/tmp/${SOURCE_BUCKET}/${SOURCE_FILE}"

case ${ACTION} in
    "copy")
    ${AWSCLI_MCS} cp "${SOURCE}" "${TEMP}"
    ${AWSCLI_AWS} cp "${TEMP}" "${TARGET}"
    rm ${TEMP}
    ;;

    "delete")
    ${AWSCLI_AWS} rm ${TARGET}
    ;;

    *)
    echo "Usage: ${0} sourcebucket sourcefile copy/delete"
    exit 1
    ;;
esac

LÄt oss starta servern:

ubuntu@ubuntu-basic-1-2-10gb:~/s3-webhook$ sudo ./s3-webhook -port 80 -
script scripts/s3_backup_mcs_aws.sh

LÄt oss se hur det hÀr fungerar. Genom MCS webbgrÀnssnitt lÀgg till test.txt-filen i myfiles-ash-hinken. Konsolloggarna visar att en begÀran gjordes till webhook-servern:

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

LÄt oss kontrollera innehÄllet i myfiles-backup-bucket i AWS:

ubuntu@ubuntu-basic-1-2-10gb:~/s3-webhook$ aws s3 --profile aws ls 
myfiles-backup
2020-07-06 09:43:10       1104 test.txt

Nu, genom webbgrÀnssnittet, kommer vi att ta bort filen frÄn myfiles-ash-hinken.

Serverloggar:

2020/07/06 09:44:46 [POST] incoming HTTP request from 
95.163.216.92:58224
delete: s3://myfiles-backup/test.txt

Hinkens innehÄll:

ubuntu@ubuntu-basic-1-2-10gb:~/s3-webhook$ aws s3 --profile aws ls 
myfiles-backup
ubuntu@ubuntu-basic-1-2-10gb:~$

Filen raderas, problemet Àr löst.

Slutsats och Att göra

All kod som anvÀnds i den hÀr artikeln Àr i mitt förrÄd. Det finns ocksÄ exempel pÄ skript och exempel pÄ rÀkning av signaturer för registrering av webhooks.

Den hÀr koden Àr inget annat Àn ett exempel pÄ hur du kan anvÀnda S3 webhooks i dina aktiviteter. Som jag sa i början, om du planerar att anvÀnda en sÄdan server i produktionen mÄste du Ätminstone skriva om servern för asynkront arbete: registrera inkommande webhooks i en kö (RabbitMQ eller NATS), och dÀrifrÄn analysera dem och bearbeta dem med arbetaransökningar. Annars, nÀr webhooks kommer massivt, kan du stöta pÄ brist pÄ serverresurser för att slutföra uppgifter. NÀrvaron av köer gör att du kan distribuera servern och arbetarna, samt lösa problem med upprepade uppgifter i hÀndelse av fel. Det Àr ocksÄ lÀmpligt att Àndra loggningen till en mer detaljerad och mer standardiserad.

Lycka!

Mer lÀsning om Àmnet:

KĂ€lla: will.com

Köp pĂ„litlig hosting för webbplatser med DDoS-skydd, VPS VDS-servrar đŸ”„ Köp pĂ„litlig webbhotell med DDoS-skydd, VPS VDS-servrar | ProHoster