Contoh aplikasi dipacu peristiwa berdasarkan webhooks dalam storan objek S3 Mail.ru Cloud Solutions

Contoh aplikasi dipacu peristiwa berdasarkan webhooks dalam storan objek S3 Mail.ru Cloud Solutions
Mesin kopi Rube Goldberg

Seni bina dipacu peristiwa meningkatkan kecekapan kos sumber yang digunakan kerana ia hanya digunakan pada masa ia diperlukan. Terdapat banyak pilihan tentang cara melaksanakan ini dan tidak mencipta entiti awan tambahan sebagai aplikasi pekerja. Dan hari ini saya tidak akan bercakap tentang FaaS, tetapi tentang webhooks. Saya akan menunjukkan contoh tutorial pengendalian acara menggunakan cangkuk web storan objek.

Beberapa perkataan tentang penyimpanan objek dan cangkuk web. Storan objek membolehkan anda menyimpan sebarang data dalam awan dalam bentuk objek, boleh diakses melalui S3 atau API lain (bergantung pada pelaksanaan) melalui HTTP/HTTPS. Webhooks biasanya panggilan balik HTTP tersuai. Ia biasanya dicetuskan oleh peristiwa, seperti kod yang ditolak ke repositori atau ulasan yang disiarkan pada blog. Apabila peristiwa berlaku, tapak asal menghantar permintaan HTTP ke URL yang ditentukan untuk webhook. Akibatnya, anda boleh membuat acara pada satu tapak mencetuskan tindakan pada tapak lain (wiki). Dalam kes di mana tapak sumber ialah storan objek, peristiwa bertindak sebagai perubahan kepada kandungannya.

Contoh kes mudah apabila automasi sedemikian boleh digunakan:

  1. Mencipta salinan semua objek dalam storan awan yang lain. Salinan mesti dibuat dengan segera apabila fail ditambah atau ditukar.
  2. Penciptaan automatik siri lakaran kecil fail grafik, menambahkan tera air pada gambar dan pengubahsuaian imej lain.
  3. Pemberitahuan tentang ketibaan dokumen baharu (contohnya, perkhidmatan perakaunan yang diedarkan memuat naik laporan ke awan, dan pemantauan kewangan menerima pemberitahuan tentang laporan baharu, menyemak dan menganalisisnya).
  4. Kes yang sedikit lebih kompleks melibatkan, contohnya, menjana permintaan kepada Kubernetes, yang mencipta pod dengan bekas yang diperlukan, menghantar parameter tugas kepadanya dan selepas pemprosesan meruntuhkan bekas.

Sebagai contoh, kami akan membuat varian tugas 1, apabila perubahan dalam baldi storan objek Mail.ru Cloud Solutions (MCS) disegerakkan dalam storan objek AWS menggunakan webhooks. Dalam kes yang dimuatkan sebenar, kerja tak segerak harus disediakan dengan mendaftarkan webhook dalam baris gilir, tetapi untuk tugas latihan kami akan melakukan pelaksanaan tanpa ini.

Skim kerja

Protokol interaksi diterangkan secara terperinci dalam Panduan untuk webhook S3 pada MCS. Skim kerja mengandungi unsur-unsur berikut:

  • Perkhidmatan penerbitan, yang berada di bahagian storan S3 dan menerbitkan permintaan HTTP apabila webnhook dicetuskan.
  • Pelayan penerima webhook, yang mendengar permintaan daripada perkhidmatan penerbitan HTTP dan melakukan tindakan yang sesuai. Pelayan boleh ditulis dalam mana-mana bahasa; dalam contoh kami, kami akan menulis pelayan dalam Go.

Ciri khas pelaksanaan webhooks dalam API S3 ialah pendaftaran pelayan penerima webhook pada perkhidmatan penerbitan. Khususnya, pelayan penerima webhook mesti mengesahkan langganan kepada mesej daripada perkhidmatan penerbitan (dalam pelaksanaan webhook lain, pengesahan langganan biasanya tidak diperlukan).

Sehubungan itu, pelayan penerima webhook mesti menyokong dua operasi utama:

  • membalas permintaan perkhidmatan penerbitan untuk mengesahkan pendaftaran,
  • memproses peristiwa masuk.

Memasang pelayan penerima webhook

