Docker Composeでネットワークサービス群を5分で作れるようにした（dhcp/radius/proxy/tftp/syslog/dns）

## はじめに
[CentOS7で各種ネットワークサービスを基本設定したメモ（dhcp/radius/proxy/tftp/syslog）](https://qiita.com/bashaway/items/2bf96ae84ebb5c84ba7d)
をCentOS8で再構築しました。今回は各サービスをDockerでコンテナに閉じ込めています。

自分で使う用に docker-compose を利用したところ、５分くらいで環境のリストアができるようになったので、記録に残します。

## 更新
DHCPはIPマスカレード環境でうまく動作しなかったので、network_mode を host に修正しました。
パケット内にIPアドレスが埋め込まれており、単純なNAPTだとコンテナ内のアドレスがDHCPサーバとなってしまうため。

DNS64とDNSキャッシュの機能を持つ(unbound)も追加しました。


## なにができるようになるのか

### 以下のような環境を作成できます。

[![Screenshot from Gyazo](https://gyazo.com/b64caf5702b9f179b50cb5cda2b7e266/raw)](https://gyazo.com/b64caf5702b9f179b50cb5cda2b7e266)

docker-compose したホストの同一ポートにバインドしますので、外部端末から `ホストのアドレス:サービスのポート` にアクセスすると、各コンテナに到着します。
また、各種ログを同一ネットワーク上の syslog を待ち受けているコンテナにログを送信するようにしています。


以下のコンテナが生成されます。

|server|app|address|listen|
|:-:|:-:|:-:|:-:|
|proxy|squid|172.20.0.2|8080/tcp|
|syslog|rsyslog|172.20.0.3|514/udp|
|radius|freeRADIUS|172.20.0.4|1812,1813/udp|
|dns|unbound|172.20.0.5|53/udp,tcp|
|dhcp|ISC-Kea|-|67,68/udp|
|tftp|tftp-server|-|69/udp|

```
# docker ps
CONTAINER ID        IMAGE               COMMAND             CREATED              STATUS              PORTS                                    NAMES
3d7fec4d9ffd        infraserv:dns       "/usr/sbin/init"    About a minute ago   Up 58 seconds       0.0.0.0:53->53/tcp, 0.0.0.0:53->53/udp   dns
c34f033b140c        infraserv:radius    "/usr/sbin/init"    About a minute ago   Up 57 seconds       0.0.0.0:1812-1813->1812-1813/udp         radius
eb32cce0d7b9        infraserv:dhcp      "/usr/sbin/init"    About a minute ago   Up 59 seconds                                                dhcp
fedd69042ec3        infraserv:tftp      "/usr/sbin/init"    About a minute ago   Up 59 seconds                                                tftp
3e033a44c162        infraserv:syslog    "/usr/sbin/init"    About a minute ago   Up 58 seconds       0.0.0.0:514->514/udp                     syslog
d2454fc12ae8        infraserv:proxy     "/usr/sbin/init"    About a minute ago   Up 57 seconds       0.0.0.0:8080->8080/tcp                   proxy
```



以下のパラメータのネットワークが生成されます。

|key|value|
|:-:|:-:|
|name|infraserv_infranet|
|subnet|172.20.0.0/24|
|interface|docker1|


tftp/dhcpは `--net=host` な環境で動作しているため、 `docker network` は以下のような状態です。

```
# docker network inspect infraserv_infranet
[
    {
        "Name": "infraserv_infranet",
        "Id": "58a9c3da443b49416003d4f3ed5192a521c728270826a18da293000ae4b1004e",
        "Created": "2020-02-19T07:00:15.610028349+09:00",
        "Scope": "local",
        "Driver": "bridge",
        "EnableIPv6": false,
        "IPAM": {
            "Driver": "default",
            "Options": null,
            "Config": [
                {
                    "Subnet": "172.20.0.0/24"
                }
            ]
        },
        "Internal": false,
        "Attachable": true,
        "Ingress": false,
        "ConfigFrom": {
            "Network": ""
        },
        "ConfigOnly": false,
        "Containers": {
            "3d7fec4d9ffd315a6fb087b6a7f28453d7009a8eecd60a5110a3f4f7c4e2564c": {
                "Name": "dns",
                "EndpointID": "537b189764340697c9ea4f727211df450226a09a65aa24f20f275f56346d52fc",
                "MacAddress": "02:42:ac:14:00:05",
                "IPv4Address": "172.20.0.5/24",
                "IPv6Address": ""
            },
            "3e033a44c1625b7dd30a8a358f40c96594f462a6714caf39d726d4cb401ffcfd": {
                "Name": "syslog",
                "EndpointID": "3083640a976bd89e33d0f478eef9e6faa468cecccaea23729cf01f1ba24692f3",
                "MacAddress": "02:42:ac:14:00:03",
                "IPv4Address": "172.20.0.3/24",
                "IPv6Address": ""
            },
            "c34f033b140cee61992bbc3f1d9d652155121a27462aa460413b7be646e0ab6e": {
                "Name": "radius",
                "EndpointID": "f3c7bdc9c08fb283681f412996949126fa5f73213f9a265b6371e028efdc0eb1",
                "MacAddress": "02:42:ac:14:00:04",
                "IPv4Address": "172.20.0.4/24",
                "IPv6Address": ""
            },
            "d2454fc12ae861ff3e240ef26c95c55907382465148e1c4b829d48b5af91d60b": {
                "Name": "proxy",
                "EndpointID": "b81e9ea373b2fb7e0a68f1d24534fc6ebb78c01e24e6eb838ecd06127307a202",
                "MacAddress": "02:42:ac:14:00:02",
                "IPv4Address": "172.20.0.2/24",
                "IPv6Address": ""
            }
        },
        "Options": {
            "com.docker.network.bridge.enable_ip_masquerade": "true",
            "com.docker.network.bridge.host_binding_ipv4": "0.0.0.0",
            "com.docker.network.bridge.name": "docker1"
        },
        "Labels": {
            "com.docker.compose.network": "infranet",
            "com.docker.compose.project": "infraserv_new",
            "com.docker.compose.version": "1.25.3"
        }
    }
]
```

### 初期設定

[後続の手順](#作業内容) で設定ファイルの修正をしない場合は、以下のパラメータで各サービスが動作します。

#### radius

初期状態では以下の２ユーザとenableパスワードが利用できるようになります。

|ユーザ名|パスワード|備考|
|:-:|:-:|:-:|
|foo|bar|通常ユーザでのログイン|
|hoge|fuga|Cisco機器にログインすると自動で特権に昇格|
|\$enab15\$|fuga|Cisco機器のenableコマンドで遷移する際のパスワード|


MACアドレスバイパスでは、以下のMACアドレスの場合に、ダイナミックVLAN用のアトリビュートを付与してAcceptされます。

|MACアドレス|VLAN文字列|
|:-:|:-:|
|112233445566|default_seg|
|aabbccddeeff|default_seg|

#### DHCP
リース情報

|項目|値|
|:--:|:--:|
|リース時間|10時間|
|DNSサーバ|8.8.8.8|


リース対象セグメント

|セグメント|レンジ|GW|
|:--:|:--:|:--:|
|10.1.20.0/24|10.1.20.33 - 10.1.20.62|10.1.20.1|
|10.1.22.0/24|10.1.22.33 - 10.1.20.230|10.1.22.1|


Option43によりアクセスポイントに送付するコントローラアドレス

|対象|VCI文字列|コントローラアドレス|
|:--:|:--:|:--:|
|Cisco|Cisco AP|10.254.10.201,10.254.10.202|
|Aruba|ArubaAP|10.254.10.206|

リクエストを受け付けるIFを設定ファイル `kea-dhcp4.conf` に記載するのですが、デフォルトで `ens192` としています。
IFの表記が異なる場合には、設定ファイルの修正が必要です。


## 事前準備

CentOS と Docker と Docker Compose があれば、ここの手順はスキップで [作業内容](#作業内容) から始めてください。


### CentOS8（10分）
CentOS8は最小構成で問題ありません。
もし手元になければ、 [ESXi6.7にCentOS8を最小構成で構築](https://qiita.com/bashaway/items/ed9997629d5b02cfca05) を参照してください。

### Docker（5分）
```
dnf -y update
dnf config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo
dnf -y --nobest install docker-ce docker-ce-cli containerd.io
dnf -y update https://download.docker.com/linux/centos/7/x86_64/stable/Packages/containerd.io-1.2.10-3.2.el7.x86_64.rpm
dnf -y update
systemctl enable docker
systemctl start docker
```

### Docker Compose（1分）
```
curl -L "https://github.com/docker/compose/releases/download/1.25.3/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
chmod +x /usr/local/bin/docker-compose
```



## 作業内容

### firewall のポリシー追加（10秒）
```
firewall-cmd --add-service=dns   --zone=public --permanent
firewall-cmd --add-service=tftp   --zone=public --permanent
firewall-cmd --add-masquerade   --zone=public --permanent
firewall-cmd --reload
```

### 各サービスのDockerコンテナをつくる（5分）

各サービスのDockerfileと設定ファイル、それらをまとめる docker-compose.yml は [GitHub](https://github.com/bashaway/infraserv) にあるものを使います。


```
git clone https://github.com/bashaway/infraserv
```

デフォルトの設定から変更する場合は、以下のエントリなどを参照してください。
設定ファイルの修正なしでもビルドには影響ありません。
ビルド後に修正しても大丈夫ですし。

**DHCP**
[DockerでKea DHCPを構築。CiscoとArubaに同時にOption43が渡せるようになった。](https://qiita.com/bashaway/items/631290fcbab82f858234)

**RADIUS**
[DockerのFreeRADIUSでCiscoのログイン認証＋MAC認証+ダイナミックVLANした（CentOS8）](https://qiita.com/bashaway/items/0f331872456fb8681641)

**Proxy**
[Dockerでproxyサーバ](https://qiita.com/bashaway/items/9e8538aa340e591231cb)

**TFTP**
[Dockerでtftpサーバ](https://qiita.com/bashaway/items/018b489a7aaf3290d858)

**Syslog**
[Dockerのrsyslogでコンテナ間や他サーバから転送されるログを集約した](https://qiita.com/bashaway/items/50c97e45e7ebad92ccfc)


設定ファイルの修正が終わったら、コンテナをつくります。

```
cd infraserv
docker-compose build
docker-compose up -d
```

### いらなくなったら

```
コンテナ削除
docker-compose stop
docker-compose rm -f

イメージもいらなければ
docker-compose rmi -f
```


## 中身の解説

### docker-compose.yml
`docker-compose.yml` は、以下のように構成されています。


```docker:docker-compose.yml
version: '3'

services:

  proxy:
    build: ./proxy
    image: infraserv:proxy
    container_name: proxy
    hostname: proxy
    restart: always
    networks:
      infranet:
        ipv4_address: 172.20.0.2
    ports:
      - 8080:8080
    cap_add:
      - SYS_ADMIN
    security_opt:
      - seccomp:unconfined
    volumes:
      - /sys/fs/cgroup:/sys/fs/cgroup:ro
    environment:
      TZ: 'Asia/Tokyo'

  syslog:
    build: ./syslog
    image: infraserv:syslog
    container_name: syslog
    hostname: syslog
    restart: always
    networks:
      infranet:
        ipv4_address: 172.20.0.3
    ports:
      - 514:514/udp
    cap_add:
      - SYS_ADMIN
    security_opt:
      - seccomp:unconfined
    volumes:
      - /sys/fs/cgroup:/sys/fs/cgroup:ro
    environment:
      TZ: 'Asia/Tokyo'

  radius:
    build: ./radius
    image: infraserv:radius
    container_name: radius
    hostname: radius
    restart: always
    networks:
      infranet:
        ipv4_address: 172.20.0.4
    ports:
      - 1812:1812/udp
    cap_add:
      - SYS_ADMIN
    security_opt:
      - seccomp:unconfined
    volumes:
      - /sys/fs/cgroup:/sys/fs/cgroup:ro
    environment:
      TZ: 'Asia/Tokyo'

  dns:
    build: ./dns
    image: infraserv:dns
    container_name: dns
    hostname: dns
    restart: always
    networks:
      infranet:
        ipv4_address: 172.20.0.5
    ports:
      - 53:53/udp
      - 53:53/tcp
    cap_add:
      - SYS_ADMIN
    security_opt:
      - seccomp:unconfined
    volumes:
      - /sys/fs/cgroup:/sys/fs/cgroup:ro
    environment:
      TZ: 'Asia/Tokyo'

  tftp:
    build: ./tftp
    image: infraserv:tftp
    container_name: tftp
    hostname: tftp
    restart: always
    network_mode: host
    cap_add:
      - SYS_ADMIN
    security_opt:
      - seccomp:unconfined
    volumes:
      - /sys/fs/cgroup:/sys/fs/cgroup:ro
    environment:
      TZ: 'Asia/Tokyo'

  dhcp:
    build: ./dhcp
    image: infraserv:dhcp
    container_name: dhcp
    hostname: dhcp
    restart: always
    network_mode: host
    cap_add:
      - SYS_ADMIN
    security_opt:
      - seccomp:unconfined
    volumes:
      - /sys/fs/cgroup:/sys/fs/cgroup:ro
    environment:
      TZ: 'Asia/Tokyo'

networks:
  infranet:
    driver: bridge
    driver_opts:
      com.docker.network.bridge.enable_ip_masquerade: "true"
      com.docker.network.bridge.host_binding_ipv4: "0.0.0.0"
      com.docker.network.bridge.name: "docker1"
    ipam:
      config:
        - subnet: 172.20.0.0/24

```


## さいごに
Dockerでコンテナにしておくと、ホスト機が汚れなくて気持ちいい

##出典
http://docs.docker.jp/engine/reference/commandline/toc.html