#Starlink をPrometheusで監視しAmazon ECS AnywhereでAWS連携する

2022.10.31

ども、大瀧です。

東日本の皆さん、先日サービス開始したStarlinkを活用してますか。アンテナを設置する場所の視界など安定利用のためには独特な要件があり、Starlinkスマートフォンアプリで視界のチェックや直近の切断履歴などを参照できます。一方でアプリで参照できる履歴は直近7時間分であったり、アプリ利用のためにスマートフォンを用意する必要があったりと使い方によっては不便な面もあります。そこで本ブログでは、Starlinkの運用に役立つ監視の仕組みとしてPrometheusとAWSクラウドを組み合わせた構成をご紹介します。

StarlinkキットにはgRPC APIが生えている

Starlinkを契約すると送付される衛星受信キットにはアンテナ本体(以下Dish)とWi-Fiルーター(以下Starlinkルーター)が含まれており、どちらにもgRPCのAPIがありアクセスできます。StarlinkアプリがStarlink回線(Wi-Fi)に接続しているときにこのAPIを利用して情報を参照しているようです。で、有志がこのAPIの非公式情報をGitHubに公開しています。

APIを叩く非公式Prometheus Exporterもあります。

このStarlink Exporterを含めたPrometheus+Granafaコンテナを一発で立ち上げるDocker Compose構成にStarlink Monitoring Systemと名付けたものをExporterの作者が公開しています。

まずは手元にあるRaspberry Piを有線LANでStarlinkルーターに接続し、これを動作させてみました。

  • Raspberry Pi: Raspberry Pi 4 モデルB 8GB
  • OS: Ubuntu Server 20.04.5 LTS
  • Docker: Docker Engine - Community 20.10.21
$ git clone https://github.com/danopstech/starlink.git
$ cd starlink
$ sudo docker-compose up -d

WebブラウザでRaspberry Piのホスト名やIPアドレスの3000番ポートにアクセスすると、Grafanaのログイン画面が表示されます。

初期ユーザー名 admin とパスワード admin でログインできます *1。ログイン後の初期画面に遷移したら左のメニューからSearchでダッシュボードの検索画面を表示、 starlink で検索すると、Starlink Exporterのメトリクスを表示するStarlinkダッシュボードを表示できます。

Prometheusで保存している(保存期間は15日間)様々なデータのグラフが表示されます。かっこいい!

一方で、画面上部のID周りは軒並み No Data ということに気づきます。グラフではメトリクス starlink_dish_cell_id などを参照しているので、cURLで直接Starlink Exporterを動作させ様子を見てみると。。。

pi@raspberrypi:~$ curl localhost:9817/metrics | grep -v '^#'
starlink_dish_alert_mast_not_near_vertical 0
starlink_dish_alert_motors_stuck 0
starlink_dish_alert_slow_eth_speeds 0
starlink_dish_alert_thermal_shutdown 0
starlink_dish_alert_thermal_throttle 0
starlink_dish_alert_unexpected_location 0
starlink_dish_backup_beam 0
starlink_dish_bore_sight_azimuth_deg 0
starlink_dish_bore_sight_elevation_deg 0
starlink_dish_cell_id 0
starlink_dish_currently_obstructed 0
starlink_dish_downlink_throughput_bytes 0
starlink_dish_first_nonempty_slot_seconds -1
starlink_dish_fraction_obstruction_ratio 0
starlink_dish_info{country_code="",device_id="",hardware_version="",software_version="",utc_offset="0"} 1
starlink_dish_initial_gateway_id 0
starlink_dish_initial_satellite_id 0
starlink_dish_last_24h_obstructed_seconds 0
starlink_dish_pop_ping_drop_ratio 1
starlink_dish_pop_ping_latency_seconds -0.0010000000474974513
starlink_dish_pop_rack_id 0
starlink_dish_prolonged_obstruction_duration_seconds 0
starlink_dish_prolonged_obstruction_interval_seconds NaN
starlink_dish_scrape_duration_seconds 0.013614033
starlink_dish_snr 0
starlink_dish_state 0
starlink_dish_time_to_slot_end_seconds 0
starlink_dish_up 1
starlink_dish_uplink_throughput_bytes 9328.1318359375
starlink_dish_uptime_seconds 0
starlink_dish_valid_seconds 0

えっと、Exporter側では多くのデータを取得できていないようですね😅。APIの仕様はStarlinkアプリのバージョンアップなどに連動して改変されているようで、例えば以下のIssueで問題が報告されています。

このIssueからいくつかリンクを徘徊すると、SysdigによってフォークされAPIを更新したものを見つけました。Docker Composeで指定するDockerイメージをそちらに変更すると、取得できる項目がいくつか増えました。

docker-compose.yaml

version: "3.3"
services:
  starlink_exporter:
    image: "sysdigdan/starlink_exporter:latest"

再度試してみると。。。

