ノート:

通知イベントでOracle Cloud Infrastructureカスタム関数を起動し、更新されたメッセージをLarkコラボレーション・ツールに公開

イントロダクション

Oracle Cloud Infrastructure (OCI)のお客様は、インスタンス・イベント、アラーム、コンソールのお知らせなどのイベントを含む、サブスクライブされたOCI通知トピックを通じて通知を受信します。これらのサブスクライブされたトピックでは、通知ターゲットとしてOCI関数もサポートされており、通知イベント中にカスタム関数を起動し、API起動をサポートする通信チャネルに更新された通知詳細を送信できます。このチュートリアルでは、これらの更新された通知をメッセージングAPIを使用するエンタープライズ・コラボレーション・プラットフォームであるLarkに転送する方法を説明します。

カスタムOCIファンクションを使用すると、様々なデータを取得してアクションを実行できます。次に、次のような例をいくつか示します:

このチュートリアルでは、STOPなど、インスタンスの電源イベントに応じてカスタムOCIファンクションをトリガーする方法を包括的に説明します。ユーザーは、サブスクライブされた様々なOCI通知トピックに基づいて、この機能を柔軟にカスタマイズしてトリガーできます。OCIファンクションの詳細は、OCIファンクションの概要を参照してください。

目標

OCIファンクションでは、OCI通知、OCIアナウンスメントのサブスクライブされた通知トピック、コンピュート・インスタンスのイベントなどに基づいて起動できるカスタム・コードを記述できます。このチュートリアルでは、通知イベントに基づいて起動されるPythonコードで記述されたカスタム関数を作成し、コード内のWebフックURLを使用して更新されたメッセージをLarkコラボレーション・ツールに公開しました。これにより、エンド・ユーザーが使用できる必要な追加情報を含めるおよび更新できます。

前提条件

対象読者

このチュートリアルは、Cloud Serviceプロバイダの管理者および専門家を対象としています。

アーキテクチャ

次に、サンプル・ユース・ケース・トポロジおよびソリューションの高レベル・アーキテクチャを示します。

OCI Azure Interconnect Cross Region Connectivity Architecture

カスタムOCIファンクションを作成し、通知イベントに基づいて起動する場合は、このアーキテクチャを参照できます。このチュートリアルで説明する一連のタスクに従って、このアーキテクチャを設定および検証できます。

タスク1: 動的グループの作成

動的グループを使用すると、OCIコンピュート・インスタンスを(ユーザー・グループと同様に)プリンシパル・アクターとしてグループ化できます。

ノート:動的グループを作成するには、管理者権限が必要です。

  1. OCIコンソール・テナンシ・アカウントにサインインします。

  2. 「サービス」メニューから「アイデンティティとセキュリティ」を選択し、「アイデンティティ」セクションから「動的グループ」を選択します。

  3. 「動的グループの作成」をクリックします。

  4. 意味のある「名前」および「説明」を入力します。

  5. 「ルール1」セクションで、次の行を追加します。

    ALL {resource.type = 'fnfunc', resource.compartment.id = 'ocid1.compartment.oc1', instance.compartment.id = 'ocid1.compartment.XXXXX'}

    ノート:

    • コンパートメントIDを目的のコンパートメントIDに置き換えます。
    • 動的グループに特定のファンクション・リソースOCIDを含めることもできます。
  6. 「作成」をクリックすると、次のイメージに示すように、動的グループが正常に作成されます。

    作成された動的グループ

タスク2: 動的グループOCI IAMポリシーの作成

Oracle Cloud Infrastructure Identity and Access Management (OCI IAM)を使用すると、クラウド・リソースにアクセスできるユーザーを制御できます。このアーキテクチャが機能するには、コンピュート、ネットワークおよびその他の複数のサービスに、Function as a Service faasへのアクセス権を付与する必要があります。

  1. 「サービス」メニューから「アイデンティティとセキュリティ」を選択し、「アイデンティティ」セクションから「ポリシー」を選択します。

  2. 「ポリシーの作成」をクリックします。

  3. 適切な「名前」および「説明」を入力し、必ず正しいコンパートメントを選択してください(この例では、コンパートメント名oc-demoを使用します)。

  4. 「ポリシー・ビルダー」セクションで、「手動エディタの表示」オプションを有効にし、次の行を貼り付けます:

    Allow dynamic-group <dynamic_group_name> to read instances in compartment <compartment_name_path>

    Allow dynamic-group <dynamic_group_name> to read vnics in compartment <compartment_name_path>

    Allow dynamic-group <dynamic_group_name> to read vnic-attachments in compartment <compartment_name_path>

    ノート: dynamic_group_name名とcompartment_name_pathを必要な値に置き換えます。

  5. 「作成」をクリックすると、次のイメージに示すように、ポリシーがroot/yourコンパートメント・レベルで正常に作成されます。

    作成されたIAMポリシー

