Adjust のリアルタイムコールバックを Cloud Logging に流す


1. はじめに

Adjust のリアルタイムコールバックを利用すると、 Adjust の計測結果を指定のサーバーに送信する事ができます。
この記事では、 Adjust のデータを Cloud Functions に送信して Cloud Logging へ流すための設計をまとめます。

2. アーキテクチャ

Adjust でリアルタイムコールバックを利用する際、受け口となるサーバーが必要となります。
今回は Cloud Logging へ送る事が目的なので、同じ GCP の Cloud Functions を使います。

アーキテクチャの完成予想図はこちらです。

3. サーバーを建てる

アーキテクチャで記述した通り、サーバーには Cloud Functions を利用します。
以下のパラメータで Cloud Functions を作成します。

Cloud Functions の設定

項目 設定内容
関数名 adjust-server
リージョン asia-northeast1
トリガーのタイプ HTTP
認証 認証が必要
ランタイム Go 1.13
エントリポイント GetRawData

Cloud Functions は複数言語のランタイムに対応していますが、今回は Go 1.13 で実行します。
ログの出力は構造を変更しやすいように uber-go/zap を利用します。

package p

import (
    "fmt"
    "net/http"

    "go.uber.org/zap"
)

var zlogger *zap.Logger

func init() {
    var err error
    zlogger, err = zap.NewProduction()
    if err != nil {
        fmt.Printf("request parse failed. %v", err)
        return
    }
}

func GetRawData(_ http.ResponseWriter, r *http.Request) {
    if err := r.ParseForm(); err != nil {
        fmt.Printf("request parse failed. %v", err)
        return
    }

    fields := make([]zap.Field, 0, len(r.Form)+1)
    fields = append(fields, zap.Namespace("body"))

    for k, v := range r.Form {
        fields = append(fields, zap.String(k, v[0]))
    }

    zlogger.Info("AdjustLogger", fields...)
}

デプロイが完了したらトリガーURLを叩いてみましょう。

$ curl https://asia-northeast1-${project_id}.cloudfunctions.net/adjust-server

クエリパラメータを追加して叩くと、パラメータ情報もログとして出力されます。

4. Adjust のリアルタイムコールバック設定

Adjust 側で行う設定は以下の公式ドキュメントに書かれています。
データの管理 > ローデータエクスポート > リアルタイムコールバック

抜粋すると、以下の手順で設定できます。

① 該当アプリの下部に表示されている(▲)ボタンを選択します。
② その他の設定 (All Settings)​> ローデータエクスポート (Raw Data Export)​ > リアルタイムコールバック (Real-Time Callbacks)​を選択します。
③ グローバルコールバック(GLOBAL CALLBACK)​を選択する。
④ コールバックURLを入力します(コールバックURLのテンプレートおよび推奨のプレースホルダーを参照)。
⑤ UPDATE​を選択します。

今回は例としてグローバルコールバックを使用します。
コールバックURLは、先ほど作成した Cloud Functions のトリガーURLに必要なクエリパラメータを追加したURLになります。

https://asia-northeast1-${project_id}.cloudfunctions.net/adjust-server?app_id={app_id}&app_name={app_name}

app_id, app_name 以外の情報が欲しい場合は Adjust Placeholders にプレースホルダーのドキュメントがあるので、必要なクエリパラメータを探して設定して下さい。

コールバックURLが設定できたら Adjust のイベントを発火させてみましょう。
正しく疎通できていれば以下のようなログが Cloud Logging に出力され、 jsonPayload.body の中にプレースホルダーの情報が表示されます。

{
    "insertId": "000000-...",
    "jsonPayload": {
        "msg": "AdjustLogger",
        "body": {
            "app_id": "foo",
            "app_name": "bar"
        },
        "level": "info",
        "caller": "serverless_function_source_code/function.go:33",
    },
    "resource": {
        "type": "cloud_function",
        "labels": {
            "project_id": "xxx",
            "function_name": "adjust-server",
            "region": "asia-northeast1"
        }
    },
    ...
}

5. IP 制限をかける

これまでの設定で、 Adjust から送られるリアルタイムコールバックの情報を Cloud Logging に流すことができました。
ただ、今のままだと外部から指定のURLに直接アクセスできるので Adjust 以外の情報が混入する可能性があります。

この問題を解決するため、 Cloud Armor で Adjust の IP をホワイトリストに設定します。

