FogFlow

https://nexus.lab.fiware.org/repository/raw/public/badges/chapters/processing.svg
https://nexus.lab.fiware.org/repository/raw/public/badges/stackoverflow/fiware.svg

FogFlowは、次のようなさまざまなコンテキスト (context) に基づいて、クラウドとエッジ上の動的データ処理フローを自動的に調整する IoT edge computing framework です:

  • system context: すべてのレイヤーから利用可能なシステム リソース;
  • data context: 利用可能なすべてのデータエンティティの登録済みメタデータ;
  • usage context: QoS、遅延、および帯域幅コストの観点からユーザーが定義した予想される使用意図 (usage intention)

高度なインテント ベースのプログラミング モデル (intent-based programming) とコンテキスト駆動型のサービス オーケストレーションのおかげで、FogFlow は、最小限の開発労力とほぼゼロの運用オーバーヘッドで最適化された QoS を提供できます。現在、FogFlow は、小売、スマートシティ、スマートインダストリーの分野でさまざまなビジネス ユースケースに適用されています。

今日、スマートシティ、スマートインダストリー、およびコネクテッドカー向けの IoT インフラストラクチャ プロバイダーは、 さまざまな IoT サービス、特に低遅延を必要とするサービスをサポートするための地理分散インフラストラクチャを管理するために、 多くの複雑さと高い運用コストに直面しています。FogFlow は、クラウドとエッジ上で IoT サービスを動的に調整する分散実行 フレームワークであり、内部帯域幅の消費を削減し、低遅延と高速応答時間を提供します。

FogFlow は、高いスケーラビリティと信頼性を備えた自動化および最適化された IoT サービス オーケストレーションを提供する ことにより、インフラストラクチャ プロバイダーが運用コストを大幅に削減するのを支援します。FogFlow は、サービス開発者と システム インテグレーターが、開発コストを抑えて市場投入までの時間を短縮して IoT サービスを迅速に実現するためのインテント ベースのプログラミング モデル (Intent-based programming model) と開発ツールも提供します。

FogFlow システムの全体的なアーキテクチャ ビューを下の図に示します。インフラストラクチャ リソースは、クラウド、 エッジ ノード、センサー デバイス、およびアクチュエーターとして垂直に分割されます。データ分析などの計算集約型タスクは クラウド サーバーで実行できますが、ストリーム処理などの一部のタスクはエッジ ノード (IoT ゲートウェイや計算機能を備えた エンドポイント デバイスなど) に効果的に移動できます。センサーは、(さまざまなセンサー デバイスによって観測された) 観測データをエッジ ノードに存在するブローカーと共有し、エッジ ノードはロジックに基づいてこのデータを計算し、 アクチュエーターに応答を送信します。

_images/fogflow-overall-view.png

モチベーション

FogFlow は IoT エッジ コンピューティング フレームワークであり、次の懸念に対処するように設計されています:

  • クラウドのみのソリューションのコストは高すぎて、1000を超える地理分散デバイスで大規模なIoTシステムを実行できません。
  • 多くの IoT サービスでは、エンド ツー エンドのレイテンシが10ミリ秒未満などの高速な応答時間が必要です。
  • サービス プロバイダーは、クラウド エッジ環境で IoT サービスを迅速に設計および展開するために、非常に複雑でコストに直面しています。ビジネス需要は時間とともに急速に変化しており、サービス プロバイダーは、共有クラウド エッジ インフラストラクチャ上で新しいサービスを速いスピードで試してリリースする必要があります。
  • 地理的に分散した ICT インフラストラクチャ上で IoT サービスを迅速に設計および展開するためのプログラミング モデルの欠如。
  • さまざまなアプリケーション間でデータと派生した結果を共有および再利用するための相互運用性とオープン性の欠如。

FogFlow を使用すると、サービス プロバイダーは、最小限の開発労力で IoT サービスを簡単にプログラムでき、また、市場投入までの時間を短縮して新しい IoT サービスをリリースできます。一方、IoT プラットフォームのオペレーターにとって、FogFlow は、低運用コストと最適化された QoS を使用して、クラウドとエッジ上で遅延の影響を受けやすいIoT サービスをシームレスにサーバー化するのに役立ちます。

ハイレベル ビュー

FogFlow の独自の機能はコンテキスト駆動型 (context-driven) です。つまり、FogFlow は、次の3種類のコンテキストに基づいて、クラウドとエッジ上で動的なデータ処理フローを調整できます。

  • System context: 時間の経過とともに変化する利用可能なリソース
    クラウド エッジ環境のリソースは本質的に地理的に分散しており、時間の経過とともに動的に変化します。 クラウドコンピューティングと比較して、このようなクラウド エッジ環境のリソースはより 異質動的 です。
  • Data context: 生のセンサーデータと中間データの両方を含む、利用可能なデータの構造と登録されたメタデータ
    標準化され統合されたデータモデルと通信インターフェイス、 つまり NGSI に基づいて、FogFlow は、データタイプ、属性、登録されたメタデータ、リレーション、および地理的位置など、 システム内のセンサーおよびデータ処理タスクによって生成されたすべてのデータのコンテンツを表示できます。
  • Usage context: すべての異なるタイプのユーザー (開発者、サービス コンシューマー、データ プロバイダー) によって定義され、達成したいことを指定する高レベルのインテント (high level intents)
    たとえば、サービス コンシューマーの場合、どのジオスコープ内のどのタイプの QoS でどのタイプの結果が期待されるかを 指定できます。データ プロバイダーの場合、データを誰がどのように利用するかを指定できます。FogFlow では、実行時に ユーザーが定義できる目標を達成するために、オーケストレーションの決定が行われます。これらの新機能を有効にするために、 より高度なアルゴリズムに取り組んでいます。

これらの3種類のコンテキストを活用することで、FogFlow はよりインテリジェントで自動的な方法で IoT サービスを調整できます。

_images/highlevelview.png

技術的メリット

次の図に示すように、FogFlow は、IoT サービスプロバイダーに標準ベースのデータ中心のエッジプログラミング モデルを提供し、 さまざまなビジネス需要に対応するサービスを簡単かつ迅速に実現します。FogFlow は、データ駆動型で最適化されたサービス オーケストレーション メカニズムにより、インフラストラクチャ プロバイダーが都市規模の IoT サービスの数千のクラウド ノードと エッジ ノードを自動的かつ効率的に管理して、最適化されたパフォーマンスを実現できるようにします。したがって、スマートシティや スマートファクトリーなどの大規模な IoT プロジェクトでは、FogFlow は開発と運用のコストを節約し、生産性を向上させ、 市場投入までの時間を短縮し、スケーラビリティと信頼性を向上させることができます。

_images/benefit.png

差別化

EdgeX、Azure IoT Edge、Amazon Greengrass などの他の既存の IoT エッジ コンピューティング フレームワークと比較して。 FogFlow には、次の図に示す次の固有の機能があります

  • FogFlow のサービス オーケストレーションは、生のイベントやトピックではなく、コンテキストによって駆動されます。
    この機能は、すべてのブローカーで利用可能なエンティティ データの更新の概要を提供する新しいレイヤー、つまり IoT Discovery を導入する設計によって実現されます。イベントまたはトピックベースのオーケストレーションと比較して、 FogFlow のコンテキスト ベースのオーケストレーションはより柔軟で軽量です。これは、FogFlow のオーケストレーションの 決定が、関連するすべてのデータ ストリームを読み取ることなく、集約されたコンテキストに基づいて行うことができるため です。一方、FogFlow は、ユーザーが定義した高レベルの意図を考慮して、QoS を向上させるために最適化された オーケストレーションの決定を行います。
  • FogFlow サービスとアプリケーションは、個々のエッジ ノードの観点からではなく、すべてのクラウド ノードとエッジ ノードのグローバルビューに対して設計されています。
    この設計原則により、必要な開発作業と管理オーバーヘッドを大幅に簡素化できます。特に、FogFlow は、クラウドとエッジ間、 または異なるエッジ ノード間のタスク調整方法の詳細を知らなくても、すべてのクラウド ノードとエッジ ノード間でシームレスに 実行できる分散アプリケーションをサポートできます。実行されます。ただし、他のほとんどの IoT エッジ コンピューティング フレームワークでは、サービスまたはアプリケーションはエッジごとに設計されており、実際には分散サービスまたは アプリケーションではありません。これらのサービスまたはアプリケーションはクラウドまたは一部のエッジで実行できますが、 分散ファションのクラウド ノードとエッジ ノード上で実行することはできません。
_images/comparison1.png

より詳細な区別は、次の表にまとめられています。

_images/comparison2.png

これは、FogFlow の1ページの入門チュートリアルです。FIWARE ベースのアーキテクチャでは、FogFlow を使用して、エッジ ノード (IoT ゲートウェイや Raspberry Pi など)で生データを変換および前処理する目的で、IoT デバイスとOrion Context Broker の間でデータ処理機能を動的にトリガーできます。

チュートリアルでは、温度センサー データのエッジで異常検出を行う簡単な例を使用して、一般的な FogFlow システムのセット アップを紹介します。FogFlow と Orion Context Broker を相互に統合して使用するユースケース実装の例について説明します。

ユースケースを実装するたびに、FogFlow は、オペレーター、Docker イメージ、フォグ ファンクション 、サービス トポロジーなどの内部 NGSI エンティティを作成します。したがって、これらのエンティティ データは FogFlow システムにとって非常に重要であり、どこかに保存する必要があります。メモリは揮発性であり、電源が失われるとコンテンツが失われるため、エンティティ データを FogFlow メモリに保存することはできません。この問題を解決するために、FogFlow は Dgraph に永続ストレージを導入します。永続ストレージは、FogFlow エンティティ データをグラフの形式で保存します。

次の図に示すように、このユースケースでは、接続された温度センサーが更新メッセージを FogFlow システムに送信します。これにより、事前定義されたフォグ ファンクションの実行中のタスク インスタンスがトリガーされ、分析結果が生成されます。フォグ ファンクションは、FogFlow ダッシュボードで事前に指定されていますが、温度センサーがシステムに接続された場合にのみトリガーされます。実際の分散セットアップでは、実行中のタスク インスタンスは、温度センサーに近いエッジ ノードにデプロイされます。生成された分析結果が生成されると、FogFlow システムから Orion Context Broker に転送されます。これは、参照 URL として Orion Context Broker を使用したサブスクリプションが発行されたためです。

_images/systemview.png

FogFlow を実行するための前提条件のコマンドは次のとおりです:

  1. docker
  2. docker-compose

Ubuntu 16.04 の場合、docker-ce と docker-compose をインストールする必要があります。

Docker CE をインストールするには、Install Docker CE を参照してください。必要なバージョン > 18.03.1-ce です。

重要

また、ユーザーが sudo なしで Docker コマンドを実行できるようにしてください

Docker Compose をインストールするには、Install Docker Compose を参照してください。必要なバージョン> 2.4.2 です。

1台のマシンですべてのFogFlowコンポーネントをセットアップ

必要なすべてのスクリプトを取得

以下のように docker-compose ファイルと構成ファイルをダウンロードします。

# the docker-compose file to start all FogFlow components on the cloud node
wget https://raw.githubusercontent.com/smartfog/fogflow/master/release/3.2/cloud/docker-compose.yml

# the configuration file used by all FogFlow components
wget https://raw.githubusercontent.com/smartfog/fogflow/master/release/3.2/cloud/config.json

# the configuration file used by the nginx proxy
wget https://raw.githubusercontent.com/smartfog/fogflow/master/release/3.2/cloud/nginx.conf

IP構成を変更

ご使用の環境に応じて、config.json で以下の IP アドレスを変更する必要があります。

  • my_hostip:これはホストマシンの IP であり、ホストマシンの Web ブラウザと Docker コンテナの両方からアクセスできる必要があります。これには "127.0.0.1" を使用しないでください。
  • site_id: 各 FogFlow ノード (クラウド ノードまたはエッジ ノード) は、システム内で自身を識別するために一意の文字列ベースの ID を持っている必要があります。
  • physical_location: FogFlow ノードの地理的位置。
  • worker.capacity: FogFlow ノードが呼び出すことができる Docker コンテナーの最大数を意味します。

重要

"127.0.0.1" を my_hostip の IP アドレスとして使用しないでください。これは、Docker コンテナ内で実行中のタスクにのみアクセスできるためです。

Firewall rules: FogFlow Web ポータルにアクセスできるようにするには、TCP を介した次のポート 80 および 5672 が開いている必要があります。

Mac Users: Macbook で FogFlow をテストする場合は、Docker デスクトップをインストールし、構成ファイルの my_hostip として "host.docker.internal" も使用してください。

ポート番号を変更する必要がある場合は、変更がこれら3つの構成ファイルすべてで一貫していることを確認してください。

すべての FogFlow コンポーネントを起動

すべての FogFlow コンポーネントの Docker イメージをプルし、FogFlow システムを起動します。

#if you already download the docker images of FogFlow components, this command can fetch the updated images
docker-compose pull

docker-compose up -d

セットアップを検証

FogFlow クラウド ノードが正しく開始されているかどうかを確認するには、次の2つの方法があります:

  • "docker ps -a" を使用して、すべてのコンテナーが稼働していることを確認します。
docker ps -a

CONTAINER ID      IMAGE                       COMMAND                  CREATED             STATUS              PORTS                                                 NAMES
795e6afe2857   nginx:latest            "/docker-entrypoint.…"   About a minute ago   Up About a minute   0.0.0.0:80->80/tcp                                                                               fogflow_nginx_1
33aa34869968   fogflow/worker:3.2      "/worker"                About a minute ago   Up About a minute                                                                                                    fogflow_cloud_worker_1
e4055b5cdfe5   fogflow/master:3.2      "/master"                About a minute ago   Up About a minute   0.0.0.0:1060->1060/tcp                                                                           fogflow_master_1
cdf8d4068959   fogflow/designer:3.2    "node main.js"           About a minute ago   Up About a minute   0.0.0.0:1030->1030/tcp, 0.0.0.0:8080->8080/tcp                                                   fogflow_designer_1
56daf7f078a1   fogflow/broker:3.2      "/broker"                About a minute ago   Up About a minute   0.0.0.0:8070->8070/tcp                                                                           fogflow_cloud_broker_1
51901ce6ee5f   fogflow/discovery:3.2   "/discovery"             About a minute ago   Up About a minute   0.0.0.0:8090->8090/tcp                                                                           fogflow_discovery_1
51eff4975621   dgraph/standalone       "/run.sh"                About a minute ago   Up About a minute   0.0.0.0:6080->6080/tcp, 0.0.0.0:8000->8000/tcp, 0.0.0.0:8082->8080/tcp, 0.0.0.0:9082->9080/tcp   fogflow_dgraph_1
eb31cd255fde   rabbitmq:3              "docker-entrypoint.s…"   About a minute ago   Up About a minute   4369/tcp, 5671/tcp, 15691-15692/tcp, 25672/tcp, 0.0.0.0:5672->5672/tcp                           fogflow_rabbitmq_1

重要

不足しているコンテナーがある場合は、"docker ps -a" を実行して、FogFlow コンポーネントが何らかの問題で終了していないかどうかを確認できます。ある場合は、"docker logs [container ID]" を実行して、出力ログをさらに確認できます。

  • FogFlow DashBoard からシステム ステータスを確認します。

Web ブラウザで FogFlow ダッシュボードを開くと、次の URL を介して現在のシステム ステータスを確認できます: http://<coreservice_ip>/index.html

i FogFlow クラウド ノードがゲートウェイの背後にある場合は、ゲートウェイ IP から coreservice_ip へのマッピングを作成してから、ゲートウェイ IP を介して FogFlow ダッシュボードにアクセスする必要があります。
FogFlow クラウド ノードが AzureCloud、Google Cloud、Amazon Cloud などのパブリッククラウド内の VM である場合は、VM のパブリック IP を介して FogFlow ダッシュボードにアクセスする必要があります。

FogFlow ダッシュボードにアクセスできるようになると、次の Web ページが表示されます:

_images/dashboard.png

既存の IoT サービスを試す

FogFlow クラウド ノードがセットアップされると、FogFlow エッジ ノードを実行せずに既存の IoT サービスを試すことができます。たとえば、次のような簡単なフォグ ファンクションを試すことができます。

3回のクリックですべての定義済みサービスを初期化

  • 上部のナビゲーター バーにある "Operator Registry" をクリックして、事前定義されたオペレーターの初期化をトリガーします。

最初に "Operator Registry" をクリックすると、事前定義されたオペレーターのリストが FogFlow システムに登録されます。2回クリックすると、次の図に示すように、更新されたリストが表示されます。

_images/operator-list.png
  • 上部のナビゲーター バーで "Service Topology" をクリックして、事前定義されたサービス トポロジーの初期化をトリガーします。

最初に "Service Topology" をクリックすると、事前定義されたトポロジーのリストが FogFlow システムに登録されます。2回クリックすると、次の図に示すように、更新されたリストが表示されます。

_images/topology-list.png
  • 上部のナビゲーターバーの "Fog Function" をクリックして、事前定義されたフォグ ファンクションの初期化をトリガーします。

最初に "Fog Function" をクリックすると、事前定義されたファンクションのリストが FogFlow システムに登録されます。2回クリックすると、次の図に示すように、更新されたリストが表示されます。

_images/function-list.png

IoT デバイスをシミュレートしてフォグ ファンクションをトリガー

フォグファンクションをトリガーする方法は2つあります:

1. FogFlow ダッシュボードを介して “Temperature” センサーエンティティを作成

デバイス登録ページからデバイス エンティティを登録できます: "System Status" -> "Device" -> "Add"。次に、次の要素を入力して "Temperature" センサー エンティティを作成できます:

  • Device ID: 一意のエンティティIDを指定します。
  • Device Type: エンティティ タイプとして “Temperature” を使用します。
  • Location: マップ上の場所 (location) を選択します。
_images/device-registration.png

2. NGSI エンティティの更新を送信して、“Temperature” センサーエンティティを作成

エンティティの更新のために FogFlow Broker に curl リクエストを送信します:

curl -iX POST \
          'http://my_hostip/ngsi10/updateContext' \
          -H 'Content-Type: application/json' \
          -d '
        {
            "contextElements": [
                {
                    "entityId": {
                        "id": "Device.Temp001",
                        "type": "Temperature",
                        "isPattern": false
                        },
                    "attributes": [
                            {
                            "name": "temperature",
                            "type": "float",
                            "value": 73
                            },
                            {
                            "name": "pressure",
                            "type": "float",
                            "value": 44
                            }
                        ],
                    "domainMetadata": [
                            {
                            "name": "location",
                            "type": "point",
                            "value": {
                            "latitude": -33.1,
                            "longitude": -1.1
                            }}
                        ]
                }
            ],
            "updateAction": "UPDATE"
        }'

フォグ ファンクションがトリガーされているかどうかを確認

システム管理 (System Management) の "Task" の下にタスクが作成されているかどうかを確認します。

_images/fog-function-task-running.png

システム管理の "Stream" の下にストリームが作成されているかどうかを確認します。

_images/fog-function-streams.png

ドキュメントのこの部分では、FogFlow の概念的な概要と、インスタンスの開発で FogFlow を使用する方法について説明します。 FogFlow は、動的な NGSI ベース (Next Generation Service Interface - based) のデータ処理フローをプロデューサーと コンシューマーの間でオンデマンドで調整し、タイムリーな結果を提供して迅速なアクションを実行するためのクラウドおよびエッジ 環境です。コンテキスト プロデューサーはセンサー ベースのデバイスですが、コンシューマーは何らかのアクションを実行する コマンドを受信するアクチュエータ デバイスです。

FogFlow は、分散型で自律的な方法で IoT サービス オーケストレーションの決定を実行できます。つまり、各 FogFlow エッジ ノードは、ローカル コンテキスト ビューに基づいてのみ独自の決定を行うことができます。このようにして、ワークロードの 大部分は、常に中央のクラウドに依存することなく、エッジで直接処理できます。この "cloudless" アプローチにより、FogFlow は高速な応答時間を提供するだけでなく、高いスケーラビリティと信頼性を実現します。

FogFlow ベースのインスタンスを定義してトリガーするには、このドキュメントのインテント ベースのプログラミング モデル (Intent based programming model) の部分を参照してください。

コア コンセプト

オペレーター (Operator)

FogFlow では、オペレーターは、リスニング ポートを介して NGSI10 ノーティファイ メッセージとして特定の入力ストリームを 受信し、受信したデータを処理し、特定の結果を生成し、生成された結果を NGSI10 アップデートとして公開するタイプの データ処理ユニットを提示します。

オペレーターの実装は、少なくとも1つの Docker イメージに関連付けられています。さまざまなハードウェアアーキテクチャ (64ビットまたは32ビットの x86 および ARM など) をサポートするために、同じオペレーターを複数の Docker イメージに 関連付けることができます。

タスク(Task)

タスクは、サービス トポロジー内の論理データ処理ユニットを表すデータ構造です。 各タスクはオペレーターに関連付けられています。タスクは、次のプロパティで定義されます。

  • name: このタスクを表示するための一意の名前。
  • operator: 関連するオペレーターの名前。
  • groupBy: タスク インスタンスの単位を制御するための粒度。サービス オーケストレーターが作成する必要のあるタスク インスタンスの数を決定するために使用されます。
  • input_streams: 選択された入力ストリームのリスト。各入力ストリームはエンティティ タイプによって識別されます。
  • output_streams: 生成された出力ストリームのリスト。各ストリームはエンティティ タイプによって識別されます。

FogFlow では、各入力/出力ストリームは、NGSI コンテキスト エンティティのタイプとして表されます。 これらは通常、エンドポイント デバイスまたはデータ処理タスクのいずれかによって生成および更新されます。

実行時に、groupBy プロパティで定義された粒度に従って、同じタスクに対して複数のタスク インスタンスを作成できます。 どの入力ストリームがどのタスク インスタンスに送られるかを決定するために、タスクの入力ストリームを指定するために 次の2つのプロパティが導入されています。

  • Shuffling: タスクの各タイプの入力ストリームに関連付けられています。その値は、ブロードキャスト (broadcast) またはユニキャスト (unicast) のいずれかです。

    • broadcast: 選択した入力ストリームは、このオペレーターのすべてのタスク インスタンスに繰り返し割り当てられる必要があります
    • unicast: 選択した各入力ストリームは、特定のタスク インスタンスに1回だけ割り当てる必要があります。
  • Scoped: 入力ストリームを選択するために要件のジオスコープを適用する必要があるかどうかを決定します。その値は true または false のいずれかです。

タスク インスタンス (Task Instance)

実行時に、タスクは入力データと指定された出力タイプを使用して FogFlow によって構成され、構成されたタスクは Docker コンテナーで実行されるタスク インスタンスとして起動されます。現在、各タスク インスタンスは、クラウドまたはエッジ ノードのいずれかで専用の Docker コンテナーにデプロイされています。

サービス テンプレート (Service Template)

各 IoT サービスは、サービス テンプレートによって記述されます。サービス テンプレートは、リンクされたオペレーターのセットを備えたサービス トポロジー、または単一のオペレーターを備えたフォグ ファンクションです。たとえば、サービス トポロジーを使用してサービス テンプレートを指定すると、次の情報が含まれます。

  • topology name: トポロジーの一意の名前。
  • service description: このサービスの内容を説明するテキスト。
  • priority: トポロジー内のすべてのタスクの優先度レベルを定義します。これは、リソースをタスクに割り当てる方法を決定するためにエッジ ノードによって使用されます。
  • resource usage: このトポロジーのタスクがエッジ ノードのリソースを排他的に使用できるかどうかを定義します。つまり、他のトポロジーのタスクとリソースを共有しないことを意味します。

現在、FogFlow は、開発者が設計フレーズ中にサービス トポロジーまたはフォグ ファンクションを簡単に定義して注釈を付けることができるグラフィカル エディタを提供しています。

動的データ フロー (Dynamic data flow )

要件を受け取ると、トポロジー マスターはデータ フロー実行グラフを作成し、それらをクラウドとエッジにデプロイします。主な手順は、2つの主要なステップを含む次の図に示されています。

_images/service-topology.png
  • service topology から execution plan に: トポロジー マスターのタスク生成アルゴリズムによって実行されます。
    生成された実行プラン (execution plan) には次のものが含まれます: 1)サービス トポロジー (service topology) のどの部分がトリガーされるか。 2)トリガーされたタスクごとに作成する必要のあるインスタンスの数。 3)および各タスク インスタンスをその入力ストリームと出力ストリームでどのように構成するか。
  • execution plan から deployment plan に: トポロジー マスターのタスク割り当てアルゴリズムによって実行されます。
    生成された展開計画 (deployment plan) は、特定の最適化の目的に従って、どのタスク インスタンスをどのワーカー (クラウド内またはエッジ) に割り当てるかを決定します。現在、FogFlow のタスク割り当ては、エッジ ノードに過負荷をかけることなくノード間のデータ トラフィックを削減するように最適化されています。

FogFlow ストレージ (FogFlow Storage)

以前は、FogFlow はその内部データ構造を使用して、オペレーター、フォグ ファンクション、Docker イメージ、サービス トポロジーなどの FogFlow 内部エンティティを格納していました。FogFlow は、FogFlow 内部 NGSI エンティティを格納するための永続ストレージをサポートしていませんでした。したがって、FogFlow Broker がダウンするたびに、保存されているすべての内部エンティティが失われます。したがって、この問題を解決するために、FogFlow は Dgraph という名前の永続ストレージを使用しています。

永続ストレージは、そのデバイスへの電源が遮断された後もデータを保持するデータ ストレージ デバイスです。不揮発性ストレージと呼ばれることもあります。

Dgraph データモデルは、データセット、レコード、および属性で構成されています。ここで、レコードは Dgraph のデータの基本単位であり、属性はレコードスキーマの基本単位です。属性 (キーと値のペアとも呼ばれます) からの割り当ては、Dgraph のレコードを記述します。永続ストレージを使用したデータのフロー図は次のとおりです:

_images/persistent_data_flow.png
  1. FogFlow のユーザーは、デザイナーを介して Web ブラウザーを使用して FogFlow 内部エンティティーを作成できます。
  2. FogFlow のユーザーは、Designer を介してclient (curl) を使用して FogFlow 内部エンティティを作成できます。
  3. Designer は、必要に応じて、作成されたエンティティを Dgraph データベースに保存して取得できます。
  4. Designer は、Dgraph データベースから古い登録済みエンティティを取得し、Cloud Broker に登録できます。

グラフデータベースをサポートする利用可能なデータベースはたくさんあります。たとえば、Neo4j です。Dgraph はデータベースの使用率が最も高いデータベースの1つです。FogFlow は Dgraph を使用しています。Dgraph を選択した理由は次のとおりです:

  1. Dgraph は、グラフデータの読み込みに関して Neo4j より160倍高速です。
  2. Dgraph は、Neo4j と比較して5分の1のメモリを消費します。
  3. Dgraph は、ジョブ (job) を遂行するために必要なほとんどの機能をサポートしています。

インテント ベースのプログラミング (Intent-Based Programming)

現在、次の2つのプログラミング モデルが FogFlow によって提供されており、さまざまなタイプのワークロード パターンをサポートしています。

  1. Fog Function (フォグ ファンクション)
  2. Service Topology (サービス トポロジー)

フォグ ファンクション (Fog Function)

フォグ ファンクションを定義してトリガー

FogFlow は、サーバーレス エッジ コンピューティングを可能にします。つまり、開発者はいわゆるフォグ ファンクションを定義して送信でき、残りは FogFlow によって自動的に実行されます。

  • 入力データが利用可能になったときに送信されたフォグ ファンクションをトリガーします。
  • 定義された粒度に従って、作成するインスタンスの数を決定します。
  • 作成したインスタンスをデプロイする場所を決定します。

上記のテキストのインスタンスは、その中で処理ロジックを実行するタスク インスタンスを指し、この処理ロジックは FogFlow のオペレーターによって提供されます。事前にユーザー登録が必要です。オペレーターの例の実装については、次のセクションで説明します。

タスク オペレーターの登録

オペレーター コードは、Docker イメージの形式である必要があり、Docker Hub で使用できる必要があります。FogFlow へのオペレーターのレジストレーションは、次の2つの方法のいずれかで行うことができます。

注釈

各オペレーターは一意の名前を持っている必要がありますが、同じオペレーターを複数の Docker イメージに関連付けることができます。各イメージは、1つの特定のハードウェアまたはオペレーティング システム用ですが、同じデータ処理ロジックを実装するためのものです。実行時に、FogFlow は、エッジ ノードの実行環境に基づいて、エッジ ノードでスケジュールされたタスクを実行するための適切な Docker イメージを選択します。

FogFlow Task Designer から登録

FogFlow にオペレーターを登録するには2つのステップがあります。

オペレーターを登録して、 オペレーターの名前と必要な入力パラメーターを定義します。このコンテキストでは、オペレーターはいくつかのパラメーターを持つ名前付き要素に他なりません。次の図は、登録されているすべてのオペレーターとそのパラメーター数のリストを示しています。

_images/operator-list.png