タスク3: カスタム機能イメージを格納するリポジトリの作成

コンテナ・レジストリを使用すると、コンテナ・イメージ(Dockerイメージなど)をOracle管理レジストリ内に格納し、共有および管理できます。

  1. コンソールで、サービス・メニューを開き、「開発者サービス」をクリックします。「コンテナ」で、「コンテナ・レジストリ」をクリックします。

  2. 「リポジトリの作成」をクリックします。

  3. 「リポジトリの作成」ダイアログ・ボックスで、任意の「コンパートメント」および「リポジトリ名」を指定し、「プライベート」のままにします。

  4. 「リポジトリの作成」をクリックすると、次のイメージに示すように、指定したコンパートメントにコンテナ・レジストリが正常に作成されます。

    コンテナ・レジストリ・リポジトリが作成されました

タスク4: ファンクションアプリケーションを格納するサブネットを含むVirtual Cloudネットワークの作成。

仮想クラウド・ネットワーク(VCN)は、OCIに定義するネットワークです。サブネット、ルート表およびゲートウェイが含まれます。

ノート: すでにVCNが作成されている場合は、このタスクをスキップしてタスク5に進むことができます。

  1. OCI Webコンソールの左上隅にある「サービス」メニューをクリックします。

  2. 「ネットワーキング」で、「Virtual Cloud Networks」を選択します。

  3. 「Virtual Cloud Networks」ページで、「Start VCN Wizard」をクリックします。

  4. 「インターネット接続性を持つVCNの作成」を選択し、「VCNウィザードの起動」をクリックします。

  5. VCN構成を完了し、「Next」をクリックします

  6. 「作成」をクリックすると、次のイメージに示すように、サブネットを含む仮想クラウド・ネットワークが正常に作成されます。

    サブネットを使用した仮想ネットワークの作成

タスク5: ファンクションを格納するアプリケーションの作成

  1. サービス・メニューを開き、「開発者サービス」をクリックします。「ファンクション」で、「アプリケーション」をクリックします。

  2. 「アプリケーションの作成」をクリックします。

  3. 「アプリケーションの作成」ウィンドウで、アプリケーションの「名前」(たとえば、function-app)を選択し、タスク4で作成したVCNを選択して、パブリック・サブネットを選択します。

  4. 「作成」をクリックすると、次のイメージに示すように、ファンクション・アプリケーションが正常に作成されます。

    作成されたファンクション・アプリケーション

タスク6: ファンクションを格納するファンクションのデプロイ

