Ekzemplo de okazaĵ-movita aplikaĵo bazita sur rethokoj en la S3-objekta stokado de Mail.ru Cloud Solutions

Ekzemplo de okazaĵ-movita aplikaĵo bazita sur rethokoj en la S3-objekta stokado de Mail.ru Cloud Solutions
Rube Goldberg kafmaŝino

Event-movita arkitekturo pliigas la kostefikecon de la uzitaj resursoj ĉar ili estas uzitaj nur en la momento kiam ili estas bezonataj. Estas multaj ebloj pri kiel efektivigi ĉi tion kaj ne krei pliajn nubajn entojn kiel laboristajn aplikojn. Kaj hodiaŭ mi parolos ne pri FaaS, sed pri rethokoj. Mi montros lernilon ekzemplon pri traktado de eventoj uzante objektajn stokadretajn rethokojn.

Kelkajn vortojn pri objektostokado kaj rethokoj. Objektostokado permesas vin stoki ajnajn datumojn en la nubo en la formo de objektoj, alireblaj per S3 aŭ alia API (depende de efektivigo) per HTTP/HTTPS. Webhooks estas ĝenerale kutimaj HTTP-revokoj. Ili estas tipe ekigitaj de evento, kiel kodo puŝita al deponejo aŭ komento afiŝita en blogo. Kiam okazaĵo okazas, la originejo sendas HTTP-peton al la URL specifita por la rethoko. Kiel rezulto, vi povas fari eventojn sur unu retejo ekigi agojn sur alia (vikio). En la kazo kie la fonto retejo estas objektostokado, eventoj funkcias kiel ŝanĝoj al ĝia enhavo.

Ekzemploj de simplaj kazoj kiam tia aŭtomatigo povas esti uzita:

  1. Krei kopiojn de ĉiuj objektoj en alia nuba stokado. Kopioj devas esti kreitaj sur la flugo kiam dosieroj estas aldonitaj aŭ ŝanĝitaj.
  2. Aŭtomata kreado de serio de bildetoj de grafikaj dosieroj, aldonado de akvomarkoj al fotoj kaj aliaj bildaj modifoj.
  3. Sciigo pri la alveno de novaj dokumentoj (ekzemple, distribuita kontada servo alŝutas raportojn al la nubo, kaj financa monitorado ricevas sciigojn pri novaj raportoj, kontrolas kaj analizas ilin).
  4. Iom pli kompleksaj kazoj implikas, ekzemple, generi peton al Kubernetes, kiu kreas pod kun la necesaj ujoj, pasas taskoparametrojn al ĝi, kaj post prilaborado kolapsas la ujon.

Ekzemple, ni faros varianton de tasko 1, kiam ŝanĝoj en la objekto-stokado de Mail.ru Cloud Solutions (MCS) estas sinkronigitaj en AWS-objekta stokado per rethokoj. En vera ŝarĝita kazo, nesinkrona laboro devus esti provizita registrante rethokojn en atendovico, sed por la trejna tasko ni faros la efektivigon sen ĉi tio.

Skemo de laboro

La interaga protokolo estas detale priskribita en Gvidilo al S3-rethokoj sur MCS. La laborskemo enhavas la jenajn elementojn:

  • Eldonservo, kiu estas ĉe la S3-stokado kaj publikigas HTTP-petojn kiam la webnhook estas ekigita.
  • Webhook ricevanta servilo, kiu aŭskultas petojn de la HTTP-eldonservo kaj faras taŭgajn agojn. La servilo povas esti skribita en iu ajn lingvo; en nia ekzemplo, ni skribos la servilon en Go.

Speciala trajto de la efektivigo de rethokoj en la S3 API estas la registrado de la rethook ricevanta servilo sur la eldonservo. Aparte, la rethook ricevanta servilo devas konfirmi la abonon al mesaĝoj de la eldonservo (en aliaj rethook-efektivigoj, konfirmo de abono kutime ne estas postulata).

Sekve, la rethook ricevanta servilo devas subteni du ĉefajn operaciojn:

  • respondi al la peto de la eldonservo por konfirmi registradon,
  • prilabori venontajn eventojn.

Instalante rethook ricevan servilon

Por ruli la rethook ricevan servilon, vi bezonas Linuksan servilon. En ĉi tiu artikolo, kiel ekzemplo, ni uzas virtualan petskribon, kiun ni deplojas sur MCS.

