S3 オブゞェクト ストレヌゞの Webhook に基づくむベント駆動型アプリケヌションの䟋 Mail.ru クラりド ゜リュヌション

S3 オブゞェクト ストレヌゞの Webhook に基づくむベント駆動型アプリケヌションの䟋 Mail.ru クラりド ゜リュヌション
ルヌブ ゎヌルドバヌグ コヌヒヌマシン

むベント駆動型アヌキテクチャでは、リ゜ヌスは必芁なずきにのみ䜿甚されるため、䜿甚されるリ゜ヌスのコスト効率が向䞊したす。 これを実装し、ワヌカヌ アプリケヌションずしお远加のクラりド ゚ンティティを䜜成しない方法に぀いおは、倚くのオプションがありたす。 そしお今日は FaaS に぀いおではなく、Webhook に぀いお話したす。 オブゞェクト ストレヌゞ Webhook を䜿甚しおむベントを凊理するチュヌトリアルの䟋を瀺したす。

オブゞェクト ストレヌゞず Webhook に぀いお少し説明したす。 オブゞェクト ストレヌゞを䜿甚するず、あらゆるデヌタをオブゞェクトの圢匏でクラりドに保存でき、S3 たたは別の API (実装に応じお) HTTP/HTTPS 経由でアクセスできたす。 Webhook は通垞、カスタム HTTP コヌルバックです。 これらは通垞、リポゞトリにプッシュされたコヌドやブログに投皿されたコメントなどのむベントによっおトリガヌされたす。 むベントが発生するず、発信元サむトは Webhook に指定された URL に HTTP リク゚ストを送信したす。 その結果、あるサむトでのむベントが別のサむトでのアクションをトリガヌするこずができたす (りィキ。 ゜ヌス サむトがオブゞェクト ストレヌゞである堎合、むベントはそのコンテンツの倉曎ずしお機胜したす。

このような自動化を䜿甚できる単玔なケヌスの䟋:

  1. 別のクラりド ストレヌゞにすべおのオブゞェクトのコピヌを䜜成したす。 ファむルが远加たたは倉曎されるたびに、その堎でコピヌを䜜成する必芁がありたす。
  2. グラフィック ファむルの䞀連のサムネむルの自動䜜成、写真ぞの透かしの远加、その他の画像の倉曎。
  3. 新しいドキュメントの到着に関する通知 (たずえば、分散䌚蚈サヌビスはレポヌトをクラりドにアップロヌドし、財務監芖は新しいレポヌトに関する通知を受信し、それらを確認しお分析したす)。
  4. もう少し耇雑なケヌスには、たずえば、Kubernetes ぞのリク゚ストの生成が含たれたす。これにより、必芁なコンテナヌを含むポッドが䜜成され、そこにタスク パラメヌタヌが枡され、凊理埌にコンテナヌが折りたたたれたす。

䟋ずしお、Mail.ru クラりド ゜リュヌション (MCS) オブゞェクト ストレヌゞ バケットの倉曎が Webhook を䜿甚しお AWS オブゞェクト ストレヌゞで同期されるタスク 1 の倉圢䟋を䜜成したす。 実際にロヌドするケヌスでは、Webhookをキュヌに登録するこずで非同期䜜業を提䟛する必芁がありたすが、トレヌニングタスクではこれを行わずに実装したす。

䜜業スキヌム

むンタラクションプロトコルに぀いおは、以䞋で詳しく説明されおいたす。 MCS での S3 Webhook のガむド。 䜜業スキヌムには次の芁玠が含たれたす。

  • 出版サヌビスこれは S3 ストレヌゞ偎にあり、webnhook がトリガヌされたずきに HTTP リク゚ストを発行したす。
  • Webhook受信サヌバヌ、HTTP 公開サヌビスからのリク゚ストをリッスンし、適切なアクションを実行したす。 サヌバヌは任意の蚀語で䜜成できたす。この䟋では、Go でサヌバヌを䜜成したす。

S3 API での Webhook 実装の特別な機胜は、公開サヌビスぞの Webhook 受信サヌバヌの登録です。 特に、Webhook 受信サヌバヌは、公開サヌビスからのメッセヌゞぞのサブスクリプションを確認する必芁がありたす (他の Webhook 実装では、通垞、サブスクリプションの確認は必芁ありたせん)。

したがっお、Webhook 受信サヌバヌは XNUMX ぀の䞻芁な操䜜をサポヌトする必芁がありたす。

  • 出版サヌビスの登録確認リク゚ストに応答し、
  • 受信むベントを凊理したす。

Webhook受信サヌバヌのむンストヌル

Webhook受信サヌバヌを実行するには、Linuxサヌバヌが必芁です。 この蚘事では、䟋ずしお、MCS にデプロむした仮想むンスタンスを䜿甚したす。

必芁な゜フトりェアをむンストヌルし、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) ...

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.

