Functionとeventgridを使用して、ストレージアカウントログの自動分析と変換を実現します

この記事は以前のアイデアです。前回の記事では、アイデアを共有しました。PowerShellスクリプトを使用してストレージアカウントのアクセスログをダウンロードし、Log Analyticsに自動的にアップロードして、LAに直接アクセスできるようにすることができます。ログの分析とクエリ。この方法はシンプルで便利ですが、結局のところ自動化された方法ではありません。アイデアを拡張した後、eventgridと関数を組み合わせてこの方法を自動化されたソリューションに変換することもできます。

まず、EventGridとFunctionが何であるかを最初に普及させましょう

EventGrid

Azure Event Gridを使用すると、イベントベースのアーキテクチャを使用してアプリケーションを簡単に生成できます。まず、サブスクライブするAzureリソースを選択してから、イベントの送信先となるイベントハンドラーまたはWebHookエンドポイントを提供します。イベントグリッドには、ストレージブロブやリソースグループなどのAzureサービスからのイベントのサポートが組み込まれています。イベントグリッドは、カスタムテーマを使用した独自のイベントもサポートします。

簡単に言えば、さまざまなイベントをトリガーしてターゲットを絞った応答を行うことができるトリガーのようなものです。ロジックアプリのトリガーのように聞こえますが、eventgridは単純なイベント転送ツールであり、ダウンストリームの処理方法です。他の製品によって完全に完成した次の図は、イベント送信用のメッセージキューと同様に、イベントグリッドが配置されている場所にも表示されます。

https://docs.microsoft.com/en-us/azure/event-grid/?WT.mc_id=AZ-MVP-5001235

写真1.png

関数

Azure Functionsは、ユーザーがコードの記述を減らし、保守が必要なインフラストラクチャを減らし、コストを節約できるようにするサーバーレスソリューションです。サーバーの展開と保守について心配する必要はありません。クラウドインフラストラクチャは、アプリケーションの実行を維持するために必要なすべての最新のリソースを提供します。

機能は実際には理解しやすいです。今ではすべてのクラウドに基本的に同様の製品があります。水平方向に比較すると、フルマネージドコード実行プラットフォームであるAWSラムダです。

https://docs.microsoft.com/zh-cn/azure/azure-functions/functions-overview?WT.mc_id=AZ-MVP-5001235

上の図を組み合わせると、実際に私たちの考えを見ることができます。Eventgirdにはblobトリガーが組み込まれています。つまり、新しいblobが表示されると、自動的にeventgridがトリガーされ、ダウンストリームの処理手順では、次の機能を組み合わせることができます。コードは実際には既製です。前のコードを使用してください。少し変更する必要があります。全体的なワークロードは非常に小さいです。

もちろん、ストレージアカウントログは$ logsコンテナに保存され、このコンテナはAzureバックエンドでeventgridをトリガーしないため、実際にはここに隠れた問題があります。これは少し注意が必要です。使用する方法は、関数を作成することです。 、次にazcopyを使用して、ログ同期を別のコンテナに定期的に同期します。コードは1行だけで簡単なので、今は書きません。

実装手順

以下の具体的な実装手順を見てみましょう。まず、関数アプリを作成します。関数アプリと関数の関係は非常に単純です。関数アプリは、関数が実行されるプラットフォームと同等です。コードはこのプラットフォームで実行されます。関数アプリには、多くの関数

関数アプリを作成する

関数アプリを作成するプロセスは非常に簡単です。PowerShellコアとしてランタイムを選択します

写真2.png

関数の作成 

Functionアプリを作成したら、その中に関数を作成できます。Azureには、実際には偶数グリッドトリガー機能が組み込まれています。作成時に選択するだけです。

写真4.png


WeChatscreenshot_20210112104638.png


イベントグリッドサブスクリプションの作成

関数の準備ができたら、eventgridを準備し、関数で直接イベントグリッドサブスクリプションを作成できます。

写真5.png