Untuk menjalankan pelayan penerima webhook, anda memerlukan pelayan Linux. Dalam artikel ini, sebagai contoh, kami menggunakan tika maya yang kami gunakan pada MCS.

Mari pasang perisian yang diperlukan dan lancarkan pelayan penerima 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) ...

Klon folder dengan pelayan penerima webhook:

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.

Mari mulakan pelayan:

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

Langgan perkhidmatan penerbitan

Anda boleh mendaftarkan pelayan penerima webhook anda melalui API atau antara muka web. Untuk memudahkan, kami akan mendaftar melalui antara muka web:

  1. Mari pergi ke bahagian baldi di dalam bilik kawalan.
  2. Pergi ke baldi yang akan kami konfigurasikan webhooks dan klik pada gear:

Contoh aplikasi dipacu peristiwa berdasarkan webhooks dalam storan objek S3 Mail.ru Cloud Solutions

Pergi ke tab Webhooks dan klik Tambah:

Contoh aplikasi dipacu peristiwa berdasarkan webhooks dalam storan objek S3 Mail.ru Cloud Solutions
Isikan medan:

Contoh aplikasi dipacu peristiwa berdasarkan webhooks dalam storan objek S3 Mail.ru Cloud Solutions

ID β€” nama webhook.

Peristiwa - peristiwa yang hendak dihantar. Kami telah menetapkan penghantaran semua peristiwa yang berlaku apabila bekerja dengan fail (menambah dan memadam).

URL β€” webhook menerima alamat pelayan.

Awalan/akhiran penapis ialah penapis yang membolehkan anda menjana webhooks hanya untuk objek yang namanya sepadan dengan peraturan tertentu. Contohnya, untuk membolehkan webhook mencetuskan hanya fail dengan sambungan .png, dalam Akhiran penapis anda perlu menulis "png".

Pada masa ini, hanya port 80 dan 443 disokong untuk mengakses pelayan penerima webhook.

Jom klik Tambah cangkuk dan kita akan melihat perkara berikut:

Contoh aplikasi dipacu peristiwa berdasarkan webhooks dalam storan objek S3 Mail.ru Cloud Solutions
Hook menambah.

Pelayan penerima webhook menunjukkan dalam lognya kemajuan proses pendaftaran cangkuk:

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

Pendaftaran selesai. Dalam bahagian seterusnya, kita akan melihat dengan lebih dekat pada algoritma operasi pelayan penerima webhook.

Penerangan tentang pelayan penerima webhook

Dalam contoh kami, pelayan ditulis dalam Go. Mari kita lihat prinsip asas operasinya.

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

Pertimbangkan fungsi utama:

  • Ping() - laluan yang bertindak balas melalui URL/ping, pelaksanaan paling mudah bagi siasatan keaktifan.
  • Webhook() - laluan utama, pengendali URL/webhook:
    • mengesahkan pendaftaran pada perkhidmatan penerbitan (pergi ke fungsi Pengesahan Langganan),
    • memproses webhook masuk (fungsi Gorecords).
  • Fungsi HmacSha256 dan HmacSha256hex ialah pelaksanaan algoritma penyulitan HMAC-SHA256 dan HMAC-SHA256 dengan output sebagai rentetan nombor perenambelasan untuk mengira tandatangan.
  • utama ialah fungsi utama, memproses parameter baris arahan dan mendaftarkan pengendali URL.

Parameter baris perintah yang diterima oleh pelayan:

  • -port ialah port di mana pelayan akan mendengar.
  • -alamat - Alamat IP yang akan didengari oleh pelayan.
  • -skrip ialah program luaran yang dipanggil untuk setiap cangkuk masuk.

Mari kita lihat lebih dekat beberapa fungsi:

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

}

Fungsi ini menentukan sama ada permintaan untuk mengesahkan pendaftaran atau webhook telah tiba. Seperti berikut daripada dokumentasi, jika pendaftaran disahkan, struktur Json berikut diterima dalam permintaan Pos:

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

Pertanyaan ini perlu dijawab:

content-type: application/json

{"signature":Β«ea3fce4bb15c6de4fec365d36bcebbc34ccddf54616d5ca12e1972f82b6d37afΒ»}

Di mana tandatangan dikira sebagai:

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

Jika webhook tiba, struktur permintaan Post kelihatan seperti ini:

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

