S3 nesne depolamasındaki web kancalarını temel alan olay odaklı bir uygulama örneği Mail.ru Bulut Çözümleri

S3 nesne depolamasındaki web kancalarını temel alan olay odaklı bir uygulama örneği Mail.ru Bulut Çözümleri
Rube Goldberg kahve makinesi

Olay odaklı mimari, kullanılan kaynakların yalnızca ihtiyaç duyulduğu anda kullanılması nedeniyle maliyet verimliliğini artırır. Bunun nasıl uygulanacağına ve çalışan uygulamalar olarak ek bulut varlıkları oluşturulmamasına ilişkin birçok seçenek vardır. Ve bugün FaaS'tan değil web kancalarından bahsedeceğim. Nesne depolama web kancalarını kullanarak olayların işlenmesine ilişkin öğretici bir örnek göstereceğim.

Nesne depolama ve web kancaları hakkında birkaç söz. Nesne depolama, S3 veya başka bir API (uygulamaya bağlı olarak) aracılığıyla HTTP/HTTPS yoluyla erişilebilen nesneler biçiminde bulutta herhangi bir veriyi saklamanıza olanak tanır. Web kancaları genellikle özel HTTP geri aramalarıdır. Bunlar genellikle kodun bir depoya gönderilmesi veya bir blogda yayınlanan yorum gibi bir olay tarafından tetiklenir. Bir olay meydana geldiğinde, kaynak site, web kancası için belirtilen URL'ye bir HTTP isteği gönderir. Sonuç olarak, bir sitedeki olayların diğer sitedeki eylemleri tetiklemesini sağlayabilirsiniz (wiki). Kaynak sitenin bir nesne deposu olması durumunda olaylar, içeriğinde değişiklik görevi görür.

Bu tür otomasyonun kullanılabileceği basit durumlara örnekler:

  1. Başka bir bulut depolama alanındaki tüm nesnelerin kopyalarını oluşturmak. Dosyalar eklendiğinde veya değiştirildiğinde kopyalar anında oluşturulmalıdır.
  2. Bir dizi grafik dosyasının küçük resmini otomatik olarak oluşturma, fotoğraflara filigran ekleme ve diğer görüntü değişiklikleri.
  3. Yeni belgelerin gelişiyle ilgili bildirim (örneğin, dağıtılmış bir muhasebe hizmeti raporları buluta yükler ve finansal izleme, yeni raporlar hakkında bildirimler alır, bunları kontrol eder ve analiz eder).
  4. Biraz daha karmaşık durumlar, örneğin gerekli kapsayıcıları içeren bir bölme oluşturan Kubernetes'e bir istek oluşturulmasını, görev parametrelerinin ona iletilmesini ve işlendikten sonra kapsayıcının daraltılmasını içerir.

Örnek olarak, Mail.ru Bulut Çözümleri (MCS) nesne depolama grubundaki değişiklikler web kancaları kullanılarak AWS nesne depolamasında senkronize edildiğinde görev 1'in bir çeşidini yapacağız. Gerçek yüklü bir durumda webhook'ların kuyruğa kaydedilmesiyle asenkron çalışma sağlanmalıdır ancak eğitim görevi için uygulamayı bu olmadan yapacağız.

Çalışma düzeni

Etkileşim protokolü ayrıntılı olarak açıklanmaktadır. MCS'deki S3 web kancaları kılavuzu. Çalışma şeması aşağıdaki unsurları içerir:

  • Yayıncılık hizmeti, S3 depolama tarafındadır ve webnhook tetiklendiğinde HTTP isteklerini yayınlar.
  • Web kancası alıcı sunucusuHTTP yayınlama hizmetinden gelen istekleri dinleyen ve uygun eylemleri gerçekleştiren. Sunucu herhangi bir dilde yazılabilir; örneğimizde sunucuyu Go'ya yazacağız.

Web kancalarının S3 API'de uygulanmasının özel bir özelliği, web kancası alıcı sunucusunun yayınlama hizmetine kaydedilmesidir. Özellikle, web kancası alıcı sunucusunun, yayınlama hizmetinden gelen mesajlara aboneliği onaylaması gerekir (diğer web kancası uygulamalarında, aboneliğin onayı genellikle gerekli değildir).

Buna göre webhook alıcı sunucusunun iki ana işlemi desteklemesi gerekir:

  • yayıncılık hizmetinin kaydı onaylama talebine yanıt vermek,
  • gelen olayları işleyin.

Webhook alıcı sunucusunu yükleme

