LAN内のラズパイからDockerコンテナへsyslog,http通信

## はじめに

**家のLAN内でラズパイのsyslogを監視したい**
ラズパイのsyslogを fluentd で捕捉したい
・・・そしていずれは kibana でグラフィカルに見たい！

**今回はラズパイのsyslogをDockerに立てたfluentdで閲覧するところまで行う**

（おまけ）その過程で、疎通確認も兼ねてHTTPアクセスもしてみた

**～編集後記～**
単にWinマシンのIPアドレスへアクセスしてもDockerコンテナまでは届かない
HTTPによるTCP通信も同時に試していたことで、syslog(UDP)がDockerコンテナへ届かない問題の原因切り分けができた

### 検証環境

DockerのホストはWindowsマシン

同一のプライベートアドレス空間にあるラズパイがWindowsへsyslogを投げる

- Windows 11 Home (Dockerホスト)
  - 192.168.10.101
- ラズパイ 3B+
  - 192.168.10.81

まだWindowsにDocker環境がない場合の参考：[Windows＋WSL2でDocker環境を用意しよう](https://www.kagoya.jp/howto/cloud/container/wsl2_docker/)

## LANからDockerコンテナへアクセス許可

冒頭の編集後記でも書いた通り、単純に 「http:／／Windowマシン」としても
**Dockerホスト以外のマシンDockerコンテナへまで通信が届かない**
（ホストからはhttp:／／localhostで簡単にDockerコンテナへアクセスできるのに）

### WSL2から既定の動作が変わっているらしい 

[ローカル エリア ネットワーク (LAN) からの WSL 2 ディストリビューションへのアクセス](https://learn.microsoft.com/ja-jp/windows/wsl/networking#accessing-a-wsl-2-distribution-from-your-local-area-network-lan)

コマンドプロンプトで `wsl -l -v` を実行すると、WSLのVERSIONを確認できる

```powershell
  NAME                      STATE           VERSION
* docker-desktop-data       Running         2
  podman-machine-default    Stopped         2
  Ubuntu                    Running         2
  docker-desktop            Running         2
```

VERSIONは2でした
なので、ひと手間必要です
（WSL1がどうだったかは知る由もない）

### WSL2(Ubuntu)のIPアドレスを取得する

Windowsの検索で「Ubuntu」を検索して実行
黒い窓が立ち上がる

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/272511/7460d5a6-6141-0d96-0c51-77d13c609e10.png)

`ip addr`でetho0に割り当てられているIPアドレス（ここでは `172.17.82.122`） を調べる

```
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP group default qlen 1000
    link/ether 00:15:5d:7b:a8:d8 brd ff:ff:ff:ff:ff:ff
    inet 172.17.82.122/20 brd 172.17.95.255 scope global eth0
```

### Windowsポートフォワード設定

先ほど調べたIPアドレス `172.17.82.122` に対してポートフォワード設定を行う

```powershell
netsh interface portproxy add v4tov4 listenport=24224 listenaddress=0.0.0.0 connectport=24224 connectaddress=172.17.82.122
netsh interface portproxy add v4tov4 listenport=8000 listenaddress=0.0.0.0 connectport=8000 connectaddress=172.17.82.122
netsh interface portproxy add v4tov4 listenport=5140 listenaddress=0.0.0.0 connectport=5140 connectaddress=172.17.82.122
```

設定が反映されているか確認する

```powershell
netsh interface portproxy show v4tov4
```

コマンドの結果2行が表示され、設定が反映されていることがわかる

```powershell
ipv4 をリッスンする:         ipv4 に接続する:

Address         Port        Address         Port
--------------- ----------  --------------- ----------
0.0.0.0         24224       172.17.82.122   24224
0.0.0.0         8000        172.17.82.122   8000
0.0.0.0         5140        172.17.82.122   5140
```

### Windowsファイアウォールの設定

受信の規則から、必要なポートへのアクセスを許可する
今回許可するのは以下３つ
- syslog用 `5140/tcp`
- 汎用デバッグ用 `24224/tcp`
- HTTP用 `8000/tcp`

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/272511/65300c9c-c29d-a261-187b-1f3e33b8c807.png)

あらたに3行の規則を追加する

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/272511/714b1148-a8e0-5c54-6f76-b436e43d7ea9.png)

セキュリティ上、念のため、送信元はラズパイ(`192.168.10.81`)に限定している

## Dockerコンテナを立ち上げる

fluentdと軽量httpサーバの２つを立ち上げる

### docker-compose.yml

