運用をなるべく楽にするためのAWS-backedなオンプレミス外形監視

2022.04.04

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

ども、ゲストのNTT東日本 大瀧です。 サーバーシステムの運用に欠かせないのが、サーバーを外部から監視する外形監視の仕組みです。最近はSaaSで提供される監視サービスも増えていますが、オンプレミス環境で稼働するシステムはインターネットからの直接アクセスを許容しないことが多くひと工夫が必要です。 そこで本ブログでは、外形監視を行うホストをオンプレミスに置きつつそのホストの運用コストを最小限にするべく、AWSの運用管理系サービスを駆使した構成例をご紹介します。

なるべくAWSに外出しする構成

運用コストを下げる戦略としては、オンプレミスのホストではなるべく情報を持たず監視の設定や結果、ログをすべてAWSのマネージドサービスに寄せるようにしました。

監視とメトリクス収集、保存はPrometheusエコシステムのソフトウェアやサービスを選びました。Kubernetesでの利用実績が多いことからイミュータブルな造りを意識していそうという理由で、最初に外形監視を実行するblackbox exporter、そのあとメトリクスを保存するAmazon Managed Service for Prometheus(以下AMP)、最後にその2つをつなぐAWS Distro for OpenTelemetry(以下ADOT) Collectorを見つけてきてうまく連携できる組み合わせができました。

オンプレミスで実行するblackbox exporterとADOT CollectorはDockerコンテナイメージが公開されているので、Amazon Elastic Container Service(以下ECS)のオンプレミス対応版であるECS Anywhereを利用してコンテナとして実行します。ECS Anywhereを利用することでコンテナの配置や稼働管理、コンテナ自体のログの管理をAWSから行えるわけです。ADOT Collectorは設定情報をAWS Systems Manager Parameter Store(以下パラメータストア)から取得する機能があるので、設定もAWSに置くようにしています。

では構築手順を追っていきましょう。

動作確認環境

  • AWSリージョン: 東京リージョン
  • blackbox exporterのバージョン: v0.20.0
  • ADOT Collectorのバージョン: v0.17.0
  • ECS AnywhereホストのLinux: Ububntu Server 20.04.4 LTS x86_64

手順1. AMPの構成

AMPの初期構成は非常にシンプルです。保存先はワークスペースという単位で定義されるので、任意の名称でワークスペースを作成すればOKです。

[作成]ボタンをクリックし、任意のワークスペース名を入れて作成します。

ワークスペースの作成を開始するとアクセスするためのいくつかのエンドポイントが表示されます。このあとADOT Collectorからの書き込み設定のために、リモート書き込みURL の値を控えておきます。

手順2. ADOT Collectorの設定

続いて、ADOT Collectorの設定をSystems Managerのパラメータストアに作成します。設定するYAMLの構文は、ADOTの元であるOpenTelemetory Collectorに準拠します。

OpenTeremetryの設定は、ざっくり以下の4つの要素をYAMLに記述します。

要素名 説明
recerivers データソースからの取得設定
processors データ処理設定
exporters データの出力設定
services 上記要素の組み合わせ設定

今回はreceiversとしてblackbox exporter、exportersとしてAMPを指定します。データ処理は特に行わないので、processorsは定義しません。では構成例を見てみましょう。

---
receivers:
  prometheus:
    config:
      global:
        scrape_interval: 60s
        scrape_timeout: 10s
      scrape_configs:
      - job_name: 'blackbox'
        metrics_path: /probe
        params:
          module: [http_2xx]
        static_configs:
          - targets:
            - prometheus.io
        relabel_configs:
          - source_labels: [__address__]
            target_label: __param_target
          - source_labels: [__param_target]
            target_label: instance
          - target_label: __address__
            replacement: exporter:9115
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]

2~22行目のreceiversには、prometheus.config以下にPrometheusの設定がべた書きできます。以下の設定例を参考に、今回はblackbox exporterからprometheus.ioに対してHTTPレスポンス2XXが返ってくるかを監視するようにしました。

後述しますが、今回はADOT Collectorのコンテナからblackbox exporterコンテナにPull型で監視を実行するので22行目のexporter:9115の部分が、コンテナの実行環境(ECSのタスク定義)によって変わります。

23~30行目のexportersは、以下のAdotのドキュメントの設定をほぼそのまま持ってきました。endpointに手順1で控えておいたリモート書き込みURLを貼り付けます。

ECS Anywhere環境ではIAMタスクロール経由でのクレデンシャル取得がうまく動かなかったので、ADOT用のIAMユーザーを作成しAPIキーとシークレットキーを環境変数経由で渡す形にしました。環境変数の設定は後のステップでフォローするので、ここでは特にクレデンシャルに関する記述はありません。

32~37行目のextensionsは構成例のものをそのまま持ってきただけなので、それぞれどのような働きなのかはきちんと調べられていません、すみません。。。

