Datadogで監視できないポートがある

筆者が現在参画中のプロジェクトではシステムの監視サービスとしてDatadogを利用しています。Datadogではインフラやアプリのパフォーマンスなど、システムのあらゆる箇所をリアルタイムで監視できます。

今回はその中でもポート監視で詰まった点があるので、備忘録として記事に残しておきます。ポート番号は実際の数字ではなく仮の値を記載しています。


## 通信できないポートがある
Datadogでポート監視するには、Agent のコンフィギュレーションディレクトリのルートにある```conf.d/```フォルダーの```tcp_check.d/conf.yaml```ファイルを編集する必要があります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2661124/ee8f73ab-9d20-e53f-40b9-45c929b6db76.png)


https://docs.datadoghq.com/ja/integrations/tcp_check/?tab=host

https://docs.datadoghq.com/ja/agent/guide/agent-configuration-files/?tab=agentv6v7#agent-%E3%81%AE%E6%A7%8B%E6%88%90%E3%83%87%E3%82%A3%E3%83%AC%E3%82%AF%E3%83%88%E3%83%AA


今回はLinuxを使用しているので```/etc/datadog-agent/conf.d/tcp_check.d/conf.yaml```に設定を書き込んでいきます。公式サイトによると、以下のように書けばよいことがわかります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2661124/0d462678-526e-0dfa-0ca8-ddf9438a7fa7.png)

<details><summary>使用可能なすべてのコンフィギュレーションオプションの詳細全体 
</summary>

```yaml
## All options defined here are available to all instances.
#
init_config:

    ## @param service - string - optional
    ## Attach the tag `service:<SERVICE>` to every metric, event, and service check emitted by this integration.
    ##
    ## Additionally, this sets the default `service` for every log source.
    #
    # service: <SERVICE>

## Every instance is scheduled independently of the others.
#
instances:

    ## @param name - string - required
    ## Name to assign to your TCP check instance.
    #
  - name: <TCP_CHECK_INSTANCE_NAME>

    ## @param host - string - required
    ## Host to connect to.
    #
    host: <TCP_HOST_TO_CONNECT_TO>

    ## @param port - integer - required
    ## Port of the host to connect to.
    #
    port: <PORT>

    ## @param timeout - number - optional - default: 10
    ## Timeout of the TCP query in second.
    #
    # timeout: 10

    ## @param collect_response_time - boolean - optional - default: false
    ## The `collect_response_time` parameter instructs the check to create a
    ## metric 'network.tcp.response_time', tagged with the host name,
    ## reporting the response time in seconds.
    #
    # collect_response_time: false

    ## @param ip_cache_duration - number - optional
    ## Time in seconds to cache the IP address of the given host. If duration is not set,
    ## the cache will expire only upon error.
    ##
    ## Set ip_cache_duration to `0` if the check should resolve the IP address on every check run.
    #
    # ip_cache_duration: 120

    ## @param multiple_ips - boolean - optional - default: false
    ## Enable to run the check against all IPs attached to `host`.
    #
    # multiple_ips: false

    ## @param ipv4_only - boolean - optional - default: false
    ## Enable to run the check against only IPv4-formatted addresses on every check run.
    #
    # ipv4_only: false

    ## @param tags - list of strings - optional
    ## A list of tags to attach to every metric and service check emitted by this instance.
    ##
    ## Learn more about tagging at https://docs.datadoghq.com/tagging
    #
    # tags:
    #   - <KEY_1>:<VALUE_1>
    #   - <KEY_2>:<VALUE_2>

    ## @param service - string - optional
    ## Attach the tag `service:<SERVICE>` to every metric, event, and service check emitted by this integration.
    ##
    ## Overrides any `service` defined in the `init_config` section.
    #
    # service: <SERVICE>

    ## @param min_collection_interval - number - optional - default: 15
    ## This changes the collection interval of the check. For more information, see:
    ## https://docs.datadoghq.com/developers/write_agent_check/#collection-interval
    #
    # min_collection_interval: 15

    ## @param empty_default_hostname - boolean - optional - default: false
    ## This forces the check to send metrics with no hostname.
    ##
    ## This is useful for cluster-level checks.
    #
    # empty_default_hostname: false

    ## @param metric_patterns - mapping - optional
    ## A mapping of metrics to include or exclude, with each entry being a regular expression.
    ##
    ## Metrics defined in `exclude` will take precedence in case of overlap.
    #
    # metric_patterns:
    #   include:
    #   - <INCLUDE_REGEX>
    #   exclude:
    #   - <EXCLUDE_REGEX>
```
</details>