このステップでは、このチュートリアルの前提条件セクションからダウンロードできるzipアーカイブを使用します。

  1. OCIクラウド・コンソールに移動し、「開発者ツール」「クラウド・シェル」をクリックします。

    クラウド・シェルの起動

  2. 「Cloud Shellの起動」ボタンをクリックすると、新しい小さいシェル・ウィンドウがページの最後に表示されます。そのウィンドウの右上隅で、歯車のメニューをクリックし、「アップロード」を選択します。

    ZIPファイルのアップロード

  3. このチュートリアルの前提条件セクションにあるzipファイルをアップロードし、コピーしたディレクトリに移動します。

  4. 通知JSONを読み取ってIPアドレス詳細などのフィールドを追加し、更新されたメッセージを使用してLark WebフックURLにメッセージを送信できるように、作成した次のfunc.pyファイルが表示されます。

    • parse_message: ファンクション読取り通知JSONおよび更新メッセージ
    • get_ip_address: コンピュート、ネットワーク・クライアント・ライブラリを使用して、インスタンスのリソースOCIDに基づくIPアドレスなどの追加の詳細を読み取るファンクション。
    • make_post: WebフックURLを使用してLarkチャネルに投稿する機能。

    ノート:

    • OCI python sdkを使用していますが、go/java sdksを使用して、サポートされている他の言語に基づいてカスタマイズできます。
    • WebフックURLは、Larkまたはその他のSlackなどのコラボレーション・ツールのいずれかを更新する必要があります。
    • この機能は、要件に基づいてカスタマイズできます。特定の通知JSONペイロードを使用して値を読み取っていますが、コンソールのお知らせJSONやその他のイベントJSONも使用できます。
    ###
    This is a sample code,
    End user can modify as needed
    ###
    import io
    import oci
    import json
    import logging
    import requests
    
    """
    Read Notification Message
    Add IP address of Resource.
    """
    def parse_message(body):
        notification = ""
        ocid = ""
        type = body["source"]
        description = body["eventType"]
        compartment_id = body["data"]["compartmentId"]
        compartment_name = body["data"]["compartmentName"]
        affected_resources = ""
    
        if len(body["data"]) > 0:
            signer = oci.auth.signers.get_resource_principals_signer()
            affected_resources = "Affected Resources: "
            ocid = body["data"]["resourceId"]
            notification_reason = body["data"]["additionalDetails"]["instanceActionType"]
            affected_resources += "\nResource OCID: " + ocid
            resource_ip_address = get_ip_address(signer, ocid)
            affected_resources += "\nResource Private IP Address: " + resource_ip_address
    
        notification = type + " " + "\n\n" + compartment_name + " - " + compartment_id + "\n\n" + description + "\n\n" + affected_resources + "\n\n" + notification_reason
        logging.getLogger().debug(notification)
    
        make_post(notification)
    
    """
    Get Resource IP address
    based of resource OCID.
    """
    def get_ip_address(signer, resource_id):
        compute_client = oci.core.ComputeClient(config={}, signer=signer)
        network_client = oci.core.VirtualNetworkClient(config={}, signer=signer)
        instance_details = compute_client.get_instance(instance_id=resource_id).data
        vnic_response = compute_client.list_vnic_attachments(compartment_id=instance_details.compartment_id, instance_id=resource_id)
        vnics = vnic_response.data
    
        for vnic in vnics:
            vnic_details = network_client.get_vnic(vnic_id=vnic.vnic_id).data
            private_ip = vnic_details.private_ip
            return private_ip
    
    """
    Post a Message to Lark.
    You can also use OCI Vault/Secret to store Lark credentials and access them here.
    """
    def make_post(post_text):
        url = "https://open.larksuite.com/open-apis/bot/v2/hook/XXXX"
        headers = {
            "Content-Type": "application/json"
        }
        req_body = {
            "msg_type": "text",
            "content": {
                "text": post_text
            }
        }
        payload = json.dumps(req_body)
        try:
            post_response=requests.post(url=url, data=payload, headers=headers)
        except Exception as e:
            logging.getLogger().error(e)
            return
    
        response_dict = json.loads(post_response.text)
        code = response_dict.get("StatusCode", -1)
    
        if code != 0:
            logging.getLogger().error("error sending post text, code: " + str(code))
        return
    
    def to_bool(a):
        return True if a == "True" else False
    
    """This is the function entry point.
    ctx will contain function variables defined in OCI console,
    data contains the payload
    """
    def handler(ctx, data: io.BytesIO = None):
        try:
            cfg = dict(ctx.Config())
            for a in cfg:
                cfg[a]=to_bool(cfg[a])
    
        except Exception as e:
            print('ERROR: Missing configuration keys', e, flush=True)
            logging.getLogger().debug(cfg)
            return 'error parsing config keys: ' + str(ex)
    
        try:
            raw_body = data.getvalue()
            body = json.loads(raw_body)
            logging.getLogger().info(body)
            parse_message(body)
        except (Exception, ValueError) as ex:
            logging.getLogger().error('error parsing json payload: ' + str(ex))
            return 'error parsing json payload: ' + str(ex)
    
  5. fn deployコマンドを使用してファンクションをデプロイし、クラウド・シェルでファンクションdockerイメージおよび関連する依存関係を構築します。イメージを指定したDockerレジストリにプッシュし、前に作成したアプリケーションのOCI Functionsにファンクションをデプロイできます。

    fn -v deploy --app <app-name>
    

    たとえば:

    fn -v deploy --app function-app
    

    ノート: func.yamlファイルを参照できます。docker関数に必要な詳細を参照してください。

  6. デプロイすると、次のイメージに示すように、ファンクションが正常に作成されます。

    作成された関数

