ECSとDatadogを使ったネットワーク機器のモニタリング

インフラエンジニアの菅原です。

カンムはバンドルカードというVisaプリペイドカードのサービスを提供していますが、Visaと決済情報をやりとりするためにオンプレミスのサーバと通信しています。

カンムのサービスはAWS上で構築されており、AWSとオンプレミスのサーバの通信はAWS Direct Connectを経由してます。

また、ネットワーク制御のためスイッチとしてCisco CatalystとJuniper SRXを使用しています。

f:id:winebarrel:20220130132559j:plain

ネットワーク機器は通常のサーバと同様になにかしらの問題が発生することがあるため、SNMPによるメトリクスの収集やSNMPトラップでのイベントの検知が必要になります。

また、Syslogはネットワーク機器内にファイルとして保存されていますが、外部にログを転送・保存しておくことで何か問題が発生したときに分析がやりやすくなります。

以前まではEC2インスタンスSNMPの収集・SNMPトラップの受信・ネットワーク機器用のSyslogサーバ、NTPサーバの運用を行っていました。

f:id:winebarrel:20220130134323j:plain

ECSとDatadogによる監視の構築

EC2インスタンスはサーバーの自体の管理やOS・ミドルウェアのアップデートなどでそれなりに運用の手間がかかります。

そこでECSとDatadogを使って、コンテナとSaaSでネットワーク機器の監視をできるようにしました。

f:id:winebarrel:20220130135659j:plain

Datadog AgentによるSNMPの収集とSNMPトラップの受信

ネットワーク機器のSNMPの収集とSNMPトラップの受信にはDatadog Agentのコンテナを使用しています。*1

SNMPトラップはUDPで送信されるためNetwork Load Balancer(NLB)を使ったECSサービスを作成しました。

Dockerfile

FROM datadog/agent:7

# (中略)

COPY datadog.yaml.tmpl /etc/datadog-agent/
COPY snmp.d_conf.yaml.tmpl /etc/datadog-agent/conf.d/snmp.d/conf.yaml.tmpl
COPY ping.d_conf.yaml.tmpl /etc/datadog-agent/conf.d/ping.d/conf.yaml.tmpl

# https://github.com/progrium/entrykit を使っています
ENTRYPOINT [ \
  "render",\
  "/etc/datadog-agent/datadog.yaml", \
  "--", \
  "render",\
  "/etc/datadog-agent/conf.d/snmp.d/conf.yaml", \
  "--", \
  "/bin/entrypoint.sh" \
  ]

datadog.yml

# cf. https://github.com/DataDog/datadog-agent/blob/main/pkg/config/config_template.yaml
snmp_traps_enabled: true
snmp_traps_config:
  bind_host: "0.0.0.0"
  community_strings:
    - '{{ var "COMMUNITY_STRING" }}'

# NOTE: Needed for SNMP trap
logs_enabled: true

snmp.d/conf.yml

# cf. https://docs.datadoghq.com/ja/network_performance_monitoring/devices/setup/?tab=snmpv2
init_config:
  loader: core
  use_device_id_as_hostname: true
instances:
{{ range $_, $ip_address := var "IP_ADDRESSES" | split "," }}
- ip_address: "{{ $ip_address }}"
  community_string: "{{ var "COMMUNITY_STRING" }}"
{{ end }}

Datadog Agentで収集された情報はDatadogに送られます。

f:id:winebarrel:20220130141331p:plain

SNMPトラップはDatadog Logsに送られます。

f:id:winebarrel:20220130141837p:plain

RsyslogによるSyslogの受信とDatadogへの送信

ネットワーク機器からのSyslogの受信にはRsyslogのコンテナを使用しています。

Datadog Agentと同じNLBを使ったECSサービス上でコンテナを起動し、受信したSyslogはDadadog Logsへと送られます。*2

Dockefile

FROM    ubuntu:20.04

# (中略)

COPY rsyslog.conf.tmpl /etc/
COPY datadog.conf.tmpl /etc/rsyslog.d/

ENTRYPOINT [ \
  "render",\
  "/etc/rsyslog.d/datadog.conf", \
  "--", \
  "render",\
  "/etc/rsyslog.conf", \
  "--", \
  "rsyslogd", "-n" \
  ]

rsyslog.conf

module(load="imuxsock")
module(load="immark" interval="20")

module(load="imudp")
input(type="imudp" port="{{ var "RSYSLOG_PORT" | default 514 }}")