https://github.com/DataDog/integrations-core/blob/master/tcp_check/datadog_checks/tcp_check/data/conf.yaml.example

サンプルを参考にし、以下のような設定ファイルを作成しました。
```yaml
  - name: qiita-sample-ec2-1                       
    host: localhost                                           
    port: 1000                                               
    collect_response_time: true                               
                                                              
  - name: qiita-sample-ec2-2                    
    host: localhost                                        
    port: 2000                                             
    collect_response_time: true                               
```

datadog-agentを再起動し状態を確認してみると、datadog-agentが正常に動いていることがわかります。
こんな感じの記述が確認できます。

```

    tcp_check (4.6.0)
    -----------------
      Instance ID: tcp_check:qiita-sample-ec2-1:xxxxxxxxxxx [OK]
      Configuration Source: file:/etc/datadog-agent/conf.d/tcp_check.d/conf.yaml
      Total Runs: 1
      Metric Samples: Last Run: 1, Total: 1
      Events: Last Run: 0, Total: 0
      Service Checks: Last Run: 1, Total: 1
      Average Execution Time : 1ms
      Last Execution Date : 2023-08-29 10:26:52 JST / 2023-08-29 01:26:52 UTC (1693272412000)
      Last Successful Execution Date : 2023-08-29 10:26:52 JST / 2023-08-29 01:26:52 UTC (1693272412000)

      Instance ID: tcp_check:qiita-sample-ec2-2:xxxxxxxxxx [OK]
      Configuration Source: file:/etc/datadog-agent/conf.d/tcp_check.d/conf.yaml
      Total Runs: 1
      Metric Samples: Last Run: 2, Total: 2
      Events: Last Run: 0, Total: 0
      Service Checks: Last Run: 1, Total: 1
      Average Execution Time : 1ms
      Last Execution Date : 2023-08-29 10:26:51 JST / 2023-08-29 01:26:51 UTC (1693272411000)
      Last Successful Execution Date : 2023-08-29 10:26:51 JST / 2023-08-29 01:26:51 UTC (1693272411000)
```

これでOKと思っていたのですが、Datadogで確認してみると```network.tcp.can_connect```というインスタンスとDatadog間の通信の有無を表すメトリクスが0のものと1のものに分かれていることが発覚しました。


ポート1000がDatadogと通信できず、ポート2000は通信できていることが判明します。

Datadogから確認できるグラフのイメージは以下のような形です。上が1000で下が2000です。

**1000**
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2661124/25895c32-1159-d8d8-4802-924a8e6a0821.png)


**2000**
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2661124/06baf720-5e1f-c130-9416-e7ff009b8070.png)

datadog-agentとしては問題なさそうなので、datadog-agentとDatadogの間の疎通に問題がありそうです。

datadog-agentがOKと言っているのでポートは開いているはずですが、問題はポートにあるだろうという信念から、ポート周りを調査していました。```netstat -tuln```を調べた結果以下のようになりました。

```bash
[root@ip-10-28-84-83 tcp_check.d]# netstat -tuln | grep 1000
tcp        0      0 0.0.0.0:1000           0.0.0.0:*               LISTEN
[root@ip-10-28-84-83 tcp_check.d]# netstat -tuln | grep 2000
tcp6       0      0 :::2000                :::*                    LISTEN
```

IPv4とIPv6という差異が発生しています。
使用可能なすべてのコンフィギュレーションオプションの詳細全体をもう一度確認してみると、以下のような記載があります。
```yaml
    ## @param ipv4_only - boolean - optional - default: false
    ## Enable to run the check against only IPv4-formatted addresses on every check run.
    #
    # ipv4_only: false
```
こちらをそのまま読むと、この値をtrueにすると、デフォルトではIPv4とIPv6でチェックを実行していたのをIPv4のみのチェックに変更する、という風に読めます。

しかし、成功しているものと失敗しているものの違いにIPv4かIPv6かぐらいしか見当たらなかったので、2000の方の設定に対して```ipv4_only: true```を加えてみます。すると、まさかの成功でした。つまり、```ipv4_only: false```という状態は、IPv6のみのチェックを行っている、と推測できます。


## あとがき
Enable to run the check against only IPv4-formatted addresses on every check run.という文章を考えるとデフォルトではIPv4でもIPv6でもチェックを実行しているように推測できます。デフォルトでどちらも実行していると記載されているわけではありませんが、この記載でデフォルトではIPv4をチェックしていないのは少し不親切な気もします。

DatadogのQiita記事や公式以外の企業ブログがかなり少なくて、少し詰まってしまいました。AWSでは公式以外にも数多の技術記事が公開されていますが、そのありがたみを改めて実感しました。