"register" ボタンをクリックすると、下にデザイン エリアが表示され、オペレーターを作成してパラメーターを追加できます。オペレーター アプリケーションのポートを定義するには、"service_port" を使用し、その値として有効なポート番号を指定します。アプリケーションは、このポートを介して外部からアクセスできます。

_images/operator-registry.png

Docker イメージを登録し、オペレーターを選択して、 Docker イメージを定義し、すでに登録されているオペレーターをそれに関連付けます。

次の図は、登録されているすべての Docker イメージのリストと各イメージの重要な情報を示しています。

_images/dockerimage-registry-list.png

"register" ボタンをクリックすると、以下のようなフォームが表示されます。必要事項をご記入の上、"register" ボタンをクリックしてご登録ください。フォームは次のように説明されます。

  • Image: オペレーターの Docker イメージの名前
  • Tag: タグは、オペレーターの Docker イメージを公開するために使用されます。デフォルトでは "latest" です。
  • Hardware Type: x86 または ARM (Raspberry Pi など) を含む、Docker イメージがサポートするハードウェア タイプ。
  • OS Type: Docker イメージがサポートするオペレーティングシステム タイプ。現在、これは Linux のみに限定されています。
  • Operator: オペレーター名。一意である必要があり、サービス トポロジーを定義するときに使用されます。
  • Prefetched: これがチェックされている場合、すべてのエッジ ノードがこの Docker イメージのフェッチを事前に開始することを意味します。それ以外の場合、オペレーターの Docker イメージは、エッジ ノードがこのオペレーターに関連付けられたスケジュールされたタスクを実行する必要がある場合にのみ、オンデマンドでフェッチされます。

重要

Docker イメージの名前は、Docker Hub に公開されている名前と一致している必要があることに注意してください。デフォルトでは、FogFlow は、オペレーター用に Docker Hub に登録されている名前を使用して、必要な Docker イメージをフェッチします。

_images/dockerimage-registry.png

NGSI アップデートを送信してプログラムで登録

構築された NGSI アップデート メッセージの Docker イメージをクラウドにデプロイされた IoT Broker に送信することで、オペレーターを登録することもできます。

オペレーターとそのオペレーターの Docker イメージを登録するための curl と JavaScript ベースのコード例を次に示します。

注釈

JavaScript コード例では、JavaScript ベースのライブラリを使用して FogFlow IoT Broker とやり取りします。これは、ライブラリで GitHub コード リポジトリ (designer/public/lib/ngsi) から見つけることができます。これは、Web ページの ngsiclient.js に含まれている必要があります。

注釈

curl の場合は、Clould IoT Broker がローカルホストのポート 8070 で実行されていることを前提としています。

curl -iX POST \
  'http://localhost:8070/ngsi10/updateContext' \
-H 'Content-Type: application/json' \
-d '
{
        "contextElements": [
        {
                "entityId":{
                        "id":"counter",
                        "type":"Operator"
                },
                "attributes":[
                {
                        "name":"designboard",
                        "type":"object",
                        "value":{
                        }
                },
                {
                        "name":"operator",
                        "type":"object",
                        "value":{
                                "description":"",
                                "name":"counter",
                                "parameters":[

                                ]
                        }
                }
                ],
                "domainMetadata":[
                {
                        "name":"location",
                        "type":"global",
                        "value":"global"
                }
                ]
        },
        {
                   "entityId":{
                          "id":"fogflow/counter.latest",
                          "type":"DockerImage"
                   },
                   "attributes":[
                          {
                                 "name":"image",
                                 "type":"string",
                                 "value":"fogflow/counter"
                          },
                          {
                                 "name":"tag",
                                 "type":"string",
                                 "value":"latest"
                          },
                          {
                                 "name":"hwType",
                                 "type":"string",
                                 "value":"X86"
                          },
                          {
                                 "name":"osType",
                                 "type":"string",
                                 "value":"Linux"
                          },
                          {
                                 "name":"operator",
                                 "type":"string",
                                 "value":"counter"
                          },
                          {
                                 "name":"prefetched",
                                 "type":"boolean",
                                 "value":false
                          }
                   ],
                   "domainMetadata":[
                          {
                                 "name":"operator",
                                 "type":"string",
                                 "value":"counter"
                          },
                          {
                                 "name":"location",
                                 "type":"global",
                                 "value":"global"
                          }
                   ]
                }
        ],
"updateAction": "UPDATE"
}'
name = "counter"

//register a new operator
var newOperatorObject = {};

newOperatorObject.entityId = {
        id : name,
        type: 'Operator',
        isPattern: false
};

newOperatorObject.attributes = [];

newOperatorObject.attributes.designboard = {type: 'object', value: {}};

var operatorValue = {}
operatorValue = {description: "Description here...", name: name, parameters: []};
newOperatorObject.attributes.operator = {type: 'object', value: operatorValue};

newOperatorObject.metadata = [];
newOperatorObject.metadata.location = {type: 'global', value: 'global'};

// assume the config.brokerURL is the IP of cloud IoT Broker
var client = new NGSI10Client(config.brokerURL);
client.updateContext(newOperatorObject).then( function(data) {
        console.log(data);
}).catch( function(error) {
        console.log('failed to register the new Operator object');
});

image = {}

image = {
        name: "fogflow/counter",
        tag: "latest",
        hwType: "X86",
        osType: "Linux",
        operator: "counter",
        prefetched: false
};

newImageObject = {};

newImageObject.entityId = {
        id : image.name + '.' + image.tag,
        type: 'DockerImage',
        isPattern: false
};

newImageObject.attributes = [];
newImageObject.attributes.image = {type: 'string', value: image.name};
newImageObject.attributes.tag = {type: 'string', value: image.tag};
newImageObject.attributes.hwType = {type: 'string', value: image.hwType};
newImageObject.attributes.osType = {type: 'string', value: image.osType};
newImageObject.attributes.operator = {type: 'string', value: image.operator};
newImageObject.attributes.prefetched = {type: 'boolean', value: image.prefetched};

newImageObject.metadata = [];
newImageObject.metadata.operator = {type: 'string', value: image.operator};
newImageObject.metadata.location = {type: 'global', value: 'global'};

client.updateContext(newImageObject).then( function(data) {
        console.log(data);
}).catch( function(error) {
        console.log('failed to register the new Docker Image object');
});

FogFlow ダッシュボードを使用して、パラメーターを持つオペレーターを作成することをお勧めします。ただし、ユーザーが curl を使用したい場合は、上のイメージに示されているパラメーターを使用したオペレーター登録の例について、以下を参照できます。その後、ユーザーはこのオペレーターを使用する Docker イメージを登録できます。

ここでの x 変数と y 変数は、単にデザイナー ボードの座標です。ユーザーが指定しない場合、デフォルトでは、すべての要素ブロックが平面の原点に配置されます。

curl -iX POST \
          'http://localhost:8070/ngsi10/updateContext' \
        -H 'Content-Type: application/json' \
        -d '
        {
                "contextElements": [
                        {
                           "entityId":{
                              "id":"iota",
                              "type":"Operator"
                           },
                           "attributes":[
                              {
                                 "name":"designboard",
                                 "type":"object",
                                 "value":{
                                    "blocks":[
                                       {
                                          "id":1,
                                          "module":null,
                                          "type":"Parameter",
                                          "values":{
                                             "name":"service_port",
                                             "values":[
                                                "4041"
                                             ]
                                          },
                                          "x":-425,
                                          "y":-158
                                       },
                                       {
                                          "id":2,
                                          "module":null,
                                          "type":"Parameter",
                                          "values":{
                                            "name":"service_port",
                                            "values":[
                                                "7896"
                                             ]
                                          },
                                          "x":-393,
                                          "y":-51
                                       },
                                       {
                                          "id":3,
                                          "module":null,
                                          "type":"Operator",
                                          "values":{
                                             "description":"",
                                             "name":"iota"
                                          },
                                          "x":-186,
                                          "y":-69
                                       }
                                    ],
                                    "edges":[
                                       {
                                          "block1":2,
                                          "block2":3,
                                          "connector1":[
                                             "parameter",
                                             "output"
                                          ],
                                          "connector2":[
                                             "parameters",
                                             "input"
                                          ],
                                          "id":1
                                       },
                                       {
                                          "block1":1,
                                          "block2":3,
                                          "connector1":[
                                             "parameter",
                                             "output"
                                          ],
                                          "connector2":[
                                             "parameters",
                                             "input"
                                          ],
                                          "id":2
                                       }
                                    ]
                                 }
                              },
                              {
                                 "name":"operator",
                                 "type":"object",
                                 "value":{
                                    "description":"",
                                    "name":"iota",
                                    "parameters":[
                                       {
                                          "name":"service_port",
                                          "values":[
                                             "7896"
                                          ]
                                       },
                                       {
                                          "name":"service_port",
                                          "values":[
                                             "4041"
                                         ]
                                       }
                                    ]
                                 }
                              }
                           ],
                           "domainMetadata":[
                              {
                                 "name":"location",
                                 "type":"global",
                                 "value":"global"
                              }
                           ]
                        }
                ],
        "updateAction": "UPDATE"
        }'

"Dummy" フォグ ファンクションを定義

次の手順は、FogFlow Task Designer が提供する Web ポータルを使用して、単純な "dummy" フォグ ファンクションを定義およびテストする方法を示しています。"Dummy" オペレーターは、デフォルトですでに FogFlow に登録されています。

FogFlow エディターからフォグ ファンクションを作成

タスク デザインボード上でマウスを右クリックすると、メニューがポップアップ表示されます。

_images/fog-function-create-new.png

表示されるメニューには、次の項目が含まれます:

  • Task: フォグ ファンクション名と処理ロジック(またはオペレーター)を定義するために使用されます。タスクには入力ストリームと出力ストリームがあります。
  • EntityStream: 入力データストリームとして、フォグ ファンクション タスクとリンクできる入力データ要素です。

ポップアップ メニューから "Task" をクリックすると、以下に示すように、タスク要素がデザインボードに配置されます。

_images/fog-function-add-task-element.png

次の図に示すように、右上隅にある "configuration" ボタンをクリックして、タスクの構成を開始します。タスクの名前を指定し、事前登録されたオペレーターのリストからオペレーターを選択してください。

_images/fog-function-configure-task-element.png

ポップアップ メニューから "EntityStream" をクリックして、デザインボードに "EntityStream" 要素を配置してください。

_images/fog-function-add-entityStream-element.png

次のものが含まれています:

  • Selected Type: 可用性がフォグ ファンクションをトリガーする入力ストリームのエンティティ タイプを定義するために使用されます。
  • Selected Attributes: 選択されたエンティティ タイプについて、フォグ ファンクションに必要なエンティティ属性。"all" は、すべてのエンティティ属性を取得することを意味します。
  • Group By: このフォグ ファンクションの粒度を定義する、選択したエンティティ属性の1つである必要があります。
  • Scoped: エンティティ データが場所固有であるかどうかを示します。True は、場所固有のデータがエンティティに記録されていることを示し、False は、ブロードキャストされたデータの場合に使用されます。たとえば、特定の場所ではなく、すべての場所に当てはまるルールまたはしきい値データです。

注釈

粒度 (granularity) は、このフォグ ファンクションのインスタンスの数を決定します。原則として、定義されたフォグ ファンクションのタスク インスタンスの数は、使用可能な入力データについて、選択されたエンティティ属性の一意の値の総数に等しくなります。また、各インスタンスは、特定の属性値を持つすべての入力エンティティを処理するように割り当てられます。

この例では、粒度は "id" で定義されています。これは、FogFlow が個々のエンティティ Id ごとに新しいタスク インスタンスを作成することを意味します。

以下に示すように、構成ボタンをクリックして EntityStream を構成します。この例では、"dummy" フォグ ファンクションの入力データのエンティティ タイプとして "Temperature" を選択します。

_images/fog-function-configure-entityStream-element.png

タスクには複数の EntityStream が存在する可能性があり、ここに示すように、それらをタスクに接続する必要があります。

_images/fog-function-connect-elements.png

独自のファンクションのコードを提供

現在、FogFlow を使用すると、開発者は登録済みのオペレーター内で独自のファンクション コードを指定できます。サンプル オペレーターについては、ダミー オペレーター コード (dummy operator code) を参照してください。

exports.handler = function(contextEntity, publish, query, subscribe) {
    console.log("enter into the user-defined fog function");

    var entityID = contextEntity.entityId.id;

    if (contextEntity == null) {
        return;
    }
    if (contextEntity.attributes == null) {
        return;
    }

    var updateEntity = {};
    updateEntity.entityId = {
        id: "Stream.result." + entityID,
        type: 'result',
        isPattern: false
    };
    updateEntity.attributes = {};
    updateEntity.attributes.city = {
        type: 'string',
        value: 'Heidelberg'
    };

    updateEntity.metadata = {};
    updateEntity.metadata.location = {
        type: 'point',
        value: {
            'latitude': 33.0,
            'longitude': -1.0
        }
    };

    console.log("publish: ", updateEntity);
    publish(updateEntity);
};

上記の JavaScript コード例は、フォグ ファンクションの実装と見なすことができます。 この例のフォグ ファンクションは、"publish" コールバック ファンクションを呼び出すことによって固定エンティティを単純に書き込みます。

フォグ ファンクションの入力パラメーターは、次のように事前定義され、固定されています:

  • contextEntity: 受信したエンティティ データを表します。
  • publish: 生成された結果を FogFlow システムに公開するためのコールバック ファンクション
  • query: オプション。これは、独自の内部ファンクション ロジックが FogFlow コンテキスト管理システムから追加のエンティティ データをクエリする必要がある場合にのみ使用されます。
  • subscribe: オプション。これは、独自の内部ファンクション ロジックが FogFlow コンテキスト管理システムから追加のエンティティ データをサブスクライブする必要がある場合にのみ使用されます。

重要

コールバック ファンクションの クエリサブスクライブ の場合、"extra" とは、フォグ ファンクションのアノテーションの入力として定義されていないエンティティ データを意味します。

フォグ ファンクションの実装の JavaScript ベースのテンプレート (Javascript-based template for fog function) も FogFlow リポジトリで提供されています。フォグ ファンクションについては、JavaScript ベースのテンプレートを参照してください

Java と Python のテンプレートもリポジトリにあります。

これらの3つのコールバック ファンクションを使用する方法を示すいくつかの例を次に示します。

  • publish の使用例:
    var updateEntity = {};
    updateEntity.entityId = {
           id: "Stream.Temperature.0001",
           type: 'Temperature',
           isPattern: false
    };
    updateEntity.attributes = {};
    updateEntity.attributes.city = {type: 'string', value: 'Heidelberg'};
    
    updateEntity.metadata = {};
    updateEntity.metadata.location = {
        type: 'point',
        value: {'latitude': 33.0, 'longitude': -1.0}
    };
    
    publish(updateEntity);
    
  • query の使用例:
    var queryReq = {}
    queryReq.entities = [{type:'Temperature', isPattern: true}];
    var handleQueryResult = function(entityList) {
        for(var i=0; i<entityList.length; i++) {
            var entity = entityList[i];
            console.log(entity);
        }
    }
    
    query(queryReq, handleQueryResult);
    
  • subscribe の使用例:
    var subscribeCtxReq = {};
    subscribeCtxReq.entities = [{type: 'Temperature', isPattern: true}];
    subscribeCtxReq.attributes = ['avg'];
    
    subscribe(subscribeCtxReq);
    

フォグ ファンクションをサブミット

"Submit" ボタンをクリックすると、注釈付きのフォグ ファンクションが FogFlow にサブミットされます。

_images/fog-function-submit.png

"dummy" フォグ ファンクションをトリガー

定義された "dummy" フォグ ファンクションは、必要な入力データが利用可能な場合にのみトリガーされます。次のコマンドを使用して、 "Temperature" センサー エンティティを作成して ファンクションをトリガーできます。次の必要な情報を入力してください。

  • Device ID: 一意のエンティティ ID を指定します。
  • Device Type: エンティティ タイプとして "Temperature" を使用します。
  • Location: 地図上に場所を配置します。
_images/device-registration.png

デバイスプロファイルが登録されると、新しい "Temperature" センサーエンティティが作成され、"dummy" フォグ ファンクションが自動的にトリガーされます。

_images/fog-function-triggering-device.png

フォグ ファンクションをトリガーするもう1つの方法は、NGSI エンティティのアップデートを送信して、"Temperature" センサー エンティティを作成することです。次のコマンドを実行して、FogFlow Broker に POST リクエストを発行できます。

curl -iX POST \
  'http://localhost:8080/ngsi10/updateContext' \
  -H 'Content-Type: application/json' \
  -d '
{
    "contextElements": [
        {
            "entityId": {
                "id": "Device.temp001",
                "type": "Temperature",
                "isPattern": false
            },
            "attributes": [
            {
              "name": "temp",
              "type": "integer",
              "value": 10
            }
            ],
            "domainMetadata": [
            {
                "name": "location",
                "type": "point",
                "value": {
                    "latitude": 49.406393,
                    "longitude": 8.684208
                }
            }
            ]
        }
    ],
    "updateAction": "UPDATE"
}'

以下の方法でフォグ ファンクションが作動しているか確認してください。

  • 次の図に示すように、このフォグ ファンクションのタスク インスタンスを確認してください
    _images/fog-function-task-running.png
  • 次の図に示すように、実行中のタスク インスタンスによって生成された結果を確認します
    _images/fog-function-streams.png

サービス トポロジー (Service Topology)

サービス トポロジーを定義してトリガー

FogFlow では、サービス トポロジーは複数のオペレーターのグラフとして定義されます。サービス トポロジー内の各オペレーターには、同じトポロジー内の他のタスクへの依存関係を示す入力と出力の注釈が付けられます。フォグ ファンクションとは異なり、サービス トポロジーは、カスタマイズされた "intent" オブジェクトによってオンデマンドでトリガーされます。

次のセクションでは、開発者がサービス トポロジーを定義およびテストする方法を簡単な例で説明します。

異常検出のユースケース

このユース ケース スタディは、小売店が異常なエネルギー消費をリアルタイムで検出するためのものです。次の図に示すように、小売会社にはさまざまな場所に多数のショップが分散しています。ショップごとに、ショップ内のすべての電源パネルからの電力消費を監視するために Raspberry Pi デバイス (エッジ ノード) が展開されます。エッジで異常な電力使用が検出されると、ショップのアラーム メカニズムがトリガーされ、ショップの所有者に通知されます。さらに、検出されたイベントは、情報集約のためにクラウドに報告されます。集約された情報は、ダッシュボード サービスを介してシステム オペレーターに提示されます。さらに、システム オペレータは、異常検出のルールを動的に更新できます。

_images/retails.png
  • Anomaly Detector (異常検出器): このオペレーターは、小売店の電源パネルから収集されたデータに基づいて異常イベントを検出します。2種類の入力があります:

    • オペレーターによって提供および更新される検出ルール。検出ルールの入力ストリームタイプは broadcast に関連付けられています。つまり、このオペレーターのすべてのタスク インスタンスでルールが必要です。このオペレーターの粒度は shopID に基づいています。つまり、ショップごとに専用のタスク インスタンスが作成および構成されます。
    • 電源パネルからのセンサーデータ
  • Counter (カウンター): このオペレーターは、各都市 (each city) のすべてのショップの異常イベントの総数をカウントします。したがって、そのタスクの粒度は city です。その入力ストリーム タイプは、前のオペレーター (異常検出器) の出力ストリーム タイプです。

結果コンシューマー (result consumers) には2つのタイプがあります:

  1. クラウド内のダッシュボード サービス。グローバル スコープのカウンター オペレーターによって生成された最終的な集計結果をサブスクライブします。
  2. 各ショップのアラーム。小売店のローカル エッジ ノードで異常検出タスクによって生成された異常イベントをサブスクライブします。
_images/retail-flow.png

サービス トポロジーに必要なオペレーター機能を実装

設計されたサービス トポロジーを定義する前に、サービス トポロジーで使用されるすべてのオペレーターは、ユーザーまたは FogFlow システムの他のプロバイダーによって提供される必要があります。この特定のユースケースでは、anomaly_detector と counter の2つのオペレーターを実装する必要があります。コード リポジトリで提供されている例を参照してください。

サービス トポロジーを指定

サービス トポロジーで使用されるタスクが実装および登録されていると仮定すると、サービス トポロジーを指定する方法は2つあります。

FogFlow トポロジー エディタの使用

最初の方法は、FogFlow エディターを使用してサービス トポロジーを指定することです。

_images/retail-topology-1.png

図のように、以下の重要な情報を提供する必要があります。

  1. 以下を含むトポロジー プロファイルを定義します
    • topology name:トポロジーの一意の名前。
    • service description:このサービスの内容を説明するテキスト。
  2. サービス トポロジー内のデータ処理フローのグラフを描画します

    デザインボードのどこかを右クリックすると、メニューがポップアップ表示されます。次に、タスクまたは入力ストリームのいずれかを選択するか、シャッフルして、意図したデザインに従ってデータ処理フローを定義できます。

  3. 以下を含む、データ フロー内の各要素のプロファイルを定義します。

    上の図に示すように、構成ボタンをクリックすると、データ処理フローの各要素のプロファイルの指定を開始できます。

    タスク プロファイルを指定するには、次の情報が必要です。

    • name: タスクの名前。
    • operator: このタスクのデータ処理ロジックを実装する演算子の名前。リストから表示できるように、事前にオペレーターを登録してください。
    • entity type of output streams: 生成された出力ストリームのエンティティ タイプを指定します。

    EntityStream プロファイルを指定するには、次の情報が必要です。

    • SelectedType: タスクによって入力ストリームとして選択されるエンティティ タイプを定義するために使用されます。

    • SelectedAttributes: タスクの状態を変更するために考慮される選択されたエンティティ タイプの1つまたは複数の属性を定義するために使用されます。

    • Groupby: このタスクのインスタンスをその場でいくつ作成するかを決定します。現在、以下のケースが含まれています。

      • このタスク用に作成するインスタンスが1つしかない場合は、"groupby" = "all" を使用してください。
      • 入力ストリームのエンティティ ID ごとに1つのインスタンスを作成する必要がある場合は、ユーザー "groupby" = "entityID" を使用してください。
      • 特定のコンテキスト メタデータの一意の値ごとに1つのインスタンスを作成する必要がある場合は、この登録済みコンテキスト メタデータの名前を使用してください。
    • Scoped: エンティティ データが場所固有であるかどうかを示します。True は、場所固有のデータがエンティティに記録されていることを示し、False は、ブロードキャストされたデータの場合に使用されます。たとえば、特定の場所ではなく、すべての場所に当てはまるルールまたはしきい値データです。

    シャッフル要素 (Shuffling element) は、タスクの出力がシャッフル要素の入力であり、同じものがシャッフルによって入力として別のタスクに転送されるように、2つのタスク間のコネクタとして機能します。

NGSI Updateを使用して作成

もう1つの方法は、構築された NGSI アップデート メッセージをクラウドにデプロイされた IoT Broker に送信することにより、サービス トポロジーを登録することです。

上の画像に示されているサービス トポロジーを登録するための curl と JavaScript ベースのコードを次に示します。ユーザーは、上記のサービス トポロジー、つまり異常検出を参照して、このコードを理解できます。

注釈

JavaScript のコード例では、JavaScript ベースのライブラリを使用して FogFlow IoT Broker とやり取りします。ライブラリは、GitHub コード リポジトリ(designer/public/lib/ngsi) から見つけることができます。Web ページに ngsiclient.js を含める必要があります。

注釈

curl の場合は、Cloud IoT Broker がローカルホストのポート 8070 で実行されていることを前提としています。

curl -iX POST \
        'http://localhost:8070/ngsi10/updateContext' \
        -H 'Content-Type: application/json' \
        -d '
        {
                "contextElements": [
                {
                        "entityId":{
                                "id":"Topology.anomaly-detection",
                                "type":"Topology"
                        },
                        "attributes":[
                        {
                                "name":"status",
                                "type":"string",
                                "value":"enabled"
                        },
                        {
                                "name":"designboard",
                                "type":"object",
                                "value":{
                                        "blocks":[
                                        {
                                                "id":1,
                                                "module":null,
                                                "type":"Task",
                                                "values":{
                                                        "name":"Counting",
                                                        "operator":"counter",
                                                        "outputs":[
                                                                "Stat"
                                                        ]
                                                },
                                                "x":202,
                                                "y":-146
                                        },
                                        {
                                                "id":2,
                                                "module":null,
                                                "type":"Task",
                                                "values":{
                                                        "name":"Detector",
                                                        "operator":"anomaly",
                                                        "outputs":[
                                                                "Anomaly"
                                                        ]
                                                },
                                                "x":-194,
                                                "y":-134
                                        },
                                        {
                                                "id":3,
                                                "module":null,
                                                "type":"Shuffle",
                                                "values":{
                                                        "groupby":"ALL",
                                                        "selectedattributes":[
                                                                "all"
                                                        ]
                                                },
                                                "x":4,
                                                "y":-18
                                        },
                                        {
                                                "id":4,
                                                "module":null,
                                                "type":"EntityStream",
                                                "values":{
                                                        "groupby":"EntityID",
                                                        "scoped":true,
                                                        "selectedattributes":[
                                                                "all"
                                                        ],
                                                        "selectedtype":"PowerPanel"
                                                },
                                                "x":-447,
                                                "y":-179
                                        },
                                        {
                                                "id":5,
                                                "module":null,
                                                "type":"EntityStream",
                                                "values":{
                                                        "groupby":"ALL",
                                                        "scoped":false,
                                                        "selectedattributes":[
                                                                "all"
                                                        ],
                                                        "selectedtype":"Rule"
                                                },
                                                "x":-438,
                                                "y":-5
                                        }
                                        ],
                                        "edges":[
                                        {
                                                "block1":3,
                                                "block2":1,
                                                "connector1":[
                                                        "stream",
                                                        "output"
                                                ],
                                                "connector2":[
                                                        "streams",
                                                        "input"
                                                ],
                                                "id":2
                                        },
                                        {
                                                "block1":2,
                                                "block2":3,
                                                "connector1":[
                                                        "outputs",
                                                        "output",
                                                         0
                                                ],
                                                "connector2":[
                                                        "in",
                                                        "input"
                                                ],
                                                "id":3
                                        },
                                        {
                                                "block1":4,
                                                "block2":2,
                                                "connector1":[
                                                        "stream",
                                                        "output"
                                                ],
                                                "connector2":[
                                                        "streams",
                                                        "input"
                                                ],
                                                "id":4
                                        },
                                        {
                                                "block1":5,
                                                "block2":2,
                                                "connector1":[
                                                        "stream",
                                                        "output"
                                                ],
                                                "connector2":[
                                                        "streams",
                                                        "input"
                                                        ],
                                                "id":5
                                        }
                                        ]
                                }
                        },
                        {
                                "name":"template",
                                "type":"object",
                                "value":{
                                        "description":"detect anomaly events in shops",
                                        "name":"anomaly-detection",
                                        "tasks":[
                                        {
                                                "input_streams":[
                                                {
                                                        "groupby":"ALL",
                                                        "scoped":true,
                                                        "selected_attributes":[

                                                        ],
                                                        "selected_type":"Anomaly"
                                                }
                                                ],
                                                "name":"Counting",
                                                "operator":"counter",
                                                "output_streams":[
                                                {
                                                        "entity_type":"Stat"
                                                }
                                                ]
                                        },
                                        {
                                                "input_streams":[
                                                {
                                                        "groupby":"EntityID",
                                                        "scoped":true,
                                                        "selected_attributes":[

                                                        ],
                                                        "selected_type":"PowerPanel"
                                                },
                                                {
                                                        "groupby":"ALL",
                                                        "scoped":false,
                                                        "selected_attributes":[

                                                        ],
                                                        "selected_type":"Rule"
                                                }
                                                ],
                                                "name":"Detector",
                                                "operator":"anomaly",
                                                "output_streams":[
                                                {
                                                        "entity_type":"Anomaly"
                                                }
                                                ]
                                        }
                                        ]
                                }
                        }
                        ],
                        "domainMetadata":[
                        {
                                "name":"location",
                                "type":"global",
                                "value":"global"
                        }
                        ]
                }
        ],
        "updateAction": "UPDATE"
}'
// the json object that represent the structure of your service topology
// when using the FogFlow topology editor, this is generated by the editor
var topology = {
        "name":"template",
        "type":"object",
        "value":{
                "description":"detect anomaly events in shops",
                "name":"anomaly-detection",
                "tasks":[
                {
                        "input_streams":[
                        {
                                "groupby":"ALL",
                                "scoped":true,
                                "selected_attributes":[

                                ],
                                "selected_type":"Anomaly"
                        }
                        ],
                        "name":"Counting",
                        "operator":"counter",
                        "output_streams":[
                        {
                                "entity_type":"Stat"
                        }
                        ]
                },
                {
                        "input_streams":[
                        {
                                "groupby":"EntityID",
                                "scoped":true,
                                "selected_attributes":[

                                ],
                                "selected_type":"PowerPanel"
                        },
                        {
                                "groupby":"ALL",
                                "scoped":false,
                                "selected_attributes":[

                                ],
                                "selected_type":"Rule"
                        }
                        ],
                        "name":"Detector",
                        "operator":"anomaly",
                        "output_streams":[
                        {
                                "entity_type":"Anomaly"
                        }
                        ]
                }
                ]
        }
}