39~44行目のservicesではここまで定義したextensionsとrecerives - exportersをパイプラインとしてつなぐ記述です。

このYAMLドキュメントをパラメータストアにセットします。Systems Managerのパラメータストア管理画面を開き、[パラメータの作成]ボタンをクリックします。

[名前]に任意のパラメータ名(今回はotel-collector-config)を入力し、[値]にYAMLドキュメントをコピー&ペーストで貼り付けてパラメータを作成します。

これでOKです。

手順3. ECS Anywhereの設定

それでは、監視とメトリクス送信を実行するコンテナ部分を設定してきましょう。まずはオンプレミスのホストでECS Anywhereのセットアップを行います。ホストはECS Anywhereの動作要件を満たしていればOKですが、今回利用するDockerコンテナイメージはいずれもx86_64アーキテクチャのみの提供です。Raspberry PiなどARM64アーキテクチャのホストで試す場合は、コンテナイメージを自前でビルドすることになると思います。

ECSの管理画面は新しい世代への代替わりの最中ですが、新しい画面では今回行う操作のうちタスク定義のEXTERNAL指定と環境変数のパラメータストア参照に対応していないため、古い画面で操作を進めます。新旧の判別は画面左のメニュー上部にあるスイッチで確認できるので、スイッチをオフにし旧画面に切り替えておきましょう。

旧画面のクラスター管理画面から、[クラスターの作成]ボタンをクリックし作成ウィザードを進めます。

  • [クラスターテンプレートの選択]画面は「ネットワーキングのみ」を選択し、[次のステップ]をクリックします
  • [クラスターの設定]画面は任意のクラスター名を入力、[作成]をクリックします
  • クラスター作成完了画面が出たら[クラスターを表示]ボタンをクリックしクラスターの画面を表示します

続いてECSインスタンス(ECS Anywhereの場合はExternalインスタンス)の登録を進めます。[ECSインスタンス]タブをクリックし、[Externalインスタンスの登録]ボタンをクリックします。

Externalインスタンスの登録ウィザードでは、ステップ1はそのまま[次のステップ]をクリックし、ステップ2で表示されるコマンドラインのうち[Linuxコマンド]の内容をコピーします。

監視ホスト上でrootユーザーの権限でコマンドラインを実行します。

$ sudo -i
# curl --proto "https" -o "/tmp/ecs-anywhere-install.sh" "https://amazon-ecs-agent.s3.amazonaws.com/ecs-anywhere-install-latest.sh" && bash /tmp/ecs-anywhere-install.sh --region "ap-northeast-1" --cluster "devio-demo" --activation-id "XXXXXXXX-XXXX-XXXX-XXXXXXXXXXXX" --activation-code "XXXXXXXXXXXXXXXXXXXXXXXXXXXX"
  :(略 Docker CEやSystems Managerエージェント、ECSエージェントをインストールしたのちECSへの登録が行われます)
# ok
##########################


##########################
This script installed three open source packages that all use Apache License 2.0.
You can view their license information here:
  - ECS Agent https://github.com/aws/amazon-ecs-agent/blob/master/LICENSE
  - SSM Agent https://github.com/aws/amazon-ssm-agent/blob/master/LICENSE
  - Docker engine https://github.com/moby/moby/blob/master/LICENSE
##########################
#

コマンドが正常に完了すると、ECSインスタンスの一覧に監視ホストの項目が追加されます。

これでOKです。

続いて、手順2で記したADOT CollectorからAMPにアクセスするためのIAMユーザーを設定します。

IAMのユーザー管理画面からAWS管理ポリシーのAmazonPrometheusRemoteWriteAccessを割り当てるIAMユーザーを作成します。作成画面の[AWS アクセスの種類を選択]では「アクセスキー - プログラムによるアクセス」のチェックをオンにします。

次画面の[アクセス許可の設定]では、「既存のポリシーを直接アタッチ」を選択し、検索フォームに「AmazonPrometheusRemoteWriteAccess」と入力、表示されるAWS管理ポリシーを選択します。

作成完了まで進め、表示されるアクセスキーIDとシークレットアクセスキーを控え、パラメータストアにセットします。手順2と同様ですが、シークレットアクセスキーは秘匿情報なので安全な文字列(Secure String)にしておきましょう。Secrets Managerでも良いかもしれません(未検証)。

今回は以下の名前で登録しました。

  • アクセスキー ID: otel-collector-aws-access-key
  • シークレットアクセスキー: otel-collector-aws-secret-key

パラメータストアを登録したので、ECSのタスク定義にコンテナイメージと各パラメータを登録します。タスク定義の作成画面では、[起動タイプの互換性の選択]で「EXTERNAL」を選択し、[次のステップ]をクリックします。