Sehubungan itu, bergantung pada permintaan, anda perlu memahami cara memproses data. Saya memilih entri sebagai penunjuk "Type":"SubscriptionConfirmation", kerana ia terdapat dalam permintaan pengesahan langganan dan tidak terdapat dalam webhook. Berdasarkan kehadiran/ketiadaan entri ini dalam permintaan POST, pelaksanaan selanjutnya program pergi sama ada ke fungsi SubscriptionConfirmation, atau ke dalam fungsi GotRecords.

Kami tidak akan mempertimbangkan fungsi Pengesahan Langganan secara terperinci; ia dilaksanakan mengikut prinsip yang ditetapkan dalam dokumentasi. Anda boleh melihat kod sumber untuk fungsi ini di repositori git projek.

Fungsi GotRecords menghuraikan permintaan masuk dan untuk setiap objek Rekod memanggil skrip luaran (yang namanya dihantar dalam parameter -skrip) dengan parameter:

  • nama baldi
  • kunci objek
  • tindakan:
    • copy - jika dalam permintaan asal EventName = ObjectCreated | PutObject | PutObjectCopy
    • padam - jika dalam permintaan asal EventName = ObjectRemoved | DeleteObject

Oleh itu, jika cangkuk tiba dengan permintaan Pos, seperti yang diterangkan atas, dan parameter -script=script.sh maka skrip akan dipanggil seperti berikut:

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

Perlu difahami bahawa pelayan penerima webhook ini bukanlah penyelesaian pengeluaran yang lengkap, tetapi contoh ringkas kemungkinan pelaksanaan.

Contoh kerja

Mari kita segerakkan fail daripada baldi utama dalam MCS kepada baldi sandaran dalam AWS. Baldi utama dipanggil myfiles-ash, yang sandaran dipanggil myfiles-backup (konfigurasi baldi dalam AWS berada di luar skop artikel ini). Sehubungan itu, apabila fail diletakkan dalam baldi utama, salinannya akan muncul dalam sandaran, dan apabila ia dipadamkan daripada yang utama, ia harus dipadamkan dalam sandaran.

Kami akan bekerja dengan baldi menggunakan utiliti awscli, yang serasi dengan storan awan MCS dan storan awan 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) ...

Mari konfigurasikan akses kepada API MCS S3:

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

Mari konfigurasikan akses kepada 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]:

Mari semak akses:

Kepada AWS:

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

Untuk MCS, apabila menjalankan arahan anda perlu menambah β€”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

Diakses.

Sekarang mari kita tulis skrip untuk memproses cangkuk masuk, mari kita panggilnya 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

Mari mulakan pelayan:

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

Mari lihat bagaimana ia berfungsi. Melalui Antara muka web MCS tambah fail test.txt pada baldi myfiles-ash. Log konsol menunjukkan bahawa permintaan telah dibuat kepada pelayan 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

Mari kita semak kandungan baldi myfiles-backup dalam 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

Sekarang, melalui antara muka web, kami akan memadamkan fail daripada baldi myfiles-ash.

Log pelayan:

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

Kandungan baldi:

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

Fail dipadam, masalah selesai.

Kesimpulan dan Tugasan

Semua kod yang digunakan dalam artikel ini ialah dalam repositori saya. Terdapat juga contoh skrip dan contoh mengira tandatangan untuk mendaftar webhooks.

Kod ini tidak lebih daripada contoh cara anda boleh menggunakan webhook S3 dalam aktiviti anda. Seperti yang saya katakan pada mulanya, jika anda bercadang untuk menggunakan pelayan sedemikian dalam pengeluaran, anda perlu sekurang-kurangnya menulis semula pelayan untuk kerja tak segerak: daftarkan webhook masuk dalam baris gilir (RabbitMQ atau NATS), dan dari sana menghuraikannya dan memprosesnya dengan aplikasi pekerja. Jika tidak, apabila webhooks tiba secara besar-besaran, anda mungkin menghadapi kekurangan sumber pelayan untuk menyelesaikan tugas. Kehadiran baris gilir membolehkan anda mengedarkan pelayan dan pekerja, serta menyelesaikan masalah dengan mengulangi tugas sekiranya berlaku kegagalan. Ia juga dinasihatkan untuk menukar pembalakan kepada yang lebih terperinci dan lebih standard.

Semoga Berjaya!

Bacaan lanjut mengenai topik:

Sumber: www.habr.com

Tambah komen