Ni instalu la necesan programaron kaj lanĉu la rethook-ricevan servilon.

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

Klonu la dosierujon kun la rethook ricevanta servilo:

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.

Ni komencu la servilon:

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

Abonu eldonservon

Vi povas registri vian rethook ricevan servilon per la API aŭ retinterfaco. Por simpleco, ni registriĝos per la retinterfaco:

  1. Ni iru al la sekcio de siteloj en la regejo.
  2. Iru al la sitelo por kiu ni agordos rethokojn kaj alklaku la ilaron:

Ekzemplo de okazaĵ-movita aplikaĵo bazita sur rethokoj en la S3-objekta stokado de Mail.ru Cloud Solutions

Iru al la langeto Webhooks kaj alklaku Aldoni:

Ekzemplo de okazaĵ-movita aplikaĵo bazita sur rethokoj en la S3-objekta stokado de Mail.ru Cloud Solutions
Plenigu la kampojn:

Ekzemplo de okazaĵ-movita aplikaĵo bazita sur rethokoj en la S3-objekta stokado de Mail.ru Cloud Solutions

ID - la nomo de la rethoko.

Evento - kiujn eventojn transdoni. Ni starigis la transdonon de ĉiuj eventoj, kiuj okazas kiam oni laboras kun dosieroj (aldono kaj forigo).

URL — rethook ricevanta serviladreson.

Filtrila prefikso/sufikso estas filtrilo, kiu ebligas al vi generi rethokojn nur por objektoj, kies nomoj kongruas kun iuj reguloj. Ekzemple, por ke la rethoko ekfunkciigu nur dosierojn kun la etendo .png, en Filtrila sufikso vi devas skribi "png".

Nuntempe, nur havenoj 80 kaj 443 estas subtenataj por aliri la rethook ricevan servilon.

Ni klaku Aldonu hokon kaj ni vidos la jenon:

Ekzemplo de okazaĵ-movita aplikaĵo bazita sur rethokoj en la S3-objekta stokado de Mail.ru Cloud Solutions
Hoko aldonis.

La rethoko ricevanta servilo montras en siaj protokoloj la progreson de la hoka registra procezo:

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

Registrado estas finita. En la sekva sekcio, ni rigardos pli detale la algoritmon de operacio de la rethook ricevanta servilo.

Priskribo de la rethook ricevanta servilo

En nia ekzemplo, la servilo estas skribita en Go. Ni rigardu la bazajn principojn de ĝia funkciado.

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

Konsideru la ĉefajn funkciojn:

  • Ping() - itinero kiu respondas per URL/ping, la plej simpla efektivigo de vivecsondilo.
  • Webhook () - ĉefa itinero, URL/webhook-traktilo:
    • konfirmas registradon ĉe la eldonservo (iru al la funkcio de Abonkonfirmo),
    • prilaboras envenantajn rethokojn (funkcio Gorecords).
  • Funkcioj HmacSha256 kaj HmacSha256hex estas efektivigoj de la ĉifrado-algoritmoj HMAC-SHA256 kaj HMAC-SHA256 kun produktaĵo kiel ĉeno de deksesuma nombroj por kalkulado de la subskribo.
  • ĉefa estas la ĉefa funkcio, prilaboras komandliniajn parametrojn kaj registras URL-traktilojn.

Komandliniaj parametroj akceptitaj de la servilo:

  • -port estas la haveno sur kiu la servilo aŭskultos.
  • -address - IP-adreso kiun la servilo aŭskultos.
  • -script estas ekstera programo kiu estas vokita por ĉiu envenanta hoko.

Ni rigardu pli detale kelkajn el la funkcioj:

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

}

Ĉi tiu funkcio determinas ĉu peto por konfirmi registradon aŭ rethoko alvenis. Kiel sekvas el dokumentado, se registriĝo estas konfirmita, la sekva Json-strukturo ricevas en la Post-peto:

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

Ĉi tiu demando devas esti respondita:

content-type: application/json

{"signature":«ea3fce4bb15c6de4fec365d36bcebbc34ccddf54616d5ca12e1972f82b6d37af»}

Kie la subskribo estas kalkulita kiel:

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

Se rethoko alvenas, la strukturo de la Post-peto aspektas jene:

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"
            }
        }
    ]
}

