Hendelsesdrevet arkitektur øker kostnadseffektiviteten til ressursene som brukes fordi de bare brukes i det øyeblikket de er nødvendige. Det er mange alternativer for hvordan du implementerer dette og ikke oppretter flere skyenheter som arbeiderapplikasjoner. Og i dag skal jeg ikke snakke om FaaS, men om webhooks. Jeg skal vise et opplæringseksempel på håndtering av hendelser ved hjelp av webhooks for objektlagring.
Noen få ord om objektlagring og webhooks. Objektlagring lar deg lagre alle data i skyen i form av objekter, tilgjengelig via S3 eller en annen API (avhengig av implementering) via HTTP/HTTPS. Webhooks er vanligvis tilpassede HTTP-tilbakekallinger. De utløses vanligvis av en hendelse, for eksempel kode som blir presset til et depot eller en kommentar som legges ut på en blogg. Når en hendelse inntreffer, sender opprinnelsesnettstedet en HTTP-forespørsel til URL-en som er spesifisert for webhook. Som et resultat kan du få hendelser på ett nettsted til å utløse handlinger på et annet (wiki). I tilfellet der kildenettstedet er et objektlager, fungerer hendelser som endringer i innholdet.
Eksempler på enkle tilfeller der slik automatisering kan brukes:
Lage kopier av alle objekter i en annen skylagring. Kopier må opprettes umiddelbart når filer legges til eller endres.
Automatisk oppretting av en serie miniatyrbilder av grafikkfiler, tilføying av vannmerker til fotografier og andre bildeendringer.
Varsling om ankomst av nye dokumenter (for eksempel laster en distribuert regnskapstjeneste opp rapporter til skyen, og økonomisk overvåking mottar varsler om nye rapporter, kontrollerer og analyserer dem).
Litt mer komplekse saker innebærer for eksempel å generere en forespørsel til Kubernetes, som lager en pod med de nødvendige beholderne, sender oppgaveparametere til den, og etter behandling kollapser beholderen.
Som et eksempel vil vi lage en variant av oppgave 1, når endringer i Mail.ru Cloud Solutions (MCS) objektlagringsbøtte synkroniseres i AWS objektlagring ved hjelp av webhooks. I et reelt belastet tilfelle bør asynkront arbeid gis ved å registrere webhooks i en kø, men for opplæringsoppgaven vil vi gjøre implementeringen uten dette.
Publiseringstjeneste, som er på S3-lagringssiden og publiserer HTTP-forespørsler når webnhook utløses.
Webhook mottaksserver, som lytter til forespørsler fra HTTP-publiseringstjenesten og utfører passende handlinger. Serveren kan skrives på et hvilket som helst språk; i vårt eksempel vil vi skrive serveren i Go.
En spesiell funksjon ved implementeringen av webhooks i S3 API er registreringen av webhook-mottaksserveren på publiseringstjenesten. Spesielt må webhook-mottaksserveren bekrefte abonnementet på meldinger fra publiseringstjenesten (i andre webhook-implementeringer er bekreftelse av abonnement vanligvis ikke nødvendig).
Følgelig må webhook-mottaksserveren støtte to hovedoperasjoner:
svare på publiseringstjenestens forespørsel om å bekrefte registreringen,
behandle innkommende hendelser.
Installere en webhook-mottaksserver
For å kjøre webhook-mottaksserveren trenger du en Linux-server. I denne artikkelen bruker vi som eksempel en virtuell forekomst som vi distribuerer på MCS.
La oss installere nødvendig programvare og starte webhook-mottaksserveren.
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) ...
Gå til bøtta som vi skal konfigurere webhooks for og klikk på tannhjulet:
Gå til Webhooks-fanen og klikk på Legg til:
Fyll ut feltene:
ID — navnet på webhook.
Hendelse - hvilke hendelser som skal overføres. Vi har satt overføring av alle hendelser som oppstår når du arbeider med filer (legger til og sletter).
URL — webhook som mottar serveradresse.
Filterprefiks/suffiks er et filter som lar deg generere webhooks kun for objekter hvis navn samsvarer med visse regler. For eksempel, for at webhook skal utløse bare filer med filtypen .png, i Filtersuffiks du må skrive "png".
For øyeblikket støttes bare portene 80 og 443 for tilgang til webhook-mottaksserveren.
La oss klikke Legg til krok og vi vil se følgende:
Krok lagt til.
Webhook-mottaksserveren viser i sine logger fremdriften til hook-registreringsprosessen:
Funksjonene HmacSha256 og HmacSha256hex er implementeringer av HMAC-SHA256 og HMAC-SHA256 krypteringsalgoritmer med utdata som en streng med heksadesimale tall for beregning av signaturen.
main er hovedfunksjonen, behandler kommandolinjeparametere og registrerer URL-behandlere.
Kommandolinjeparametere akseptert av serveren:
-port er porten som serveren vil lytte til.
-adresse - IP-adresse som serveren vil lytte til.
-script er et eksternt program som kalles for hver innkommende krok.
La oss se nærmere på noen av funksjonene:
//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)
}
}
Denne funksjonen bestemmer om en forespørsel om å bekrefte registrering eller en webhook har kommet. Som følger av dokumentasjon, hvis registreringen er bekreftet, mottas følgende Json-struktur i Post-forespørselen:
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»
}
Følgelig, avhengig av forespørselen, må du forstå hvordan du behandler dataene. Jeg valgte oppføringen som en indikator "Type":"SubscriptionConfirmation", siden den er til stede i forespørselen om abonnementsbekreftelse og ikke er til stede i webhook. Basert på tilstedeværelsen/fraværet av denne oppføringen i POST-forespørselen, går videre kjøring av programmet enten til funksjonen SubscriptionConfirmation, eller inn i funksjonen GotRecords.
Vi vil ikke vurdere funksjonen for abonnementsbekreftelse i detalj; den implementeres i henhold til prinsippene angitt i dokumentasjon. Du kan se kildekoden for denne funksjonen på prosjekt git repositories.
GotRecords-funksjonen analyserer en innkommende forespørsel og kaller for hvert Record-objekt et eksternt skript (hvis navn ble sendt i -script-parameteren) med parameterne:
bøttenavn
objektnøkkel
handling:
kopi - hvis i den opprinnelige forespørselen EventName = ObjectCreated | PutObject | PutObjectCopy
slett - hvis i den opprinnelige forespørselen EventName = ObjectRemoved | SlettObjekt
Dermed, hvis en krok kommer med en Post-forespørsel, som beskrevet ovenfor, og parameteren -script=script.sh, vil skriptet kalles som følger:
script.sh bucketA some-file-to-bucket copy
Det skal forstås at denne webhook-mottaksserveren ikke er en komplett produksjonsløsning, men et forenklet eksempel på en mulig implementering.
Eksempel på arbeid
La oss synkronisere filene fra hovedbøtten i MCS til backupbøtten i AWS. Hovedbøtten kalles myfiles-ash, den sikkerhetskopien kalles myfiles-backup (bøttekonfigurasjonen i AWS er utenfor rammen av denne artikkelen). Følgelig, når en fil plasseres i hovedbøtten, bør kopien vises i den sikkerhetskopiente, og når den slettes fra den viktigste, bør den slettes i sikkerhetskopifilen.
Vi vil jobbe med bøtter ved å bruke awscli-verktøyet, som er kompatibelt med både MCS skylagring og AWS skylagring.
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) ...
La oss konfigurere tilgang til 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]:
La oss konfigurere tilgang til 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]:
La oss sjekke tilgangene:
Til AWS:
ubuntu@ubuntu-basic-1-2-10gb:~$ aws s3 ls --profile aws
2020-07-06 08:44:11 myfiles-backup
For MCS, når du kjører kommandoen, må du legge til —endpoint-url:
La oss se hvordan det fungerer. Gjennom MCS webgrensesnitt legg til test.txt-filen i myfiles-ash-bøtten. Konsollloggene viser at en forespørsel ble sendt til webhook-serveren:
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
La oss sjekke innholdet i myfiles-backup-bøtten i AWS:
Nå, gjennom nettgrensesnittet, vil vi slette filen fra myfiles-ash-bøtten.
Serverlogger:
2020/07/06 09:44:46 [POST] incoming HTTP request from
95.163.216.92:58224
delete: s3://myfiles-backup/test.txt
Innhold i bøtte:
ubuntu@ubuntu-basic-1-2-10gb:~/s3-webhook$ aws s3 --profile aws ls
myfiles-backup
ubuntu@ubuntu-basic-1-2-10gb:~$
Filen er slettet, problemet er løst.
Konklusjon og ToDo
All kode som brukes i denne artikkelen er i lageret mitt. Det finnes også eksempler på skript og eksempler på telling av signaturer for registrering av webhooks.
Denne koden er ikke mer enn et eksempel på hvordan du kan bruke S3 webhooks i aktivitetene dine. Som jeg sa i begynnelsen, hvis du planlegger å bruke en slik server i produksjon, må du i det minste skrive om serveren for asynkront arbeid: registrere innkommende webhooks i en kø (RabbitMQ eller NATS), og derfra analysere dem og behandle dem med arbeidersøknader. Ellers, når webhooks kommer massivt, kan du støte på mangel på serverressurser for å fullføre oppgaver. Tilstedeværelsen av køer lar deg distribuere serveren og arbeiderne, samt løse problemer med gjentatte oppgaver i tilfelle feil. Det er også lurt å endre loggingen til en mer detaljert og mer standardisert.