var design = {
        "name":"designboard",
        "type":"object",
        "value":{
                "blocks":[
                {
                        "id":1,
                        "module":null,
                        "type":"Task",
                        "values":{
                                "name":"Counting",
                                "operator":"counter",
                                "outputs":[
                                        "Stat"
                                ]
                        },
                        "x":202,
                        "y":-146
                },
                {
                        "id":2,
                        "module":null,
                        "type":"Task",
                        "values":{
                                "name":"Detector",
                                "operator":"anomaly",
                                "outputs":[
                                        "Anomaly"
                                ]
                        },
                        "x":-194,
                        "y":-134
                },
                {
                        "id":3,
                        "module":null,
                        "type":"Shuffle",
                        "values":{
                                "groupby":"ALL",
                                "selectedattributes":[
                                        "all"
                                ]
                        },
                        "x":4,
                        "y":-18
                },
                {
                        "id":4,
                        "module":null,
                        "type":"EntityStream",
                        "values":{
                                "groupby":"EntityID",
                                "scoped":true,
                                "selectedattributes":[
                                        "all"
                                ],
                                "selectedtype":"PowerPanel"
                        },
                        "x":-447,
                        "y":-179
                },
                {
                        "id":5,
                        "module":null,
                        "type":"EntityStream",
                        "values":{
                                "groupby":"ALL",
                                "scoped":false,
                                "selectedattributes":[
                                        "all"
                                ],
                                "selectedtype":"Rule"
                        },
                        "x":-438,
                        "y":-5
                }
                ],
                "edges":[
                {
                        "block1":3,
                        "block2":1,
                        "connector1":[
                                "stream",
                                "output"
                        ],
                        "connector2":[
                                "streams",
                                "input"
                        ],
                        "id":2
                },
                {
                        "block1":2,
                        "block2":3,
                        "connector1":[
                                "outputs",
                                "output",
                                0
                        ],
                        "connector2":[
                                "in",
                                "input"
                        ],
                        "id":3
                },
                {
                        "block1":4,
                        "block2":2,
                        "connector1":[
                                "stream",
                                "output"
                        ],
                        "connector2":[
                                "streams",
                                "input"
                        ],
                        "id":4
                },
                {
                        "block1":5,
                        "block2":2,
                        "connector1":[
                                "stream",
                                "output"
                        ],
                        "connector2":[
                                "streams",
                                "input"
                        ],
                        "id":5
                }
                ]
        }
}

//submit it to FogFlow via NGSI Update
var topologyCtxObj = {};

topologyCtxObj.entityId = {
        id : 'Topology.' + topology.value.name,
        type: 'Topology',
        isPattern: false
};

topologyCtxObj.attributes = {};
topologyCtxObj.attributes.status = {type: 'string', value: 'enabled'};
topologyCtxObj.attributes.designboard = design;
topologyCtxObj.attributes.template = topology;

// assume the config.brokerURL is the IP of cloud IoT Broker
var client = new NGSI10Client(config.brokerURL);

// send NGSI10 update
client.updateContext(topologyCtxObj).then( function(data) {
        console.log(data);
}).catch( function(error) {
        console.log('failed to submit the topology');
});

インテント (Intent) を送信してサービス トポロジーをトリガー

開発者が指定されたサービス トポロジーと実装されたオペレーターを送信すると、次の2つの手順でサービス データ処理ロジックをトリガーできます:

  • サービス トポロジーを個別のタスクに分割する高レベルのインテント オブジェクトを送信します。
  • そのサービス トポロジーのタスクに入力ストリームを提供します。

インテント オブジェクトは、次のプロパティを持つ FogFlow ダッシュボードを使用して送信されます。

  • Topology: インテント オブジェクトの対象となるトポロジーを指定します。
  • Priority: トポロジー内のすべてのタスクの優先度レベルを定義します。これは、リソースをタスクに割り当てる方法を決定するためにエッジ ノードによって使用されます。
  • Resource Usage: トポロジーがエッジ ノードのリソースをどのように使用できるかを定義します。排他的な方法で共有するということは、トポロジーが他のトポロジーのタスクとリソースを共有しないことを意味します。もう1つの方法は包括的です。
  • Objective: 最大スループット、最小遅延、最小コストをワーカーでのタスク割り当てに設定できます。ただし、この機能はまだ完全にはサポートされていないため、現時点では "None" に設定できます。
  • Geoscope: 入力ストリームを選択する必要がある定義済みの地理的領域です。グローバル ジオスコープとカスタム ジオスコープを設定できます。
_images/intent-registry.png

FogFlow トポロジー マスターは、サービス トポロジーに含まれるタスクの入力ストリームを待機します。インテント オブジェクトのスコープ内にあるコンテキスト データが受信されるとすぐに、最も近いワーカーでタスクが開始されます。

Anomaly-Detector (異常検出器) ユースケースの入力ストリームを送信するための curl の例を次に示します。PowerPanel (電源パネル) とルール データが必要です。

注釈

ユーザーは、Simulated Powerpanel Devices (シミュレートされた電源パネル デバイス) を使用して電源パネルデータを送信することもできます。

注釈

curl の場合は、Cloud IoT Broker がローカルホストのポート 8070 で実行されていることを前提としています。

curl -iX POST \
  'http://localhost:8070/ngsi10/updateContext' \
-H 'Content-Type: application/json' \
-d '
{
        "contextElements": [
        {
           "entityId":{
              "id":"Device.PowerPanel.01",
              "type":"PowerPanel"
           },
           "attributes":[
              {
                 "name":"usage",
                 "type":"integer",
                 "value":4
              },
              {
                 "name":"shop",
                 "type":"string",
                 "value":"01"
              },
              {
                 "name":"iconURL",
                 "type":"string",
                 "value":"/img/shop.png"
              }
           ],
           "domainMetadata":[
              {
                 "name":"location",
                 "type":"point",
                 "value":{
                    "latitude":35.7,
                    "longitude":138
                 }
              },
              {
                 "name":"shop",
                 "type":"string",
                 "value":"01"
              }
           ]
        } ],
        "updateAction": "UPDATE"
}'
curl -iX POST \
  'http://localhost:8070/ngsi10/updateContext' \
-H 'Content-Type: application/json' \
-d '
{
        "contextElements": [
        {
           "entityId":{
              "id":"Stream.Rule.01",
              "type":"Rule"
           },
           "attributes":[
              {
                 "name":"threshold",
                 "type":"integer",
                 "value":30
              }
           ]
        }],
        "updateAction": "UPDATE"
}'

インテント モデル (Intent Model)

次の図に示すように、インテント オブジェクト (Intent object) は基本的にこれらのプロパティで構成されます。

  • サービス トポロジー (Serivce topology) は、インテント オブジェクトがトリガーされる計算ロジックを指定します。
  • Geoscope は、入力ストリームを選択する必要がある地理的な場所として定義されます。ジオスコープはグローバル値として選択できるだけでなく、カスタム ジオスコープを設定することもできます。
  • サービス レベル オブジェクト (Service Level Object - SLO) は、最大スループット、最小遅延、最小コストの目標であり、ワーカーでのタスク割り当てに設定できます。ただし、この機能はまだ完全にはサポートされていないため、ユーザーはこれを無視できます。今のところ "None" に設定できます。
  • リソース使用量は、トポロジーがエッジ ノードのリソースをどのように使用できるかを定義します。それは排他的または包括的のいずれかです。排他的な方法では、トポロジーが他のトポロジーのタスクとリソースを共有しないことを意味します。一方、包括的トポロジーは、他のトポロジーのタスクとリソースを共有します。
_images/intent_model.png

3つの重要な要素

IoT サービスをプログラムするための3つの重要な要素は、次の図に示されています。

_images/key_elements.png

FogFlow では、複数のオペレーターがサービス トポロジーとして定義されるグラフを形成します。サービス トポロジー内の各オペレーターには、同じトポロジー内の他のタスクへの依存関係を示す入力と出力の注釈が付けられます。サービス トポロジーでは、さまざまなオペレーターを簡単に構成して、わずか数分でサービス ロジックを形成できます。その後、実行時に、サービス ユーザーによって定義された高レベルのデータ使用インテント (data usage intent) に基づいて、データ処理フローを自動的にトリガーできます。サービス ユーザーは、データ プロデューサーまたは結果コンシューマー (result consumers) のいずれかになります。

サービス トポロジーの "Hello-World" の例

タスク オペレーターの登録

オペレーターを登録 して、オペレーターの名前と必要な入力パラメーターを定義します。 このコンテキストでは、オペレーターはいくつかのパラメーターを持つ名前付き要素に他なりません。 次の図は、登録されているすべてのオペレーターとそのパラメーター数のリストを示しています。

_images/operator_dashboard.png

"register" ボタンをクリックすると、下にデザイン エリアが表示され、オペレーターを作成してパラメーターを追加できます。オペレーター "Hello-World" の名前を追加し、オペレーターの説明を追加します (オプションです)。パラメーター名を追加します。ここでは、hello と記述され、値がデフォルトとして設定されています。

_images/register_operator3.png

Docker イメージを登録し、オペレーターを選択して、 Docker イメージを定義し、すでに登録されているオペレーターをそれに関連付けます。

次の図は、登録されているすべての Docker イメージのリストと各イメージの重要な情報を示しています。

_images/docker_image1.png

"register" ボタンをクリックすると、以下のようなフォームが表示されます。必要事項をご記入の上、"register" ボタンをクリックして登録してください。フォームは次のように説明されます。

  • Image: オペレーター のDocker イメージの名前
  • Tag: タグは、オペレーターのDockerイメージを公開するために使用されます。デフォルトでは "latest" です。
  • Hardware Type: x86 または ARM (Raspberry Pi など) を含む、Docker イメージがサポートするハードウェア タイプです。
  • OS Type: Docker イメージがサポートするオペレーティングシステム タイプ。現在、これは Linux のみに限定されています。
  • Operator: オペレーター名。一意である必要があり、サービス トポロジーを定義するときに使用されます。
  • Prefetched: これがチェックされている場合、すべてのエッジ ノードがこの Docker イメージのフェッチを事前に開始することを意味します。それ以外の場合、オペレーターの Docker イメージは、エッジ ノードがこのオペレーターに関連付けられたスケジュールされたタスクを実行する必要がある場合にのみ、オンデマンドでフェッチされます。

重要

Docker イメージの名前は、Docker Hub に公開されている名前と一致している必要があることに注意してください。デフォルトでは、FogFlow は、オペレーター用に Docker Hub に登録されている名前を使用して、必要な Docker イメージをフェッチします。

_images/docker_image.png

"Hello-World" のサービストポロジーを定義してトリガー

FogFlow Topology Editor を使用してサービス トポロジーを定義します。

_images/topology_register.png

図のように、以下の重要な情報を提供する必要があります。

  1. 以下を含むトポロジー プロファイルを定義します。

    • topology name: トポロジーの一意の名前。
    • service description: このサービスの内容を説明するテキスト。
  2. サービス トポロジー内のデータ処理フローのグラフを描画します。

    デザインボードのどこかを右クリックすると、メニューがポップアップ表示され、タスクまたは入力ストリームの選択を開始するか、データ処理フローを定義するためにシャッフルすることができます。

タスク プロファイルを指定するには、次の情報が必要です。

  • name: タスクの名前
  • operator: このタスクのデータ処理ロジックを実装するオペレーターの名前。リストから表示できるように、オペレーターを事前に登録する必要があります。
  • entity type of output streams: 生成された出力ストリームのエンティティ タイプを指定します。

EntityStream プロファイルを指定するには、次の情報が必要です。

  • SelectedType:タスクによって入力ストリームとして選択されるエンティティ タイプを定義するために使用されます。

  • SelectedAttributes:タスクの状態を変更するために、選択されたエンティティ タイプのどの属性が考慮されるかを定義するために使用されます。

  • Groupby:このタスクのインスタンスをその場でいくつ作成するかを決定します。現在、以下のケースが含まれています。

    • このタスク用に作成するインスタンスが1つしかない場合は、"groupby" = "all" を使用してください。
    • 入力ストリームのエンティティ ID ごとに1つのインスタンスを作成する必要がある場合は、"lgroupby" = "entityID" を使用してください。
    • 特定のコンテキスト メタデータの一意の値ごとに1つのインスタンスを作成する必要がある場合は、この登録済みコンテキスト メタデータの名前を使用してください
  • Scoped: エンティティ データが場所固有 (location-specific) であるかどうかを示します。True は、場所固有のデータがエンティティに記録されていることを示し、False は、ブロードキャストされたデータの場合に使用されます。たとえば、特定の場所ではなく、すべての場所に当てはまるルールまたはしきい値データです。

    シャッフル要素 (Shuffling element) は、タスクの出力がシャッフル要素の入力であり、同じものがシャッフルによって入力として別のタスクに転送されるように、2つのタスク間のコネクタとして機能します。

インテントを送信してサービス トポロジーをトリガー

開発者が指定されたサービス トポロジーと実装されたオペレーターを送信すると、次の2つの手順でサービス データ処理ロジックをトリガーできます:

  • サービス トポロジーを個別のタスクに分割する高レベルのインテント オブジェクトを送信します。0
  • そのサービス トポロジーのタスクに入力ストリームを提供します。

インテント オブジェクトは、次のプロパティを持つ FogFlow ダッシュボードを使用して送信されます。

  • Topology: インテント オブジェクトの対象となるトポロジーを指定します。
  • Priority: トポロジー内のすべてのタスクの優先度レベルを定義します。これは、リソースをタスクに割り当てる方法を決定するためにエッジ ノードによって使用されます。
  • Resource Usage: トポロジーがエッジ ノードのリソースをどのように使用できるかを定義します。排他的な方法で共有するということは、トポロジーが他のトポロジーのタスクとリソースを共有しないことを意味します。もう1つの方法は包括的です。
  • Objective: 最大スループット、最小遅延、最小コストをワーカーでのタスク割り当てに設定できます。ただし、この機能はまだ完全にはサポートされていないため、現時点では "None" に設定できます。
  • Geoscope: 入力ストリームを選択する必要がある定義済みの地理的領域 (defined geographical area) です。グローバル ジオスコープとカスタム ジオスコープを設定できます。
_images/intent.png

FogFlow トポロジー マスターは、サービストポロジーに含まれるタスクの入力ストリームを待機します。インテント オブジェクト (Intent object) のスコープ内にあるコンテキスト データが受信されるとすぐに、最も近いワーカーでタスクが開始されます。

コントリビューションとコーディングのガイドライン

FogFlow コントリビューション ガイド

このドキュメントでは、FogFlow にコントリビューションするためのガイドラインについて説明します。コードにコントリビューションすることを計画している場合は、このドキュメントを読んで、その内容に精通する必要があります。

一般的な原則

  • FogFlow は Go プログラミング言語を使用します (ただし、テストツールや他のスクリプトなどの他のツールは python、java、bash で記述できます)。
  • 効率的なコード (つまり、パフォーマンスを向上させるコード) は、非効率的なコードより優先されます。複雑なコードよりも単純なコード (つまり、よりクリーンで短いコード) が推奨されます。単純さのわずかなペナルティで効率の大幅な節約が可能です。効率のわずかなペナルティを伴う単純さの大幅な節約も可能です。
  • FogFlow に提供されるコードは、コードで作業するすべての開発者に共通のプログラミングスタイルを設定するために、コード スタイル ガイドライン (code style guidelines) に従う必要があります。

コントリビューション ワークフロー 自体 (プルリクエストなど) は、別のドキュメント FIWARE 開発ガイドライン (FIWARE Development Guidelines) で説明されていることに注意してください。

ブランチ 管理ガイドライン

_images/gitGuideline.jpg

コミュニティには、寿命が無限の2つの主要なブランチがあります:

  1. Master branch: これは非常に安定したブランチであり、常に本番環境に対応しており、本番環境でのソースコードの最新リリースバージョンが含まれています。
  2. Development branch: Master ブランチ (Master branch) から派生した Development ブランチ (Development branch) は、次のリリースで計画されているさまざまな機能を統合するためのブランチとして機能します。このブランチは、Master ブランチほど安定している場合とそうでない場合があります。これは、開発者がコラボレーションして機能ブランチ (Feature Branch) をマージする場所です。すべての変更は、何らかの方法でマスターにマージして戻し、リリース番号でタグ付けする必要があります。

これらの2つの主要なブランチとは別に、ワークフローには他のブランチがあります:

  • Feature Branch: 機能開発、つまり拡張またはドキュメント化のために Development ブランチからフォークしたブランチです。機能の開発または拡張の実装後に、Development ブランチにマージされます。
  • Bug Branch: Development ブランチから分岐したブランチです。バグ修正後、Development ブランチにマージされます。
  • Hotfix branch: ホットフィックス ブランチは、Master ブランチから作成されます。現在のプロダクト リリースであり、深刻なバグが原因で問題が発生していますが、開発の変更はまだ不安定です。その後、ホットフィックス ブランチから分岐して、問題の修正を開始する場合があります。重大なバグのみの場合で、これは最もまれな機会です。

注意: ホットフィックス ブランチを作成およびマージする権限を持っているのは NEC Laboratories Europe (NLE)、および、NEC Technologies India (NECTI) のメンバーのみです。

ブランチの命名規則
ブランチ ブランチ命名ガイドライン 備考
Feature branches development から分岐する必要があります。development にマージして戻す必要があります。ブランチの命名規則: feature-feature_id feature_id は、https://github.com/smartfog/fogflow/issues の Github Issue ID です。
Bug Branches development から分岐する必要があります。development にマージして戻す必要があります。ブランチの命名規則: bug-bug_id bug_id は、https://github.com/ScorpioBroker/ScorpioBroker/issues の Github Issue ID です。
Hotfix Branches master branch から分岐する必要があります。master branch にマージして戻す必要があります。ブランチの命名規則: hotfix-bug number Bug number は、https://github.com/ScorpioBroker/ScorpioBroker/issues の Github Issue ID です。
ブランチへのアクセス許可
  • Master - Master ブランチでマージしてプルリクエストを受け入れることができるのは、NLE メンバーと NECTI の特権メンバーのみであるという非常に厳しい傾向があります。マスターへのプルリクエストは、NECTI または NLE メンバーのみが作成できます。
  • Development - コミュニティ メンバーは誰でもプルリクエストをDevelopment ブランチに上げることができますが、NLE または NECTI メンバーが確認する必要があります。Development ブランチのコミットは、travis.yml で定義されているすべてのテストケースが正常に実行された場合にのみMaster ブランチに移動されます。

コード スタイルのガイドライン

現在、すべての FogFlow の既存のコードベースがこれらのルールに準拠しているわけではないことに注意してください。ガイドラインが確立される前に書かれたコードのいくつかの部分があります。ただし、すべての新しいコードの貢献はこれらのルールに従わなければならず、最終的には、古いコードはガイドラインに準拠するように変更されます。

‘従わなければならない (MUST follow)’ ルール

M1 (ヘッダー ファイルを含む):

ルール: すべてのヘッダーまたはソースファイルには、必要なすべてのヘッダー ファイルが含まれている必要があり、他のヘッダー ファイルは含まれていません。他のヘッダー ファイルのインクルードに依存してはなりません。また、すべてのヘッダー ファイルとソースファイルには、それ自体を必要としないヘッダー ファイルを含めてはなりません (MUST NOT)。

根拠: 各ファイルは、他のファイルに含まれるものと含まれないものに依存してはなりません。また、ヘッダー ファイルに必要以上のファイルが含まれている場合、その 'クライアント' には、それらの 'extra' (追加) ファイルも含める以外に選択肢はありません。これは競合につながることがあるため、回避する必要があります。さらに、コンパイル時間が長くなります。

確認方法: 手動

M2 (著作権ヘッダー)

ルール: すべてのファイルは、ソースコードであるかどうかに関係なく、著作権ヘッダーを持っている必要があります。

Golang ファイルの場合:

Python、bash スクリプトなどの場合:

# Copyright 20XX FogFlow Authors.

# This file is part of FogFlow.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#    http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
# implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# For Python, bash script  etc.:

# Author: <the author>

根拠: すべてのファイルに同種の著作権ヘッダーを設定します。

確認方法: 手動

M3 (関数ヘッダー)

ルール: すべての関数にはヘッダーが必要です (MUST)。ヘッダーには、関数の機能の簡単な説明、パラメーターの説明リスト、および戻り値が含まれている必要があります (SHOULD) 。

例:

/* ****************************************************************************
*
* parseUrl - parse a URL and return its pieces
*
*  [ Short description if necessary ]
*
* PARAMETERS
*   - url         The URL to be examined
*   - host        To output the HOST of the URL
*   - port        To output the PORT of the URL
*   - path        To output the PATH of the URL
*   - protocol    To output the PROTOCOL of the URL
*
* RETURN VALUE
*   parseUrl returns TRUE on successful operation, FALSE otherwise
*
* NOTE
*   About the components in a URL: according to
*   https://tools.ietf.org/html/rfc3986#section-3,
*   the scheme component is mandatory, i.e. the 'http://' or 'https://' must
*   be present, otherwise the URL is invalid.
*/

根拠: このように準備すると、コードが読みやすくなります。

確認方法: 手動

M4 (インデント)

ルール: スペースのみを使用し(つまり、タブを使用せず)、一度に2つのスペース (TWO spaces) をインデントします。

根拠: 2つの空白で十分です。行が長くなりすぎない。

確認方法: 手動

M5 (変数宣言):

ルール: 宣言された各変数は、別々の行に配置する必要があります。

var  i  int;
var  j  int;

次の使用は避けなければなりません (MUST):

var  i, j, k int;

根拠: 読みやすくなります。

確認方法: 手動

M6 (命名規則):

ルール: 次の命名規則が適用されます。

  • 名前は文字で始まる必要があり、任意の数の追加の文字と数字を含めることができます。
  • 関数名を数字で始めることはできません。
  • 関数名にスペースを含めることはできません。
  • 名前が大文字で始まる関数が他のパッケージにエクスポートされる場合。関数名が小文字で始まる場合、他のパッケージにはエクスポートされませんが、同じパッケージ内でこの関数を呼び出すことができます。
  • 関数名が複数の単語で構成されている場合は、キャメル ケースを使用してそのような名前を表します (例:empName、empAddress など)。
  • 関数名では大文字と小文字が区別されます (car、Car、および CAR は3つの異なる変数です)。

根拠: このルールにより、理解が容易になります。

確認方法: 手動

M7 (インデントやその他のフォーマットのためにコミットする前に gofmt を使用してください):

ルール: gofmt -r '(a) -> a' -w FileName

  • gofmt を適用する前のコード
package main
          import "fmt"
// this is demo to format code
           // with gofmt command
var a int=2;
           var b int=5;
                    var c string= `hello world`;
           func print(){
                        fmt.Println("Value for a,b and c is : ");
                          fmt.Println(a);
                               fmt.Println((b));
                                     fmt.Println(c);
                       }
  • ルール適用後のコード
package main

import "fmt"

// this is demo to format code
// with gofmt command
var a int = 2
var b int = 5
var c string = `hello world`

func print() {
        fmt.Println("Value for a,b and c is : ")
        fmt.Println(a)
        fmt.Println((b))
        fmt.Println(c)
             }

パッケージのフォーマットには gofmt /path/to/package を使用することに注意してください。

根拠: これにより、コードが再フォーマットされ、ファイルが更新されます。

確認方法: 手動

M8 (コマンドと演算子の分離):

ルール: 演算子 (+, *, =, == etc) の後には1つのスペースが続きます。カンマの後には1つのスペースが続きます。

