kubernetesでのDHCPサーバ構築

## はじめに
私が行った研究に関連して，KubernetesでDHCPサーバの構築について知ることが出来たので，今回得た知識をまとめました．

## DHCPサーバとは
ネットワーク内の機器に 指定した範囲のIP アドレスを動的に割り当て、これらのアドレスの割り当て、更新、再利用を管理するサーバのことです．また，IPアドレスだけでなく，サブネット，デフォルトゲートウェイ，DNSサーバのIPアドレスのように，ネットワークの利用に必要な設定情報を割り当てます．

## 構成について
dockerで作成したKea DHCP ServerコンテナをDockerリポジトリへPushし，それをKubernetesのYamlファイルで使用するにしています．

## DockerでのKeaDHCPサーバ構築について
以下のDockerfileとdocker-compose.yamlを用いてコンテナを作成しました．
設定ファイルやシェルスクリプトはKubernetesでの構築にある，Config Mapを参照（kea-dhcp4.conf，start.sh）．

```Dockerfile
FROM debian:latest

RUN apt-get update && \
    apt-get install -y mariadb-server mariadb-client kea

RUN mkdir -p /run/mysqld && \
    chown mysql:mysql /run/mysqld

RUN apt-get update && \
    apt-get install -y kea-admin vim

ADD kea-dhcp4.conf /etc/kea/kea-dhcp4.conf
ADD ./start.sh /etc/kea/start.sh
RUN chmod +x /etc/kea/start.sh
RUN mkdir -p /var/run/kea/ && touch /var/run/kea/logger_lockfile

# MySQL起動後にスキーマを初期化する
ENTRYPOINT ["sh", "/etc/kea/start.sh"]
```

ポート番号や，DBのユーザ名・DB名・パスワードなどは自身が作成するものに合わせるようにしてください．
今回作成したDHCPサーバはコンテナネットワークではなく，ホストのネットワークを使用しています．
```docker-compose.yaml
version: "3.3"
services:
  kea:
    build: .
    environment:
      MARIADB_HOST: DBのホスト名
      MARIADB_NAME: DB名
      MARIADB_USER: ユーザ名
      MARIADB_PASSWORD: パスワード
    image: docker.cloudsmith.io/isc/docker/kea-dhcp4:2.5.7
    container_name: kea
    restart: always
    tty: true
    depends_on:
      - kea-db

    ports:
      - ポート番号:ポート番号

    network_mode: host

  kea-db:
    container_name: kea-db
    restart: always
    build:
      context: ./db
    environment:
      MARIADB_HOST: DBのホスト名
      MARIADB_ROOT_PASSWORD: DBのルートユーザのパスワード
      MARIADB_DATABASE: DB名
      MARIADB_USER: DBのユーザ名
      MARIADB_PASSWORD: ユーザが使用するパスワード
      TZ: 'Asia/Tokyo'
    volumes:
      - ./db/data:/var/lib/mysql
    command: --default-authentication-plugin=mysql_native_password --character-set-server=binary --collation-server=binary

    ports:
      - DBのポート番号:DBのポート番号

    network_mode: host
    
networks:
  host:
```

## KubernetesでのKeaDHCPサーバ構築について
クラスター構成はノードが3台で，全てがマスターです．
以下のyamlファイルを用いてDHCPサーバのPodの作成を行います．

```dhcp-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: kea-dhcp-deployment
spec:
  replicas: 3
  selector:
    matchLabels:
      app: kea
  template:
    metadata:
      labels:
        app: kea
    spec:
      hostNetwork: true
      containers:
      - name: kea
        image: dockerリポジトリ名
        volumeMounts:
        - name: config-volume
          mountPath: コンフィグマップのマウント先のパス
        ports:
          - containerPort: コンテナポート番号
      volumes:
      - name: config-volume
        configMap:
          name: dhcp-config
      imagePullSecrets:
      - name: 自身が作成したSecret名

---
apiVersion: v1
kind: Service
metadata:
  name: kea-dhcp-service
spec:
  selector:
    app: kea
  ports:
    - protocol: TCP
      port: ポート番号
      nodePort: ノードポート番号
  type: LoadBalancer
```