イベントグリッドサブスクリプションを作成する場合、選択できるタイプは多数あります。ここで、ストレージタイプを選択してください。

写真6.png


ストレージアカウントのイベントタイプを構成します

写真7.png


次に、パスを特定の範囲に制限する必要があるため、フィルターを構成する必要性に注意してください。すべてのblobがイベントをトリガーするわけではありません。

写真8.png

トリガーの準備もできたら、関数で処理するコードを準備できます

コードを書く

前のコードはループで処理され、eventgridは実際に1つずつプッシュされるため、ここでのロジックは少し調整する必要があります

関数ビルド-署名($ customerId、$ sharedKey、$ date、$ contentLength、$ method、$ contentType、$ resource)
{ 
    $ xHeaders = "x-ms-date:" + $ date 
    $ stringToHash = $ method + "` n "+ $ contentLength +" `n" + $ contentType + "` n "+ $ xHeaders +" `n" + $ resource 

    $ bytesToHash = [Text.Encoding] :: UTF8.GetBytes($ stringToHash)
    $ keyBytes = [Convert ] :: FromBase64String($ sharedKey)

    $ sha256 = New-Object System.Security.Cryptography.HMACSHA256 
    $ sha256.Key = $ keyBytes 
    $ calculatedHash = $ sha256.ComputeHash($ bytesToHash)
    $ encodingHash = [Convert] :: ToBase64String($計算された
    ハッシュ$ authorization = 'SharedKey {0}:{1}' -f $ customerId、$ encodingHash 
    return $ authorization 
}

関数Post-LogAnalyticsData($ customerId、$ sharedKey、$ body、$ logType)
{ 

    

    $ method = "POST" 
    $ contentType = "application / json" 
    $ resource = "/ api / logs" 
    $ rfc1123date = [DateTime] :: UtcNow .ToString( "r")
    $ contentLength = $ body.Length 
    $ signature = Build-Signature ` 
        -customerId $ customerId` 
        -sharedKey $ sharedKey` 
        -date $ rfc1123date` -contentLength 
        $ contentLength ` 
        -method $ method` -contentType 
        $ contentType ` 
        -resource $ resource 
    $ uri =" https:// "+ $ customerId +" .ods.opinsights.azure.com "+ $ resource +"?api-version = 2016-04-01 " 

    $ headers = @ {
        "承認" = $ signature; 
        "Log-Type" = $ logType; 
        "x-ms-date" = $ rfc1123date; 
        "time-generated-field" = $ TimeStampField; 
    } 

    $ response = Invoke-WebRequest -Uri $ uri -Method $ method -ContentType $ contentType -Headers $ headers -Body $ body -UseBasicParsing 
    return $ response.StatusCode 
} 

Function ConvertSemicolonToURLEncoding([String] $ InputText)
{ 
    $ ReturnText = "" 
    $ chars = $ InputText.ToCharArray()



    $ StartConvert = $ false 



    foreach($ c in $ chars)
    { 
        if($ c -eq '"'){ 
            $ StartConvert =!$ StartConvert 
        }


        if($ StartConvert -eq $ true -and $ c -eq ';')
        { 
            $ ReturnText + = "%3B" 
        } else { 
            $ ReturnText + = $ c 
        } 
    } 

    return $ ReturnText 
}

関数FormalizeJsonValue ($ Text)
{ 
    $ Text1 = "" 
    if($ Text.IndexOf( "` "")-eq 0){$ Text1 = $ Text} else {$ Text1 = "` "" + $ Text + "` ""} 
    if($ Text1.IndexOf ( "%3B")- 
        ge 0){ $ ReturnText = $ Text1.Replace( "%3B"、 ";") 
    } else { 
        $ ReturnText = $ Text1 
    } 
    return $ ReturnText 
}

関数ConvertLogLineToJson([String] $ logLine)
{


    $ logLineEncoded = ConvertSemicolonToURLEncoding($ logLine)

    $ elements = $ logLineEncoded.split( ';')

    

    $ FormattedElements = New-Object System.Collections.ArrayList 
                
    foreach($ element in $ elements)
    { 

        $ NewText = FormalizeJsonValue($ element)
        $ FormattedElements .Add($ NewText)> null 
    } 
    $ Columns =  
    ( "version-number"、
        "request-start-time"、
        "operation-type"、
        "request-status"、
        "http-status-code"、
        "end- to-end-latency-in-ms」、
        「server-latency-in-ms」、
        「authentication-type」、
        「リクエスターアカウント名」、
        「所有者アカウント名」、 
        "service-type"、
        "request-url"、
        "requested-object-key"、
        "request-id-header"、
        "operation-count"、
        "requester-ip-address"、
        「request-version-header」、
        「request-header-size」、
        「request-packet-size」、
        「response-header-size」、
        「response-packet-size」、
        「request-content-length」、
        「request -md5 "、
        " server-md5 "、
        " etag-identifier "、
        " last-modified-time "、
        「conditions-used」、
        「user-agent-header」、
        「referrer-header」、 
        "client-request-id" 
    )

    $ logJson = "[{"; 
    For($ i = 0; $ i -lt $ Columns.Length; $ i ++)
    { 
        $ logJson + = "` "" + $ Columns [$ i] + "` ":" + $ FormattedElements [$ i] 
        if($ i -lt $ Columns.Length-1){ 
            $ logJson + = "、" 
        } 
    } 
    $ logJson + = "}]"; 

    return $ logJson 
} 

