snmp agentのコンテナ化

# はじめに

サーバーやネットワークを監視する環境を構築するには一般的にはマネージャーと呼ばれる監視を管理するサーバー、そしてエージェントと呼ばれる監視対象ホストのアプリケーションが必要となる。
つまり100台監視したい場合にはそれぞれにエージェントを導入する必要がありまあまあ面倒くさい。

このようなエージェント監視型に対してエージェント不要のエージェントレス監視型というのがあり、後者の方が圧倒的に便利だと思うけど`OSS`での実績で言うとまだ物足りないのかなと思っている(勉強不足ならごめん)。そのため今の所エージェント型を利用している。

またエージェントにもいくつかあるがここでは多くの監視マネジャーが対応している古典的な`snmp`エージェントのコンテナ化を紹介したい。

# 実装

実を言うと`snmp`エージェントはわざわざコンテナ化するまでもなく`apt-get`などで簡単に導入できる。

```shell:apt-get(Debina/Ubuntu)
sudo apt-get install -y snmp snmpd
```

しかし、設定や`MIB`情報の登録を含めるとコンテナ化するメリットはある。
今回ベースとした「[hakengineer/snmp\-agent](https://github.com/hakengineer/snmp-agent)」を元に手を加えてみる。

## 最初のステップ〜ざっくり実装

元ネタは`Dockerfile`単体で完結しているが`entrypoint`を別ファイルに起こす。

```dockerfile:Dockerfile
FROM ubuntu:18.04

RUN apt-get update && apt-get install -y \
    snmp snmpd --no-install-recommends && \
    rm -rf /var/cache/apk/*

COPY entrypoint.sh /

ENTRYPOINT ["sh", "/entrypoint.sh"]
```

`entrypoint`の設定は、すべての`MIB`を受け入れるのとコミュニティ名は`public`のまま使うようにしている。

```shell:entrypoint.sh
#!/bin/sh

set -e

OPTIONS=$@

# =============================================================
# Settings - Replace variables
# =============================================================
## Modify snmp.conf
sed -i".orig" "s/mibs :/mibs all/" /etc/snmp/snmp.conf

# Modify snmpd.conf
cp -p /etc/snmp/snmpd.conf /etc/snmp/snmpd.conf.orig
sed -i -e "s/agentAddress  udp:127.0.0.1:161/agentAddress  udp:161/" \
    -i -e "s/view   systemonly  included   .1.3.6.1.2.1.1/#view   systemonly  included   .1.3.6.1.2.1.1/" \
    -i -e "s/view   systemonly  included   .1.3.6.1.2.1.25.1/#view   systemonly  included   .1.3.6.1.2.1.25.1/" \
    -i -e "s/rocommunity public  default    -V systemonly/rocommunity public default/" \
    -i -e "s/rocommunity6 public  default   -V systemonly/#rocommunity6 public  default   -V systemonly/" /etc/snmp/snmpd.conf


# =============================================================
# Run service
# =============================================================
service snmpd start && /bin/bash


exec "$@"
```

:::note warn
`ubuntu 20.04`に上げようとしたが`agentAddress`の設定でエラーが出て起動しないため`18.04`にした。
[server \- Failed to start snmpd\.service on UBUNTU Linux OS \- Ask Ubuntu](https://askubuntu.com/questions/1334325/failed-to-start-snmpd-service-on-ubuntu-linux-os)
:::

## 次のステップ〜MIBの追加

これだけでは`MIB`の情報が足らないため追加する。

```dockerfile:Dockerfile(変更箇所)
RUN apt-get update && apt-get install -y \
    snmp snmpd snmp-mibs-downloader ca-certificates --no-install-recommends && \
    rm -rf /var/cache/apk/*
```

:::note
`ca-certificates`は`wget`で`ssl`通信する時に必要である。
なお`wget`は`snmp-mibs-downloader`との依存関係で含まれる。
:::

```shell:entrypoint.sh(サービス起動の前に追加)
# =============================================================
# Download mibs
# =============================================================
MIBS_DIR=/usr/share/snmp/mibs

download-mibs

## Additional MIBs
# wget http://www.iana.org/assignments/ianaippmmetricsregistry-mib/ianaippmmetricsregistry-mib -O ${MIBS_DIR}/iana/IANA-IPPM-METRICS-REGISTRY-MIB
wget http://pastebin.com/raw/p3QyuXzZ -O ${MIBS_DIR}/ietf/SNMPv2-PDU
wget http://pastebin.com/raw/gG7j8nyk -O ${MIBS_DIR}/ietf/IPATM-IPMC-MIB
```

::: note
上記`MIB`を追加する例をあちこちで見かけるがコメントアウトしている`IANA-IPPM-METRICS-REGISTRY-MIB`は既に存在するので不要だと思う。
:::

## 最後のステップ〜docker-compose化する

ついでに`docker-compose`化してみる。

```yaml:docker-compose.yml
version: "3.7"

services:
  app:
    container_name: snmp-agent
    restart: unless-stopped
    tty: true
    ports:
      - "161:161/udp"
```

この場合のメリットとして`zabbix-agent`、`node exporter`や`cAdvisor`等他のエージェントもまとめてパッケージ化できるといういところ。
たとえば`node exporter`を追加したければ以下のようにすればよい。

```yaml:docker-compose.yml
version: "3.7"

services:
  snmp-agent:
    container_name: snmp-agent
    restart: unless-stopped
    tty: true
    ports:
      - "161:161/udp" 
  node-exporter:
    image: prom/node-exporter:v1.3.1
    container_name: node-exporter
    restart: unless-stopped
    command:
      - '--path.rootfs=/host'
    ports:
      - "9100:9100"
    volumes:
      - '/:/host:ro,rslave'
```

## 補足〜プライベートMIBの登録

`caribou_hy`さんの記事「[ルーター、スイッチの情報をSNMPで取得 by WSL2\(Ubuntu\)](https://qiita.com/caribou_hy/items/85dfb575c1b73a8d0d69)」にあるようにルーターやスイッチ用の`MIB`を登録したいなら`entrypoint.sh`に以下を追加する。

```shell:entrypoint.sh(サービス起動の前にさらに追加)
# Private MIBs
# NEC MIBs
mkdir -p ${MIBS_DIR}/nec
wget https://jpn.nec.com/univerge/ix/Manual/MIB/PICO-SMI-MIB.txt -O ${MIBS_DIR}/nec/PICO-SMI-MIB.txt
wget https://jpn.nec.com/univerge/ix/Manual/MIB/PICO-SMI-ID-MIB.txt -O ${MIBS_DIR}/nec/PICO-SMI-ID-MIB.txt
wget https://jpn.nec.com/univerge/ix/Manual/MIB/PICO-IPSEC-FLOW-MONITOR-MIB.txt -O ${MIBS_DIR}/nec/PICO-IPSEC-FLOW-MONITOR-MIB.txt

## Fujitsu MIBs
mkdir -p ${MIBS_DIR}/fujitsu
cd /var/tmp
wget https://fenics.fujitsu.com/products/downloads/products/download/sr-s/firm/rev22/SRS-MIB.zip
unzip SRS-MIB.zip
unzip SRS-MIB/srs.zip
mv srs.txt ${MIBS_DIR}/fujitsu/SRS-MIB.txt
rm -fr SRS-MIB*
cd

# YAMAHA MIBs
cd ${MIBS_DIR}
wget -O - 'http://www.rtpro.yamaha.co.jp/RT/docs/mib/yamaha-private-mib.tar.gz' | tar zxf -
mv yamaha-private-mib yamaha
chmod -x yamaha/*.txt*
cd
```

## 完成版

完成版はいつもの`Makefile`で実装。

:::note warn
ちなみに環境変数で値を変更できるようにしているが`docker-compose`+`Dockerfile`で環境変数を使う場合ってこんな面倒なことしなければならないのは自分の勉強不足のせい？
:::

:::note
コミュニティ名を`public`から変更したい場合は同様に環境変数で定義して`entrypoint.sh`にて`sed`で置換してやればよい。
:::

https://github.com/higebobo/docker-snmp-agent

`snmpwalk`、`snmpget`や更には`snmptrap`の使用例も`Makefile`内のタスクで定義しているので参考にされたし。

# 最後に

やっぱりエージェントレスだよなとしみじみ思いつつ、ここは`k8s`を使えば一括デプロイなんかも楽になるんだろうな。使ったこと無いけど。