Config Mapは以下のようにしました．
kea-dhcp4.confのpoolsの箇所は動的に割り当てたいIPアドレスの範囲を書くようにします．
```dhcp-config.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: dhcp-config
data:
  static-mac-ip.json: |
    # Static IP address'
    # MAC address to IP
    #この下の中括弧には静的に割り当てたい機器のMACアドレスとホスト名，固定したいIPアドレスを書く
    {
        "hw-address": "MACアドレス",
        "ip-address": "固定したいIPアドレス",
        "hostname": "ホスト名"
    }

  kea-ctrl-agent.conf: |
    {
        "Control-agent": {
            "http-host": "ホストのIPアドレス",
            "http-port": ポート番号,

            "control-sockets": {
                "dhcp4": {
                    "socket-type": "unix",
                    "socket-name": "/share/kea-dhcp4-ctrl.sock"
                },
                "dhcp6": {
                    "socket-type": "unix",
                    "socket-name": "/share/kea-dhcp6-ctrl.sock"
                },
                "d2": {
                    "socket-type": "unix",
                    "socket-name": "/share/kea-dhcp-ddns-ctrl.sock"
                }
            },

            "hooks-libraries": [],

            "loggers": [
                {
                    "name": "kea-ctrl-agent",
                    "output_options": [
                        {
                            "output": "stdout",
                            "pattern": "%-5p %m\n"
                        }
                    ],
                    "debuglevel": 0
                }
            ]
        }
    }
  kea_dhcp4.conf: |
    {
        "Dhcp4": {
            "lease-database": {
                "type": "mysql",
                "name": "DHCPの名前",
                "user": "ユーザ名",
                "password": "パスワード",
                "host": "ホストのIPアドレス",
                "port": ポート番号,
                "lfc-interval": 600,
            },
            "hosts-database": {
                "type": "mysql",
                "name": "DHCPの名前",
                "user": "ユーザ名",
                "password": "パスワード",
                "host": "ホストのIPアドレス",
                "port": 3ポート番号
            },
            "expired-leases-processing": {
                "reclaim-timer-wait-time": 10,
                "flush-reclaimed-timer-wait-time": 25,
                "hold-reclaimed-time": 3600,
                "max-reclaim-leases": 100,
                "max-reclaim-time": 250,
                "unwarned-reclaim-cycles": 5
            },
            "renew-timer": 300,
            "rebind-timer": 400,
            "valid-lifetime": 600,
            "dhcp-ddns": {
                "enable-updates": true,
                "server-ip": "127.0.0.1",
                "server-port":deploymentで記述したポート番号,
                "hostname-char-set": "[^A-Za-z0-9-]",
                "hostname-char-replacement": "-",
                "replace-client-name": "when-not-present",
                "generated-prefix": "ip",
                "qualifying-suffix": "ホスト名の後ろにつくドメイン"
            },
            "subnet4": [
                {
                    "subnet": "サブネット",
                    "pools": [ { "pool": "xxx.xxx.xxx.xxx - xxx.xxx.xxx.xxx" } ],
                    "reservations": [
                        {
                            "hw-address": "DHCPサーバのMACアドレス",
                            "hostname": "DHCPサーバのホスト名"
                        },
                        <?include "/etc/kea/static-mac-ip.json"?>
                    ],
                    "option-data": [
                        {
                            "name": "routers",
                            "code": 3,
                            "space": "dhcp4",
                            "csv-format": true,
                            "data": "ゲートウェイのIPアドレス"
                        },
                        {
                            "name": "domain-name-servers",
                            "code": 6,
                            "space": "dhcp4",
                            "csv-format": true,
                                "data": "DNSのIPアドレス"
                        },
                        {
                            "name": "domain-search",
                            "code": 119,
                            "space": "dhcp4",
                            "csv-format": true,
                            "data": "ドメイン名"
                        }
                    ],
                    "ddns-update-on-renew": false,
                    "ddns-use-conflict-resolution": false
                }
            ],
            "interfaces-config": {
                "interfaces": ["NIC名"]
            },
            "control-socket": {
                "socket-type": "unix",
                "socket-name": "/tmp/kea-dhcp4-ctrl.sock"
            },
            "loggers": [
                {
                    "name": "kea-dhcp",
                    "output_options": [
                        {
                            "output": "/var/log/kea/syslog",
                            "pattern": "%-5p %m\n"
                        }
                    ],
                    "severity": "INFO",
                    "debuglevel": 1
                }
            ]
        }
    }
  start.sh: |
    #!/bin/bash
    echo "Start script"
    # ここにスタートアップのコマンドを書く
    sleep 5
    kea-admin db-upgrade mysql -u 【ユーザ名】 -p【パスワード】 -n 【ユーザ名】 -h 【ホストのIPアドレス】

    #既存のテーブルが存在するかを確認
    EXISTING_TABLES=$(mysql -u 【ユーザ名】 -p【パスワード】 -h 【ホストのIPアドレス】 kea -e "SHOW TABLES" | wc -l)

    #テーブルが存在しない場合にのみ db-init コマンドを実行
    if [ "$EXISTING_TABLES" -eq 0 ]; then
        kea-admin db-init mysql -u 【ユーザ名】 -p【パスワード】 -h 【ホストのIPアドレス】
    fi

    # バイナリデータを正しく格納するため、hwaddr、client_id、hostnameなどの カラムのデータ型をBINARYに変更
    mysql -u 【ユーザ名】 -p【パスワード】 -h {{ .PodIP }} -e "USE kea; ALTER TABLE lease4 MODIFY COLUMN hwaddr VARBINARY(100), MODIFY COLUMN client_id VARBINARY(100), MODIFY COLUMN hostname VARCHAR(255);"

    # kea-dhcp4の起動
    /usr/sbin/kea-dhcp4 -c /etc/kea/kea_dhcp4.conf
```
DNSへ登録するttlは下記の箇所で設定しているため，それぞれの設定にしてください．上記は最小値の10分に設定しています．
リース期限の設定は`lease-database`の`lfc-interval`で設定しています．
```
"renew-timer": 300,
"rebind-timer": 400,
"valid-lifetime": 600
```