タスク7: トピックへのファンクションのサブスクライブ

  1. サービス・メニューを開き、「開発者サービス」をクリックします。「アプリケーション統合」で、「通知」をクリックします。必ず正しいコンパートメントに配置してください。

  2. 「トピックの作成」をクリックします。

  3. 適切な名前を設定して、「作成」をクリックします。

  4. トピックの作成後、トピックのリストからトピックを選択します。

  5. 「トピック」ウィンドウで、左側の「リソース」の下にある「サブスクリプション」を選択し、「サブスクリプションの作成」をクリックします。

  6. 「サブスクリプションの作成」サイド・ウィンドウで、「ファンクション」にするプロトコルを選択し、コンパートメント、アプリケーションおよびタスク6で作成されたファンクションを選択します。

  7. 次のイメージに示すように、「作成」をクリックします。ファンクションはトピックに正常にサブスクライブされます。

    作成済通知サブスクリプション

タスク8: インスタンスおよび通知イベント・ルールの作成

このステップのファンクションを検証するには、タスク7instance-stoppedなどのイベントに対するインスタンスおよび関連する通知の作成トピックを作成します。

  1. コンソール内で、「コンピュート」「インスタンス」にナビゲートしてコンピュート・インスタンスを作成します。

  2. 「インスタンスの作成」アイコンをクリックし、必要な詳細を指定します:

    • インスタンス名
    • インスタンスのコンパートメント
    • 目的のADの選択
    • ネットワークVCNおよびパブリック・サブネットの選択
    • 公開SSHキーのコピー・ペースト
    • 「作成」をクリックします。
  3. インスタンスで実行中が表示されるのを待機してから、次のコマンドを使用してインスタンスにログインします。

    ssh opc@<public ip> -i <private key>
    
  4. 通知イベントを作成するには、「コンピュート」「インスタンス」「インスタンスの詳細」「通知」ウィンドウにナビゲートします。

  5. 「通知の作成」をクリックし、「インスタンス・ステータスを停止に変更」などのQuickStartテンプレートを選択します。

  6. イベント・ルールの「名前」を入力し、タスク7から作成済トピックを選択して、「通知の作成」をクリックします。次のイメージに示すように、通知イベント・ルールはサブスクライブ済トピックに正常に作成する必要があります。

    作成済イベント・ルール

タスク9: 通知イベント・ルールの検証

このステップでは、関連付けられた通知トピックをトリガーするインスタンスを停止します。通知ペイロードを表示する電子メール・アドレスを含めることもできます。

  1. 作成したインスタンスに移動し、「停止」をクリックします。

  2. インスタンスが停止したら、サブスクライブされた通知トピックを通じて電子メールを受信し、ファンクションをトリガーする必要があります。

  3. 次のイメージに示すように、電子メールを受信したことを確認します。

    OCI通知トピックEメール

  4. WebフックURLを含めるために使用したLarkチャネルに移動します。

    Lark通知投稿

    ノート:この更新メッセージが受信した電子メールから慎重に表示された場合は、カスタム関数に基づいて、OCI sdkを使用してインスタンスのIPアドレスを含めました。

  5. [オプション]コンソールのお知らせの詳細に従って、この通知トピックを更新機能の詳細に関連付けることもできます。これらのドキュメントに従って、詳細を確認することができます。

    ノート:カスタム関数コードを変更して、正しいJSONペイロードを読み取っていることを確認し、適宜変更する必要があります。サービス・チームから受信したサンプルお知らせJSONペイロードを使用できます。

    OCIのお知らせ通知サブスクリプション

次のステップ

このチュートリアルでは、カスタマイズされた関数を使用して通知JSONペイロードを読み取り、OCI SDKライブラリを使用してそのペイロードを更新し、メッセージをLarkなどの共通コラボレーション・ツールに公開する方法をエンド・ユーザーに示します。この機能を展開して、「リソース・タグ」、「ネットワーク詳細」などの詳細を追加できます。

承認

その他の学習リソース

docs.oracle.com/learnで他のラボをご覧いただくか、Oracle Learning YouTubeチャネルでより無料のラーニング・コンテンツにアクセスしてください。また、education.oracle.com/learning-explorerにアクセスして、Oracle Learning Explorerになります。

製品ドキュメントについては、Oracle Help Centerを参照してください。