Sekve, depende de la peto, vi devas kompreni kiel prilabori la datumojn. Mi elektis la eniron kiel indikilon "Type":"SubscriptionConfirmation", ĉar ĝi ĉeestas en la abonkonfirma peto kaj ne ĉeestas en la rethoko. Surbaze de la ĉeesto/foresto de ĉi tiu eniro en la POST-peto, plua ekzekuto de la programo iras aŭ al la funkcio SubscriptionConfirmation, aŭ en la funkcion GotRecords.

Ni ne konsideros la funkcion de Abonkonfirmo detale; ĝi estas efektivigita laŭ la principoj fiksitaj en dokumentado. Vi povas vidi la fontkodon por ĉi tiu funkcio ĉe projektaj git-deponejoj.

La funkcio GotRecords analizas envenantan peton kaj por ĉiu Record-objekto vokas eksteran skripton (kies nomo estis pasigita en la parametro -script) kun la parametroj:

  • sitelo nomo
  • objekta ŝlosilo
  • ago:
    • kopii - se en la originala peto EventName = ObjektoKreita | MetuObjekton | MetuObjektonKopion
    • forigi - se en la originala peto EventName = ObjektoForigita | ForigiObjekton

Tiel, se hoko alvenas kun Post-peto, kiel priskribite altaj, kaj la parametro -script=script.sh tiam la skripto estos nomita jene:

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

Oni devas kompreni, ke ĉi tiu rethook ricevanta servilo ne estas kompleta produktadsolvo, sed simpligita ekzemplo de ebla efektivigo.

Ekzemplo de laboro

Ni sinkronigu la dosierojn de la ĉefa sitelo en MCS al la rezerva sitelo en AWS. La ĉefa sitelo nomiĝas myfiles-ash, la rezerva estas nomita myfiles-backup (agordo de sitelo en AWS estas preter la amplekso de ĉi tiu artikolo). Sekve, kiam dosiero estas metita en la ĉefa sitelo, ĝia kopio devus aperi en la rezerva, kaj kiam ĝi estas forigita de la ĉefa, ĝi devus esti forigita en la rezerva.

Ni laboros kun siteloj uzante la awscli ilon, kiu estas kongrua kun kaj MCS-nuba stokado kaj AWS-nuba stokado.

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

Ni agordu aliron al la 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]:

Ni agordu aliron al la 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]:

Ni kontrolu la alirojn:

Al AWS:

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

Por MCS, dum vi ruliĝas la komandon, vi devas aldoni —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

Alirita.

Nun ni skribu skripton por prilabori la envenantan hokon, ni nomu ĝin 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=""
SOURCE_FILE=""
ACTION=""

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: 
#!/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
sourcebucket sourcefile copy/delete" exit 1 ;; esac

Ni komencu la servilon:

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

Ni vidu kiel ĝi funkcias. Tra MCS-retinterfaco aldonu la test.txt dosieron al la myfiles-ash sitelo. La konzolaj protokoloj montras, ke peto estis farita al la rethook-servilo:

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

Ni kontrolu la enhavon de la myfiles-backup sitelo en 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

Nun, per la retinterfaco, ni forigos la dosieron el la myfiles-ash sitelo.

Servilaj protokoloj:

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

Enhavo de sitelo:

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

La dosiero estas forigita, la problemo estas solvita.

Konkludo kaj ToDo

Ĉiu kodo uzata en ĉi tiu artikolo estas en mia deponejo. Estas ankaŭ ekzemploj de skriptoj kaj ekzemploj de kalkulado de subskriboj por registri rethokojn.

Ĉi tiu kodo estas nenio pli ol ekzemplo de kiel vi povas uzi S3-retajn hokojn en viaj agadoj. Kiel mi diris komence, se vi planas uzi tian servilon en produktado, vi devas almenaŭ reverki la servilon por nesinkrona laboro: registri envenantajn rethokojn en atendovico (RabbitMQ aŭ NATS), kaj de tie analizi ilin kaj prilabori ilin. kun laboristaj aplikoj. Alie, kiam rethokoj amase alvenas, vi eble renkontos mankon de servilaj rimedoj por plenumi taskojn. La ĉeesto de vostoj permesas vin distribui la servilon kaj laboristojn, kaj ankaŭ solvi problemojn kun ripetado de taskoj en kazo de misfunkciadoj. Estas ankaŭ konsilinde ŝanĝi la registradon al pli detala kaj pli normigita.

Bonŝancon!

Pli da legado pri la temo:

fonto: www.habr.com

Aldoni komenton