takutakahashi.dev

DHCP & TFTP Server を k8s で動かす

PXE Server を k8s で動かす検証をしています。
まずは、DHCP と TFTP を k8s で動かせるか試します。

成果物は全て以下のリポジトリに格納しています。

https://github.com/takutakahashi/k8s-pxe

DHCP と TFTP の役割は?

DHCP

TFTP Server address などの PXE Boot する際に必要な情報は
DHCP から降らせる必要があるみたいです。知らなかった。

PXE Boot する NIC は、まずブロードキャストパケットを投げて DHCP から情報を要求します。
その後 DHCP から IP や TFTP Server address を受け取った NIC は、
TFTP から Boot に必要なファイルをダウンロードして処理を進める、という流れになります。

TFTP

TFTP Server 自体は、簡素なアップロード/ダウンロードの機能を持ちます。 PXE Boot するためには、まずブートローダが必要となります。
Linux は、たいてい /boot 以下にブートローダがあって、それを読むのですが、
PXE Boot するサーバはローカルにブートローダを持ちません。
TFTP Server にブートローダを置いて、PXE Boot 時にダウンロードしてきてロードします。

設定

ネットワーク

DHCP Server には、ホームネットワークの DHCP を担当してもらいます。
なので、DHCP Server が直接ホームネットワークのアドレスに到達できる必要がありそうです。

具体的には、hostNetwork: true を指定してノードの ns を共有する必要があります。

    spec:
      hostNetwork: true

containers

イメージには、andyshinn/dnsmasq を利用します。
dhcpd + tftp-hpa で試行錯誤したのですがうまくいかず、
all in one で使える dnsmasq にしました。

dnsmasq.conf を configmap からマウントします。
追加で、tftp で利用するディレクトリをマウントします。

      containers:
      - image: andyshinn/dnsmasq
        args:
          - --log-facility=-
        securityContext:
          capabilities:
            add: ["NET_ADMIN"]
        imagePullPolicy: Always
        name: dnsmasq
        volumeMounts:
        - mountPath: /tftpboot
          name: tftpboot
        - mountPath: /etc/dnsmasq.conf
          name: dnsmasq-conf
          subPath: dnsmasq.conf

configmap

dnsmasq.conf を configmap にセットします。 pxe-service は、これを書くと良い理由が正直くわかってません。

apiVersion: v1
data:
  dnsmasq.conf: |
    port=0
    dhcp-range=10.10.0.100,10.10.0.149,255.255.255.0,2h
    dhcp-option = option:router, 10.10.0.1
    dhcp-option = option:dns-server, 8.8.8.8
    log-dhcp
    enable-tftp
    tftp-root=/tftpboot
    pxe-service=0,"Raspberry Pi Boot"
kind: ConfigMap
metadata:
  name: dnsmasq-conf
  namespace: kube-pxe-system

起動

これで DHCP Server と TFTP Server ができました。起動してみます。
起動する前に router の DHCP を止めておかないと、ブロードキャストガチャになります。

dnsmasq-dhcp[1]: 2804706199 DHCPREQUEST(eno1) 10.10.0.145 xx:xx:xx:xx:xx:xx
dnsmasq-dhcp[1]: 2804706199 tags: eno1
dnsmasq-dhcp[1]: 2804706199 DHCPACK(eno1) 10.10.0.145 xx:xx:xx:xx:xx:xx OPPO-Reno-A
dnsmasq-dhcp[1]: 2804706199 requested options: 1:netmask, 3:router, 6:dns-server, 15:domain-name,
dnsmasq-dhcp[1]: 2804706199 requested options: 26:mtu, 28:broadcast, 51:lease-time, 58:T1,
dnsmasq-dhcp[1]: 2804706199 requested options: 59:T2, 43:vendor-encap
dnsmasq-dhcp[1]: 2804706199 next server: 10.10.0.11
dnsmasq-dhcp[1]: 2804706199 sent size:  1 option: 53 message-type  5
dnsmasq-dhcp[1]: 2804706199 sent size:  4 option: 54 server-identifier  10.10.0.11
dnsmasq-dhcp[1]: 2804706199 sent size:  4 option: 51 lease-time  2h
dnsmasq-dhcp[1]: 2804706199 sent size:  4 option: 58 T1  1h
dnsmasq-dhcp[1]: 2804706199 sent size:  4 option: 59 T2  1h45m
dnsmasq-dhcp[1]: 2804706199 sent size:  4 option:  1 netmask  255.255.255.0
dnsmasq-dhcp[1]: 2804706199 sent size:  4 option: 28 broadcast  10.10.0.255
dnsmasq-dhcp[1]: 2804706199 sent size:  4 option:  6 dns-server  8.8.8.8
dnsmasq-dhcp[1]: 2804706199 sent size:  4 option:  3 router  10.10.0.1

いい感じにリースできていそうです。

まとめ

hostNetwork というチートを使ってしまいましたが、
一応 DHCP と TFTP を k8s に立てることができました。
metallb の L2 Mode なら、Service を利用した DHCP できそうな気がするので、
近々やってみようと思います。

この DHCP + TFTP を利用して Raspberry Pi 4 を Network Boot できたので、
続きの記事を書こうと思います。