module(load="imtcp")
input(type="imtcp" port="514")

module(load="omstdout")

$WorkDirectory /var/spool/rsyslog
$IncludeConfig /etc/rsyslog.d/*.conf
$AbortOnUncleanConfig on
$DefaultNetstreamDriverCAFile /etc/ssl/certs/ca-certificates.crt

action(type="omstdout")

datadog.conf

## Set the Datadog Format to send the logs
$template DatadogFormat,"{{ var "DD_API_KEY" }} <%pri%>%protocol-version% %timestamp:::date-rfc3339% %HOSTNAME% %app-name% - - [metas ddsource=\"rsyslog\" ddtags=\"env:prd\"] %msg%\n"

action(
  type="omfwd"
  protocol="tcp"
  target="intake.logs.datadoghq.com"
  port="10516" template="DatadogFormat"
  StreamDriver="gtls"
  StreamDriverMode="1"
  StreamDriverAuthMode="x509/name"
  StreamDriverPermittedPeers="*.logs.datadoghq.com"
  action.resumeRetryCount="10"
  action.reportSuspension="on"
)

Datadog Logsに送られたSyslogはコンソールから見ることができます。

f:id:winebarrel:20220130143356p:plain

Amazon Time Sync ServiceによるNTPサービス

ネットワーク機器はNTPサーバとしてAWS上のサーバを参照しています。

ntpdのコンテナを作成してもよかったのですがAWSAmazon Time Sync Serviceを提供しているので、stoneを使ってNTPをAmazon Time Sync Serviceに中継するようにしました。

Dockerfile

FROM debian:bullseye AS build

ARG STONE_VERSION=2.4

RUN apt-get update && \
  apt-get install -y curl build-essential

RUN curl -sSfLO https://www.gcd.org/sengoku/stone/stone-${STONE_VERSION}.tar.gz && \
  tar xf stone-${STONE_VERSION}.tar.gz --strip-components 1 && \
  make linux

FROM debian:bullseye-slim

COPY --from=build stone /usr/local/bin/

ENTRYPOINT ["/usr/local/bin/stone"]

タスク定義の一部

      command: [
        // NTP
        // cf. https://aws.amazon.com/jp/blogs/news/keeping-time-with-amazon-time-sync-service/
        '169.254.169.123:123/udp',
        '123/udp',
        '--',
        // HTTP (for healthcheck)
        '169.254.169.253:53',
        '80',
      ],

苦労した点

NLBのヘルスチェック

NLBでUDPを使っている場合でもヘルスチェックはTCPで行われます。 そのため、各コンテナでTCPのヘルスチェックができるように工夫しました。

  • Datadog Agentはいくつかデーモンが立ち上がっているので、そのうちの一つでLISTENされているポートをヘルスチェックに利用しています
  • RsyslogはTCPでのSyslogの受信は行わないのですが、ヘルスチェックのためにinput(type="imtcp" port="514")の設定を追加しました
  • stoneはそれ自体がヘルスチェック機能を持っていないので、VPCDNSサーバにTCPパケットを中継してヘルスチェックとしています

DatadogとRsyslogの接続が切れる

ドキュメントにも書いてあるのですが、DatadogとRsyslogの接続は非アクティブな状態が続くと切断されて再接続ができません。

このためmodule(load="immark" interval="20")して定期的にログを流すようにしています。 また、切断されても気づけるようにログが一定時間流れなかったらアラートをあげるようにもしています。

ECSのデプロイ後にSyslogが受信できなくなる

ECSをデプロイすると一部のネットワーク機器からSyslogが受信できなくなるという問題もありました。 ネットワーク機器はNLBのIPアドレスを参照しているのですが、デプロイ完了後も古いコンテナのほうにSyslogが流れて続けてしまい、新しいコンテナにはSyslogが流れなくなるという状態になっていました。

詳しい原因を調査できていないのですが、NLBのTarget GroupでConnection termination on deregistrationを有効にすることで、この問題を解決できました。

f:id:winebarrel:20220130150057p:plain

まとめ

いままでは監視用のEC2インスタンスの運用が地味に手間だったのですが、コンテナ化によってだいぶ手間を軽減することができました。

また、Datadogを利用することでメトリクスやログの閲覧がとても楽になりました。

カンムでは引き続きEC2からECSの移行が進行中です。興味のあるインフラエンジニアを絶賛募集しております。

open.talentio.com