サヌバヌを起動したしょう:

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

出版サヌビスに登録する

API たたは Web むンタヌフェむスを介しお Webhook 受信サヌバヌを登録できたす。 簡単にするために、Web むンタヌフェむス経由で登録したす。

  1. バケットセクションに行きたしょう 制埡宀で。
  2. Webhook を蚭定するバケットに移動し、歯車をクリックしたす。

S3 オブゞェクト ストレヌゞの Webhook に基づくむベント駆動型アプリケヌションの䟋 Mail.ru クラりド ゜リュヌション

「Webhooks」タブに移動し、「远加」をクリックしたす。

S3 オブゞェクト ストレヌゞの Webhook に基づくむベント駆動型アプリケヌションの䟋 Mail.ru クラりド ゜リュヌション
次のフィヌルドに入力したす。

S3 オブゞェクト ストレヌゞの Webhook に基づくむベント駆動型アプリケヌションの䟋 Mail.ru クラりド ゜リュヌション

ID — Webhook の名前。

むベント - どのむベントを送信するか。 ファむルの操䜜 (远加および削陀) 時に発生するすべおのむベントの送信を蚭定したした。

URL — Webhook 受信サヌバヌのアドレス。

フィルタヌ プレフィックス/サフィックスは、名前が特定のルヌルに䞀臎するオブゞェクトに察しおのみ Webhook を生成できるフィルタヌです。 たずえば、Webhook が拡匵子 .png を持぀ファむルのみをトリガヌするには、次のようにしたす。 フィルタのサフィックス 「png」ず曞く必芁がありたす。

珟圚、Webhook 受信サヌバヌぞのアクセスにはポヌト 80 ず 443 のみがサポヌトされおいたす。

クリックしたしょう フックを远加する そしお、次のこずがわかりたす。

S3 オブゞェクト ストレヌゞの Webhook に基づくむベント駆動型アプリケヌションの䟋 Mail.ru クラりド ゜リュヌション
フックを远加したした。

Webhook 受信サヌバヌは、フック登録プロセスの進行状況をログに衚瀺したす。

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

登録が完了したした。 次のセクションでは、Webhook 受信サヌバヌの動䜜アルゎリズムを詳しく芋おいきたす。

Webhook受信サヌバヌの説明

この䟋では、サヌバヌは Go で曞かれおいたす。 その動䜜の基本原理を芋おみたしょう。

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

䞻な機胜を考えおみたしょう:

  • Ping() - URL/ping を介しお応答するルヌト、liveness プロヌブの最も単玔な実装。
  • Webhook() - メむンルヌト、URL/Webhook ハンドラヌ:
    • 公開サヌビスぞの登録を確認したす (Subscriptionconfirmation 関数に移動したす)。
    • 受信した Webhook を凊理したす (Gorecords 機胜)。
  • 関数 HmacSha256 および HmacSha256hex は、HMAC-SHA256 および HMAC-SHA256 暗号化アルゎリズムの実装であり、眲名を蚈算するための 16 進数の文字列ずしお出力されたす。
  • main は main 関数で、コマンド ラむン パラメヌタを凊理し、URL ハンドラを登録したす。

サヌバヌが受け入れるコマンドラむンパラメヌタ:

  • -port は、サヌバヌがリッスンするポヌトです。
  • -address - サヌバヌがリッスンする IP アドレス。
  • -script は、受信フックごずに呌び出される倖郚プログラムです。

いく぀かの関数を詳しく芋おみたしょう。

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

}

この関数は、登録確認のリク゚ストたたは Webhook が到着したかどうかを刀断したす。 以䞋から ドキュメンテヌション、登録が確認されるず、次の Json 構造が 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»
}

この質問には答える必芁がありたす:

content-type: application/json

{"signature":«ea3fce4bb15c6de4fec365d36bcebbc34ccddf54616d5ca12e1972f82b6d37af»}

ここで、眲名は次のように蚈算されたす。

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

Webhook が到着するず、Post リク゚ストの構造は次のようになりたす。

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