pi@raspberrypi:~$ curl localhost:9817/metrics | grep -v '^#'
starlink_dish_alert_install_pending 0
starlink_dish_alert_is_heating 0
starlink_dish_alert_mast_not_near_vertical 0
starlink_dish_alert_motors_stuck 0
starlink_dish_alert_roaming 0
starlink_dish_alert_slow_eth_speeds 0
starlink_dish_alert_thermal_shutdown 0
starlink_dish_alert_thermal_throttle 0
starlink_dish_alert_unexpected_location 0
starlink_dish_anti_rollback_version 0
starlink_dish_boot_count 10
starlink_dish_bore_sight_azimuth_deg 1.4277397394180298
starlink_dish_bore_sight_elevation_deg 63.974029541015625
starlink_dish_currently_obstructed 0
starlink_dish_dish_stow_requested 0
starlink_dish_downlink_throughput_bytes 18631.09765625
starlink_dish_eth_speed 1000
starlink_dish_first_nonempty_slot_seconds 0
starlink_dish_fraction_obstruction_ratio 0.03731893002986908
starlink_dish_gps_sats 13
starlink_dish_gps_valid 1
starlink_dish_info{country_code="JP",device_id="ut01000000-00000000-XXXXXXXX",hardware_version="rev2_proto4",manufactured_version="",software_version="223c055e-8fe8-42e6-8d00-cd4c6a466252.uterm.release",utc_offset="32401"} 1
starlink_dish_info_debug{count_by_reason="map[]",count_by_reason_delta="map[]",last_count="0",last_reason="BOOT_REASON_UNKNOWN"} 1
starlink_dish_is_dev 0
starlink_dish_is_hit 0
starlink_dish_outage_did_switch 0
starlink_dish_outage_duration{cause="UNKNOWN",start_time="0"} 0
starlink_dish_pop_ping_drop_ratio 0
starlink_dish_pop_ping_latency_seconds 0.02257142774760723
starlink_dish_prolonged_obstruction_duration_seconds 1.5567706823349
starlink_dish_prolonged_obstruction_interval_seconds 224.99998474121094
starlink_dish_prolonged_obstruction_valid 0
starlink_dish_scrape_duration_seconds 0.007364572
starlink_dish_software_partitions_equal 0
starlink_dish_up 1
starlink_dish_uplink_throughput_bytes 17238.58984375
starlink_dish_uptime_seconds 21020
starlink_dish_valid_seconds 20613

ざっと眺めた感じでは、Starlinkアプリの[SETTINGS] - [ADVANCED] - [DEBUG DATA]で表示できるSTARLINK DISHの項目と近いものが並んでいる気がします。

AWSと連携する

ここまではRaspberry PiでDockerを用いてPrometheusとGrafanaを実行しました。データの保存や複数のキットを監視するユースケースを考えると、いずれもクラウド上に構成するのがより良いと考えられます。また、Dockerコンテナの設定変更やコンテナ自体の実行状態の管理などもクラウドに任せたいですね。そこで、それらの機能を提供するAWSマネージドサービスと組み合わせた構成を示します。

それぞれの役割を以下に解説します。Prometheusサーバーの役割がADOT CollectorとAMPに分かれているのがポイントです。

項目名 説明
Prometheus Exporterコンテナ Starlink DishのgRPC APIにアクセスしメトリクスを取得する
AWS Distro for OpenTelemetry(ADOT) Collectorコンテナ Prometheus Exporterへのメトリクスの定期取得とAMPへのメトリクス送信
Amazon Managed Service for Prometheus(AMP) ADOT Collectorコンテナから送信されるメトリクスを受け取り、保存する
Amazon Managed Service for Grafana(AMG) AMPにメトリクスをクエリし、ダッシュボードで可視化する
Amazon ECS Anywhere Raspberry Piで実行するDockerコンテナの管理や監視、コンテナログ管理 *2

具体的な設定手順は、以下の記事とほぼ同等です。

上記ブログ記事では外形監視用途にBlackbox Exporterを用いていたので、それを今回のStarlink Exporterに差し替える形です。差し替える部分をピックアップします。

ADOT Collectorの設定

---
receivers:
  prometheus:
    config:
      global:
        scrape_interval: 60s
        scrape_timeout: 10s
      scrape_configs:
      - job_name: 'starlink'
        scrape_interval: 3s
        scrape_timeout:  3s
        static_configs:
          - targets: ['exporter:9817']

exporters:
  awsprometheusremotewrite:
    endpoint: "https://aps-workspaces.<リージョン名>.amazonaws.com/workspaces/ws-<ワークスペースID>/api/v1/remote_write"
    timeout: 60s
    read_buffer_size: 4096
    aws_auth:
      region: "ap-northeast-1" 
      service: "aps"

extensions:
  health_check:
  pprof:
    endpoint: :1888
  zpages:
    endpoint: :55679

service:
  extensions: [pprof, zpages, health_check]
  pipelines:
    metrics:
      receivers: [prometheus]
      exporters: [awsprometheusremotewrite]

blackbox_exporterコンテナの定義

項目名
コンテナ名 starlink-exporter
イメージ sysdigdan/starlink_exporter:latest
ポートマッピング - ホストポート <空欄のまま>
ポートマッピング - コンテナポート 9817
ポートマッピング - プロトコル tcp
ログ設定 Auto-configure CloudWatch Logsをオン

aws-otel-collectorコンテナの定義(差替部分のみ抜粋)

項目名
ネットワーク設定 - リンク starlink-exporter:exporter

この構成にすることで、Starlinkキットを様々な場所に大規模配置するようなケースでも一元的に監視し管理出来るようになりますね。

なお、そのときはADOT Collectorの設定にlabelsで設置場所固有のラベルなどを付け、AMPおよびAMGで識別できるようにすると良いでしょう。

まとめ

StarlinkキットにはgRPC APIがありPrometheusのexporterを用いて監視に利用できることと、ECS AnywhereとADOT Collectorを用いてAWSと連携する様子をご紹介しました。

参考URL

脚注

  1. そのあとパスワード変更画面になるので、適当なパスワードに変更します
  2. コンテナログは既定の構成ではCloudWatch Logsに送信します