Webhook alıcı sunucusunu çalıştırmak için bir Linux sunucusuna ihtiyacınız vardır. Bu yazımızda örnek olarak MCS üzerinde konuşlandırdığımız sanal bir örneği kullanıyoruz.

Gerekli yazılımı yükleyelim ve webhook alıcı sunucusunu başlatalım.

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

Klasörü webhook alıcı sunucusuyla kopyalayın:

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.

Sunucuyu başlatalım:

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

Yayınlama hizmetine abone olun

Webhook alıcı sunucunuzu API veya web arayüzü aracılığıyla kaydedebilirsiniz. Basit olması açısından web arayüzü üzerinden kayıt olacağız:

  1. Kovalar bölümüne gidelim kontrol odasında.
  2. Web kancalarını yapılandıracağımız pakete gidin ve donanıma tıklayın:

S3 nesne depolamasındaki web kancalarını temel alan olay odaklı bir uygulama örneği Mail.ru Bulut Çözümleri

Web Kancaları sekmesine gidin ve Ekle'ye tıklayın:

S3 nesne depolamasındaki web kancalarını temel alan olay odaklı bir uygulama örneği Mail.ru Bulut Çözümleri
Alanları doldurun:

S3 nesne depolamasındaki web kancalarını temel alan olay odaklı bir uygulama örneği Mail.ru Bulut Çözümleri

Kimlik — web kancasının adı.

Olay - hangi olayların iletileceği. Dosyalarla çalışırken (ekleme ve silme) meydana gelen tüm olayların aktarımını ayarladık.

URL — webhook alıcı sunucu adresi.

Filtre öneki/son eki, yalnızca adları belirli kurallarla eşleşen nesneler için web kancaları oluşturmanıza olanak tanıyan bir filtredir. Örneğin, webhook'un yalnızca .png uzantılı dosyaları tetiklemesi için Filtre son eki “png” yazmanız gerekiyor.

Şu anda webhook alıcı sunucusuna erişim için yalnızca 80 ve 443 numaralı bağlantı noktaları desteklenmektedir.

Haydi tıklayalım Kanca ekle ve şunları göreceğiz:

S3 nesne depolamasındaki web kancalarını temel alan olay odaklı bir uygulama örneği Mail.ru Bulut Çözümleri
Kanca eklendi.

Webhook alıcı sunucusu, günlüklerinde kanca kayıt işleminin ilerlemesini gösterir:

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

Kayıt tamamlandı. Bir sonraki bölümde webhook alıcı sunucunun çalışma algoritmasına daha yakından bakacağız.

Webhook alıcı sunucusunun açıklaması

Örneğimizde sunucu Go'da yazılmıştır. Operasyonunun temel prensiplerine bakalım.

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

Ana işlevleri göz önünde bulundurun:

  • Ping() - bir canlılık araştırmasının en basit uygulaması olan URL/ping yoluyla yanıt veren bir rota.
  • Webhook() - ana rota, URL/webhook işleyicisi:
    • yayınlama hizmetine kaydı onaylar (AbonelikOnay işlevine gidin),
    • gelen web kancalarını işler (Gorecords işlevi).
  • HmacSha256 ve HmacSha256hex işlevleri, imzayı hesaplamak için onaltılık sayılardan oluşan bir dize olarak çıktı veren HMAC-SHA256 ve HMAC-SHA256 şifreleme algoritmalarının uygulamalarıdır.
  • main ana işlevdir, komut satırı parametrelerini işler ve URL işleyicilerini kaydeder.

Sunucu tarafından kabul edilen komut satırı parametreleri:

  • -port, sunucunun dinleyeceği bağlantı noktasıdır.
  • -adres - Sunucunun dinleyeceği IP adresi.
  • -script, gelen her kanca için çağrılan harici bir programdır.

Bazı işlevlere daha yakından bakalım:

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

}

Bu işlev, kaydı onaylamaya yönelik bir isteğin veya bir web kancasının gelip gelmediğini belirler. Aşağıdaki gibi belgeleme, kayıt onaylanırsa Post isteğinde aşağıdaki Json yapısı alınır:

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

Bu sorunun yanıtlanması gerekiyor:

content-type: application/json

{"signature":«ea3fce4bb15c6de4fec365d36bcebbc34ccddf54616d5ca12e1972f82b6d37af»}

İmzanın şu şekilde hesaplandığı yer:

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

Bir webhook gelirse Gönderi isteğinin yapısı şöyle görünü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"
            }
        }
    ]
}