FogFunction(va`r1, var2, var3) {
        if (var1 == var2) {
                 var2 = var3;
         }
}

ルール未適用

FogFunction(var1,var2,var3) {
        if (var1==var2) {
                var1=var3;
         }
}

根拠: 目に優しい。

確認方法: 手動

‘従わなければならない (MUST follow)’ ルール

S1 (エラー管理):

ルール: 2番目の引数で返されたエラーは管理する必要があります。

  • 悪い実装
FogContextElement, _ := preprocess(UpdateContextElement)
  • 良い実装
preprocessed, err := preprocess(bytes)
if err != nil {
  return Message{}, err
 }

S2 (メッセージの印刷エラー):

ルール: Golang の標準に従って、エラー文字列を大文字にしたり、句読点で終わらせたりしないでください。

  • 悪い実装
if len(in) == 0 {
 return "", fmt.Errorf("Input is empty")
 }
  • 良い実装
if len(in) == 0 {
        return nil, errors.New("input is empty")
 }

S3 (ネストを避ける):

ルール: コードの記述中にネストを避ける。

  • 悪い実装
func FogLine(msg *Message, in string, ch chan string) {
    if !startWith(in, stringComment) {
        token, value := parseLine(in)
          if token != "" {
              f, contains := factory[string(token)]
                if !contains {
                    ch <- "ok"
                } else {
                   data := f(token, value)
                   enrichMessage(msg, data)
                   ch <- "ok"
                }
                } else {
                    ch <- "ok"
                    return
                 }
                 } else {
                    ch <- "ok"
                    return
           }
  }
  • 良い実装
func FogLine(in []byte, ch chan interface{}) {
    // Filter empty lines and comment lines
    if len(in) == 0 || startWith(in, bytesComment) {
       ch <- nil
       return
    }

    token, value := parseLine(in)
    if token == nil {
          ch <- nil
          log.Warnf("Token name is empty on line %v", string(in))
          return
    }

    sToken := string(token)
    if f, contains := factory[sToken]; contains {
          ch <- f(sToken, value)
          return
    }

    log.Warnf("Token %v is not managed by the parser", string(in))
    ch <- nil
}

S4 (前提条件)

ルール: 処理を開始する前に、関数がパラメーターを評価し、必要に応じてエラーを返すことを強くお勧めします。

  • 悪い実装
a, err := f1()
if err == nil {
b, err := f2()
    if err == nil {
        return b, nil
    } else {
        return nil, err
  }
} else {
    return nil, err
 }
  • 良い実装
a, err := f1()
if err != nil {
    return nil, err
}
b, err := f2()
if err != nil {
    return nil, err
}
return b, nil

S5 (If 条件)

ルール: Golang には、if 条件でいくつかの改善されたバージョンがあります。

  • Golang での悪い実装
f, contains := array[index]
if contains {
    // Do something
}
  • 良い実装
if f, contains := array[index]; contains {
    // Do something
}

S5 (Switch)

ルール: スイッチ条件では常にデフォルトを使用します。

  • 悪い実装
switch simpleToken.token {
case tokenTitle:
    msg.Title = value
case tokenAdep:
    msg.Adep = value
case tokenAltnz:
    msg.Alternate = value
 // Other cases
}
  • 良い実装
switch simpleToken.token {
case tokenTitle:
    msg.Title = value
case tokenAdep:
    msg.Adep = value
case tokenAltnz:
    msg.Alternate = value
// Other cases
default:
    log.Errorf("unexpected token type %v", simpleToken.token)
    return Message{}, fmt.Errorf("unexpected token type %v", simpleToken.token)
}

S5 (コンスタント管理)

ルール: コンスタント値は ADEXP と ICAO メッセージによって管理されるべきです。

  • 悪い実装
const (
    AdexpType = 0 // TODO constant
    IcaoType  = 1
)
  • 良い実装
const (
    AdexpType = iota
    IcaoType
)

システム概要

FogFlow は、クラウドとエッジ上の動的処理フローをサポートする分散実行フレームワークです。複数の NGSI ベースのデータ処理タスクを動的かつ自動的に合成して高レベルの IoT サービスを形成し、共有クラウド エッジ環境内でそれらのサービスの展開を調整および最適化できます。

FogFlow クラウド エッジの共有環境は、次の図に示すように、1つの FogFlow クラウド ノードと複数の FogFlow エッジ ノードで作成できます。この図では、FogFlow システムで実行されているすべての統合機能を確認できます。

_images/FogFlow_System_Design.png

FogFlow は現在、後で使用するために内部エンティティ データを保存するためのグラフデータベースをサポートしています。FogFlow システムでは、グラフデータベースの相互作用ポイントはDesigner ーです。したがって、FogFlow Web ブラウザーまたは curl や python クライアントなどの他のクライアントを介して作成する FogFlow エンティティは、エンティティ作成要求が直接 Designer に送信されます。次に、 Designer はこのエンティティ リクエストを Cloud Broker に送信してエンティティを登録し、同時に Designer はこのデータを Dgraph に送信してデータベースに保存します。

FogFlow システムが再起動するたびに、Designer は Dgraphへ のクエリ リクエストをトリガーし、保存されているすべてのエンティティを Dgraph から取得してから、これらのエンティティを Cloud Broker に送信して登録します。

注釈

FogFlow Designer は、Discovery と CloudBroker に依存しています。

FogFlow Designer と Dgraph の統合は、gRPC を介して行われます。ここで、Dgraph クライアントは、gRPC を使用して以下のコードのように Designer サーバーで実装されます。gRPC のデフォルトポートは9080で、FogFlow では9082ポートが使用されます。

/*
creating grpc client for making connection with dgraph
*/
function newClientStub() {
    return new dgraph.DgraphClientStub(config.HostIp+":"+config.grpcPort, grpc.credentials.createInsecure());
}

// Create a client.
function newClient(clientStub) {
   return new dgraph.DgraphClient(clientStub);
}

新しい FogFlow エンティティが Web ブラウザーによって作成されるたびに、要求は Designer に送信されるか、ユーザーは任意のクライアントを使用して Designer 上にエンティティを直接作成します。次に、Designer は2つのタスクを実行します:

  1. エンティティを登録するために Cloud Broker にリクエストを送信します。
  2. Dgraph クライアントを呼び出してエンティティ データを保存します。Dgraph クライアントは、スキーマを作成した後、Dgraph サーバーとの接続を作成し、データを Dgraph に送信します。これとは別に、FogFlow システムが再起動すると、Designer から別のフローがトリガーされます。このフローでは、Designer は Dgraph からすべての保存されたエンティティ データをクエリし、これらのエンティティを登録するために Cloud Broker に転送します。

スキーマを作成し、Dgraph にデータを挿入するためのコードを垣間見ることができます。

/*
create schema for node
*/
async function setSchema(dgraphClient) {
    const schema = `
         attributes: [uid] .
         domainMetadata: [uid] .
         entityId: uid .
         updateAction: string .
         id: string .
         isPattern: bool .
         latitude: float .
         longitude: float .
         name: string .
         type: string .
               value: string .
    `;
    const op = new dgraph.Operation();
    op.setSchema(schema);
    await dgraphClient.alter(op);
}

/*
insert data into database
*/
async function createData(dgraphClient,ctx) {
    const txn = dgraphClient.newTxn();
    try {
        const mu = new dgraph.Mutation();
        mu.setSetJson(ctx);
        const response = await txn.mutate(mu);
        await txn.commit();
    }
         finally {
       await txn.discard();
    }
}

詳細なコードについては、 https://github.com/smartfog/fogflow/blob/development/designer/dgraph.js を参照してください。

このページでは、FogFlow 統合について簡単に紹介します。詳細については、リンクを参照してください。

統合には主にノースバウンドとサウスバウンドの2種類があり、センサー デバイスからブローカーへのデータ フローはノースバウンド フローと呼ばれ、ブローカーからアクチュエータ デバイスへのデータ フローはサウスバウンド フローと呼ばれます。ノースバウンドおよびサウスバウンドのデータ フローの詳細は、この (this) ページで確認できます。

FogFlow は Scorpio Broker と統合できます。Scorpio は、NGSI-LD 準拠のコンテキスト ブローカーです。そのため、NGSI-LD アダプターは、FogFlow エコシステムが Scorpio Context Broker と対話できるように構築されています。NGSI-LD アダプターは、NGSI データ形式を NGSI-LD に変換し、それを Scorpio Broker に転送します。詳細は、 Integrate FogFlow with Scorpio Broker のページで確認できます。

FogFlow NGSI-LD サポート: FogFlow は、NGSI9 および NGSI10 とともに NGSI-LD APIs サポートを提供しています。NGSI-LD 形式は、FogFlow または他の GEs のコンポーネント間のコンテキスト共有通信を明確かつよりよく理解する目的で FIWARE が使用するリンクトデータモデル を利用することを目的としています。より効率的な方法で情報を推測するためにデータ間の関係を確立することにより、NGSIv1 モデルおよび NGSIv2 モデルの間でデータを維持する複雑さを軽減します。

  • このモデルを組み込む理由は、エッジ コンピューティングのバックボーンを形成しているリンクトデータの関連付けが直接必要なためです。
  • これにより、FogFlow と Scorpio Broker 間の相互作用のように、相互作用が可能になったため、FogFlow と他の GEs の間のギャップが埋められます。

NGSI-LD APIs の詳細は、 API Walkthrough ページで確認できます。

FogFlow は、NGSI APIs を使用して Orion Context Broker と統合することもできます。詳細は、FogFlow とFIWARE の統合ページ (Integrate FogFlow with FIWARE) で確認できます。

同様に、WireCloud との FogFlow 統合は、WireCloud のさまざまなウィジェットを使用してデータを視覚化するために提供されています。QuantumLeap との FogFlow 統合は、時系列ベースの履歴データを保存することです。詳細については 、WireCloud の場合は FogFlow を WireCloud と統合 (Integrate FogFlow with WireCloud) のページ、QuantumLeap の場合は FogFlow を QuantumLeap と統合 (Integrate FogFlow with QuantumLeap) のページで確認できます。

FogFlow は、FogFlow クラウド ノードと FogFlow エッジ ノード間、および2つのエッジ ノード間の安全な通信も提供します。FogFlow で HTTP ベースの安全な通信を実現するには、FogFlow クラウド ノードと FogFlow エッジ ノードが独自のドメイン名を持っている必要があります。さらに、詳細な構成とセットアップの手順は、セキュリティ (Security) のページで確認できます。

システム セットアップ

前提条件

FogFlow を起動するための前提条件のコマンドは次のとおりです:

  1. docker
  2. docker-compose

Ubuntu 16.04 の場合、docker-ce と docker-compose をインストールする必要があります。

Docker CE をインストールするには、Install Docker CE を参照してください。必要なバージョン > 18.03.1-ce です。

重要

また、ユーザーが sudo なしで Docker コマンドを実行できるようにしてください。

Docker Compose をインストールするには、Install Docker Compose を参照してください。必要なバージョン> 2.4.2 です。

FogFlow クラウド ノードを起動

必要なすべてのスクリプトを取得

以下のように docker-compose ファイルと構成ファイルをダウンロードします。

# the docker-compose file to start all FogFlow components on the cloud node
wget https://raw.githubusercontent.com/smartfog/fogflow/master/release/3.2/cloud/docker-compose.yml

# the configuration file used by all FogFlow components
wget https://raw.githubusercontent.com/smartfog/fogflow/master/release/3.2/cloud/config.json

# the configuration file used by the nginx proxy
wget https://raw.githubusercontent.com/smartfog/fogflow/master/release/3.2/cloud/nginx.conf

IP 構成を変更

ご使用の環境に応じて、config.json で以下の IP アドレスを変更する必要があります。

  • my_hostip: FogFlow クラウド ノードの IP とこの IP アドレスは、FogFlow エッジ ノードからアクセス可能である必要があります。これには "127.0.0.1" を使用しないでください。
  • site_id: 各 FogFlow ノード (クラウド ノードまたはエッジ ノード) は、システム内で自身を識別するために一意の文字列ベースの ID を持っている必要があります。
  • physical_location: FogFlow ノードの地理的位置。
  • worker.capacity: FogFlow ノードが呼び出すことができる Docker コンテナーの最大数を意味します。

Elasticsearch と Metricbeat の IP 構成を変更

ご使用の環境に応じて、docker-compose.yml の次の IP アドレスを変更する必要があります。

  • output.elasticsearch.hosts: metricbeat が csv 形式でデータを共有する elasticsearch のホストの場所です。

また、ご使用の環境に応じて、metricbeat.docker.yml の次の IP アドレスを変更する必要があります。

  • name: Grafana metric ダッシュボードのエッジ ノードからのクラウド ノードの一意性に付けられた名前です。IP アドレスの代わりに任意の名前を指定できます。
  • hosts: Elasticsearch データベースのホストの場所であり、metricbeat がメトリックデータを共有します。

重要

my_hostip の IP アドレスとして "127.0.0.1" を使用しないでください。これらは Docker コンテナ内で実行中のタスクによって使用されます。

Firewall rules: external_ip を介して FogFlow Web ポータルにアクセスできるようにします。次のポートも開いている必要があります: TCP の場合は80 および 5672

FogFlow Cloud Node ですべてのコンポーネントを起動

すべての FogFlow コンポーネントの Docker イメージをプルし、FogFlow システムを起動します。

# if you already download the docker images of FogFlow components, this command can fetch the updated images
    docker-compose pull

    docker-compose up -d

セットアップを検証

FogFlow クラウド ノードが正しく開始されているかどうかを確認するには、次の2つの方法があります:

  • "docker ps -a" を使用して、すべてのコンテナーが稼働していることを確認します。
docker ps -a

CONTAINER ID      IMAGE                       COMMAND                  CREATED             STATUS              PORTS                                                 NAMES
90868b310608      nginx:latest            "nginx -g 'daemon of…"   5 seconds ago       Up 3 seconds        0.0.0.0:80->80/tcp                                       fogflow_nginx_1
d4fd1aee2655      fogflow/worker          "/worker"                6 seconds ago       Up 2 seconds                                                                 fogflow_cloud_worker_1
428e69bf5998      fogflow/master          "/master"                6 seconds ago       Up 4 seconds        0.0.0.0:1060->1060/tcp                               fogflow_master_1
9da1124a43b4      fogflow/designer        "node main.js"           7 seconds ago       Up 5 seconds        0.0.0.0:1030->1030/tcp, 0.0.0.0:8080->8080/tcp       fogflow_designer_1
bb8e25e5a75d      fogflow/broker          "/broker"                9 seconds ago       Up 7 seconds        0.0.0.0:8070->8070/tcp                               fogflow_cloud_broker_1
7f3ce330c204      rabbitmq:3              "docker-entrypoint.s…"   10 seconds ago      Up 6 seconds        4369/tcp, 5671/tcp, 25672/tcp, 0.0.0.0:5672->5672/tcp     fogflow_rabbitmq_1
9e95c55a1eb7      fogflow/discovery       "/discovery"             10 seconds ago      Up 8 seconds        0.0.0.0:8090->8090/tcp                               fogflow_discovery_1
399958d8d88a      grafana/grafana:6.5.0   "/run.sh"                29 seconds ago      Up 27 seconds       0.0.0.0:3003->3000/tcp                               fogflow_grafana_1
9f99315a1a1d      fogflow/elasticsearch:7.5.1 "/usr/local/bin/dock…" 32 seconds ago    Up 29 seconds       0.0.0.0:9200->9200/tcp, 0.0.0.0:9300->9300/tcp       fogflow_elasticsearch_1
57eac616a67e      fogflow/metricbeat:7.6.0 "/usr/local/bin/dock…"   32 seconds ago     Up 29 seconds                                                                  fogflow_metricbeat_1

重要

不足しているコンテナーがある場合は、"docker ps -a" を実行して、FogFlow コンポーネントが何らかの問題で終了していないかどうかを確認できます。ある場合は、"docker logs [container ID]" を実行して、出力ログをさらに確認できます。

  • FogFlow DashBoard からシステム ステータスを確認します。

Web ブラウザで FogFlow ダッシュボードを開くと、次の URL を介して現在のシステム ステータスを確認できます: http://<coreservice_ip>/index.html

重要

FogFlow クラウド ノードがゲートウェイの背後にある場合は、ゲートウェイ IP から coreservice_ip へのマッピングを作成してから、ゲートウェイ IP を介して FogFlow ダッシュボードにアクセスする必要があります。 FogFlow クラウド ノードが AzureCloud、Google Cloud、Amazon Cloud などのパブリッククラウド内の VM である場合は、VM のパブリック IP を介して FogFlow ダッシュボードにアクセスする必要があります。

FogFlow ダッシュボードにアクセスできるようになると、次の Web ページが表示されます:

_images/dashboard.png

Grafana ダッシュボードで Elasticsearch を構成

Grafana ダッシュボードは Web ブラウザーからアクセスでき、URL: http://<output.elasticsearch.hosts>:3003/ を介して現在のシステム ステータスを確認できます。Grafana ログインのデフォルトのユーザー名とパスワードは、それぞれ admin と admin です。

  • Grafana に正常にログインしたら、ホームダッシュボードの "Create your first data source" をクリックして、データソースを設定します。
  • Add Data Sourch ページから Elasticsearch を選択します。これで、下の図と同じページの Data Sources/Elasticsearch が表示されます。
_images/Elastic_config.png
  1. データソースに名前を付けます。
  2. HTTP の詳細で、elasticsearch とポートの URL に言及します。URL には HTTP を含める必要があります。
  3. Access で Server(default) を選択します。URL は、Grafana バックエンド/サーバーからアクセスできる必要があります。
  4. Elasticsearch の詳細で、Time フィールド名に @timestamp を入力します。ここで、時間フィールドのデフォルトを Elasticsearch インデックスの名前で指定できます。インデックス名またはワイルドカードには時間パターンを使用します。
  5. Elasticsearch バージョンを選択します。

次に、"Save & Test" ボタンをクリックします。

Metricbeat を設定

  • 以下のように、metricbeat.docker.yml ファイルの Elasticsearch の詳細を変更します:
name: "<155.54.239.141_cloud>"
metricbeat.modules:
- module: docker
  #Docker module parameters that has to be monitored based on user requirement, example as below
  metricsets: ["cpu","memory","network"]
  hosts: ["unix:///var/run/docker.sock"]
  period: 10s
  enabled: true
- module: system
  #System module parameters that has to be monitored based on user requirement, example as below
  metricsets: ["cpu","load","memory","network"]
  period: 10s

output.elasticsearch:
  hosts: '155.54.239.141:9200'

既存の IoT サービスを試す

FogFlow クラウド ノードがセットアップされると、FogFlow エッジ ノードを実行せずに既存の IoT サービスを試すことができます。たとえば、次のような簡単なフォグ ファンクションを試すことができます。

  • 上部のナビゲーター バーにある "Operator Registry" をクリックして、事前定義されたオペレーターの初期化をトリガーします。

最初に "Operator Registry" をクリックすると、事前定義されたオペレーターのリストが FogFlow システムに登録されます。2回クリックすると、次の図に示すように、更新されたリストが表示されます。

_images/operator-list.png
  • 上部のナビゲーター バーで "Service Topology" をクリックして、事前定義されたサービス トポロジーの初期化をトリガーします。

最初に "Service Topology" をクリックすると、事前定義されたトポロジーのリストが FogFlow システムに登録されます。2回クリックすると、次の図に示すように、更新されたリストが表示されます。

_images/topology-list.png
  • 上部のナビゲーターバーの "Fog Function" をクリックして、事前定義されたフォグ ファンクションの初期化をトリガーします。

最初に "Fog Function" をクリックすると、事前定義されたファンクションのリストが FogFlow システムに登録されます。2回クリックすると、次の図に示すように、更新されたリストが表示されます。

_images/function-list.png
  • フォグ ファンクションをトリガーする IoT デバイス エンティティを作成します。

デバイス登録ページ (device registration pag) からデバイス エンティティを登録できます:

  1. "System Status" をクリックします。
  2. "Device" をクリックします。
  3. "Add" をクリックします。

次に、次のデバイス登録ページが表示されます。

_images/device-registration.png
  • フォグ ファンクションがトリガーされているかどうかを確認します

システム管理 (System Management) の "Task" の下にタスクが作成されているかどうかを確認します。

_images/fog-function-task-running.png

システム管理の "Stream" の下にストリームが作成されているかどうかを確認します。

_images/fog-function-streams.png

FogFlow エッジ ノードを開始

通常、FogFlow エッジ ノードは、Worker、IoT Broker、およびシステム監視エージェントの metricbeat をデプロイする必要があります。 エッジ ノードの Edge IoT Broker は、同じエッジ ノードで起動されたすべてのタスク インスタンス間のデータ フローを確立できます。 ただし、この Edge IoT Broker はオプションです。特に、エッジ ノードが非常に制約のあるデバイスであり、データに依存せずにいくつかのタスクしかサポートできない場合はそうです。

FogFlow エッジ ノードを開始する手順は次のとおりです:

Docker Engine をインストール

Docker CE と Docker Compose をインストールするには、Respberry Pi へのDocker CE と Docker Compose のインストール (Install Docker CE and Docker Compose on Respberry Pi)を参照してください。

注釈

FogFlow のすべてのタスク インスタンスは Docker コンテナー内で起動されるため、Docker エンジンを各エッジ ノードにインストールする必要があります。

デプロイメント スクリプトをダウンロード

#download the deployment scripts
wget https://raw.githubusercontent.com/smartfog/fogflow/master/docker/edge/http/start.sh
wget https://raw.githubusercontent.com/smartfog/fogflow/master/docker/edge/http/stop.sh
wget https://raw.githubusercontent.com/smartfog/fogflow/master/docker/edge/http/metricbeat.docker.yml

#make them executable
chmod +x start.sh  stop.sh

デフォルトの構成ファイルをダウンロード

#download the configuration file
wget https://raw.githubusercontent.com/smartfog/fogflow/master/docker/edge/http/config.json

構成ファイルを変更

簡単なテストにはデフォルト設定を使用できますが、ご使用の環境に応じて次のアドレスを変更する必要があります:

  • coreservice_ip: クラウド ノードで実行されている FogFlow コア サービスのアクセス可能な IP アドレスです。 クラウド部分の構成を参照してください。
  • external_hostip: これは外部 IP アドレスであり、Cloud Broker がアクセスできます。エッジ ノードが NAT の背後にある場合に役立ちます。
  • my_hostip は、デフォルトの Docker ブリッジの IP であり、ホストの "docker0" ネットワーク インターフェイスです。
  • site_id: エッジ ノードのユーザー定義 ID です。そのノードの Broekr IDs とWorker IDs は、この Site ID に従って形成されます。
  • container_autoremove: タスクに関連付けられたコンテナーが、その処理が完了すると削除されるように構成するために使用されます。
  • start_actual_task: 最小限の労力を実行する代わりに、タスクの開始または終了、または実行中のタスクの維持に必要なすべてのアクティビティをタスク構成とともに含めるように FogFlow Worker を構成します。True に保つことをお勧めします。
  • capacity: FogFlow ノードが呼び出すことができる Docker コンテナーの最大数です。ユーザーは、ノードでのリソースの可用性を考慮して制限を設定できます。
//you can see the following part in the default configuration file
{
    "coreservice_ip": "155.54.239.141",
    "external_hostip": "35.234.116.177",
    "my_hostip": "172.17.0.1",


    "site_id": "002",


    "worker": {
    "container_autoremove": false,
    "start_actual_task": true,
    "capacity": 4
    }


}

Metricbeat 構成ファイルを変更

使用する環境に応じて、start.sh の次のアドレスを変更する必要があります;

  • output.elasticsearch.hosts: これは、metricbeat がメトリックデータを共有する elasticsearch ホストの IP アドレスです。
  • 以下のように、metricbeat.docker.yml ファイルの Elasticsearch の詳細を変更します。
name: "<155.54.239.141/edge02>"
metricbeat.modules:
- module: docker
  #Docker module parameters to monitor based on user requirement,example as below
  metricsets: ["cpu","memory","network"]
  hosts: ["unix:///var/run/docker.sock"]
  period: 10s
  enabled: true
- module: system
  #System module parameters to monitor based on user requirement, example as below
  metricsets: ["cpu","load","memory","network"]
  period: 10s

output.elasticsearch:
  hosts: '155.54.239.141:9200'

エッジ ノード コンポーネントを開始

注釈

エッジ ノードが ARM ベースの場合、コマンド パラメーターとして arm を追加してください。

#start both components in the same script
./start.sh

#if the edge node is ARM-basd, please attach arm as the command parameter
#./start.sh  arm

エッジ ノード コンポーネントの停止

#stop both components in the same script
./stop.sh

デバイスとの統合

IoT デバイス/アクチュエーターとの統合には2つのタイプがあります:

  1. サウスバウンド統合
  2. ノースバウンド統合

センサー デバイスからブローカーに向かうデータ フローの場合はノースバウンド フローと呼ばれ、ブローカーからアクチュエータ デバイスに向かうデータ フローの場合はサウスバウンド フローと呼ばれます。

このチュートリアルでは、サウスバウンド フロー、つまり FogFlow がアクチュエータ デバイスを制御して環境を変更する方法に焦点を当てます。

サウスバウンド統合

アクチュエータ デバイスを FogFlow と統合

IoT デバイスには次の2つのタイプがあります:

  • 環境データを収集し、それを何らかのアプリケーションにプッシュするセンサー。
  • 環境に対して何らかのアクションを実行するアクチュエータ。

サウスバウンドが FIWARE のコンテキストで実際にどのように機能するかについての基本的な考え方を理解するには、この (this) チュートリアルを参照してください。

NGSI 対応デバイスとの統合

次の図は、FogFlow でサウスバウンド フローがどのように実行されるかを示しています。

_images/ngsi-device-integration.png

NGSI デバイスを使用するには、ユーザーはこの単純な Lamp デバイスを起動できます。このデバイスは、オン/オフコマンドを受信したときにランプのステータスを出力します。

Lamp デバイスを起動した後、次の curl リクエストを使用して FogFlow に Lamp デバイスを登録します。

curl -iX POST \
'http://<Thin_Broker_IP>:8070/NGSI9/registerContext' \
-H 'Content-Type: application/json' \
-H 'fiware-service: openiot' \
-H 'fiware-servicepath: /' \
-d '
{
        "contextRegistrations": [
            {
                "entities": [
                    {
                        "type": "Lamp",
                        "isPattern": "false",
                        "id": "Lamp.001"
                    }
                ],
                "attributes": [
                    {
                        "name": "on",
                        "type": "command"
                    },
                    {
                        "name": "off",
                        "type": "command"
                    }
                ],
                "providingApplication": "http://<Lamp_Host_IP>:8888"
            }
        ],
    "duration": "P1Y"
}'

以下は、Lamp (NGSI デバイス) で "on" コマンドを実行してオンにする要求です。このリクエストは Thin broker で発生することに注意してください。Thin broker は登録でプロバイダーを見つけ、このコマンド アップデートをそのプロバイダー、つまりデバイスに送信します。

curl -iX POST \
'http://<Thin_Broker_IP>:8070/ngsi10/updateContext' \
-H 'Content-Type: application/json' \
-H 'fiware-service: openiot' \
-H 'fiware-servicepath: /' \
-d '{
    "contextElements": [
    {
        "entityId": {
        "id": "Lamp.001",
        "type": "Lamp",
        "isPattern": false
        },
        "attributes": [
             {
                 "name": "on",
                 "type": "command",
                 "value": ""
             }
         ]
    }
    ],
    "updateAction": "UPDATE"
}'

このコマンド アップデートを送信すると、ユーザーはログで起動された Lamp デバイスのステータスを確認できます。"Lamp : on" になります。サポートされているもう1つのコマンドは、ユーザーがデバイスに送信できる "off" です。ユーザーは、コマンドの更新をノースバウンド方向に送信する独自のカスタマイズされたデバイスを持つことができます。

NGSI でサポートされていないデバイスとの統合

FIWARE が提供する IoT Agent は、非 NGSI デバイスと FogFlow の Thin Broker ーの間の双方向の仲介者として機能します。特定のプロトコルに基づくデバイスの場合、個別の IoT Agent があります。たとえば、MQTT ベースのデバイス用の IoT Agent for JSON 、超軽量デバイス用の IoT Agent for Ultralight などです。非 NGSI デバイスのサウスバウンド フローを次の図に示します。これは、デバイス プロトコル固有の IoT Agent を利用します。

_images/non-ngsi-device-integration.png

Ultralight デバイスの使用

Ultralight アクチュエータ デバイスと FogFlow の統合を以下の例に示します。

Ultralight デバイスを使用してサウスバウンドで作業するには、IoT Agent for Ultralight および Ultralight デバイスが実行されている必要があります。このための docker-compose ファイルは、ここ (here) にあります。このファイルの "tutorial" サービスは、デバイス サービスを提供します。開始するには、ユーザーは環境変数に基づいてこのファイルを編集する必要があります。

次の図は、http://tutorial_IP:3000/device/monitor にある IoT デバイス モニター ダッシュボードを示しています。

"lamp001" は "off" 状態であることに注意してください。この統合では、FogFlow を使用して Lamp デバイスを点灯します。

_images/device-monitor-1.png

デバイスの登録: デバイスの登録は IoT Agent で行われ、デバイスが提供するデータを示します。以下は、IoT Agent でデバイスを作成または登録するための curl リクエストです。ここで、Lamp デバイスは、エンティティ "urn:ngsi-ld:Lamp:001" のコンテキスト プロバイダーであると想定されるID "lamp001" で登録されています。これに対応して、IoT Agent はデバイスを Thin broker に登録し、そのデバイスのエンティティを Thin broker 自体に作成します。

curl -iX POST \
'http://<IoT_Agent_IP>:4041/iot/devices' \
-H 'Content-Type: application/json' \
-H 'fiware-service: openiot' \
-H 'fiware-servicepath: /' \
-d '{
  "devices": [
    {
      "device_id": "lamp001",
      "entity_name": "urn:ngsi-ld:Lamp:001",
      "entity_type": "Lamp",
      "protocol": "Ultralight",
      "transport": "HTTP",
      "endpoint": "http://<Device_Host_IP>:3001/iot/lamp001",
      "commands": [
        {"name": "on","type": "command"},
        {"name": "off","type": "command"}
       ],
       "attributes": [
        {"object_id": "s", "name": "state", "type":"Text"},
        {"object_id": "l", "name": "luminosity", "type":"Integer"}
       ],
       "static_attributes": [
         {"name":"refStore", "type": "Relationship","value": "urn:ngsi-ld:Store:001"}
      ]
    }
  ]
}'

デバイスへのコマンドの送信: 外部アプリケーションまたはフォグ ファンクションは、デバイスのタイプに応じて、オン/オフ、ロック/ロック解除、オープン/クローズなどのコマンドをデバイスに送信することにより、アクチュエータ デバイスを制御できます。デバイスでサポートされているコマンドは、上記のデバイス登録を通じて Thin Broker に認識されます。

以下の curl リクエストは、"on" コマンドを lamp001 デバイスに送信します。

curl -iX POST \
'http://<Thin_Broker_IP>:8070/ngsi10/updateContext' \
-H 'Content-Type: application/json' \
-H 'fiware-service: openiot' \
-H 'fiware-servicepath: /' \
-d '{
    "contextElements": [
    {
        "entityId": {
        "id": "urn:ngsi-ld:Lamp:001",
        "type": "Lamp",
        "isPattern": false
        },
        "attributes": [
             {
                 "name": "on",
                 "type": "command",
                 "value": ""
             }
         ]
    }
    ],
    "updateAction": "UPDATE"
}'

上記のリクエストは、FogFlow エンティティの更新を示しています。これは、FIWARE Orion などの他のブローカーによってサポートされている形式とは少し異なります。そのため、FogFlow では以下のリクエストもサポートされています。

curl -iX POST \
'http://<Thin_Broker_IP>:8070/v1/updateContext' \
-H 'Content-Type: application/json' \
-H 'fiware-service: openiot' \
-H 'fiware-servicepath: /' \
-d '{
    "contextElements": [
        {
            "type": "Lamp",
            "isPattern": "false",
            "id": "urn:ngsi-ld:Lamp:001",
            "attributes": [
                {
                    "name": "on",
                    "type": "command",
                    "value": ""
                }
            ]
        }
    ],
    "updateAction": "UPDATE"
}'

Lamp の状態を再度確認すると、下図のように点灯状態になります。

_images/device-monitor-2.png

MQTT デバイスの使用

MQTT デバイスは、サブスクライブおよびパブリッシュ ストラテジーで機能する MQTT プロトコルで実行され、クライアントは MQTT ブローカーをパブリッシュおよびサブスクライブします。別のクライアントが MQTT ブローカーにデータを公開すると、すべてのサブスクライブしているクライアントに通知されます。

Mosquitto Broker は、MQTT デバイスのシミュレーションに使用されます。Mosquitto Broker は、トピックと呼ばれる一意に識別されたリソースでのデータの公開とサブスクリプションを可能にします。これらのトピックは、“/<apikey>/<device_id>/<topicSpecificPart>” の形式で定義されています。ユーザーは、Mosquitto がインストールされているホストで直接サブスクライブすることにより、これらのトピックの更新を追跡できます。

さらに進むための前提条件

  • Mosquitto Broker をインストールします。
  • MQTT ブローカーの場所を事前構成して IoT Agent を起動します。簡単にするために、docker-compose ファイルの IoT Agent for JSON の環境変数に以下を追加してから、docker-compose を実行します。
- IOTA_MQTT_HOST=<MQTT_Broker_Host_IP>
- IOTA_MQTT_PORT=1883   # Mosquitto Broker runs at port 1883 by default.

IoT Agent for JSON でノースバウンドとサウスバウンドの両方のデータ フローを許可するには、ユーザーはデバイス登録用に api-key も提供する必要があります。これにより、IoT Agent は api-key を使用してトピックをパブリッシュおよびサブスクライブできます。 。このため、追加のサービスプロビジョニング リクエストが IoT Agent に送信されます。FogFlow で MQTT デバイスを操作する手順を以下に示します。

次の curl リクエストを使用して、IoT Agent でサービスを作成します。

curl -iX POST \
  'http://<IoT_Agent_IP>:4041/iot/services' \
  -H 'Content-Type: application/json' \
  -H 'fiware-service: iot' \
  -H 'fiware-servicepath: /' \
  -d '{
"services": [
   {
     "apikey":      "FFNN1111",
     "entity_type": "Lamp",
     "resource":    "/iot/json"
   }
]
}'

次の curl リクエストを使用して、Lamp デバイスを登録します。

curl -X POST \
  http://<IoT_Agent_IP>:4041/iot/devices \
  -H 'content-type: application/json' \
  -H 'fiware-service: iot' \
  -H 'fiware-servicepath: /' \
  -d '{
  "devices": [
    {
      "device_id": "lamp001",
      "entity_name": "urn:ngsi-ld:Lamp:001",
      "entity_type": "Lamp",
      "protocol": "IoTA-JSON",
      "transport": "MQTT",
      "commands": [
        {"name": "on","type": "command"},
        {"name": "off","type": "command"}
       ],
       "attributes": [
        {"object_id": "s", "name": "state", "type":"Text"},
        {"object_id": "l", "name": "luminosity", "type":"Integer"}
       ],
       "static_attributes": [
         {"name":"refStore", "type": "Relationship","value": "urn:ngsi-ld:Store:001"}
       ]
    }
  ]
}'

Mosquitto トピックをサブスクライブ: サービスとデバイスが正常に作成されたら、別々の端末で Mosquitto Broker の次のトピックをサブスクライブして、これらのトピックで公開されているデータを追跡します:

mosquitto_sub -h <MQTT_Host_IP> -t "/FFNN1111/lamp001/attrs"
mosquitto_sub -h <MQTT_Host_IP> -t "/FFNN1111/lamp001/cmd"

Thin Broker へのデータの公開: このセクションでは、ノースバウンド トラフィックについて説明します。IoT Agent は、["/+/+/attrs/+","/+/+/attrs","/+/+/configuration/commands","/+/+/cmdexe"] などのデフォルト トピックをサブスクライブします。そのため、属性データを IoT Agent に送信するには、以下のコマンドを使用して MosquittoBroker のトピックに関するデータを公開する必要があります。

mosquitto_pub -h <MQTT_Host_IP> -t "/FFNN1111/lamp001/attrs" -m '{"luminosity":78, "state": "ok"}'

Mosquitto ブローカーはこの更新について IoT Agent に通知するため、データは ThinBroker でも更新されます。

更新されたデータは、下の図に示すように、サブスクライブされたトピック "/FFNN1111/lamp001/attrs" でも表示できます。

_images/mqtt-data-update.png

デバイスコマンドの実行: このセクションでは、サウスバウンド トラフィック フロー、つまり、デバイスでコマンドを実行する方法について説明します。このために、以下のコマンド updateContext リクエストを Thin Broker に送信します。Thin Broker は、このコマンド アップデートのプロバイダーを見つけて、UpdateContext 要求をそのプロバイダーに転送します。この場合、IoT Agent がプロバイダーです。IoT Agent は、リンクされている Mosquitto ブローカーの "/FFNN1111/lamp001/cmd" トピックでコマンドを公開します。

curl -iX POST \
'http://<Thin_Broker_IP>:8070/ngsi10/updateContext' \
-H 'Content-Type: application/json' \
-H 'fiware-service: iot' \
-H 'fiware-servicepath: /' \
-d '{
    "contextElements": [
    {
        "entityId": {
        "id": "urn:ngsi-ld:Lamp:001",
        "type": "Lamp",
        "isPattern": false
        },
        "attributes": [
             {
                 "name": "on",
                 "type": "command",
                 "value": ""
             }
         ]
    }
    ],
    "updateAction": "UPDATE"
}'

更新されたデータは、次の図に示すように、サブスクライブされたトピック "/FFNN1111/lamp001/cmd" で表示できます。これは、"on" コマンドが MQTT デバイスで正常に実行されたことを意味します。

_images/mqtt-cmd-update.png

ユーザーは、カスタマイズしたデバイスを使用して、コマンド結果を Thin Broker 側で公開できます。

RegisterContext の他の APIs

Registration を取得

以下は、FogFlow System 内の Thin Broker からデバイス登録を取得するための curl リクエストです。これにより、どのブローカーにそのデバイスに関するレジストレーション情報が含まれているかがわかります。

curl -iX GET \
'http://<Thin_Broker_IP>:8070/NGSI9/registration/Lamp001' \
-H 'fiware-service: openiot' \
-H 'fiware-servicepath: /'

上記の登録のデバイスの registration id は、FogFlow 内の "Lamp001.openiot.~" になります。

FIWARE ヘッダー (つまり、"fiware-service" と "fiware-servicepath") はリクエストでオプションであるため、ユーザーは次の方法で Thin Broker でレジストレーションを探すこともできます。結果は、検索対象に完全に依存します。

curl -iX GET \
'http://<Thin_Broker_IP>:8070/NGSI9/registration/Lamp001.openiot.~'

Registration を削除

次の curl リクエストは、FogFlow のデバイス レジストレーションを削除します。

curl -iX DELETE \
'http://<Thin_Broker_IP>:8070/NGSI9/registration/Lamp001' \
-H 'fiware-service: openiot' \
-H 'fiware-servicepath: /'

このリクエストにより、レジストレーション "Lamp001.openiot.~" が削除されます。FIWARE ヘッダー (つまり、"fiware-service" および "fiware-servicepath") は必須です。

ノースバウンド統合

IoT デバイスを FogFlow に接続

NGSI 対応デバイスを使用

デバイスが NGSI を介して FogFlow と通信できる場合、デバイスを FogFlow に接続するのは非常に簡単です。デバイスで実行するには、いくつかの小さなアプリケーションが必要です。たとえば、複数のセンサーまたはアクチュエーターが接続された Raspberry Pi などです。

次の例では、シミュレートされた PowerPanel デバイスを NGSI を介して FogFlow に接続する方法を示しています。このサンプルコードには、アプリケーションフォルダーの FogFlow code repository からもアクセスできます。

Node.js は、このサンプルコードを実行する必要があります。Node.js と npm をインストールしてください。

'use strict';

const NGSI = require('./ngsi/ngsiclient.js');
const fs = require('fs');

// read device profile from the configuration file
var args = process.argv.slice(2);
if(args.length != 1){
    console.log('please specify the device profile');
    return;
}

var cfgFile = args[0];
var profile = JSON.parse(
    fs.readFileSync(cfgFile)
);

var ngsi10client;
var timer;

// find out the nearby IoT Broker according to my location
var discovery = new NGSI.NGSI9Client(profile.discoveryURL)
discovery.findNearbyIoTBroker(profile.location, 1).then( function(brokers) {
    console.log('-------nearbybroker----------');
    console.log(brokers);
    console.log('------------end-----------');
    if(brokers && brokers.length > 0) {
        ngsi10client = new NGSI.NGSI10Client(brokers[0]);

        // generating data observations periodically
        timer = setInterval(function(){
            updateContext();
        }, 1000);

        // register my device profile by sending a device update
        registerDevice();
    }
}).catch(function(error) {
    console.log(error);
});

// register device with its device profile
function registerDevice()
{
    var ctxObj = {};
    ctxObj.entityId = {
        id: 'Device.' + profile.type + '.' + profile.id,
        type: profile.type,
        isPattern: false
    };

    ctxObj.attributes = {};

    var degree = Math.floor((Math.random() * 100) + 1);
    ctxObj.attributes.usage = {
        type: 'integer',
        value: degree
    };
    ctxObj.attributes.shop = {
        type: 'string',
        value: profile.id
    };
    ctxObj.attributes.iconURL = {
        type: 'string',
        value: profile.iconURL
    };

    ctxObj.metadata = {};

    ctxObj.metadata.location = {
        type: 'point',
        value: profile.location
    };

    ngsi10client.updateContext(ctxObj).then( function(data) {
        console.log(data);
    }).catch(function(error) {
        console.log('failed to update context');
    });
}

// update context for streams
function updateContext()
{
    var ctxObj = {};
    ctxObj.entityId = {
        id: 'Stream.' + profile.type + '.' + profile.id,
        type: profile.type,
        isPattern: false
    };

    ctxObj.attributes = {};

    var degree = Math.floor((Math.random() * 100) + 1);
    ctxObj.attributes.usage = {
        type: 'integer',
        value: degree
    };
    ctxObj.attributes.deviceID = {
        type: 'string',
        value: profile.type + '.' + profile.id
    };

    ctxObj.metadata = {};

    ctxObj.metadata.location = {
        type: 'point',
        value: profile.location
    };
    ctxObj.metadata.shop = {
        type: 'string',
        value: profile.id
    };

    ngsi10client.updateContext(ctxObj).then( function(data) {
        console.log(data);
    }).catch(function(error) {
        console.log('failed to update context');
    });
}

process.on('SIGINT', function()
{
    if(ngsi10client) {
        clearInterval(timer);

        // to delete the device
        var entity = {
            id: 'Device.' + profile.type + '.' + profile.id,
            type: 'Device',
            isPattern: false
        };
        ngsi10client.deleteContext(entity).then( function(data) {
            console.log(data);
        }).catch(function(error) {
            console.log('failed to delete context');
        });

        // to delete the stream
        var entity = {
            id: 'Stream.' + profile.type + '.' + profile.id,
            type: 'Stream',
            isPattern: false
        };
        ngsi10client.deleteContext(entity).then( function(data) {
            console.log(data);
        }).catch(function(error) {
            console.log('failed to delete context');
        });
    }
});

discoveryURL は profile1.json で変更する必要があります。

{
    "discoveryURL":"http://35.198.104.115:443/ngsi9",
    "location": {
        "latitude": 35.692221,
        "longitude": 139.709059
    },
    "iconURL": "/img/shop.png",
    "type": "PowerPanel",
    "id": "01"
}

次のようにインストールする必要があるパッケージ:

npm install

このサンプルコードを次のように実行します:

node powerpanel.js profile1.json

NGSI がサポートされていないデバイスの場合

NGSI がサポートされていない IoT デバイス (on-NGSI IoT Devices) を接続するために、FIWARE は MQTT、Ultralight などのさまざまなプロトコルに基づいて IoT デバイスと連携する IoT Agent を提供します。IoT Agent は NGSIv1 または NGSIv2 の両方で通信できますが、現在 FogFlow は NGSIv1 のみをサポートしています。そのため、ユーザーは NGSIv1 形式を使用するように IoT Agent を構成する必要があります。

ユーザーは、クラウド ノードの起動に使用される docker-compose ファイルを直接実行することで、FogFlow クラウド ノードで IoT Agent を実行できます。デフォルトでは、IoT Agent はすでに許可されています。ユーザーは、必要がない場合はオプト アウトできます。

エッジ ノード上の IoT Agent を実行するために、ユーザーは、Start Edge ファイルで関連するコマンドのコメントを解除することができます。

ロケーションベースの温度データを Thin Broker に送信する FIWARE IoT Agent for JSON の使用例を以下に示します。Iot Agent は、NGSI データをブローカーに送信するために次の3つの要求を必要とします。

  • サービス プロビジョニング: サービス プロビジョニングまたはグループ プロビジョニングは、匿名デバイスの認証キー、オプションのコンテキスト ブローカー エンドポイントなどのデフォルトのコマンドまたは属性を設定するために IoT Agent によって使用されます。

以下は、IoT Agent でサービスを作成または登録するための curl リクエストです。

curl -iX POST \
  'http://<IoT_Agent_IP>:4041/iot/services' \
  -H 'Content-Type: application/json' \
  -H 'fiware-service: iot' \
  -H 'fiware-servicepath: /' \
  -d '{
"services": [
   {
     "apikey":      "FFNN1111",
     "entity_type": "Thing",
     "resource":    "/iot/json"
   }
]
}'
  • デバイス プロビジョニング: デバイス プロビジョニングは、デバイスが IoT Agent に送信するデータとデータ属性を指定するために使用されます。

以下の curl リクエストは、エンティティ "Thing1111" のデータを IoT Agent に送信するデバイス ID "Device1111" を持つデバイスを登録するために使用されます。

curl -X POST \
  http://<IoT_Agent_IP>:4041/iot/devices \
  -H 'content-type: application/json' \
  -H 'fiware-service: iot' \
  -H 'fiware-servicepath: /' \
  -d '{
        "devices": [{
                "device_id": "Device1111",
                "entity_name": "Thing1111",
                "entity_type": "Thing",
                "attributes": [{
                        "object_id":"locationName",
                        "name": "locationName",
                        "type": "string"
                },{
                        "object_id": "locationId",
                        "name": "locationId",
                        "type": "string"
                },{
                        "object_id": "Temperature",
                        "name": "Temperature",
                        "type": "integer"
                }
                ]}]
}'
  • センサーデータの更新: IoT Agent は、受信したデータをデバイス登録にマッピングし、それに対応する NGSI アップデートを作成します。IoT Agent はデバイスから非 NGSI 形式でデータを受信することに注意してください。

"Device1111" に代わって実際に "Thing1111" エンティティの更新を IoT Agent に送信する curl リクエストを以下に示します。

curl -X POST \
  'http://<IoT_Agent_IP>:7896/iot/json?i=Device1111&k=FFNN1111' \
  -H 'content-type: application/json' \
  -H 'fiware-service: iot' \
  -H 'fiware-servicepath: /' \
  -d '{
    "locationName":"Heidelberg",
    "locationId":"0011",
    "Temperature":20
}'

IoT Agent は、デバイスから更新を受信するとすぐに、Thin Broker に NGSIv1 UpdateContext 要求の形式でエンティティ データを更新するように要求します。

FogFlow を FIWARE と統合

FogFlow は、FIWARE エコシステムの公式 Generic Enabler (GE) として、Cloud-Edge Orchestrator として独自の地位を占めており、データの取り込み、変換、および高度な分析のために、クラウドとエッジ上で動的なデータ処理フローをシームレスに起動および管理します。

次の図に示すように、FogFlow は、他の FIWARE GEs と相互作用して、次の2つのレイヤーで FIWARE ベースの IoT プラットフォームを強化できます。 上位層では、FogFlow は次の2つの方法で標準化された NGSI インターフェースを介して Orion Context Broker と相互作用できます。

Orion Broker とFogFlow を統合

Orion を起動

Orion のドキュメントに従って、Orion Context Broker インスタンスをここからセットアップできます: Installing Orion.

以下のコマンドを使用して、Docker で Orion をセットアップすることもできます (Docker はこの方法で必要です) 注: Orion コンテナーは MongoDB データベースに依存しています。

前提条件: Docker がインストールされている必要があります

最初に、以下のコマンドを使用して MongoDB コンテナーを起動します:

sudo docker run --name mongodb -d mongo:3.4

そして、このコマンドで Orion を実行します:

sudo docker run -d --name orion1 --link mongodb:mongodb -p 1026:1026 fiware/orion -dbhost mongodb

すべてが動作することを確認します:

curl http://<Orion IP>:1026/version

Note: パブリックアクセスのためにファイアウォールのポート 1026 を許可します。

サブスクリプションを発行して、生成された結果を Orion Context Broker に転送

次の curl リクエストを使用して、Fogflow Broker を FIWARE Orion にサブスクライブします:

curl -iX POST \
  'http://coreservice_ip/ngsi10/subscribeContext' \
  -H 'Content-Type: application/json'  \
  -H 'Destination: orion-broker'  \
  -d '
{
  "entities": [
    {
      "id": ".*",
      "type": "Result",
      "isPattern": true
    }
  ],
  "reference": "http://<Orion IP>:1026/v2/op/notify"
}'

このサブスクリプション リクエストは制限や属性を使用せず、エンティティ タイプに基づく一般的なサブスクリプション リクエストであることに注意してください。

Orion Context Broker から結果をクエリ

ブラウザで次の URL にアクセスし、目的のコンテキストエンティティを検索します:

curl http://<Orion IP>:1026/v2/entities/

最初の方法は、Orion Context Broker を FogFlow IoT サービスによって生成されるコンテキスト情報の宛先と見なすことです。この場合、NGSI サブスクリプションは、外部アプリケーションまたは FogFlow ダッシュボードによって発行され、要求されたコンテキスト更新を指定された Orion Context Broker に転送するように FogFlow に要求する必要があります。

_images/orion-integration.png

どのエンティティを Orion Context Broker に転送するかを FogFlow に指示する方法は2つあります。最初の方法は、FogFlow Broker への生のサブスクリプションを発行することです。2番目の方法は、これを行うための小さな JavaScript プログラムを作成することです。以下に例を示します。統合は Orion Context Broker の NGSIv2 インターフェースを使用していることに注意してください。

重要

  • fogflowBroker: FogFlow Broker の IP アドレス。構成ファイルの "webportal_ip" または "coreservice_ip" の場合があります。これは、FogFlow システムにアクセスする場所までです。
  • orionBroker: 実行中の Orion インスタンスのアクセス可能な IP アドレス。
curl -iX POST \
  'http://fogflowBroker:8080/ngsi10/subscribeContext' \
  -H 'Content-Type: application/json' \
  -H 'Destination: orion-broker' \
  -d '{"entities": [{"type": "PowerPanel", "isPattern": true}],
                            "reference": "http://orionBroker:1026/v2/op/notify"} '
// please refer to the JavaScript library, located at  https://github.com/smartfog/fogflow/tree/master/designer/public/lib/ngsi

//  entityType: the type of context entities to be pushed to Orion Context Broker
//  orionBroker: the URL of your running Orion Context Broker
function subscribeFogFlow(entityType, orionBroker)
{
    var subscribeCtxReq = {};
    subscribeCtxReq.entities = [{type: entityType, isPattern: true}];
    subscribeCtxReq.reference =  'http://' + orionBroker + '/v2/op/notify';

    client.subscribeContext4Orion(subscribeCtxReq).then( function(subscriptionId) {
        console.log(subscriptionId);
        ngsiproxy.reportSubID(subscriptionId);
    }).catch(function(error) {
        console.log('failed to subscribe context');
    });
}


// client to interact with IoT Broker
var client = new NGSI10Client(config.brokerURL);

subscribeFogFlow('PowerPanel', 'cpaasio-fogflow.inf.um.es:1026');

要求されたデータがOrion Context Broker にプッシュされているかどうかを確認するには、次の NGSIv2 クエリを送信して確認します。

curl http://orionBroker:1026/v2/entities?type=PowerPanel -s -S -H 'Accept: application/json'

データソースとしての Orion Context Broker

2番目の方法は、Orion Context Broker を追加情報を提供するデータソースと見なすことです。この場合、簡単なフォグ ファンクションを実装して、必要な情報を FogFlow システムにフェッチできます。いずれの場合も、既存の Orion ベースの FIWARE システムに変更を加える必要はありません。したがって、このタイプの統合は、ほとんど労力をかけずに高速に実行できます。

下位層では、MQTT、COAP、OneM2M、OPC-UA、LoRaWAN などの NGSI 以外でサポートされているデバイスと統合するために、FogFlow は既存の IoT Agents のモジュールを再利用し、フォグ ファンクション プログラミング モデルに基づいて FogFlow アダプターに変換できます。これらのアダプターを使用すると、FogFlow は、デバイス統合に必要なアダプターをエッジで直接起動できます。このようにして、FogFlow はさまざまな IoT デバイスと通信できます。

FogFlow を NGSI-LD Broker と統合

チュートリアルでは、FogFlow を高度なデータ分析フレームワークとして利用して、Scorpio、Orion-LD、Stellio などの NGSI-LD Broker でキャプチャされた生データに加えてオンデマンド データ分析を可能にする方法を紹介します。次の図は、これを行う方法の簡単な例を 詳細に示しています。主に、8つのステップを持つ3つの側面が含まれています。

  • NGSI-LD Broker から FogFlow システムに生データをフェッチする方法 (ステップ1-3)
  • FogFlow のサーバーレス機能を使用してカスタマイズされたデータ分析を行う方法 (ステップ4)
  • 生成された分析結果を NGSI-LD Broker にプッシュして、さらに共有する方法 (ステップ5-8)
_images/fogflow-ngsild-broker.png

詳細な手順を検討する前に、以下の情報に従って FogFlow システムとNGSI-LD Broker をセットアップしてください。

まず、`FogFlow on a Single Machine`_ を参照 して、単一のホストマシン上に FogFlow システムをセットアップしてください。

NGSI-LD Broker に関しては、Scorpio、Orion-LD、Stellio のさまざまな選択肢があります。ここでは、詳細な手順を示す具体的な例として Orion-LD を取り上げます。同じホストマシンに Orion-LD ブローカーをセットアップするには、次の手順を参照してください。 他のブローカー (Scorpio、Stellio など)との統合では、リクエストのポート番号と構成ファイルを少し変更する必要があります。

# fetch the docker-compose file
wget https://raw.githubusercontent.com/smartfog/fogflow/development/test/orion-ld/docker-compose.yml

# start the orion-ld broker
docker-compose pull
docker-Compose up -d

次の手順を開始する前に、Orion-LD Broker と FogFlow システムが正しく実行されているかどうかを確認してください。

# Orion-LD Broker が実行されているかどうかを確認します

curl localhost:1026/ngsi-ld/ex/v1/version

# FogFlow システムが正しく実行されているかどうかを確認します

ブラウザから FogFlow ダッシュボードを開きます

Orion-LD から FogFlow にデータをフェッチする方法

ステップ 1: Orion-LD へのサブスクリプションを発行します

curl -iX POST \
          'http://localhost:1026/ngsi-ld/v1/subscriptions' \
          -H 'Content-Type: application/json' \
          -H 'Accept: application/ld+json' \
          -H 'Link: <https://fiware.github.io/data-models/context.jsonld>; rel="https://uri.etsi.org/ngsi-ld/v1/ngsi-ld-core-context.jsonld"; type="application/ld+json"' \
          -d ' {
        "type": "Subscription",
        "entities": [{
           "type": "Vehicle"
        }],
        "notification": {
           "format": "keyValues",
           "endpoint": {
               "uri": "http://192.168.0.59:8070/ngsi-ld/v1/notifyContext/",
               "accept": "application/ld+json"
            }
        }
                }'

ステップ 2: エンティティの更新を Orion-LD に送信します

curl --location --request POST 'http://localhost:1026/ngsi-ld/v1/entityOperations/upsert?options=update' \
--header 'Content-Type: application/json' \
--header 'Link: <https://fiware.github.io/data-models/context.jsonld>; rel="https://uri.etsi.org/ngsi-ld/v1/ngsi-ld-core-context.jsonld"; type="application/ld+json"' \
--data-raw '[
{
   "id": "urn:ngsi-ld:Vehicle:A106",
   "type": "Vehicle",
   "brandName": {
                  "type": "Property",
                  "value": "Mercedes"
    },
    "isParked": {
                  "type": "Relationship",
                  "object": "urn:ngsi-ld:OffStreetParking:Downtown1",
                  "providedBy": {
                                  "type": "Relationship",
                                  "object": "urn:ngsi-ld:Person:Bob"
                   }
     },
     "speed": {
                "type": "Property",
                "value": 120
      },
     "location": {
                    "type": "GeoProperty",
                    "value": {
                              "type": "Point",
                              "coordinates": [-8.5, 41.2]
                    }
     }
}
]'

ステップ 3: FogFlow がサブスクライブされたエンティティを受信するかどうかを確認します

FogFlow thinBroker から "Vehicle" エンティティをクエリするための curl コマンドを準備してください。

curl -iX GET \
          'http://localhost:8070/ngsi-ld/v1/entities?type=Vehicle' \
          -H 'Content-Type: application/ld+json' \
          -H 'Accept: application/ld+json' \
          -H 'Link: <https://fiware.github.io/data-models/context.jsonld>; rel="https://uri.etsi.org/ngsi-ld/v1/ngsi-ld-core-context.jsonld"; type="application/ld+json"'

データ分析機能をプログラムして適用する方法

ステップ 4: fogfunction1 を適用して、カスタマイズされたデータ分析を実行します

"/application/operator/alert" のコードを変更して、簡単な分析を行ってください。たとえば、 車両の速度がしきい値を超えたときにアラート メッセージを生成します。

生成された結果を NGSI-LD Broker にプッシュ バックする方法

オペレーター、Docker イメージ、Fog ファンクションを含む fogfunction2 をデフォルトで登録してください。 それらをデザイナの初期化リストに入れます。

ステップ 5: fogfunction2 をトリガーする更新メッセージを送信します

#please write the curl message to trigger fogfunction2

ステップ 6: fogfunction2 が作成されているかどうかを確認します

fogfunction2 がトリガーされているかどうかをユーザーが確認できる場所を説明します。

ステップ 7: Orion-LD が転送された結果を受信したかどうかを確認します

curl -iX GET \
          'http://localhost:8070/ngsi-ld/v1/entities?type=Alert' \
          -H 'Content-Type: application/ld+json' \
          -H 'Accept: application/ld+json' \
          -H 'Link: <https://fiware.github.io/data-models/context.jsonld>; rel="https://uri.etsi.org/ngsi-ld/v1/ngsi-ld-core-context.jsonld"; type="application/ld+json"'

FogFlow を QuantumLeap と統合

QuantumLeap は、NGSIv2 の時空間データを保存、クエリ、取得するための REST サービスです。QuantumLeap は、NGSI の半構造化データを表形式に変換し、時系列データベースに保存します。

次の図は、fogflow と QuantumLeap の統合を示しています。

_images/quantum-leap-fogflow-integration.png
  1. ユーザーは、NGSIv2 の FogFlow Broker にサブスクリプション要求を送信します。
  2. ユーザーは、NGSIv1 の FogFlow Broker にアップデート要求を送信します。
  3. FogFlow Broker は、NGSIv2 の QuantumLeap にノーティファイします。

統合手順

前提条件:

  • FogFlow は、少なくとも1つのノードで稼働している必要があります。
  • QuantumLeap は、少なくとも1つのノードで稼働している必要があります。

FogFlow Broker に QuantumLeap の サブスクリプション リクエストを送信します:

    curl -iX POST \
    'http://<FogFlow Broker>:8070/v2/subscriptions' \
     -H 'Content-Type: application/json' \
     -d '
    {
    "description": "A subscription to get info about Room1",
    "subject": {
            "entities": [{
                    "id": "Room4",
                    "type": "Room",
                    "isPattern": false
            }],
            "condition": {
                    "attrs": [
                            "temperature"
                    ]
            }
    },
    "notification": {
            "http": {
                    "url": "http://<Quantum-leap-Host-IP>:8668/v2/notify"
            },
            "attrs": [
                    "temperature"
            ]
    },
    "expires": "2040-01-01T14:00:00.00Z",
    "throttling": 5
}'

上記のサブスクリプションで定義されたタイプと属性のエンティティを使用して、FogFlow Broker に 更新リクエストを送信します。 リクエストの例を以下に示します:

   curl -iX POST \
   'http://<Fogflow broker>:8070/ngsi10/updateContext' \
    -H 'Content-Type: application/json' \
   -d '
 {
   "contextElements": [{
           "entityId": {
                   "id": "Room4",
                   "type": "Room",
                   "isPattern": false
           },
           "attributes": [{
                   "name": "temperature",
                   "type": "Integer",
                   "value": 155
           }],
           "domainMetadata": [{
                   "name": "location",
                   "type": "point",
                   "value": {
                           "latitude": 49.406393,
                           "longitude": 8.684208
                   }
           }]
   }],
   "updateAction": "UPDATE"
}'

FogFlow Broker は Quantumleap にノーティフィケーションを送信します。以下のコマンドで結果を確認します:

http://<QuantuLeap-Host-Ip>:8668/v2/entities/Room4/attrs/temperature

結果:

_images/quantum-leap-result.png

FogFlow を WireCloud と統合

WireCloud 、最先端のエンドユーザー開発、RIA、およびセマンティック テクノロジーに基づいて構築されており、サービスのインターネットのロングテールを活用することを目的とした次世代のエンドユーザー中心の Web アプリケーション マッシュアップ プラットフォームを提供します。

次の図は、FogFlow と WireCloud の統合を示しています。

_images/wc-fogflow-integration.png
  1. WireCloud は、NGSIv2 のFogFlow Broker にサブスクリプション リクエストを送信します。
  2. ユーザーは、アップデート要求を NGSIv1 のFogFlow Broker に送信します。
  3. FogFlow Broker はNGSIv2 で WireCloud に通知します。

統合手順

前提条件:

  • FogFlow は、少なくとも1つのノードで稼働している必要があります。
  • WireCloud は、WireCloudのインストール手順 (WireCloud installation steps) を実行している必要があります。

WireCloud を使用してFogFlow をサブスクライブする手順:

ステップ1: Wirecloud ダッシュボード ホームを開きます。

_images/wc-home.png

ステップ2: 新しいワークスペースを追加します。

_images/wc-options.png

ステップ3: 新しいワークスペースに名前を付けます。

_images/wc-create-workspace.png

ステップ4: 新しいワークスペース WC_fog を作成しました。

_images/wc-workspace-created.png

ステップ5: ユーザーが作成したすべてのリソースといくつかのデフォルトのリソースを表示します。

_images/wc-myresources-button.png

ステップ6: WireCloud ライブラリで利用可能なリソースと Wiget。

_images/wc-myresources.png

ステップ7: 独自のワークスペースのワイヤーリングを作成します。

_images/wc-wiring-button.png

ステップ8: セクションで Find components をクリックします。

_images/wc-find-components-button.png

ステップ9: データを表示するための2つの Spy wiring Widget と、エンティティを表示するための2番目のウィジェットを追加します。ユーザーは独自のウィジェットを使用してデータを表示し、要件に応じてエンティティの詳細を確認できます。

_images/wc-wiring_add-widget.png

ステップ10: 指定されたデータの Context Broker をサブスクライブするためにNGSI source Widget を追加します。

_images/wc-wiring_add-operator.png

ステップ11: 追加したコンポーネントを作業スペースにドラッグ アンド ドロップします。

_images/wc-wiring_drag-and-drop.png

ステップ12: 下の図のようにドロップされたコンポーネントを追加します。NGSI source のエンティティに接続された Spy wiring はデータを表示し、NGSI type の他の1つのコンポーネントはエンティティの詳細を表示します。

_images/wc-wire-components.png

ステップ13: NGSI ソースの設定に移動して、Context Broker へのサブスクリプション要求用に構成します。

_images/wc-ngsi-source-settings.png

ステップ14: FogFlow broker の URL (NGSI server URL)、NGSI proxy URL、NGSI エンティティ タイプ、ID pattern、属性を指定し、Accept をクリックしてサブスクリプション リクエストをヒットします。

_images/wc-operator-settings-form.png

上記のサブスクリプションで定義されたタイプと属性のエンティティを使用して、FogFlow Broker に アップデート リクエストを送信 します。リクエストの例を以下に示します:

   curl -iX POST \
   'http://<Fogflow broker>:8070/ngsi10/updateContext' \
    -H 'Content-Type: application/json' \
   -d '
 {
   "contextElements": [{
           "entityId": {
                   "id": "Room1",
                   "type": "Room",
                   "isPattern": false
           },
           "attributes": [{
                   "name": "temperature",
                   "type": "Integer",
                   "value": 155
           }],
           "domainMetadata": [{
                   "name": "location",
                   "type": "point",
                   "value": {
                           "latitude": 49.406393,
                           "longitude": 8.684208
                   }
           }]
   }],
   "updateAction": "UPDATE"
}'

結果:

_images/WCresult.png

Kubernetes のインテグレーション

FogFlow のコンポーネントは、ソースコードを介して構築することも、docker-compose ツールを使用して docker 環境で構築することもできます。Docker 環境では、FogFlow の各コンポーネントが単一インスタンスとして実行されています。単一のコンポーネント コンテナがダウンした場合、FogFlow システム全体を再起動する必要があり、単一のサービスが過負荷になると、負荷を処理するように拡張できなくなります。これらの問題を克服するために、FogFlow は Kubernetes に移行しました。FogFlow コンポーネントは、エンドユーザーの要件に基づいて Kubernetes クラスター環境にデプロイされます。さまざまなクラスター構成を展開できます:

  1. 同じノード上のマスターとワーカー
  2. シングル マスターとシングル ワーカー
  3. シングル マスター ノードとマルチ ワーカー ノード
  4. 複数のマスター ノードとマルチ ワーカー ノード

クラスターに加えて、K8s の次の機能が FogFlow に実装されています:

1. 高可用性と負荷分散: 高可用性とは、単一障害点が発生しないように、Kubernetes とそのサポート コンポーネントをセットアップすることです。環境セットアップで複数のアプリケーションが単一のコンテナーで実行されている場合、そのコンテナーは簡単に失敗する可能性があります。Kubernetes の高可用性のための仮想マシンと同じように、コンテナーの複数のレプリカを実行できます。負荷分散は、バックエンド サーバーのグループ全体に着信ネットワーク トラフィックを分散するのに効率的です。ロードバランサーは、サーバーのクラスター全体にネットワークまたはアプリケーション トラフィックを分散するデバイスです。ロードバランサーは、クラスターの高可用性とパフォーマンスの向上を実現するために大きな役割を果たします。

  1. 自己回復 (Self-healing): ポッドのいずれかが手動で削除された場合、またはポッドが誤って削除されたか、再起動された場合。Kubernetes にはポッドを自動修復する機能があるため、デプロイによってポッドが確実に戻されます。
  2. 自動ロールアウトとロールバック: ローリング アップデートによって実現できます。ローリング アップデートは、実行中のアプリのバージョンをアップデートするためのデフォルトの戦略です。以前のポッドのサイクルを更新し、新しいポッドを段階的に取り込みます。導入された変更によって本番環境が中断された場合は、その変更をロールバックする計画が必要です。Kubernetes と kubectl は、デプロイなどのリソースへの変更をロールバックするためのシンプルなメカニズムを提供します。
  3. Helmサポートでデプロイを容易にする: Helm は、Kubernetes アプリケーションのインストールと管理を合理化するツールです。Kubernetes アプリケーションの管理に役立ちます。Helm Chart は、最も複雑な Kubernetes アプリケーションでさえも定義、インストール、アップグレードするのに役立ちます。FogFlow ドキュメントは、Kubernetes 環境を十分に理解してアクセスできるように、上記の機能の機能の詳細で更新されます。

FogFlow K8s インテグレーションの制限

以下は、FogFlow Kubernetes ンテグレーションのいくつかの制限です。これらの制限は、将来 FogFlow で実装される予定です。

  1. FogFlow ワーカーが起動するタスク インスタンスはポッドに実装されていません。K8s ポッドを介した起動タスク インスタンスの移行は、FogFlow OSS の将来の範囲に含まれます。
  2. FogFlow Edge ノード K8s のサポート
  3. K8s 環境のセキュリティとネットワークポリシー
  4. Taints と Trait
  5. パフォーマンス評価
  6. その他の機能

Kubernetes の FogFlow クラウド アーキテクチャ図

figures/k8s-architecture.png

Dgraph、Discovery、Broker、Designer、Master、Worker、Rabbitmq などの FogFlow クラウド ノード コンポーネントは、クラスター ノードに分散されています。FogFlow コンポーネント間の通信とその動作は以前と同じであり、ワーカー ノードは Docker コンテナーでタスクインスタンスを起動します。

こちら here のリンクをたどって、Kubernetesコンポーネントがどのように機能するかを確認してください。

K8s で FogFlow を実行するための前提条件コマンドは次のとおりです。

  1. docker
  2. Kubernetes
  3. Helm

重要

ユーザーが sudo なしで Docker コマンドを実行できるようにしてください。

Kubernetes をインストールするには、Kubernetes Official Site を参照する か、代替の Install Kubernetes を確認してください。

Helm をインストールするには、Install Helm`_ を参照してください。

K8s 環境に FogFlow クラウド コンポーネントをデプロイ

Dgraph、Discovery、Broker、Designer、Master、Worker、Rabbitmq などの FogFlow クラウド ノード コンポーネントは、クラスター ノードに分散されています。FogFlow コンポーネント間の通信とその動作は通常どおりであり、ワーカー ノードは Docker コンテナーでタスク インスタンスを起動します。

必要なすべてのスクリプトを取得します

以下のように、Kubernetes ファイルと構成ファイルをダウンロードします。

# the Kubernetes yaml file to start all FogFlow components on the cloud node
wget https://raw.githubusercontent.com/smartfog/fogflow/master/helm/fogflow-chart

# the configuration file used by all FogFlow components
wget https://raw.githubusercontent.com/smartfog/fogflow/master/yaml/config.json

# the configuration file used by the nginx proxy
wget https://raw.githubusercontent.com/smartfog/fogflow/master/yaml/nginx.conf

環境に応じて IP 構成を変更します

ご使用の環境に応じて、config.json で以下の IP アドレスを変更する必要があります。

  • coreservice_ip: すべての FogFlow エッジ ノードが FogFlow クラウド ノードのコア サービス (ポート80 の nginx やポート5672のrabbitmq など) にアクセスするために使用します。通常、これは FogFlow クラウドノードのパブリック IP になります。
  • external_hostip: FogFlow クラウド ノードの構成の場合、これは、実行中の FogFlow コア サービスにアクセスするためにコンポーネント (CloudWorker および CloudBroker) によって使用される coreservice_ip と同じです。
  • internal_hostip: これはデフォルトの K8s ネットワーク インターフェースの IP であり、Linux ホストの "cni0" ネットワークインターフェースです。
  • site_id: 各 FogFlow ノード (クラウド ノードまたはエッジ ノード) は、システム内でそれ自体を識別するために、一意の文字列ベースの ID を持っている必要があります。
  • physical_location: FogFlow ノードの地理的位置 (geo-location)
  • worker.capacity: FogFlow ノードが呼び出すことができる Docker コンテナーの最大数を意味します。

values.yaml ファイルを変更

  • 要件に従って名前空間 (namespace) を編集します。必要なreplicaCount 数を追加します。
  • 環境 hostPath に従って、values.yaml ファイルの dgraph、configJson、および nginxConf パスを変更します。
  • 環境に応じて externalIP を変更します。
#Kubernetes namespace of FogFlow components
namespace: default

#replicas will make sure that no. of replicaCount mention in values.yaml
#are running all the time for the deployment
replicaCount: 1

serviceAccount:
#Specifies whether a service account should be created
  create: true
#Annotations to add to the service account
  annotations: {}
#The name of the service account to use.
#If not set and create is true, a name is generated using the fullname template
  name: ""

#hostPath for dgraph volume mount
dgraph:
  hostPath:
    path: /mnt/dgraph

#hostPath for config.json
configJson:
  hostPath:
    path: /home/necuser/fogflow/helm/files/fogflow-chart/config.json

#hostPath for nginx.conf
nginxConf:
  hostPath:
    path: /home/necuser/fogflow/fogflow/yaml/nginx.conf

#External IP to expose cluster
Service:
 spec:
  externalIPs:
  - XXX.XX.48.24

Helm Chart を使用してすべての Fogflow コンポーネントを開始

Helm-Chart フォルダーの外部から Helm コマンドを実行して、FogFlow コンポーネントを起動します。ここでは helm-chart 名は "fogflow-chart" です。

コマンドラインから設定を渡すには、helm install コマンドで "--set" フラグを追加します。

helm install ./fogflow-chart --set externalIPs={XXX.XX.48.24} --generate-name

詳細については、Helmの公式 link_ を参照してください。

セットアップを検証

FogFlow クラウド ノードが正しく開始されているかどうかを確認するには、次の2つの方法があります:

  • "kubectl get pods --namespace = <namespace_name>" を使用して、すべてのポッドが稼働していることを確認します
 kubectl get pods --namespace=fogflow


NAME                           READY   STATUS              RESTARTS   AGE
cloud-broker-c78679dd8-gx5ds   1/1     Running             0          8s
cloud-worker-db94ff4f7-hwx72   1/1     Running             0          8s
designer-bf959f7b7-csjn5       1/1     Running             0          8s
dgraph-869f65597c-jrlqm        1/1     Running             0          8s
discovery-7566b87d8d-hhknd     1/1     Running             0          8s
master-86976888d5-drfz2        1/1     Running             0          8s
nginx-69ff8d45f-xmhmt          1/1     Running             0          8s
rabbitmq-85bf5f7d77-c74cd      1/1     Running             0          8s
  • FogFlow DashBoard からシステムステータスを確認します

システムステータスは、Web ブラウザの FogFlow ダッシュボードから確認して、次の URL で現在のシステム ステータスを確認することもできます: http://<coreservice_ip>/index.html

モニタリング

Fogflow システムの状態は、システム監視ツールの Metricbeat、Elasticsearch、Grafana つまり EMG によって監視できます。これらのツールを使用すると、エッジと Fogflow Docker サービスの状態を監視できます。エッジノードにデプロイされた Metricbeat。クラウド ノードにデプロイされた Elasticsearch と Grafana。

次の図に示すように、FogFlow システム監視ツールを設定して、システムリソースの使用状況を監視します。

figures/Fogflow_System_Monitoring_Architecture.png

Grafana ダッシュボードで Elasticsearch を構成

Grafana ダッシュボード はWeb ブラウザーからアクセスでき、URL: http:///<output.elasticsearch.hosts>:3003/ を介して現在のシステム ステータスを確認できます 。Grafana ログインのデフォルトのユーザー名とパスワードは、それぞれ admin と admin です。

  • grafana に正常にログインしたら、ホーム ダッシュボードの "Create your first data source" をクリックして、データソースを設定します。
  • Add Data Source ページからElasticsearch を選択します。これで、下の図と同じページの Data Sources/Elasticsearch が表示されます。
figures/Elastic_config.png
  1. データソースに名前を付けます。
  2. HTTP の詳細で、elasticsearch とポートの URL に言及します。URL には HTTP を含める必要があります。
  3. Access で Server(default) を選択します。URL は、Grafana バックエンド/サーバーからアクセスできる必要があります。
  4. Elasticsearch の詳細で、Time フィールド名に @timestamp を入力します。ここで、時間フィールドのデフォルトを Elasticsearch インデックスの名前で指定できます。インデックス名またはワイルドカードには時間パターンを使用します。
  5. Elasticsearch バージョンを選択します。

次に、"Save & Test" ボタンをクリックします。

Metricbeat を設定

  • 以下のように、metricbeat.docker.yml ファイルの Elasticsearch の詳細を変更します:

Fogflow システムの状態は、システム監視ツールの Metricbeat、Elasticsearch、Grafana、つまり EMG によって監視できます。これらのツールを使用すると、エッジとFogflow Docker サービスの状態を監視できます。エッジノードにデプロイされた Metricbeat。クラウド ノードにデプロイされた Elasticsearch と Grafana。

次の図に示すように、FogFlow システム監視ツールを設定して、システムリソースの使用状況を監視します。

figures/Fogflow_System_Monitoring_Architecture.png

1台のマシンですべての FogFlow コンポーネントをセットアップ

必要なすべてのスクリプトを取得

以下のように docker-compose ファイルと構成ファイルをダウンロードします。

# the docker-compose file to start all FogFlow components on the cloud node
wget https://raw.githubusercontent.com/smartfog/fogflow/master/docker/core/http/docker-compose.yml

# the configuration file used by all FogFlow components
wget https://raw.githubusercontent.com/smartfog/fogflow/master/docker/core/http/config.json

# the configuration file used by the nginx proxy
wget https://raw.githubusercontent.com/smartfog/fogflow/master/docker/core/http/nginx.conf

# the configuration file used by metricbeat
wget https://raw.githubusercontent.com/smartfog/fogflow/master/docker/core/http/metricbeat.docker.yml

環境に応じてelasticsearchとmetricbeatのIP構成を変更

ご使用の環境に応じて、docker-compose.yml の次の IP アドレスを変更する必要があります。

  • output.elasticsearch.hosts: これは、metricbeat が csv 形式でデータを共有する elasticsearch のホストの場所です。

また、ご使用の環境に応じて、metricbeat.docker.yml の次の IP アドレスを変更する必要があります。

  • name: これは、Grafana メトリック ダッシュボードのエッジ ノードからのクラウド ノードの一意性に付けられた名前です。IP アドレスの代わりに任意の名前を指定できます。
  • hosts: metricsearh データベースのホストの場所であり、metricbeat がメトリックデータを共有します。

Grafana ベースのモニタリング

FogFlow クラウドのメトリックとエッジ ノードをグラフィック形式で監視するには、ダッシュボードを設定する必要があります。システム リソースを監視するための基本的な Grafana 視覚化ダッシュボード設定の例を次に示します。

  • 次の図は、メモリ使用量が最大のコンテナー リストのダッシュボードを設定する手順を示しています。
_images/Container_max_memory_usage.png
  1. Elasticsearch のクエリを作成するには、ドロップダウンリストから Query: Metrics: Average(docker.memory.usage.max), Group by: Terms(host.name), Terms(container.image.name), Date Histogram(@timestamp) を選択します。
  2. ドロップダウンから Visualization select Graph をクリックします。Draw Modes (Lines), Mode Options(Fill:1,Fill Gradient:0,Line Width:2), Stacking & Null value(Null value:connected) Axes- Left Y(Unit:bytes,Scale:linear), Right Y(Unit:short,Scale:linear), X-Axis(Mode:Time) Legend- Options(Show,As Table,To the right), Values(Max)
  3. General Title: Container memory usage max, をクリックし、説明がある場合は説明を入力します。
  • 次の図は、使用されているシステム メモリをバイト単位で表示するようにダッシュボードを設定する手順を示しています。
_images/System_Memory_Gauge.png
  1. Elasticsearch のクエリを作成するには、ドロップダウンリストから、Query: memory, Metrics: Average(system.memory.actual.used.bytes), Group by: Terms(host.name), Date Histogram(@timestamp) を選択します。
  2. ドロップダウンから Visualization select Gauge をクリックします。 Display (Show:Calculation, Calc:Last(not null), Labels, Markers), Field (Unit:bytes, Min:0, Max:100), Thresholds (50 (yellow), base (green)
  3. General Title: System memory used in bytes をクリックし、説明がある場合は説明を入力します。
  • 次の図は、ダッシュボードをセットアップして、システム メトリック データレートをパケット/秒で表示する手順を示しています。
_images/System_Metric_filter.png
  1. Elasticsearch のクエリを作成するには、ドロップダウンリストから、Query: Metrics: Average(system.memory.actual.used.bytes), Group by: Terms(agent.name), Date Histogram(@timestamp) を選択します。
  2. ドロップダウンから Visualization select Graph をクリックします。Draw Modes (Lines), Mode Options(Fill:1,Fill Gradient:0,Line Width:2), Hover tooltip(Mode: All series, Sort order:Increasing), Stacking & Null value(Null value:connected). Axes- Left Y(Unit:packets/sec, Scale:linear), Right Y(Unit:packets/sec, Scale:linear), X-Axis(Mode:Time) Legend- Options(Show,As Table,To the right), Values(Avg)
  3. General Title: System Metric filter をクリックし、説明がある場合は説明を入力します。
  • 次の図は、ライブの FogFlow クラウド ノードとエッジ ノードを表示するダッシュボードを設定する手順を示しています.
_images/Fogflow_Cloud_Edge_Nodes.png
  1. Elasticsearch のクエリを作成するには、ドロップダウンリストから、Query: Metrics: Count(), Group by: Terms(agent.name), Date Histogram(@timestamp) を選択します。
  2. ドロップダウンから Visualization select Graph をクリックします。Draw Modes (Lines), Mode Options(Fill:1,Fill Gradient:0,Line Width:2). Axes- Left Y(Unit:bytes, Scale:linear), Right Y(Unit:short, Scale:linear), X-Axis(Mode:Time). Legend- Options(Show, As Table, To the right), Values(Avg, Max).

Grafana ダッシュボードで Elasticsearch を構成

Grafana ダッシュボードは Web ブラウザーからアクセスでき、URL: http:///<output.elasticsearch.hosts>:3003/ を介して現在のシステム ステータスを確認できます 。Grafana ログインのデフォルトのユーザー名とパスワードは、それぞれ admin と admin です。

  • Grafana に正常にログインしたら、ホーム ダッシュボードの "Create your first data source" をクリックして、データソースを設定します。
  • Add Data Source ページから Elasticsearch を選択します。これで、下の図と同じページの Data Sources/Elasticsearch が表示されます。
figures/Elastic_config.png
  1. データソースに名前を付けます。
  2. HTTP の詳細で、elasticsearch とポートの URL に言及します。URL には HTTP を含める必要があります。
  3. Access で Server(default) を選択します。URL は、Grafana バックエンド/サーバーからアクセスできる必要があります。
  4. Elasticsearch の詳細で、Time フィールド名に @timestamp を入力します。ここで、Time フィールドのデフォルト をElasticsearch インデックスの名前で指定できます。インデックス名またはワイルドカードには時間パターンを使用します。
  5. Elasticsearch バージョンを選択します。

次に、"Save & Test" ボタンをクリックします。

Metricbeatを設定

  • 以下のように、metricbeat.docker.yml ファイルの Elasticsearch の詳細を変更します:

セキュリティ

HTTPS ベースの通信

クラウド エッジ通信を保護

FogFlow クラウド ノードと FogFlow エッジ ノード間の通信を保護するために、FogFlow は、主にクラウド ノードとエッジ ノード間、または2つのエッジ ノード間のデータ交換のために、NGSI9 および NGSI10 通信に HTTPS を使用するように構成できます。また、RabbitMQ で TLS を有効にすることで、トポロジー マスターとワーカー間の制御チャネルを保護できます。1つの FogFlow クラウド ノードと1つの FogFlow エッジ ノード間のデータ交換を保護するための導入手順です。

DNS サーバーを構成

次の図に示すように、HTTPS ベースの通信をサポートするように FogFlow を設定するには、FogFlow クラウド ノードと FogFlow エッジ ノードに独自のドメイン名が必要です。これは、署名された証明書をドメイン名に関連付ける必要があるためです。したがって、クラウド ノードとエッジ ノードの両方のドメイン名を解決するには、DNS サービスを使用する必要があります。 たとえば、freeDNS をこの目的に使用できます。

_images/https-setup.png

重要

クラウド ノードとエッジ ノードのドメイン名が適切に解決され、正しい IP アドレスが表示されることを確認してください。

FogFlow クラウド ノードを設定

必要なすべてのスクリプトを取得

以下のように docker-compose ファイルと構成ファイルをダウンロードします。

# download the script that can fetch all required files
wget https://raw.githubusercontent.com/smartfog/fogflow/master/docker/core/https/fetch.sh

# make this script executable
chmod +x fetch.sh

# run this script to fetch all required files
./fetch.sh

構成ファイルを変更

{
    "coreservice_ip": "cloudnode.fogflow.io",   #change this to the domain name of your own cloud node
    "external_hostip": "cloudnode.fogflow.io",  #change this to the domain name of your own cloud node
        ...
}

キーファイルと証明書ファイルを生成

# make this script executable
chmod +x key4cloudnode.sh

# run this script to fetch all required files
./key4cloudnode.sh  cloudnode.fogflow.io

クラウド ノードで FogFlow コンポーネントを起動

docker-compose up -d

セットアップを検証

docker ps

    CONTAINER ID      IMAGE                       COMMAND                  CREATED             STATUS              PORTS                                                 NAMES
    90868b310608      nginx:latest            "nginx -g 'daemon of…"   5 seconds ago       Up 3 seconds        0.0.0.0:80->80/tcp                                       fogflow_nginx_1
    d4fd1aee2655      fogflow/worker          "/worker"                6 seconds ago       Up 2 seconds                                                                 fogflow_cloud_worker_1
    428e69bf5998      fogflow/master          "/master"                6 seconds ago       Up 4 seconds        0.0.0.0:1060->1060/tcp                               fogflow_master_1
    9da1124a43b4      fogflow/designer        "node main.js"           7 seconds ago       Up 5 seconds        0.0.0.0:1030->1030/tcp, 0.0.0.0:8080->8080/tcp       fogflow_designer_1
    bb8e25e5a75d      fogflow/broker          "/broker"                9 seconds ago       Up 7 seconds        0.0.0.0:8070->8070/tcp                               fogflow_cloud_broker_1
    7f3ce330c204      rabbitmq:3              "docker-entrypoint.s…"   10 seconds ago      Up 6 seconds        4369/tcp, 5671/tcp, 25672/tcp, 0.0.0.0:5672->5672/tcp     fogflow_rabbitmq_1
    9e95c55a1eb7      fogflow/discovery       "/discovery"             10 seconds ago      Up 8 seconds        0.0.0.0:8090->8090/tcp                               fogflow_discovery_1
    399958d8d88a      grafana/grafana:6.5.0   "/run.sh"                29 seconds ago      Up 27 seconds       0.0.0.0:3003->3000/tcp                               fogflow_grafana_1
    9f99315a1a1d      fogflow/elasticsearch:7.5.1 "/usr/local/bin/dock…" 32 seconds ago    Up 29 seconds       0.0.0.0:9200->9200/tcp, 0.0.0.0:9300->9300/tcp       fogflow_elasticsearch_1
    57eac616a67e      fogflow/metricbeat:7.6.0 "/usr/local/bin/dock…"   32 seconds ago     Up 29 seconds                                                                  fogflow_metricbeat_1

FogFlow エッジ ノードを設定

必要なすべてのスクリプトを取得

以下のように docker-compose ファイルと構成ファイルをダウンロードします。

# download the script that can fetch all required files
wget https://raw.githubusercontent.com/smartfog/fogflow/master/docker/edge/https/fetch.sh

# make this script executable
chmod +x fetch.sh

# run this script to fetch all required files
./fetch.sh

構成ファイルを変更

{
    "coreservice_ip": "cloudnode.fogflow.io",   #change this to the domain name of your own cloud node
    "external_hostip": "edgenode1.fogflow.io",  #change this to the domain name of your own edge node
        ...
}

キーファイルと証明書ファイルを生成

# make this script executable
chmod +x key4edgenode.sh

# run this script to fetch all required files
./key4edgenode.sh  edgenode1.fogflow.io

エッジ ノードで FogFlow コンポーネントを開始

docker-compose up -d

セットアップを検証

docker ps

CONTAINER ID        IMAGE               COMMAND             CREATED              STATUS              PORTS                                      NAMES
16af186fb54e        fogflow/worker      "/worker"           About a minute ago   Up About a minute                                              https_edge_worker_1
195bb8e44f5b        fogflow/broker      "/broker"           About a minute ago   Up About a minute   0.0.0.0:80->80/tcp, 0.0.0.0:443->443/tcp   https_edge_broker_1

FogFlow ダッシュボードを介してシステム ステータスを確認

FogFlow ダッシュボードを Web ブラウザーで開いて、次の URL を介して現在のシステム ステータスを確認できます: https://cloudnode.fogflow.io/index.html

重要

クラウド ノードのドメイン名が適切に解決できることを確認してください。

自己署名 SSL 証明書が使用されている場合、ブラウザの警告表示は、証明書が信頼されるべきではないことを示しています。この警告を超えて進むと、https 経由で FogFlow ダッシュボードの Web ページを表示できます。

ID 管理 (Identity Management) を使用した安全な FogFlow

ID 管理 (IdM) は、いくつかの認証トークンを確立された ID に関連付けることにより、アプリケーションまたはシステムにアクセスできる個人またはグループを識別、認証するためのプロセスです。IdM は、ユーザーまたはアプリケーションに関するデータを制御するタスクです。このチュートリアルでは、FogFlow Designer のセキュリティ実装と安全な Cloud-Edge 通信について説明およびテストします。

用語

Keyrock: Keyrock は、ID 管理を担当する FIWARE コンポーネントです。Keyrock は、サービスとアプリケーションを保護するために、OAuth2 ベースの認証と承認のセキュリティを追加する機能も提供します。

PEP Proxy Wilma: PEP Proxy Wilma は、ID 管理のパフォーマンスを向上させる FIWARE Generic Enabler です。Keyrock と組み合わせて、FIWARE Generic Enabler によって公開されているエンドポイントへのアクセスを保護します。Wilma はリクエストをリッスンし、Keyrock から認証して、限られた期間キャッシュに保存します。新しいリクエストが到着すると、Wilma は最初にキャッシュをチェックインし、許可が保存されている場合は直接認証します。それ以外の場合は、認証のためにリクエストを Keyrock に送信します。

セキュリティ アーキテクチャ

_images/Integrated_Security.png

IDMとのクラウドとエッジの相互作用

FogFlow クラウド ノード フロー:

  1. アーキテクチャ図のように、PEP Proxy は FogFlow Designer に代わって最初に Keyrock に登録します。詳細な説明は、このチュートリアルの以下 (below) のトピックに記載されています。
  2. ユーザーは、Reaquest ヘッダーの PEP Proxy のアクセス トークンを使用して、PEP Proxy のプロキシ経由で Designer にアクセスできます。

FogFlow エッジ ノードフロー:

  1. エッジノードに代わって、PEP Procy の1つのインスタンスが Keyrock に事前登録され、エッジは oauth 資格情報を使用して PEP Proxy の詳細をフェッチします。詳細な説明>は、このチュートリアルの以下のトピックに記載されています。ここ here をクリックして参照してください
  2. 認証後、エッジ ノードは FogFlow クラウド ノードと通信できるようになります。
  3. すべてのデバイスは、Keyrock に登録されている各 IoT デバイスに代わって生成されたアクセス トークンを使用して、自身を登録するか、FogFlow エッジノードと通信できます

インストール

# the docker-compose file to start security components on the cloud node
wget https://raw.githubusercontent.com/smartfog/fogflow/master/docker/core/http/docker-compose.idm.yml

# the configuration file used by IdM
wget https://raw.githubusercontent.com/smartfog/fogflow/master/docker/core/http/idm_config.js

# the configuration file used by PEP Proxy
wget https://raw.githubusercontent.com/smartfog/fogflow/master/docker/core/http/pep_config.js

IP構成を変更

設定ファイルは、以下の場所でユーザー自身の環境に応じた IP アドレスで変更する必要があります。

  • docker-compose.idm.yml ファイルの PEP Proxy ホスト ポートとコンテナー ポートを変更します。
  • 環境に応じて、以下の場所で IdM 構成ファイルを変更します。
config.port = 3000;
config.host = "http://<IdM IP>:" + config.port;

config.database = {
    host: "localhost",
    password: "idm",
    username: "root",
    database: "idm",
    dialect: "mysql",
    port: undefined
};

すべてのセキュリティ コンポーネントを起動します:

docker-compose -f docker-compose.idm.yml up -d

#Check all the containers are Up and Running using "docker ps -a"
 docker ps -a

クラウド ノードにセキュリティ コンポーネントをセットアップ

以下は、ID 管理のコンポーネント間の通信をセットアップするために実行する必要のある手順です。

ステップ1: Keyrock Identity Management を使用してPEP Proxy 自体を認証します。

_images/keyrock_Account_Portal.png
Keyrock (http://180.179.214.135:3000/idm/) アカウントにユーザー資格情報 (電子メールとパスワード) でログインします。
例: admin@test.com および 1234.

ログイン後、“Applications”、”FogFLow PEP” の順にクリックします。 "PEP Proxy" リンクをクリックして、Application ID、PEP Proxy のユーザー名、および PEP Proxy のパスワードを取得します。

注意: Application ID、PEP Proxy のユーザー名、および PEP Proxy のパスワードは、‘Register PEP Proxy’ ボタンをクリックすると生成されます。

Designer を保護するために PEP Proxy を設定するには、pep_config ファイル内で以下を変更します。アプリケーションの登録中に、Keyrock ダッシュボードから PEP Proxy 資格情報を取得します。

config.pep_port = process.env.PEP_PROXY_PORT || 80;
config.idm = {
  host: process.env.PEP_PROXY_IDM_HOST || '180.179.214.135',
  port: process.env.PEP_PROXY_IDM_PORT || 3000,
  ssl: toBoolean(process.env.PEP_PROXY_IDM_SSL_ENABLED, false),
};
config.app = {
  host: process.env.PEP_PROXY_APP_HOST || '180.179.214.135',
  port: process.env.PEP_PROXY_APP_PORT || ’80’,
  ssl: toBoolean(process.env.PEP_PROXY_APP_SSL_ENABLED, false), // Use true if the app server listens in https
};

config.pep = {
  app_id: process.env.PEP_PROXY_APP_ID || '9b51b184-808c-498c-8aac-74ffedc1ee72',
  username: process.env.PEP_PROXY_USERNAME || 'pep_proxy_4abf36da-0936-46f9-a7f5-ac7edb7c86b6',
  password: process.env.PEP_PASSWORD || 'pep_proxy_fb4955df-79fb-4dd7-8968-e8e60e4d6159',
  token: {
      secret: process.env.PEP_TOKEN_SECRET || '', // Secret must be configured in order validate a jwt
  },
  trusted_apps: [],
};

上記の変更後、PEP Proxy コンテナーを再起動します。

Application Access Tokenを生成

ステップ2: Keyrock IDM に、アプリケーション アクセス トークン と リフレッシュ トークンを生成するように要求します。

  1. 以下のスクリーンショットに従って、HTTP リクエストのヘッダー、ペイロード、および承認フィールドを設定します。
  2. "Send" ボタンをクリックして、application access-token を取得します。
_images/detailDescriptionofSampleRequest.png

注意: ‘Oauth2 Credentials’ の下の Keyrock ダッシュボードから Client ID および Client Secret を取得します。

クラウド セキュリティの実装の流れは、下図からわかります。

_images/architectureDiagram.png

以下は、上記のアーキテクチャ図に関連するいくつかのポイントです:

  1. Keyrock のアプリケーションとしてデザイナー用の PEP Proxy を登録します。
  2. Keyrock はアクセス トークンを PEP Proxy に送信します。
  3. そのトークンを使用して、ユーザーはエンティティの作成リクエストをデザイナーに送信します。
  4. Designer は認証のためにトークンを Keyrock に送信します。
  5. エンティティ作成リクエストは FogFlow に転送されます。

token_access を使用したエンティティ登録

   curl -iX POST   'http://<Cloud_Public_IP>:<PEP_Host-port>/ngsi10/updateContext'  -H 'X-Auth-Token: <token>'  -H 'Content-Type: application/json'
-d '
 {
   "contextElements": [
     {
      "entityId": {
         "id": "Temperature100",
         "type": "Temperature",
         "isPattern": false
     },
      "attributes": [
         {
         "name": "temp",
         "type": "float",
         "value": 34
         }
       ],
      "domainMetadata": [
        {
         "name": "location",
         "type": "point",
         "value": {
           "latitude": 49.406393,
           "longitude": 8.684208
          }
        }
       ],
    "updateAction": "UPDATE"
    }
  ]
 }'

Edge でコンポーネントをセットアップ

FogFlow エッジノードには、主にエッジ ブローカーとエッジ ワーカーが含まれます。Iot デバイスとエッジノード間の FogFlow エッジ通信を保護するために、PEP Proxy が使用されています。Auth Token を作成するには、最初に IoT デバイスを Keyrock に登録します。そのため、スクリプトはエッジノードの開始時に呼び出し、Keyrock を使用してPEP Proxy をインスタンス化し、Keyrock API を使用して PEP Proxy が機能するように構成ファイルをセットアップします。スクリプトは次の手順を実行します。

前提条件

エッジをセットアップする前に、2つのコマンドをインストールする必要があります:

  1. curl
  2. jq

スクリプトのインストール

以下のスクリプトは、エッジ ノードを設定するためにダウンロードする必要があります。

#download the deployment scripts
wget https://raw.githubusercontent.com/smartfog/fogflow/development/docker/edge/http/start.sh
wget https://raw.githubusercontent.com/smartfog/fogflow/development/docker/edge/http/stop.sh
wget https://raw.githubusercontent.com/smartfog/fogflow/development/docker/edge/http/script.sh
wget https://raw.githubusercontent.com/smartfog/fogflow/development/docker/edge/http/oauth_config.js
wget https://raw.githubusercontent.com/smartfog/fogflow/development/docker/edge/http/pep-config.js

#make them executable
chmod +x script.sh start.sh stop.sh

IP構成を変更

構成ファイルで次のものを変更します:

  • oauth_config.js を変更し、PEP Proxy の構成設定を取得するために必要な IdM IP、エッジ IP を追加します

エッジ ノード コンポーネントを開始

#start components in the same script
./start.sh

FogFlow edge-IoT デバイスを保護するために、通信 認証トークンが各 IoT デバイスに代わって使用されています。認証トークンを作成するには、

  • KeyrockにIoTデバイスを登録する必要があります
  • スクリプトはエッジ ノードの開始時に呼び出され、Keyrock API を使用してそのエッジ ノードに代わって Keyrock で PEP Proxy を構成します

Note: start.sh スクリプトは、Application ID, Application Secret, PEP Proxy ID, PEP Proxy Secret, Authorization code, IDM Token およびコンソール上の Access token を返します。今後の使用のためにこれらを保存してください。

FogFlow との IoT デバイスの相互作用

figures/architectureDiagram1.png

図に示すリクエストのフロー:

ステップ 1 : ユーザーは自分の資格情報を使用して IDMに リクエストを送信し、そのユーザーに固有の ユーザー アクセス トークン (User Access Token) を生成します。このために、ユーザーは自分のユーザー名とパスワードとともにスクリプトを使用できます。

./user_token_generation.sh admin@test.com 1234

Note: たとえば、上記のスニペットでは、管理者のユーザー名は "admin@test.com"、パスワードは "1234" です

ステップ 2 : スクリプトは、以下に示すようにユーザー アクセス トークンを返します

figures/user_token.png

ステップ 3 : ユーザーは自分のアクセス トークン (つまり、ユーザー アクセス トークン) を IoT デバイスと共有します

ステップ 4 : 次に、スクリプトへの引数として渡された ユーザー アクセス トークンを使用して IoT デバイスが登録されます

./device_token_generation.sh f9ffa629-9aff-4c98-ac57-1caa2917fed2

Note: たとえば、上記のスニペットでは、"f9ffa629-9aff-4c98-ac57-1caa2917fed2" がユーザーアクセストークンです

ステップ 5 : スクリプトは、以下に示すように、デバイス アクセス トークンとデバイス資格情報 (ID とパスワード) を返します

figures/device_token.png

ステップ 6 : これで、上記のデバイス アクセス トークンを使用して、IoT デバイスは PEP Proxy ポートに Fogflow 固有のリクエストを行うことでエッジノードと対話できます

curl リクエストを使用して Keyrock に IoT デバイスを登録

IoT デバイスを登録するリクエストの例を以下に示します

 curl --include \
   --request POST \
   --header "Content-Type: application/json" \
   --header "X-Auth-token: <token-generated-from-script>" \
'http://keyrock/v1/applications/6e396def-3fa9-4ff9-84eb-266c13e93964/iot_agents'

Note: 後で利用するために、デバイス ID とデバイス パスワードを保存してください

figures/keyrock_iot.png

登録された IoT センサーごとに認証トークンを生成するリクエストの例を以下に示します。

curl -iX POST \
 'http://<IDM_IP>:3000/oauth2/token' \
 -H 'Accept: application/json' \
 -H 'Authorization: Basic <code-generated-from-script>' \
 -H 'Content-Type: application/x-www-form-urlencoded' \
 --data "username=iot_sensor_02bc0f75-07b5-411a-8792-4381df9a1c7f&password=iot_sensor_277bc253-5a2f-491f-abaa-c7b4e1599d6e&grant_type=password"

Note: 後で利用するために、アクセス トークンを保存してください

figures/keyrock_token.png

curl リクエストを使用してエッジ ノードにデバイスを登録

登録デバイスのペイロードの例を以下に示します。

Curl -iX POST 'http://<Application_IP>:<Application_Port>/NGSI9/registerContext' -H 'Content-Type: application/json' -H 'fiware-service: openiot' -H 'X-Auth-token: <token-generated-for-IoT-device>' -H 'fiware-servicepath: /' -d '
 {
     "contextRegistrations": [
         {
             "entities": [
                 {
                     "type": "Lamp",
                     "isPattern": "false",
                     "id": "Lamp.0020"
                 }
             ],
             "attributes": [
                 {
                     "name": "on",
                     "type": "command"
                 },
                 {
                     "name": "off",
                     "type": "command"
                 }
             ],
             "providingApplication": "http://0.0.0.0:8888"
         }
     ],
   "duration": "P1Y"
 }'

エッジ ノード コンポーネントの停止

  • 以下のスクリプトを使用して、ブローカーおよびワーカーであるエッジ コンポーネントを停止します
#stop all components in the same script
./stop.sh

システム デザイン

コンポーネントの概要

システム アーキテクチャー

FogFlow フレームワークは、クラウド ノード、エッジ ノード、IoT デバイスを含む、地理的に分散した階層型の異種 ICT インフラストラクチャで動作します。次の図は、FogFlow のシステム アーキテクチャと、3つの論理レイヤーにわたるその主要コンポーネントを示しています。

_images/architecture.png

3つのレイヤー

論理的には、FogFlow は次の3つのレイヤーで構成されています:

  • service management (サービス管理): サービス要件を具体的な実行プランに変換し、生成された実行プランをクラウドとエッジにデプロイします。
  • context management (コンテキスト管理): すべてのコンテキスト情報を管理し、柔軟なクエリおよびサブスクライブ インターフェイスを介してそれらを検出およびアクセスできるようにします。
  • data processing (データ処理): データ処理タスクを起動し、コンテキスト管理レイヤーによって提供される pub/sub インターフェイスを介してタスク間のデータ フローを確立します。

システム コンポーネント

クラウドにデプロイされる一元化されたサービス コンポーネント

  • Task Designer (タスク デザイナ): サービス プロバイダーがタスクとサービス トポロジーを指定、登録、および管理するための Web ベースのインターフェイスを提供します。
  • Topology Master (トポロジー マスター): いつ、どのタスクをインスタンス化する必要があるかを把握し、それらを動的に構成し、クラウドとエッジのどこにデプロイするかを決定します。
  • IoT Discovery: ID、エンティティ タイプ、属性リスト、メタデータなど、レジストレーションされているすべてのコンテキスト可用性情報を管理します。他のコンポーネントが NGSI9 を介して関心のあるコンテキスト可用性情報をクエリおよびサブスクライブできるようにします。

クラウドとエッジの両方にデプロイされる分散コンポーネント

  • Worker (ワーカー): トポロジー マスターからの割り当てに従って、各ワーカーはローカル ホストの Docker コンテナーでスケジュールされたタスク インスタンスを起動します。入力と出力を構成し、タスクの優先度に基づいてすべてのタスク インスタンスをローカルで管理します。
  • IoT Broker: 各ブローカーは、近くの IoT デバイスによって公開されたコンテキスト エンティティの一部を管理し、IoT デバイスが必要なエンティティをクエリしてサブスクライブするためのすべてのコンテキスト エンティティの単一のビューも提供します。

FogFlow で使用される外部サービスコンポーネント

  • Dock Registry: 開発者が提供するすべての Docker イメージを管理。
  • RabbitMQ: トポロジー マスターとワーカー間の内部通信。
  • PostgreSQL: レジストレーションされたコンテキストの可用性情報を保存するためのバックエンド データベース

プログラミング モデル

Intent ベースのプログラミング モデル

現在、次の2つのプログラミング モデルが FogFlow によって提供されており、さまざまなタイプのワークロード パターンをサポートしています。

サービス トポロジー

最初のワークロード パターンは、必要な処理フローをトリガーして、出力データがコンシューマーによって要求された場合にのみ出力データを生成することです。このパターンに基づいて IoT サービスを定義するには、サービス プロバイダーは、リンクされたオペレーターのセットで構成されるサービス トポロジーを定義する必要があり、各オペレーターには特定の粒度で注釈が付けられます。FogFlow は、オペレーターの粒度を考慮して、使用可能なデータに基づいて、そのようなオペレーターのタスク インスタンスをインスタンス化する必要がある数を決定します。

サービス トポロジーは、コンシューマーまたは任意のアプリケーションによって発行されたインテント オブジェクト (Intent object) によって明示的にトリガーされる必要があります。インテント オブジェクトは、(優先度に基づいて) サービス トポロジーをトリガーする必要がある時期を定義します。また、オプションで特定のジオスコープを定義して、トリガーされた処理ロジックを適用するためのデータソースを除外することもできます。インテント条件 (Intent conditions) を満たすサービストポロジーの一部がトリガーされ、入力データが利用可能になります。

_images/service-topology-concept.png

フォグ ファンクション (Fog Function)

2番目のワークロード パターンは、サービス設計者がストリーム処理ステップの正確なシーケンスを事前に知らないシナリオ向けに設計されています。代わりに、特定のタイプの情報を処理するための特定のオペレーターを含めるようにフォグ ファンクションを定義できます。FogFlow は、すべてのフォグ ファンクションのこの説明に基づいて、処理フローのグラフを作成できます。サービストポロジーとは異なり、フォグ ファンクションはオペレーターが1人だけの非常に単純なトポロジーであり、入力データが利用可能になるとトリガーされます。FogFlowは、さまざまなフォグ ファンクションを自動的にチェーンし、複数のフォグ ファンクションが新しいデータ アイテムを処理できるようにするため、データの到着と消失時に、絶えず変化する実行グラフを FogFlow ランタイムによって自動的にトリガーおよび管理できます。デザインの観点から、フォグ ファンクションはサービス トポロジーよりも柔軟性があります。これは、サービス処理ロジックを新しいビジネス要件に合わせて変更する必要がある場合にフォグ ファンクションを追加または削除することで、IoT サービスの全体的な処理ロジックを時間の経過とともに簡単に変更できるためです。FogFlow は、フォグ ファンクション プログラミング モデルを使用して、クラウド エッジベースの環境でサーバーレス コンピューティングをサポートできます。

_images/function-orchestration.png

コンテキスト ドリブンのサービス オーケストレーション

FogFlow では、各ワーカーは、トポロジー マスターによって割り当てられた次の2種類の展開アクションを実行するエージェントです。

  • タスク インスタンスを開始/終了する。
  • 既存の実行中のタスク インスタンスに入力ストリームを追加/削除します。

たとえば、各ワーカーは次の手順を実行してタスク インスタンスを開始します。

  1. ワーカーは、ローカルの Docker engine に、指定されたリスニング ポート番号で新しいタスク インスタンスを実行するための新しいコンテナーを作成するように要求します。
  2. タスク インスタンスの実行が開始され、指定されたポート番号でリッスンして入力データ ストリームを受信します。
  3. ワーカーは、リスニング ポートを介して実行中のタスク インスタンスに構成オブジェクトを送信します。
  4. ワーカーは、実行中のタスク インスタンスに代わって NGSI10 サブスクリプションを発行します。
  5. 必要な入力データ ストリームは、実行中のタスク インスタンスに流れ込み、リスニング ポートを介してさらに処理されます。
  6. 実行中のタスク インスタンスは、受信した入力ストリームデータを処理し、その結果を生成します。
  7. 実行中のタスク インスタンスは、NGSI10 アップデートを送信することにより、生成された結果を出力として公開します。
_images/launching-task.png

分散コンテキスト管理 (Distributed context management)

コンテキスト管理システムは、すべてのシステム コンポーネントと実行中のタスク インスタンスにグローバル ビューを提供して、統合データモデルと通信プロトコル NGSI を介してコンテキスト エンティティをクエリ、サブスクライブ、およびアップデートするように設計されています。 これは、FogFlow で標準ベースのエッジ プログラミング モデルをサポートするために非常に重要な役割を果たします。MQTT ベースの Mosquitto や Apache Kafka などの他の既存のブローカーと比較すると、FogFlow の分散コンテキスト管理システムには次の機能があります:

  • コンテキストの可用性とコンテキスト エンティティを分離します。
  • コンテキスト データ (NGSI10 経由) とコンテキスト可用性 (NGSI9 経由) の両方を管理するための分離された標準化されたインターフェイスを提供します。
  • ID ベースおよびトピック ベースのクエリとサブスクリプションだけでなく、ジオスコープ ベースのクエリとサブスクリプションもサポートします

次の図に示すように、FogFlow では、グローバルで集中化された IoT Discovery の調整の下で、多数の分散型 IoT Broker が並行して動作します。

_images/distributed-brokers.png

IoT Discovery

一元化された IoT Discovery は、コンテキスト データのコンテキスト可用性のグローバルビューを提供し、コンテキスト可用性のレジストレーション、ディスカバリー、およびサブスクリプションのための NGSI9 インターフェイスを提供します。

IoT Broker

FogFlow の IoTBroker は、各コンテキスト エンティティの最新の値のみを保持し、各エンティティ データをシステムメモリに直接保存するため、非常に軽量です。これにより、コンテキスト プロデューサーからコンテキスト コンシューマーへのデータ転送に高スループットと低レイテンシーがもたらされます。

各 IoT Broker は、コンテキスト データの一部を管理し、データを共有 IoT Discovery に登録します。ただし、すべての IoT Broker は、共有 IoT Discovery を介してどの IoT Broker がエンティティを提供するかを見つけて、そのリモート IoT Broker からエンティティをフェッチできるため、NGSI10 を介して要求されたコンテキスト エンティティを等しく提供できます。

API ウォークスルー

FogFlow Discovery API

近くのブローカーを探す

外部アプリケーションまたは IoT デバイスの場合、FogFlow Discovery から必要な唯一のインターフェースは、自身の場所に基づいて近くのブローカーを見つけることです。その後、それらは割り当てられた近くのブローカーと対話する必要があるだけです。

POST /ngsi9/discoverContextAvailability

パラメーター 説明
latitude 場所 (location) の緯度
longitude 場所 (location)の緯度
limit 予想されるブローカーの数

以下の例を確認してください。

注釈

JavaScript のコード例では、ライブラリ ngsiclient.js が必要です。application/device/powerpanel のコード リポジトリを参照してください。

curl -iX POST \
  'http://localhost:80/ngsi9/discoverContextAvailability' \
  -H 'Content-Type: application/json' \
  -d '
    {
       "entities":[
          {
             "type":"IoTBroker",
             "isPattern":true
          }
       ],
       "restriction":{
          "scopes":[
             {
                "scopeType":"nearby",
                "scopeValue":{
                   "latitude":35.692221,
                   "longitude":139.709059,
                   "limit":1
                }
             }
          ]
       }
    } '
const NGSI = require('./ngsi/ngsiclient.js');

var discoveryURL = "http://localhost:80/ngsi9";
var myLocation = {
        "latitude": 35.692221,
        "longitude": 139.709059
    };

// find out the nearby IoT Broker according to my location
var discovery = new NGSI.NGSI9Client(discoveryURL)
discovery.findNearbyIoTBroker(myLocation, 1).then( function(brokers) {
    console.log('-------nearbybroker----------');
    console.log(brokers);
    console.log('------------end-----------');
}).catch(function(error) {
    console.log(error);
});

FogFlow Broker API

https://img.shields.io/swagger/valid/2.0/https/raw.githubusercontent.com/OAI/OpenAPI-Specification/master/examples/v2.0/json/petstore-expanded.json.svg

注釈

Cloud Broker へのアクセスにはポート 80 を使用しますが、Edge Broker の場合、デフォルトのポートは 8070 です。

コンテキストの作成/アップデート

注釈

コンテキスト エンティティを作成またはアップデートするのと同じ API です。コンテキスト アップデートの場合、既存のエンティティがない場合は、新しいエンティティが作成されます。

POST /ngsi10/updateContext

パラメーター 説明
latitude 場所 (location) の緯度
longitude 場所 (location)の緯度
limit 予想されるブローカーの数

例:

curl -iX POST \
  'http://localhost:80/ngsi10/updateContext' \
  -H 'Content-Type: application/json' \
  -d '
    {
        "contextElements": [
            {
                "entityId": {
                    "id": "Device.temp001",
                    "type": "Temperature",
                    "isPattern": false
                },
                "attributes": [
                {
                  "name": "temp",
                  "type": "integer",
                  "value": 10
                }
                ],
                "domainMetadata": [
                {
                    "name": "location",
                    "type": "point",
                    "value": {
                        "latitude": 49.406393,
                        "longitude": 8.684208
                    }
                },{
                    "name": "city",
                    "type": "string",
                    "value": "Heidelberg"
                }
                ]
            }
        ],
        "updateAction": "UPDATE"
    }'
const NGSI = require('./ngsi/ngsiclient.js');
var brokerURL = "http://localhost:80/ngsi10"

var ngsi10client = new NGSI.NGSI10Client(brokerURL);

var profile = {
        "type": "PowerPanel",
        "id": "01"};

var ctxObj = {};
ctxObj.entityId = {
    id: 'Device.' + profile.type + '.' + profile.id,
    type: profile.type,
    isPattern: false
};

ctxObj.attributes = {};

var degree = Math.floor((Math.random() * 100) + 1);
ctxObj.attributes.usage = {
    type: 'integer',
    value: degree
};
ctxObj.attributes.shop = {
    type: 'string',
    value: profile.id
};
ctxObj.attributes.iconURL = {
    type: 'string',
    value: profile.iconURL
};

ctxObj.metadata = {};

ctxObj.metadata.location = {
    type: 'point',
    value: profile.location
};

ngsi10client.updateContext(ctxObj).then( function(data) {
    console.log(data);
}).catch(function(error) {
    console.log('failed to update context');
});

GET を介したコンテキストのクエリ

ID でコンテキスト エンティティを取得

GET /ngsi10/entity/#eid

パラメーター 説明
eid エンティティ ID

例:

curl http://localhost:80/ngsi10/entity/Device.temp001
特定のコンテキスト エンティティの特定の属性を取得

GET /ngsi10/entity/#eid/#attr

パラメーター 説明
eid エンティティ ID
attr フェッチする属性名を指定

例:

curl http://localhost:80/ngsi10/entity/Device.temp001/temp
単一のブローカー上のすべてのコンテキスト エンティティを確認

GET /ngsi10/entity

例:

curl http://localhost:80/ngsi10/entity

POST を介してコンテキストをクエリ

POST /ngsi10/queryContext

パラメーター 説明
entityId 特定のエンティティ ID、ID pattern、またはタイプを定義できるエンティティ フィルターを指定
restriction スコープのリストと各スコープは、ドメイン メタデータに基づいてフィルターを定義
エンティティ ID のパターンによるコンテキストのクエリ
curl -X POST 'http://localhost:80/ngsi10/queryContext' \
  -H 'Content-Type: application/json' \
  -d '{"entities":[{"id":"Device.*","isPattern":true}]}'
const NGSI = require('./ngsi/ngsiclient.js');
var brokerURL = "http://localhost:80/ngsi10"
var ngsi10client = new NGSI.NGSI10Client(brokerURL);

var queryReq = {}
queryReq.entities = [{id:'Device.*', isPattern: true}];

ngsi10client.queryContext(queryReq).then( function(deviceList) {
    console.log(deviceList);
}).catch(function(error) {
    console.log(error);
    console.log('failed to query context');
});
エンティティ タイプによるコンテキストのクエリ
curl -X POST 'http://localhost:80/ngsi10/queryContext' \
  -H 'Content-Type: application/json' \
  -d '{"entities":[{"type":"Temperature","isPattern":true}]}'
const NGSI = require('./ngsi/ngsiclient.js');
var brokerURL = "http://localhost:80/ngsi10"
var ngsi10client = new NGSI.NGSI10Client(brokerURL);

var queryReq = {}
queryReq.entities = [{type:'Temperature', isPattern: true}];

ngsi10client.queryContext(queryReq).then( function(deviceList) {
    console.log(deviceList);
}).catch(function(error) {
    console.log(error);
    console.log('failed to query context');
});
ジオスコープ (geo-scope) によるコンテキストのクエリ (サークル)
curl -X POST 'http://localhost:80/ngsi10/queryContext' \
  -H 'Content-Type: application/json' \
  -d '{
        "entities": [{
            "id": ".*",
            "isPattern": true
        }],
        "restriction": {
            "scopes": [{
                "scopeType": "circle",
                "scopeValue": {
                   "centerLatitude": 49.406393,
                   "centerLongitude": 8.684208,
                   "radius": 10.0
                }
            }]
        }
      }'
const NGSI = require('./ngsi/ngsiclient.js');
var brokerURL = "http://localhost:80/ngsi10"
var ngsi10client = new NGSI.NGSI10Client(brokerURL);

var queryReq = {}
queryReq.entities = [{type:'.*', isPattern: true}];
queryReq.restriction = {scopes: [{
                    "scopeType": "circle",
                    "scopeValue": {
                       "centerLatitude": 49.406393,
                       "centerLongitude": 8.684208,
                       "radius": 10.0
                    }
                }]};

ngsi10client.queryContext(queryReq).then( function(deviceList) {
    console.log(deviceList);
}).catch(function(error) {
    console.log(error);
    console.log('failed to query context');
});
ジオスコープ (geo-scope) によるコンテキストのクエリ (ポリゴン)
curl -X POST 'http://localhost:80/ngsi10/queryContext' \
  -H 'Content-Type: application/json' \
  -d '{
   "entities":[
      {
         "id":".*",
         "isPattern":true
      }
   ],
   "restriction":{
      "scopes":[
         {
            "scopeType":"polygon",
            "scopeValue":{
               "vertices":[
                  {
                     "latitude":34.4069096565206,
                     "longitude":135.84594726562503
                  },
                  {
                     "latitude":37.18657859524883,
                     "longitude":135.84594726562503
                  },
                  {
                     "latitude":37.18657859524883,
                     "longitude":141.51489257812503
                  },
                  {
                     "latitude":34.4069096565206,
                     "longitude":141.51489257812503
                  },
                  {
                     "latitude":34.4069096565206,
                     "longitude":135.84594726562503
                  }
               ]
            }
        }]
    }
}'
const NGSI = require('./ngsi/ngsiclient.js');
var brokerURL = "http://localhost:80/ngsi10"
var ngsi10client = new NGSI.NGSI10Client(brokerURL);

var queryReq = {}
queryReq.entities = [{type:'.*', isPattern: true}];
queryReq.restriction = {
       "scopes":[
          {
             "scopeType":"polygon",
             "scopeValue":{
                "vertices":[
                   {
                      "latitude":34.4069096565206,
                      "longitude":135.84594726562503
                   },
                   {
                      "latitude":37.18657859524883,
                      "longitude":135.84594726562503
                   },
                   {
                      "latitude":37.18657859524883,
                      "longitude":141.51489257812503
                   },
                   {
                      "latitude":34.4069096565206,
                      "longitude":141.51489257812503
                   },
                   {
                      "latitude":34.4069096565206,
                      "longitude":135.84594726562503
                   }
                ]
             }
          }
       ]
    }

ngsi10client.queryContext(queryReq).then( function(deviceList) {
    console.log(deviceList);
}).catch(function(error) {
    console.log(error);
    console.log('failed to query context');
});
ドメイン メタデータ値のフィルターを使用したコンテキストのクエリ

注釈

条件ステートメント (conditional statement) は、コンテキスト エンティティのドメイン メタデータでのみ定義できます。当面は、特定の属性値に基づいてエンティティを除外することはサポートされていません。

curl -X POST 'http://localhost:80/ngsi10/queryContext' \
  -H 'Content-Type: application/json' \
  -d '{
        "entities": [{
            "id": ".*",
            "isPattern": true
        }],
        "restriction": {
            "scopes": [{
                "scopeType": "stringQuery",
                "scopeValue":"city=Heidelberg"
            }]
        }
      }'