podを立てて，`kubectl logs [pod名]`で以下のようなログが出力されていれば正常に動作していいます．
hwtypeはMACアドレス，cidはDHCPクライアント識別子，tidはトランザクションIDが入っています．
```
2024-07-30 02:11:05.361 INFO  [kea-dhcp4.leases/102.139721203102208] DHCP4_LEASE_ADVERT [hwtype=1 ], cid=[], tid=: lease 192.168.100.144 will be advertised
2024-07-30 02:11:06.375 INFO  [kea-dhcp4.leases/102.139721203102208] DHCP4_LEASE_ALLOC [hwtype=1 ], cid=[], tid=: lease 192.168.100.144 has been allocated for 600 seconds
2024-07-30 02:11:15.590 INFO  [kea-dhcp4.leases/102.139721203102208] DHCP4_LEASE_ALLOC [hwtype=1 ], cid=[], tid=: lease 192.168.100.139 has been allocated for 600 seconds
2024-07-30 02:11:26.446 INFO  [kea-dhcp4.leases/102.139721203102208] DHCP4_LEASE_ALLOC [hwtype=1 ], cid=[], tid=: lease 192.168.100.192 has been allocated for 600 seconds
2024-07-30 02:11:31.096 INFO  [kea-dhcp4.leases/102.139721203102208] DHCP4_LEASE_ALLOC [hwtype=1 ], cid=[], tid=: lease 192.168.100.182 has been allocated for 600 seconds
2024-07-30 02:11:31.666 INFO  [kea-dhcp4.leases/102.139721203102208] DHCP4_LEASE_ALLOC [hwtype=1 ], cid=[], tid=: lease 192.168.100.21 has been allocated for 600 seconds
2024-07-30 02:11:51.865 INFO  [kea-dhcp4.leases/102.139721203102208] DHCP4_LEASE_ALLOC [hwtype=1 ], cid=[], tid=: lease 192.168.100.73 has been allocated for 600 seconds
```


## 終わりに
KeaDHCPサーバの構築や設定に関する資料が少なく，苦労したので誰かの助けになれば幸いです！