[タスクとコンテナの定義の設定]画面は設定項目が多いのでポイントをかいつまんで紹介します。

  • タスクロール: AMPへのアクセス情報はパラメータストアから環境変数で取得するため、タスクロールは不要です
  • ネットワークモード: ADOT Collectorコンテナからblackbox exporterコンテナへのアクセスにDockerのLink機能を利用します。そのため<default>を設定します
  • タスク実行ロール: 自動で作成されるロールに、パラメータストアの読み取り権限(ssm:GetParameters)を追加します

コンテナの定義は以下の通りです。

項目名
コンテナ名 blackbox-exporter
イメージ prom/blackbox-exporter:v0.20.0
ポートマッピング - ホストポート <空欄のまま>
ポートマッピング - コンテナポート 9115
ポートマッピング - プロトコル tcp
ログ設定 Auto-configure CloudWatch Logsをオン


項目名
コンテナ名 aws-otel-collector
イメージ public.ecr.aws/aws-observability/aws-otel-collector:v0.17.0
環境変数 - AOT_CONFIG_CONTENT ValueFrom: otel-collector-config
環境変数 - AWS_ACCESS_KEY_ID ValueFrom: otel-collector-aws-access-key
環境変数 - AWS_SECRET_ACCESS_KEY ValueFrom: otel-collector-aws-secret-key
ネットワーク設定 - リンク blackbox-exporter:exporter
ログ設定 Auto-configure CloudWatch Logsをオン

最後にECSサービスでタスク定義を指定すれば、コンテナが実行されます。クラスター管理画面の[サービス]タブを表示、[作成]ボタンをクリックします。

サービスの設定では、起動タイプをEXTERNAL、先ほど定義したタスク定義/リビジョンを選択し、任意のサービス名を設定します。サービスタイプはREPLICAとDAEMONのどちらでも動作しますが、今後のタスク更新時のダウンタイムを最小化するのであればREPLICAがおすすめです。

サービスを作成ししばらく待つと実行中のタスクが増加(=コンテナを実行)し、監視がスタートします。AMPに保存されたメトリクスデータは手順1のクエリURLにAWSV4署名付きのPromQLクエリで取得できます。ここではAWSV4署名付きのHTTPリクエストを送出できるawscurlで試してみます。

# あらかじめ~/.aws/credentialsファイルなどAMPにアクセスするためのIAMクレデンシャル設定を済ませておく
$ awscurl --region ap-northeast-1 --service aps "https://aps-workspaces.ap-northeast-1.amazonaws.com/workspaces/ws-XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX/api/v1/query?query=probe_success"
{"status":"success","data":{"resultType":"vector","result":[{"metric":{"__name__":"probe_success","instance":"prometheus.io","job":"blackbox"},"value":[1648982132.63,"1"]}]}}
$

valueの2番目の値が1(失敗の場合は0)なので、監視に成功していることが確認できました!AMPにはAlert manager機能もあるのでメトリクスの閾値を設定して監視失敗時にアラートを飛ばすこともできます。

まとめ

運用をなるべく楽にするためのAWS-backedなオンプレミス外形監視の構成としてECS Anywhereのコンテナで監視ソフトウェアを実行し、AMP(Amazon Managed Service for Prometheus)にメトリクスを保存する構成をご紹介しました。

考察: 安定した監視のために

安定した監視にするためには、ADOT→AMPがインターネット経由になっていることがネックになるかもしれません。ネットワークの不安定時に備えてADOT Collectorのリトライポリシーのチューニングを行うのが良いでしょう。

安定したネットワーク接続性のために、AWS Direct Connectを利用するのも有効です。AMPにはVPCエンドポイントがあるので、そちらと組み合わせることでネットワークの安定性に加え、厳密な閉域ネットワークの要求にも応えることができます。

Direct Connectを構成に組み込む場合は監視ホストをオンプレミスの代わりにAWS側へ、例えばFargateで今回のコンテナを実行する選択肢も出てくるでしょう。その場合はblackbox exporterのリトライポリシーをチューニングする感じになるでしょうか。様々な構成が考えられるので、あれこれディスカッションしてみても面白そうですね。閉域ネットワークの部分はNTT東日本が提供するクラウドゲートウェイもご検討くださいっ(宣伝)。

おまけ1: Amazon Managed Grafana(AMG)でのメトリクス可視化

AMPに保存したメトリクスを可視化する画面として、Amazon Managed Grafana(AMG)が利用できます。以下の記事を参考にGrafanaノードを立ち上げてデータソースにAMPを指定して利用できます。

私はAzure Active Directoryの代わりにOktaの評価アカウントで試してみました。今回のメトリクスを以下のように時系列で表示できます。

おまけ2: 監視SaaSのプライベートロケーションの利用

監視SaaSには、外形監視ノードをオンプレミスに配置するプライベートロケーションという機能を持つものがいくつかあります。いずれもDockerコンテナとして提供されるので、ECS Anywhereでこれらを実行するものも良いかもしれませんね。