const NGSI = require('./ngsi/ngsiclient.js');
var brokerURL = "http://localhost:80/ngsi10"
var ngsi10client = new NGSI.NGSI10Client(brokerURL);

var queryReq = {}
queryReq.entities = [{type:'.*', isPattern: true}];
queryReq.restriction = {scopes: [{
                    "scopeType": "stringQuery",
                    "scopeValue":"city=Heidelberg"
                }]};

ngsi10client.queryContext(queryReq).then( function(deviceList) {
    console.log(deviceList);
}).catch(function(error) {
    console.log(error);
    console.log('failed to query context');
});
複数のフィルターを使用したコンテキストのクエリ
curl -X POST 'http://localhost:80/ngsi10/queryContext' \
  -H 'Content-Type: application/json' \
  -d '{
        "entities": [{
            "id": ".*",
            "isPattern": true
        }],
        "restriction": {
            "scopes": [{
                "scopeType": "circle",
                "scopeValue": {
                   "centerLatitude": 49.406393,
                   "centerLongitude": 8.684208,
                   "radius": 10.0
                }
            }, {
                "scopeType": "stringQuery",
                "scopeValue":"city=Heidelberg"
            }]
        }
      }'
const NGSI = require('./ngsi/ngsiclient.js');
var brokerURL = "http://localhost:80/ngsi10"
var ngsi10client = new NGSI.NGSI10Client(brokerURL);