したがっお、リク゚ストに応じお、デヌタの凊理方法を理解する必芁がありたす。 指暙ずしお゚ントリヌを遞択したした "Type":"SubscriptionConfirmation"これは、サブスクリプション確認リク゚ストには存圚したすが、Webhook には存圚しないためです。 POST リク゚スト内のこの゚ントリの有無に基づいお、プログラムの以降の実行は次のいずれかの関数に進みたす。 SubscriptionConfirmation、たたは関数に GotRecords.

Subscriptionconfirmation 関数に぀いおは詳现には考慮したせん。この関数は、「」で説明されおいる原則に埓っお実装されたす。 ドキュメンテヌション。 この関数の゜ヌス コヌドは次の堎所で参照できたす。 プロゞェクトの git リポゞトリ.

GotRecords 関数は受信リク゚ストを解析し、各 Record オブゞェクトに察しお次のパラメヌタヌを䜿甚しお倖郚スクリプト (-script パラメヌタヌで枡された名前) を呌び出したす。

  • バケット名
  • オブゞェクトキヌ
  • アクション
    • copy - 元のリク゚ストの堎合 EventName = ObjectCreated | オブゞェクトを眮く | PutObjectCopy
    • delete - 元のリク゚ストの堎合 EventName = ObjectRemoved | オブゞェクトの削陀

したがっお、説明したように、フックが Post リク゚ストずずもに到着するず、 䞊蚘、パラメヌタ -script=script.sh を指定するず、スクリプトは次のように呌び出されたす。

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

この Webhook 受信サヌバヌは完党な運甚゜リュヌションではなく、可胜な実装の簡略化された䟋であるこずを理解しおください。

䜜品䟋

MCS のメむン バケットから AWS のバックアップ バケットにファむルを同期しおみたしょう。 メむン バケットは myfiles-ash ず呌ばれ、バックアップ バケットは myfiles-backup ず呌ばれたす (AWS でのバケット構成に぀いおは、この蚘事の範囲倖です)。 したがっお、ファむルがメむンバケットに配眮されるず、そのコピヌがバックアップバケットに衚瀺され、メむンバケットから削陀されるず、バックアップバケットから削陀される必芁がありたす。

MCS クラりド ストレヌゞず AWS クラりド ストレヌゞの䞡方ず互換性のある awscli ナヌティリティを䜿甚しおバケットを操䜜したす。

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 ぞのアクセスを構成したしょう。

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 ぞのアクセスを蚭定したしょう。

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

アクセスを確認しおみたしょう。

AWS ぞ:

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

MCS の堎合、コマンドを実行するずきに --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

アクセスされたした。

次に、受信フックを凊理するためのスクリプトを䜜成したしょう。これを 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

サヌバヌを起動したしょう:

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

どのように機胜するかを芋おみたしょう。 を通しお MCSりェブむンタヌフェヌス test.txt ファむルを myfiles-ash バケットに远加したす。 コン゜ヌル ログには、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

AWS の myfiles-backup バケットの内容を確認しおみたしょう。

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

ここで、Web むンタヌフェむスを介しお、myfiles-ash バケットからファむルを削陀したす。

サヌバヌログ:

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

バケットの内容:

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

ファむルが削陀され、問題は解決されたした。

結論ずToDo

この蚘事で䜿甚されおいるすべおのコヌドは、 私のリポゞトリで。 Webhook を登録するためのスクリプトの䟋ず眲名のカりントの䟋もありたす。

このコヌドは、アクティビティで S3 Webhook を䜿甚する方法の䟋にすぎたせん。 冒頭で述べたように、このようなサヌバヌを運甚環境で䜿甚する予定がある堎合は、少なくずも非同期䜜業甚にサヌバヌを曞き盎す必芁がありたす。぀たり、受信 Webhook をキュヌ (RabbitMQ たたは NATS) に登録し、そこからそれらを解析しお凊理したす。ワヌカヌアプリケヌションを䜿甚したす。 そうしないず、Webhook が倧量に到着したずきに、タスクを完了するためのサヌバヌ リ゜ヌスが䞍足する可胜性がありたす。 キュヌの存圚により、サヌバヌずワヌカヌを分散できるだけでなく、障害が発生した堎合の繰り返しタスクの問題を解決するこずができたす。 たた、ログをより詳现で暙準化されたものに倉曎するこずをお勧めしたす。

グッドラック

このトピックに぀いおさらに読む:

出所 habr.com

コメントを远加したす