Cloud Functions の設定を変更する

まずは作成した Cloud Functions リソースを外部からアクセスできないようにします。

adjust-server の編集を行い、
ランタイム、ビルド、接続の設定 > 接続 > 内部トラフィックと Cloud Load Balancing からのトラフィックを許可する
を設定して更新しましょう。

正しく更新されると、トリガーAPIを叩く際に403エラーが返るようになります。

Cloud Load Balancing を作成する

次に、 Cloud Load Balancing を作成します。

以下の手順でロードバランサーの設定画面に移動します。
Cloud Load Balancing > ロードバランサを作成 > HTTP(S)負荷分散

インターネット接続の設定は インターネットから自分のVMへ を選択します。
ロードバランサーの名前は 「adjust-server-lb」 としましょう。

Cloud Load Balancing を作成するためには、バックエンドとフロントエンドの設定をする必要があります。また、今回は Cloud Functions のエンドポイントを設定するため、サーバーレス NEG を設定する必要があります。
バックエンド、フロントエンド、サーバーレス NEG を以下のように設定し、 Cloud Load Balancing を作成します。

バックエンドの設定

項目 設定内容
名前 adjust-server-backend
バックエンドタイプ サーバーレスネットワークエンドポイントグループ
プロトコル HTTP
タイムアウト 30秒
バックエンド adjust-server-neg (新規作成)
セキュリティ なし

サーバーレス NEG の設定

項目 設定内容
名前 adjust-server-neg
リージョン asia-northeast1
サーバーレスネットワークエンドポイントグループの種類 Cloud Functions
関数名を選択 adjust-server

フロントエンドの設定

項目 設定内容
名前 adjust-server-frontend
プロトコル HTTP
ネットワークサービス階層 プレミアム
IPバージョン IPv4
IPアドレス エフェメラル ( or 静的IPアドレス)
ポート 80

Cloud Load Balancing リソースが作成されたら、作成された IP アドレスにアクセスしてみましょう。
Cloud Functions のトリガーURLにアクセスした時と同様にログが出力されていればOKです。

$ curl http://${lb_ip_address}

Cloud Armor のポリシーを作成する

最後に、 Cloud Armor で Adjust の IP アドレスをホワイトリストに登録します。

Cloud Armor > ポリシーを作成 から、ポリシーの設定を行います。
Adjust の IP アドレスは以下の公式ドキュメントを参照してください。
参考資料 > リスト > Adjustサーバー IP

ポリシーの設定

項目 設定内容
名前 adjust-server-policy
デフォルトのルールアクション 拒否
拒否ステータス 403 (アクセス拒否)
関数名を選択 adjust-server

ルールの追加

項目 設定内容
モード 基本モード
一致 x.x.x.x/24,x.x.x.x/24,...
アクション 許可
優先度 0

※ IPアドレスは最大で10個までしか指定できないので、複数のルールを追加します。
※ 優先度は重複できないので、新しいルールを追加する際は優先度をインクリメントしてください。

ターゲットへのポリシーの適用

項目 設定内容
タイプ ロードバランサ バックエンドサービス
ターゲット adjust-server-backend

ポリシーが作成されたら、ロードバランサーのセキュリティ設定にadjust-server-policyを追加します。

Cloud Load Balancing から adjust-server-lb の編集画面に遷移します。
バックエンドの構成 から adjust-server-backend を選択し、 セキュリティ に adjust-server-policy を設定します。

これで Cloud Functions へのアクセスを Adjust の IP からのみ許可する設定ができました。

Adjust のコールバックURLを変更する

各リソースの作成が完了したら、 Adjust のリアルタイムコールバックの設定を更新しましょう。

http://${lb_ip_address}?app_id={app_id}&app_name={app_name}

今回は省略していますが、運用する際は以下の設定もやっておくと良いでしょう。

  • Cloud DNS を使ってドメインを設定する
  • 静的 IP を取得してロードバランサーのフロントエンドに設定する
  • SSL/TLS 通信の設定

6. まとめ

Adjust のデータを Cloud Functions に送信して Cloud Logging へ流すための設計をまとめました。
簡易的に作るだけであれば Cloud Functions を使うだけで良いですが、実戦運用する際には IP 制限や負荷分散を考慮する必要があるので、 Cloud Load Balancing や Cloud Armor を併用する設計が良いと思います。