var queryReq = {}
queryReq.entities = [{type:'.*', isPattern: true}];
queryReq.restriction = {scopes: [{
                    "scopeType": "circle",
                    "scopeValue": {
                       "centerLatitude": 49.406393,
                       "centerLongitude": 8.684208,
                       "radius": 10.0
                    }
                }, {
                    "scopeType": "stringQuery",
                    "scopeValue":"city=Heidelberg"
                }]};

ngsi10client.queryContext(queryReq).then( function(deviceList) {
    console.log(deviceList);
}).catch(function(error) {
    console.log(error);
    console.log('failed to query context');
});

コンテキストを削除

ID で特定のコンテキスト エンティティを削除

DELETE /ngsi10/entity/#eid

パラメーター 説明
eid エンティティ ID

例:

curl -iX DELETE http://localhost:80/ngsi10/entity/Device.temp001

コンテキストをサブスクライブ

POST /ngsi10/subscribeContext

パラメーター 説明
entityId 特定のエンティティ ID、ID pattern、またはタイプを定義できるエンティティ フィルターを指定
restriction スコープのリストと各スコープは、ドメイン メタデータに基づいてフィルターを定義
reference ノーティフィケーションを受信する宛先
エンティティ ID のパターンによるコンテキストのサブスクライブ
curl -X POST 'http://localhost:80/ngsi10/subscribeContext' \
  -H 'Content-Type: application/json' \
  -d '{
        "entities":[{"id":"Device.*","isPattern":true}],
        "reference": "http://localhost:8066"
    }'