- fluentdは固定IPアドレスを持つ
  - ポートをホストに３つ公開する
- webも固定IPアドレスを持つ
  - 8000ポートを公開する
  - webのログはfluentdに流す

```yml
version: "3"

services:
  fluentd:
    build: ./fluentd
    volumes:
      - ./fluentd/conf:/fluentd/etc
    ports:
      - "24224:24224"
      - "24224:24224/udp"
      - "5140:5140"
    networks:
      efk-net:
        ipv4_address: 172.22.0.10
  
  web:
    image: nginx:alpine-slim
    ports:
      - 8000:80
    logging:
      driver: "fluentd"
      options:
        fluentd-address: 172.22.0.10:24224
        fluentd-async-connect: "true"
        fluentd-retry-wait: 2s
        fluentd-max-retries: 30
        tag: httpd.access
    networks:
      efk-net:
        ipv4_address: 172.22.0.20
    depends_on:
      - fluentd

networks:
  efk-net:
    driver: bridge
    ipam:
      driver: default
      config:
        - subnet: 172.22.0.0/16
```

fluentdのdockerfileについては、[前回記事](https://qiita.com/t13801206/items/d67769655fb685953eb1#dockerfile)参照

### fluent.config

ソースは２つ

- ポート24244でHTTPログと、ラズパイのechoを取得する
- ポート5140でラズパイのsyslogを取得する

取得した内容はすべて標準出力(stdout)する

```xml
<source>
  @type forward
  port 24224
  bind 0.0.0.0
</source>

<source>
  @type syslog
  port 5140
  bind 0.0.0.0
  protocol_type tcp
  tag raspi
</source>

<match raspi.**.***>
  @type stdout
</match>

<match httpd.access> 
  @type stdout
</match>

<match debug.**>
  type stdout
</match>
```

注意点として、[syslogプラグインのデフォルトがUDPになっている](https://docs.fluentd.org/input/syslog#protocol_type)ので
明示的に` protocol_type tcp`でTCPを指定する

### docker起動、ログ表示など

関連するコマンド一覧

```bash
# 開始、ログ表示
docker compose up -d
docker compose logs -f

# コンフィグやymlファイルを更新したら再起動で反映
docker compose restart

# 検証後に環境をきれいにする
docker compose down -v
```

## いざ、疎通確認！

ラズパイにTeraTermで接続し、３つの疎通確認をおこなう

### （１）デバッグ用 echo メッセージ

[馴染みあるツールで fluentd に対してお手軽にメトリクスを送信する](https://qiita.com/ciela/items/3025aa9d23fbdc9caea3)
を参考に、適当なメッセージを投げる

```bash:TCP
echo '["debug.ciela.test",1459845632,["a","b",{"first":"one","second":"two"}]]' | nc 192.168.10.101 24224
```

fluentdにログが表示されている、成功！

```powershell
2306_fluentdstudy-fluentd-1  | 2016-04-05 08:40:32.000000000 +0000 debug.ciela.test: ["a","b",{"first":"one","second":"two"}]
```

#### UDP通信がうまくいかない


`nc -u`でUDP送信すると、うまくいかない
（※ファイアウォールは開けている）

```bash:UDP
echo '["debug.ciela.test",1459845632,["a","b",{"first":"one","second":"two"}]]' | nc -u 192.168.10.101 24224
```

DockerホストであるWindowsでポートの状態を調べると、ちゃんとUDPで待っているようにみえる・・・？

```powershell:一部省略して記載
PS C:\> netstat -an | Select-String 24224

  TCP         0.0.0.0:24224          0.0.0.0:0              LISTENING
  UDP         0.0.0.0:24224          *:*
```

##### WindowsのportproxyはUDPに非対応

＜思考過程＞
- ポートフォワードの設定が足りていないのでは？
  - デフォルトがTCPで、UDPの設定も別途必要だとか
    - WindowsファイアォールもTCPとUDPはそれぞれ設定が必要だし・・

[Netsh - redirect UDP traffic to VM](https://superuser.com/questions/1274774/netsh-redirect-udp-traffic-to-vm)　←ここに答えがあった。

**TCPだけがサポートされています**

```txt
# netsh interface portproxy add v4tov4

パラメーター:

       タグ             値
       listenport     - リッスンする IPv4 ポートです。
       connectaddress - 接続する IPv4 アドレスです。
       connectport    - 接続する IPv4 ポートです。
       listenaddress  - リッスンする IPv4 アドレスです。
       protocol       - 使用するプロトコルです。現在、TCP だけがサポート
                        されています。
```

ということで、**ラズパイからのUDP通信はDockerコンテナに届かない**ことがわかった

### （２）HTTP通信

ラズパイから`curl`でWindowsマシン8000ポートにアクセスする

```bash
curl -v 192.168.10.101:8000
```

fluentdにログが表示されている、成功！

1行目はコンテナ自身のログ
2行目はfluentdが受信したログ

```powershell
2306_fluentdstudy-web-1      | 172.22.0.1 - - [18/Jun/2023:04:55:04 +0000] "GET / HTTP/1.1" 200 615 "-" "curl/7.52.1" "-"
2306_fluentdstudy-fluentd-1  | 2023-06-18 04:55:04.000000000 +0000 httpd.access: {"container_id":"6eb8246366cdca7bc7817887de8dcfa4575a644ae010263635cb4e07bb078002","container_name":"/2306_fluentdstudy-web-1","source":"stdout","log":"172.22.0.1 - - [18/Jun/2023:04:55:04 +0000] \"GET / HTTP/1.1\" 200 615 \"-\" \"curl/7.52.1\" \"-\""}
```

## （３）Syslog通信

ラズパイのsyslogコンフィグファイルに１行だけ追加する
`@@`をつけることで、TCP通信になる（`@`１つだとUDP通信）

```bash:sudo vim /etc/rsyslog.conf
# 追記ここから
*.*;auth,authpriv,cron,mail,user.none      @@192.168.10.101:24224
# 追記ここまで
```

もともとログの種類ごとに出力先が書かれているので
その近くに追記すると、あとから見返したときに分かりやすい

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/272511/3ef3c1d3-11f2-2c61-d619-3b5d0fc6d8b8.png)

ラズパイのsyslogサービスを再起動する

```bash
systemctl restart rsyslog.service
```

### ラズパイからSyslogメッセージ送信

汎用ファシリティ`local0`とプライオリティ`info`を組み合わせて
疑似メッセージをラズパイから送信する

```bash
logger -p local0.info "Message from RaspberryPi"
```

fluentdにログが表示されている、成功！

```powershell
2306_fluentdstudy-fluentd-1  | 2023-06-18 14:26:19.000000000 +0000 raspi.local0.info: {"host":"redmagic","ident":"pi","message":"Message from RaspberryPi"}
```

さらに、サービスを再起動したときのログを見る
syslogデーモンを再起動する

```bash
systemctl restart rsyslog.service
```

`raspi.daemon.info`タグでfluentdに表示されていることがわかる

```powershell
2306_fluentdstudy-fluentd-1  | 2023-06-18 14:28:13.000000000 +0000 raspi.daemon.info: {"host":"redmagic","ident":"systemd","pid":"1","message":"Stopping System Logging Service..."}
2306_fluentdstudy-fluentd-1  | 2023-06-18 14:28:13.000000000 +0000 raspi.local7.info: {"host":"redmagic","ident":"liblogging-stdlog","message":"[origin software=\"rsyslogd\" swVersion=\"8.24.0\" x-pid=\"6708\" x-info=\"http://www.rsyslog.com\"] exiting on signal 15."}
2306_fluentdstudy-fluentd-1  | 2023-06-18 14:28:13.000000000 +0000 raspi.daemon.info: {"host":"redmagic","ident":"systemd","pid":"1","message":"Stopped System Logging Service."}
2306_fluentdstudy-fluentd-1  | 2023-06-18 14:28:13.000000000 +0000 raspi.daemon.info: {"host":"redmagic","ident":"systemd","pid":"1","message":"Starting System Logging Service..."}
2306_fluentdstudy-fluentd-1  | 2023-06-18 14:28:13.000000000 +0000 raspi.local7.info: {"host":"redmagic","ident":"liblogging-stdlog","message":"[origin software=\"rsyslogd\" swVersion=\"8.24.0\" x-pid=\"6919\" x-info=\"http://www.rsyslog.com\"] start"}
2306_fluentdstudy-fluentd-1  | 2023-06-18 14:28:13.000000000 +0000 raspi.daemon.info: {"host":"redmagic","ident":"systemd","pid":"1","message":"Started System Logging Service."}
```

## おわりに

fluentdをDockerコンテナに立てて
ラズパイのsyslogを捕捉した

ラズパイのsyslogを、Dockerコンテナの標準出力で見ることができた

今度はラズパイのsyslogをkibana（ブラウザ）でみたい

## 参考

[WSL2 内の Docker サーバーに LAN 内の別 PC からアクセスする (netsh)](https://maku77.github.io/p/w6cjckc/)

## 糸冬了！！