Buna göre talebe bağlı olarak verilerin nasıl işleneceğini anlamanız gerekir. Girişi gösterge olarak seçtim "Type":"SubscriptionConfirmation"çünkü abonelik onay isteğinde mevcut olup webhook'ta mevcut değildir. POST isteğinde bu girişin varlığına/yokluğuna bağlı olarak programın daha fazla yürütülmesi ya işleve gider SubscriptionConfirmation, veya işleve GotRecords.

AbonelikOnay fonksiyonunu detaylı olarak ele almayacağız; aşağıda belirtilen ilkelere göre uygulanmaktadır. belgeleme. Bu işlevin kaynak kodunu şu adreste görüntüleyebilirsiniz: proje git depoları.

GotRecords işlevi, gelen bir isteği ayrıştırır ve her Record nesnesi için, aşağıdaki parametrelerle birlikte harici bir komut dosyasını (adı -script parametresinde aktarılan) çağırır:

  • kova adı
  • nesne anahtarı
  • eylem:
    • kopyala - orijinal istekteyse EventName = ObjectCreated | PutObject | PutObjectCopy
    • sil - orijinal istekte ise EventName = ObjectRemoved | Nesneyi Sil

Bu nedenle, açıklandığı gibi bir Post isteğiyle birlikte bir kanca gelirse yukarıdave -script=script.sh parametresi kullanıldığında komut dosyası şu şekilde çağrılacaktır:

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

Bu web kancası alıcı sunucusunun eksiksiz bir üretim çözümü olmadığı, ancak olası bir uygulamanın basitleştirilmiş bir örneği olduğu anlaşılmalıdır.

İş örneği

Dosyaları MCS'deki ana klasörden AWS'deki yedekleme paketine senkronize edelim. Ana kovanın adı myfiles-ash, yedek olanın adı ise myfiles-backup'tır (AWS'deki kova yapılandırması bu makalenin kapsamı dışındadır). Buna göre, bir dosya ana kovaya yerleştirildiğinde kopyası yedekte görünmeli, ana kovadan silindiğinde yedekte de silinmelidir.

Hem MCS bulut depolama hem de AWS bulut depolama ile uyumlu olan awscli yardımcı programını kullanarak paketlerle çalışacağız.

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

S3 MCS API'sine erişimi yapılandıralım:

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

AWS S3 API'sine erişimi yapılandıralım:

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

Erişimleri kontrol edelim:

AWS'ye:

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

MCS için, komutu çalıştırırken —endpoint-url'yi eklemeniz gerekir:

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

Erişildi.

Şimdi gelen kancayı işlemek için bir script yazalım, buna s3_backup_mcs_aws.sh adını verelim.

#!/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

Sunucuyu başlatalım:

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

Nasıl çalıştığını görelim. Başından sonuna kadar MCS web arayüzü test.txt dosyasını myfiles-ash klasörüne ekleyin. Konsol günlükleri webhook sunucusuna bir istek yapıldığını gösteriyor:

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

AWS'deki dosyalarım yedekleme paketinin içeriğini kontrol edelim:

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

Şimdi web arayüzü aracılığıyla dosyayı myfiles-ash kovasından sileceğiz.

Sunucu günlükleri:

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

Kova içeriği:

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

Dosya silinir, sorun çözülür.

Sonuç ve Yapılacaklar

Bu makalede kullanılan tüm kodlar benim depomda. Ayrıca web kancalarını kaydetmek için komut dosyası örnekleri ve imza sayma örnekleri de vardır.

Bu kod, etkinliklerinizde S3 web kancalarını nasıl kullanabileceğinizi gösteren bir örnekten başka bir şey değildir. Başlangıçta söylediğim gibi, böyle bir sunucuyu üretimde kullanmayı planlıyorsanız, en azından sunucuyu eşzamansız çalışma için yeniden yazmanız gerekir: gelen web kancalarını bir kuyruğa kaydedin (RabbitMQ veya NATS) ve oradan bunları ayrıştırıp işleyin. İşçi uygulamalarıyla. Aksi takdirde, web kancaları çok sayıda geldiğinde, görevleri tamamlamak için sunucu kaynaklarının yetersizliğiyle karşılaşabilirsiniz. Kuyrukların varlığı, sunucuyu ve çalışanları dağıtmanıza ve arıza durumunda tekrarlanan görevlerle ilgili sorunları çözmenize olanak tanır. Ayrıca günlüğe kaydetmenin daha ayrıntılı ve daha standart hale getirilmiş bir şekilde değiştirilmesi de tavsiye edilir.

İyi şanslar!

Konuyla ilgili daha fazla okuma:

Kaynak: habr.com

Yorum ekle