const NGSI = require('./ngsi/ngsiclient.js');
var brokerURL = "http://localhost:80/ngsi10"
var ngsi10client = new NGSI.NGSI10Client(brokerURL);
var mySubscriptionId;

var subscribeReq = {}
subscribeReq.entities = [{id:'Device.*', isPattern: true}];

ngsi10client.subscribeContext(subscribeReq).then( function(subscriptionId) {
    console.log("subscription id = " + subscriptionId);
        mySubscriptionId = subscriptionId;
}).catch(function(error) {
    console.log('failed to subscribe context');
});
エンティティ タイプによるコンテキストのサブスクライブ
curl -X POST 'http://localhost:80/ngsi10/subscribeContext' \
  -H 'Content-Type: application/json' \
  -d '{
        "entities":[{"type":"Temperature","isPattern":true}]
        "reference": "http://localhost:8066"
      }'
const NGSI = require('./ngsi/ngsiclient.js');
var brokerURL = "http://localhost:80/ngsi10"
var ngsi10client = new NGSI.NGSI10Client(brokerURL);

var subscribeReq = {}
subscribeReq.entities = [{type:'Temperature', isPattern: true}];

ngsi10client.subscribeContext(subscribeReq).then( function(subscriptionId) {
    console.log("subscription id = " + subscriptionId);
        mySubscriptionId = subscriptionId;
}).catch(function(error) {
    console.log('failed to subscribe context');
});
ジオスコープ (geo-scope) によるコンテキストのサブスクライブ
curl -X POST 'http://localhost:80/ngsi10/subscribeContext' \
  -H 'Content-Type: application/json' \
  -d '{
        "entities": [{
            "id": ".*",
            "isPattern": true
        }],
        "reference": "http://localhost:8066",
        "restriction": {
            "scopes": [{
                "scopeType": "circle",
                "scopeValue": {
                   "centerLatitude": 49.406393,
                   "centerLongitude": 8.684208,
                   "radius": 10.0
                }
            }]
        }
      }'
