Arsitektur berbasis peristiwa meningkatkan efisiensi biaya sumber daya yang digunakan karena sumber daya tersebut hanya digunakan pada saat dibutuhkan. Ada banyak pilihan tentang cara menerapkan ini dan tidak membuat entitas cloud tambahan sebagai aplikasi pekerja. Dan hari ini saya tidak akan berbicara tentang FaaS, tetapi tentang webhook. Saya akan menunjukkan contoh tutorial penanganan event menggunakan webhook penyimpanan objek.
Sedikit penjelasan tentang penyimpanan objek dan webhook. Penyimpanan objek memungkinkan Anda menyimpan data apa pun di cloud dalam bentuk objek, dapat diakses melalui S3 atau API lain (tergantung implementasi) melalui HTTP/HTTPS. Webhook umumnya merupakan panggilan balik HTTP khusus. Mereka biasanya dipicu oleh suatu peristiwa, seperti kode yang dimasukkan ke repositori atau komentar yang diposting di blog. Ketika suatu peristiwa terjadi, situs asal mengirimkan permintaan HTTP ke URL yang ditentukan untuk webhook. Hasilnya, Anda dapat membuat peristiwa di satu situs memicu tindakan di situs lain (wiki). Dalam kasus di mana situs sumber adalah tempat penyimpanan objek, peristiwa bertindak sebagai perubahan pada kontennya.
Contoh kasus sederhana ketika otomatisasi tersebut dapat digunakan:
Membuat salinan semua objek di penyimpanan cloud lain. Salinan harus dibuat dengan cepat setiap kali file ditambahkan atau diubah.
Pembuatan otomatis serangkaian thumbnail file grafik, menambahkan tanda air ke foto, dan modifikasi gambar lainnya.
Pemberitahuan kedatangan dokumen baru (misalnya, layanan akuntansi terdistribusi mengunggah laporan ke cloud, dan pemantauan keuangan menerima pemberitahuan tentang laporan baru, memeriksa dan menganalisisnya).
Kasus yang sedikit lebih kompleks melibatkan, misalnya, pembuatan permintaan ke Kubernetes, yang membuat sebuah pod dengan container yang diperlukan, meneruskan parameter tugas ke dalamnya, dan setelah pemrosesan, container tersebut akan diciutkan.
Sebagai contoh, kita akan membuat varian tugas 1, ketika perubahan dalam bucket penyimpanan objek Mail.ru Cloud Solutions (MCS) disinkronkan dalam penyimpanan objek AWS menggunakan webhook. Dalam kasus yang dimuat secara nyata, pekerjaan asinkron harus disediakan dengan mendaftarkan webhook dalam antrian, tetapi untuk tugas pelatihan kami akan melakukan implementasi tanpa ini.
Layanan penerbitan, yang berada di sisi penyimpanan S3 dan menerbitkan permintaan HTTP ketika webnhook dipicu.
Server penerima webhook, yang mendengarkan permintaan dari layanan penerbitan HTTP dan melakukan tindakan yang sesuai. Server dapat ditulis dalam bahasa apa pun; dalam contoh kita, kita akan menulis server dalam Go.
Fitur khusus implementasi webhook di S3 API adalah pendaftaran server penerima webhook pada layanan penerbitan. Secara khusus, server penerima webhook harus mengonfirmasi langganan pesan dari layanan penerbitan (dalam implementasi webhook lainnya, konfirmasi berlangganan biasanya tidak diperlukan).
Oleh karena itu, server penerima webhook harus mendukung dua operasi utama:
menanggapi permintaan layanan penerbitan untuk mengonfirmasi pendaftaran,
memproses kejadian yang masuk.
Memasang server penerima webhook
Untuk menjalankan server penerima webhook, Anda memerlukan server Linux. Pada artikel ini, sebagai contoh, kami menggunakan instance virtual yang kami terapkan di MCS.
Mari instal perangkat lunak yang diperlukan dan luncurkan server 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) ...
Buka bucket yang akan kita konfigurasikan webhooknya dan klik roda gigi:
Buka tab Webhook dan klik Tambahkan:
Isi kolom:
ID β nama webhook.
Acara - peristiwa mana yang akan dikirimkan. Kami telah mengatur transmisi semua peristiwa yang terjadi saat bekerja dengan file (menambah dan menghapus).
URL β alamat server penerima webhook.
Filter awalan/akhiran adalah filter yang memungkinkan Anda membuat webhook hanya untuk objek yang namanya sesuai dengan aturan tertentu. Misalnya, agar webhook hanya memicu file dengan ekstensi .png, di Filter akhiran Anda perlu menulis "png".
Saat ini, hanya port 80 dan 443 yang didukung untuk mengakses server penerima webhook.
Ayo klik Tambahkan kait dan kita akan melihat yang berikut ini:
Kait menambahkan.
Server penerima webhook menunjukkan dalam lognya kemajuan proses pendaftaran hook:
Ping() - rute yang merespons melalui URL/ping, implementasi paling sederhana dari pemeriksaan keaktifan.
Webhook() - rute utama, pengendali URL/webhook:
mengonfirmasi pendaftaran pada layanan penerbitan (buka fungsi Konfirmasi Langganan),
memproses webhook yang masuk (fungsi Gorecords).
Fungsi HmacSha256 dan HmacSha256hex merupakan implementasi algoritma enkripsi HMAC-SHA256 dan HMAC-SHA256 dengan keluaran berupa rangkaian angka heksadesimal untuk menghitung tanda tangan.
main adalah fungsi utama, memproses parameter baris perintah dan mendaftarkan penangan URL.
Parameter baris perintah yang diterima oleh server:
-port adalah port tempat server akan mendengarkan.
-alamat - Alamat IP yang akan didengarkan server.
-script adalah program eksternal yang dipanggil untuk setiap hook masuk.
Mari kita lihat lebih dekat beberapa fungsinya:
//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 apakah permintaan konfirmasi pendaftaran atau webhook telah tiba. Sebagai berikut dari dokumentasi, jika pendaftaran dikonfirmasi, struktur Json berikut diterima dalam permintaan Post:
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Β»
}
Oleh karena itu, bergantung pada permintaannya, Anda perlu memahami cara memproses data. Saya memilih entri sebagai indikator "Type":"SubscriptionConfirmation", karena ada dalam permintaan konfirmasi berlangganan dan tidak ada di webhook. Berdasarkan ada/tidaknya entri ini dalam permintaan POST, eksekusi program selanjutnya akan menuju ke fungsi tersebut SubscriptionConfirmation, atau menjadi suatu fungsi GotRecords.
Kami tidak akan mempertimbangkan fungsi Konfirmasi Langganan secara rinci; ini diterapkan sesuai dengan prinsip yang ditetapkan dalam dokumentasi. Anda dapat melihat kode sumber untuk fungsi ini di repositori proyek git.
Fungsi GotRecords mem-parsing permintaan masuk dan untuk setiap objek Record memanggil skrip eksternal (yang namanya diteruskan dalam parameter -script) dengan parameter:
nama ember
kunci objek
tindakan:
salin - jika dalam permintaan asli EventName = ObjectCreated | Letakkan Objek | Letakkan ObjekSalinan
hapus - jika dalam permintaan asli EventName = ObjectRemoved | Hapus Objek
Jadi, jika sebuah hook datang dengan permintaan Post, seperti yang dijelaskan atas, dan parameter -script=script.sh maka skrip akan dipanggil sebagai berikut:
script.sh bucketA some-file-to-bucket copy
Perlu dipahami bahwa server penerima webhook ini bukanlah solusi produksi lengkap, namun contoh sederhana dari kemungkinan implementasi.
Contoh pekerjaan
Mari sinkronkan file dari bucket utama di MCS ke bucket cadangan di AWS. Bucket utama disebut myfiles-ash, bucket cadangan disebut myfiles-backup (konfigurasi bucket di AWS berada di luar cakupan artikel ini). Oleh karena itu, ketika sebuah file ditempatkan di keranjang utama, salinannya akan muncul di keranjang cadangan, dan ketika dihapus dari keranjang utama, salinannya harus dihapus di keranjang cadangan.
Kami akan bekerja dengan bucket menggunakan utilitas awscli, yang kompatibel dengan penyimpanan cloud MCS dan penyimpanan 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) ...
Mari konfigurasikan akses ke 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]:
Mari konfigurasikan akses ke 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 kita periksa aksesnya:
Ke AWS:
ubuntu@ubuntu-basic-1-2-10gb:~$ aws s3 ls --profile aws
2020-07-06 08:44:11 myfiles-backup
Untuk MCS, saat menjalankan perintah Anda perlu menambahkan βendpoint-url:
Mari kita lihat cara kerjanya. Melalui Antarmuka web MCS tambahkan file test.txt ke keranjang myfiles-ash. Log konsol menunjukkan bahwa permintaan dibuat ke 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
Mari kita periksa isi bucket myfiles-backup di AWS:
Sekarang, melalui antarmuka web, kami akan menghapus file dari ember myfiles-ash.
Log server:
2020/07/06 09:44:46 [POST] incoming HTTP request from
95.163.216.92:58224
delete: s3://myfiles-backup/test.txt
Isi ember:
ubuntu@ubuntu-basic-1-2-10gb:~/s3-webhook$ aws s3 --profile aws ls
myfiles-backup
ubuntu@ubuntu-basic-1-2-10gb:~$
File dihapus, masalahnya terpecahkan.
Kesimpulan dan Hal yang Harus Dilakukan
Semua kode yang digunakan dalam artikel ini adalah di repositori saya. Terdapat juga contoh script dan contoh penghitungan tanda tangan untuk mendaftarkan webhook.
Kode ini tidak lebih dari contoh bagaimana Anda dapat menggunakan webhook S3 dalam aktivitas Anda. Seperti yang saya katakan di awal, jika Anda berencana untuk menggunakan server seperti itu dalam produksi, Anda setidaknya perlu menulis ulang server untuk pekerjaan asinkron: daftarkan webhook yang masuk dalam antrian (RabbitMQ atau NATS), dan dari sana parsing dan proseskan dengan aplikasi pekerja. Jika tidak, ketika webhook hadir dalam jumlah besar, Anda mungkin mengalami kekurangan sumber daya server untuk menyelesaikan tugas. Kehadiran antrian memungkinkan Anda untuk mendistribusikan server dan pekerja, serta memecahkan masalah dengan pengulangan tugas jika terjadi kegagalan. Disarankan juga untuk mengubah logging ke yang lebih detail dan terstandarisasi.