$ storageAccount = Get-AzStorageAccount -ResourceGroupName $ ResourceGroup -Name $ StorageAccountName -ErrorAction SilentlyContinue 
if($ null -eq $ storageAccount)
{ 
    throw "指定されたストレージアカウントはこのサブスクリプションに存在しません。" 
} 

$ storageContext = $ storageAccount。


$ maxReturn = 5000 
$ successPost = 0 

$ subject = $ eventGridEvent.subject.ToString()
$ BlobArray = $ subject.Split( '/')
$ container = $ BlobArray [$ BlobArray.indexof( 'containers')+ 1] 
$ BlobIndex = $ subject.indexof( 'blobs /')+ 6 
$ Blob = $ subject.substring($ BlobIndex、$ subject.length- $ BlobIndex)

Write-Output( ">ブロブのダウンロード:{0}" -f $ blob )
$ filename = "。\ log.txt" 
Get-AzStorageBlobContent -Context $ storageContext -Container $ container -Blob $ blob -Destination $ filename -Force> Null 
Write-Output( ">ログをログ分析ワークスペースに投稿する:{0} 「」-f $ blob) 

$ lines = Get-Content $ filename 

foreach($ line in $ lines)
        { 
            $ json = ConvertLogLineToJson($ line)
           

            $ response = Post-LogAnalyticsData -customerId $ customerId -sharedKey $ sharedKey -body([System.Text.Encoding] :: UTF8.GetBytes($ json))-logType $ logType 

            if($ response -eq "200"){ 
                $ successPost ++ 
            } else { 
                $ failedPost ++ 
                Write-Output "> 1つのログをLogAnalyticsワークスペースに投稿できません でした" 
            } 
        } 

        remove-item $ filename -Force 

    


Write-Output "> Log Analyticsワークスペースに投稿されたログ行:success = $ successPost、failure = $ failedPost "


最後のステップは、ファンクションアプリにストレージへのアクセスを許可することです。このステップについては詳しく説明しません。ストレージアカウントキーを使用してアクセスすることもできます。もちろん、この方法はあまりお勧めしません。

最後に、機能のモニタリングで完了した効果を確認できます

写真10.png

総括する

一般的に言って、PowerShellスクリプトを使用する方法と比べてそれほど変わっていませんが、eventgridと関数が追加されたため、ソリューション全体がより柔軟になりました。同様のアイデアを他の多くのタスクに拡張して、よりクラウドベースにすることもできます。ネイティブな方法で問題を調べて対処する

おすすめ

転載: blog.51cto.com/mxyit/2588527