const NGSI = require('./ngsi/ngsiclient.js');
var brokerURL = "http://localhost:80/ngsi10"
var ngsi10client = new NGSI.NGSI10Client(brokerURL);

var subscribeReq = {}
subscribeReq.entities = [{type:'.*', isPattern: true}];
subscribeReq.restriction = {scopes: [{
                    "scopeType": "circle",
                    "scopeValue": {
                       "centerLatitude": 49.406393,
                       "centerLongitude": 8.684208,
                       "radius": 10.0
                    }
                }]};

ngsi10client.subscribeContext(subscribeReq).then( function(subscriptionId) {
    console.log("subscription id = " + subscriptionId);
        mySubscriptionId = subscriptionId;
}).catch(function(error) {
    console.log('failed to subscribe context');
});
ドメイン メタデータ値のフィルターを使用してコンテキストをサブスクライブ

注釈

条件ステートメント (conditional statement) は、コンテキスト エンティティのドメイン メタデータでのみ定義できます。当面は、特定の属性値に基づいてエンティティを除外することはサポートされていません。

curl -X POST 'http://localhost:80/ngsi10/subscribeContext' \
  -H 'Content-Type: application/json' \
  -d '{
        "entities": [{
            "id": ".*",
            "isPattern": true
        }],
        "reference": "http://localhost:8066",
        "restriction": {
            "scopes": [{
                "scopeType": "stringQuery",
                "scopeValue":"city=Heidelberg"
            }]
        }
      }'
const NGSI = require('./ngsi/ngsiclient.js');
var brokerURL = "http://localhost:80/ngsi10"
var ngsi10client = new NGSI.NGSI10Client(brokerURL);

var subscribeReq = {}
subscribeReq.entities = [{type:'.*', isPattern: true}];
subscribeReq.restriction = {scopes: [{
                    "scopeType": "stringQuery",
                    "scopeValue":"city=Heidelberg"
                }]};

ngsi10client.subscribeContext(subscribeReq).then( function(subscriptionId) {
    console.log("subscription id = " + subscriptionId);
        mySubscriptionId = subscriptionId;
}).catch(function(error) {
    console.log('failed to subscribe context');
});
複数のフィルターでコンテキストをサブスクライブ
curl -X POST 'http://localhost:80/ngsi10/subscribeContext' \
  -H 'Content-Type: application/json' \
  -d '{
        "entities": [{
            "id": ".*",
            "isPattern": true
        }],
        "reference": "http://localhost:8066",
        "restriction": {
            "scopes": [{
                "scopeType": "circle",
                "scopeValue": {
                   "centerLatitude": 49.406393,
                   "centerLongitude": 8.684208,
                   "radius": 10.0
                }
            }, {
                "scopeType": "stringQuery",
                "scopeValue":"city=Heidelberg"
            }]
        }
      }'
const NGSI = require('./ngsi/ngsiclient.js');
var brokerURL = "http://localhost:80/ngsi10"
var ngsi10client = new NGSI.NGSI10Client(brokerURL);

var subscribeReq = {}
subscribeReq.entities = [{type:'.*', isPattern: true}];
subscribeReq.restriction = {scopes: [{
                    "scopeType": "circle",
                    "scopeValue": {
                       "centerLatitude": 49.406393,
                       "centerLongitude": 8.684208,
                       "radius": 10.0
                    }
                }, {
                    "scopeType": "stringQuery",
                    "scopeValue":"city=Heidelberg"
                }]};

// use the IP and Port number your receiver is listening
subscribeReq.reference =  'http://' + agentIP + ':' + agentPort;


ngsi10client.subscribeContext(subscribeReq).then( function(subscriptionId) {
    console.log("subscription id = " + subscriptionId);
        mySubscriptionId = subscriptionId;
}).catch(function(error) {
    console.log('failed to subscribe context');
});
サブスクリプション ID でサブスクリプションをキャンセル

DELETE /ngsi10/subscription/#sid

パラメーター 説明
sid サブスクリプションの発行時に作成されるサブスクリプション ID

curl -iX DELETE http://localhost:80/ngsi10/subscription/#sid

FogFlow Service Orchestrator APIs

FogFlow での IoT サービスの全体的な開発プロセスを次の図に示します。フォグ ファンクションの開発では、ステップ4と5が組み合わされます。つまり、フォグ ファンクションがサブミットされると、FogFlow エディターによってデフォルトの要件が発行されます。

_images/development_process.png

オペレーターを実装

設計されたサービス トポロジーを定義する前に、サービス トポロジーで使用されるすべてのオペレーターは、ユーザーまたは FogFlow システムの他のプロバイダーによって提供される必要があります。

注釈

現在、2つのテンプレートが提供されています。1つは Node.js ベースの実装用で、もう1つは Python ベースの実装用です。

オペレーターを公開 (Publish the operator)

オペレーターのイメージは、パブリック Docker レジストリーまたはプライベート Docker レジストリーに公開できます。Docker レジストリーを使用しない場合は、オペレーターの Docker イメージがすべてのエッジ ノードで構築されていることを確認する必要があります。現在、FogFlow worker は、タスク インスタンスを起動するコマンドを受信すると、最初にローカル ストレージから必要な Docker イメージを検索します。見つからない場合は、Docker レジストリーに必要な Docker イメージ (FogFlow worker の構成に応じたパブリック イメージまたはプライベート イメージ) のフェッチを開始します。

誰かがイメージを公開したい場合は、次の docker コマンドを使用できます。

docker push  [the name of your image]

注釈

このステップは、docker コマンドのみで実行されます。

オペレーターの定義と登録

構築された NGSI アップデート メッセージをクラウドにデプロイされた IoT Broker に送信することで、オペレーターの Docker イメージを登録することもできます。

これは、オペレーターの Docker イメージを登録するための JavaScript ベースのコード例です。このコード例では、JavaScript ベースのライブラリを使用してFogFlow IoT Broker とやり取りしています。ライブラリは GitHub コード リポジトリ (designer/public/lib/ngsi) から見つけることができ、ngsiclient.js は Web ページに含まれている必要があります。

var image = {
    name: "counter",
    tag: "latest",
    hwType: "X86",
    osType: "Linux",
    operatorName: "counter",
    prefetched: false
};

//register a new docker image
var newImageObject = {};

newImageObject.entityId = {
    id : image.name + ':' + image.tag,
    type: 'DockerImage',
    isPattern: false
};

newImageObject.attributes = {};
newImageObject.attributes.image = {type: 'string', value: image.name};
newImageObject.attributes.tag = {type: 'string', value: image.tag};
newImageObject.attributes.hwType = {type: 'string', value: image.hwType};
newImageObject.attributes.osType = {type: 'string', value: image.osType};
newImageObject.attributes.operator = {type: 'string', value: image.operatorName};
newImageObject.attributes.prefetched = {type: 'boolean', value: image.prefetched};

newImageObject.metadata = {};
newImageObject.metadata.operator = {
    type: 'string',
    value: image.operatorName
};

// assume the config.brokerURL is the IP of cloud IoT Broker
var client = new NGSI10Client(config.brokerURL);
client.updateContext(newImageObject).then( function(data) {
    console.log(data);
}).catch( function(error) {
    console.log('failed to register the new device object');
});

サービス トポロジーを定義して登録

通常、サービス トポロジーは、FogFlow トポロジー エディタを介して定義および登録できます。ただし、独自のコードで定義および登録することもできます。

サービス トポロジーを登録するには、構築された NGSI アップデート メッセージをコードでクラウドにデプロイされた IoT Broker に送信する必要があります。

これは、オペレーターの Docker イメージを登録するための JavaScript ベースのコード例です。このコード例では、JavaScript ベースのライブラリを使用して FogFlow IoT Broker とやり取りします。ライブラリは、GitHub コード リポジトリ (designer/public/lib/ngsi) から見つけることができます。ngsiclient.js を Web ページに含める必要があります。

// the json object that represent the structure of your service topology
// when using the FogFlow topology editor, this is generated by the editor
var topology = {
   "description":"detect anomaly events from time series data points",
   "name":"anomaly-detection",
   "priority": {
        "exclusive": false,
        "level": 100
   },
   "trigger": "on-demand",
   "tasks":[
      {
         "name":"AnomalyDetector",
         "operator":"anomaly",
         "groupBy":"shop",
         "input_streams":[
            {
                  "type": "PowerPanel",
                "shuffling": "unicast",
                  "scoped": true
            },
            {
                  "type": "Rule",
                "shuffling": "broadcast",
                  "scoped": false
            }
         ],
         "output_streams":[
            {
               "type":"Anomaly"
            }
         ]
      },
      {
         "name":"Counter",
         "operator":"counter",
         "groupBy":"*",
         "input_streams":[
            {
               "type":"Anomaly",
               "shuffling": "unicast",
               "scoped": true
            }
         ],
         "output_streams":[
            {
               "type":"Stat"
            }
         ]
      }
   ]
}

//submit it to FogFlow via NGSI Update
var topologyCtxObj = {};

topologyCtxObj.entityId = {
    id : 'Topology.' + topology.name,
    type: topology.name,
    isPattern: false
};

topologyCtxObj.attributes = {};
topologyCtxObj.attributes.status = {type: 'string', value: 'enabled'};
topologyCtxObj.attributes.template = {type: 'object', value: topology};

// assume the config.brokerURL is the IP of cloud IoT Broker
var client = new NGSI10Client(config.brokerURL);

// send NGSI10 update
client.updateContext(topologyCtxObj).then( function(data) {
    console.log(data);
}).catch( function(error) {
    console.log('failed to submit the topology');
});

サービス トポロジーをトリガーする要件エンティティを作成

これは、カスタマイズされた要件エンティティ (requirement entity) を FogFlow に送信することによってサービス トポロジーをトリガーする JavaScript ベースのコード例です。

var rid = 'Requirement.' + uuid();

var requirementCtxObj = {};
requirementCtxObj.entityId = {
    id : rid,
    type: 'Requirement',
    isPattern: false
};

var restriction = { scopes:[{scopeType: geoscope.type, scopeValue: geoscope.value}]};

requirementCtxObj.attributes = {};
requirementCtxObj.attributes.output = {type: 'string', value: 'Stat'};
requirementCtxObj.attributes.scheduler = {type: 'string', value: 'closest_first'};
requirementCtxObj.attributes.restriction = {type: 'object', value: restriction};

requirementCtxObj.metadata = {};
requirementCtxObj.metadata.topology = {type: 'string', value: curTopology.entityId.id};

console.log(requirementCtxObj);

// assume the config.brokerURL is the IP of cloud IoT Broker
var client = new NGSI10Client(config.brokerURL);
client.updateContext(requirementCtxObj).then( function(data) {
    console.log(data);
}).catch( function(error) {
    console.log('failed to send a requirement');
});

要件エンティティを削除して、サービス トポロジーを終了

これは、要件エンティティ (requirement entity) を削除してサービス トポロジーを終了する JavaScript ベースのコード例です。

var rid = [the id of your created requirement entity];

//
var client = new NGSI10Client(config.brokerURL);
client.deleteContext(rid).then( function(data) {
    console.log(data);
}).catch( function(error) {
    console.log('failed to send a requirement');
});

NGSI-LD でサポートされている APIs

次の図は、現在のスコープ内の APIs を使用して、FogFlow での NGSI-LD API サポートの目標を達成する方法の概要を示しています。API サポートには、エンティティの作成、登録、サブスクリプション、およびノーティフィケーションが含まれます。

_images/ngsild_architecture.png

Entities API

FogFlow との対話の目的で、IoT デバイスは、特定のコンテキストに従って解決されるエンティティ作成要求でブローカーにアプローチします。ブローカーはさらに、作成されたエンティティに対応して、登録要求を FogFlow Discovery に転送します。

注釈

Cloud broker へのアクセスにはポート80を使用しますが、Edge broker の場合、デフォルトのポートは8070です。ローカルホストは、FogFlow をホストするシステムのコア サービス IP です。

POST /ngsi-ld/v1/entities

c. 既存のエンティティに追加の属性を追加

POST /ngsi-ld/v1/entities/

キー バリュー
Content-Type application/json
Accept application/ld+json

リクエスト

curl -iX POST \
'http://localhost:80/ngsi-ld/v1/entities/' \
-H 'Content-Type: application/json' \
-H 'Accept: application/ld+json' \
-H 'Link: <{{link}}>; rel="https://uri.etsi.org/ngsi-ld/v1/ngsi-ld-core-context.jsonld"; type="application/ld+json"' \
-d'
 {
      "id": ""urn:ngsi-ld:Vehicle:A100",
      "type": "Vehicle",
      ""brandName1"": {
      "brandName1": {
                          "type": "Property",
                          "value": "BMW"
       }
 }'
d. 既存のエンティティの特定の属性を更新

PATCH /ngsi-ld/v1/entities/

キー バリュー
Content-Type application/json
Accept application/ld+json

リクエスト

curl -iX POST \
'http://localhost:80/ngsi-ld/v1/entities/' \
-H 'Content-Type: application/json' \
-H 'Accept: application/ld+json' \
-H 'Link: <{{link}}>; rel="https://uri.etsi.org/ngsi-ld/v1/ngsi-ld-core-context.jsonld"; type="application/ld+json"' \
 -d'
 {
       "id": ""urn:ngsi-ld:Vehicle:A100",
       "type": "Vehicle",

       "brandName": {
                          "type": "Property",
                          "value": "AUDI"
        }
 }'
e. NGSI-LD コンテキスト エンティティを削除

DELETE /ngsi-ld/v1/entities/#eid

パラメーター 説明
eid エンティティ ID

例:

curl -iX DELETE http://localhost:80/ngsi-ld/v1/entities/urn:ngsi-ld:Vehicle:A100  -H 'Content-Type: application/json' -H 'Accept: application/ld+json'
f. NGSI-LD コンテキスト エンティティの属性を削除

DELETE /ngsi-ld/v1/entities/#eid/attrs/#attrName

パラメーター 説明
eid エンティティ ID
attrName 属性名

例:

curl -iX DELETE http://localhost:80/ngsi-ld/v1/entities/urn:ngsi-ld:Vehicle:A100/attrs/brandName1
g. 特定のエンティティを取得

GET /ngsi-ld/v1/entities/#eid

パラメーター 説明
eid エンティティ ID

例:

curl http://localhost:80/ngsi-ld/v1/entities/urn:ngsi-ld:Vehicle:A4569

サブスクリプション API

新しいサブスクリプションは、サブスクライバーによって発行され、ブローカーに転送され、そこでサブスクライバーの詳細がノーティフィケーション目的で保存されます。ブローカーは FogFlowDiscovery へのリクエストを開始します。ここで、これは新しいサブスクリプションとして登録され、対応するデータの可用性を探します。データを受信すると、サブスクライブしているブローカーに情報が返されます。

a. リンク ヘッダーのコンテキストで新しいサブスクリプションを作成

POST /ngsi-ld/v1/subscriptions

ヘッダー フォーマット

キー バリュー
Content-Type application/ld+json
Link <{{link}}>; rel="https://uri.etsi.org/ngsi-ld/v1/ngsi-ld-core-context.jsonld"; type="application/ld+json"

リクエスト

curl -iX POST\
  'http://localhost:80/ngsi-ld/v1/subscriptions/' \
   -H 'Content-Type: application/ld+json' \
   -H 'Link: <{{link}}>; rel="https://uri.etsi.org/ngsi-ld/v1/ngsi-ld-core-context.jsonld"; type="application/ld+json"' \
   -d '
    {
             "type": "Subscription",
             "id"  : "urn:ngsi-ld:Subscription:71",
             "entities": [{
                             "id": "urn:ngsi-ld:Vehicle:71",
                             "type": "Vehicle"
             }],
             "watchedAttributes": ["brandName"],
             "notification": {
                             "attributes": ["brandName"],
                             "format": "keyValues",
                             "endpoint": {
                                             "uri": "http://my.endpoint.org/notify",
                                             "accept": "application/json"
                               }
             }
      }'
b. すべてのサブスクリプションを取得

GET /ngsi-ld/v1/subscriptions

例:

curl http://localhost:80/ngsi-ld/v1/subscriptions/ -H 'Accept: application/ld+json'
c. サブスクリプション ID に基づいて特定のサブスクリプションを取得

GET /ngsi-ld/v1/subscriptions/#sid

パラメーター 説明
sid サブスクリプション ID

例:

curl http://localhost:80/ngsi-ld/v1/subscriptions/urn:ngsi-ld:Subscription:71
d. サブスクリプション ID に基づいて特定のサブスクリプションを削除

DELETE /ngsi-ld/v1/subscriptions/#sid

パラメーター 説明
sid サブスクリプション ID

例:

curl -iX DELETE http://localhost:80/ngsi-ld/v1/subscriptions/urn:ngsi-ld:Subscription

ソースコードからすべてをビルド

FogFlow は、ARM プロセッサと x86 プロセッサ (32ビットと64ビット) の両方の Linux でビルドおよびインストールできます。

依存関係をインストール

  1. FogFlowをビルドするには、最初に次の依存関係をインストールします。

  2. インストールされているバージョンを確認します。

    go version   #output  go version go1.9 linux/amd64
    nodejs -v    #output    v6.10.2
    npm -v       #output  3.10.10
    
  3. 環境変数 GOPATH を設定します。

    注釈

    GOPATH は、go ベースのプロジェクトのワークスペースを定義します。go ワークスペース フォルダーには "src" フォルダーが必要であり、FogFlow コード リポジトリはこの "src" フォルダーに複製される必要があることに注意してください。たとえば、ホームフォルダが "/home/smartfog" であると仮定して、ワークスペースとして新しいフォルダ "go" を作成します。この場合、最初に "/home/smartfog/go" の下に "src" (正確にこの名前である必要があります) を作成してから、"/home/smartfog/go/src フォルダー内の FogFlow コード リポジトリをチェック アウトする必要があります。

    export GOPATH="/home/smartfog/go"
    
  4. コード リポジトリをチェック アウトします。

    cd /home/smartfog/go/src/
    git clone https://github.com/smartfog/fogflow.git
    
  5. 以下のようにソースコードからすべてのコンポーネントをビルドします。

IoT Discovery をビルド

  • ネイティブ実行可能プログラムをビルドします。

    # go the discovery folder
    cd /home/smartfog/go/src/fogflow/discovery
    # download its third-party library dependencies
    go get
    # build the source code
    go build
    
  • Docker イメージを作成します。

    # Simply ./build  can be run to perform the following commands
    
    # download its third-party library dependencies
    go get
    # build the source code and link all libraries statically
    CGO_ENABLED=0 go build -a
    # create the docker image; sudo might have to be used to run this command
    # if the docker user is not in the sudo group
    docker build -t "fogflow/discovery" .
    

IoT Broker をビルド

  • ネイティブ実行可能プログラムをビルドします。

    # go the broker folder
    cd /home/smartfog/go/src/fogflow/broker
    # download its third-party library dependencies
    go get
    # build the source code
    go build
    
  • Docker イメージを作成します。

    # simply ./build can be run to perform the following commands
    
    # download its third-party library dependencies
    go get
    # build the source code and link all libraries statically
    CGO_ENABLED=0 go build -a
    # create the docker image; sudo might have to be used to run this command
    # if the docker user is not in the sudo group
    docker build -t "fogflow/broker" .
    

Topology Master をビルド

  • ネイティブ実行可能プログラムをビルドします。

    # go the master folder
    cd /home/smartfog/go/src/fogflow/master
    # download its third-party library dependencies
    go get
    # build the source code
    go build
    
  • Docker イメージを作成します。

    # simply ./build can be run to perform the following commands
    
    # download its third-party library dependencies
    go get
    # build the source code and link all libraries statically
    CGO_ENABLED=0 go build -a
    # create the docker image; sudo might have to be used to run this command
    # if the docker user is not in the sudo group
    docker build -t "fogflow/master" .
    

Worker をビルド

  • ネイティブ実行可能プログラムをビルドします。

    # go the worker folder
    cd /home/smartfog/go/src/fogflow/worker
    # download its third-party library dependencies
    go get
    # build the source code
    go build
    
  • Docker イメージを作成します。

    # simply ./build  can be run to perform the following commands
    
    # download its third-party library dependencies
    go get
    # build the source code and link all libraries statically
    CGO_ENABLED=0 go build -a
    # create the docker image; sudo might have to be used to run this command
    # if the docker user is not in the sudo group
    docker build -t "fogflow/worker" .
    

Task Designer をビルド

  • サードパーティのライブラリの依存関係をインストールします。

    # go the designer folder
    cd /home/smartfog/go/src/fogflow/designer
    
    # install all required libraries
    npm install
    
  • Docker イメージを作成します。

    # simply ./build can be run to perform the following commands
    
    # install all required libraries
    npm install
    
    # create the docker image; sudo might have to be used to run this command
    # if the docker user is not in the sudo group
    docker build -t "fogflow/designer"  .
    

テスト

テストの前に、次の手順に従って FogFlow システム全体を単一の Linux マシンにデプロイしてください。

1台のマシンですべての FogFlow コンポーネントをセットアップします Set up all FogFlow component on a single machine

FogFlow が稼働すると、JMeter は、提供されたテスト計画を使用してエンド ツー エンドの機能テストを実行できます。詳細な手順については、こちらをご覧ください。

JMeter Test

関連出版物

  1. F. Cirillo, B. Cheng, R. Porcellana, M. Russo, G. Solmaz, H. Sakamoto, and S. P. Romano. “IntentKeeper: Intent-Oriented Data Usage Control for Federated Data Analytics, ” In IEEE LCN'20, November 2020.
  2. B. Cheng, J. Fürst, G. Solmaz, T. Sanada, "Fog Function: Serverless Fog Computing for Data Intensive IoT Services," in the proceedings of 2019 IEEE Conference on Service Computing (IEEE SCC'19) (Won the best paper award), Milan, 2019, pp.28-35
  3. M. Fadel Argerich, B. Cheng, J. Fuerst, "Reinforcement Learning based Orchestration for Elastic Services", in the proceedings of the 5th IEEE World Forum on Internet of Things, WF-IoT 2019, Limerick, Ireland, April 15-18, 2019, pp. 352-357
  4. B. Cheng, E. Kovacs, A. Kitazawa, K. Terasawa, T. Hada, M. Takeuchi, "FogFlow: Orchestrating IoT Services over Cloud and Edges", NEC Technical Journal, 2018/11
  5. B. Cheng, G. Solmaz, F. Cirillo, E. Kovacs, K. Terasawa and A. Kitazawa, "FogFlow: Easy Programming of IoT Services Over Cloud and Edges for Smart Cities", in IEEE Internet of Things Journal, 2017 (Won the Best Paper Runner-up award)
  6. B. Cheng, A. Papageorgiou and M. Bauer, "Geelytics: Enabling On-Demand Edge Analytics over Scoped Data Sources", 2016 IEEE International Congress on Big Data (IEEE BigData Congress), San Francisco, CA, 2016, pp. 101-108
  7. B. Cheng, A. Papageorgiou, F. Cirillo and E. Kovacs, "GeeLytics: Geo-distributed Edge Analytics for Large Scale IoT Systems Based on Dynamic Topology", IEEE 2nd World Forum on Internet of Things (WF-IoT), Milan, 2015, pp. 565-570.

トラブルシューティング

このドキュメントでは、FogFlow を使用するときに遭遇するいくつかの一般的な問題と、いくつかの既知の問題について説明します。 その他の問題が発生した場合は、こちらにお知らせください。 let us know

  • エッジ ノードが NAT の背後にあります
    エッジ ノードが NAT の背後にある場合、またはエッジで IoT Broker への着信通知をブロックするファイアウォールが ある場合、エッジ ノードは正しく機能しません。 近い将来、このタイプのセットアップをサポートする予定です。

連絡先

以下は、FogFlow について議論するのに適した場所です。

  1. Our Mailing List: メーリング リストでは、開発、使用法、またはその他の一般的な質問に関連することについて話し合うために、電子メールを送信します。
  2. FIWARE Q&A: 他の FIWARE ユーザーと質問や問題について議論します。
  3. GitHub Issues: バグ レポートと機能リクエストに使用します。