astamuse Lab

astamuse Labとは、アスタミューゼのエンジニアとデザイナーのブログです。アスタミューゼの事業・サービスを支えている知識と舞台裏の今を発信しています。

Docker環境でPXEブート環境を整えようとして苦しんだ話

f:id:astamuse:20181127232540j:plain

こんにちはnishikawaです。今回はDockerの勉強がてらにPXE環境の構築をしてみたので、そこでの気づきや結果などを書いていきます。

参考にしたのは、以前 弊社の元バンドマンであるgucci氏が書いてくれた記事を参考にしております。

lab.astamuse.co.jp

概要

Dockerを勉強するにあたり、PXE環境をDockerコンテナを用いて構築します。インストールするものはUbuntu Server 20.04 LTSですが、nginxの設定まで文章にしていたら記事が凄く長くなったので、この記事ではPXEでブートメニューを起動するところまでを対象とします。

最初やりたかったこと

自宅にPXE環境を構築するにあたり既存のネットワークを侵害しないようにNICが複数あるPCが必要だと思いました。理由はわざわざ資材をダウンロードしたりするのが面倒なのとSSH接続して設定などを行ったほうが楽だからです。で、自宅にワイヤレスインターフェースとイーサネットを備えたノートPCがあったので、これを利用して以下のような環境を構築しようと思いました。

これが悪夢の始まりと知らずに・・・

f:id:astamuse:20210526102758p:plain

結局構築したもの

で、多くの困難を乗り越えて最終的に構築したものが以下になります。見て分かるとおり、セグメントを物理的に分けてPXE環境を独立する予定が、同一セグメント内に集約されています。どうしてこうなったのかはこの後の文章をお読みください。

f:id:astamuse:20210526102804p:plain

最初にやった設定

では、最初構想していた環境を構築するための設定をつらつらと書いていきたいと思います。

gucci氏の記事ではtftpd-hpadhcpdを使用してましたが、同じものでやっても芸がないので今回はdnsmasqを使っていきたいと思います。

dnsmasqはDNSを提供するミドルウェアですが、DHCPやTFTPを提供する機能も持っています。なので、このコンテナを生成するためのDockerイメージを手始めに作成していきます。

Dockerイメージ作成

ディレクトリ構成は以下のような感じ

dnsmasq
├── Dockerfile
└── etc
    └── dnsmasq.conf

まずdnsmasq.confは以下のように設定を変更します。コンテナ内では root でプロセスを起動するのですが、デフォルトでは起動可能なユーザが設定されていないのでプロセスが立ち上がりません。そのためuser=rootを追加します。 あと、後ほど設定を追加するためにdnsmasq.dディレクトリ内の設定ファイルを取り入れられるようにしておきたいので、conf-dir=/etc/dnsmasq.dを有効にしておきます。

 # If you want dnsmasq to change uid and gid to something other
 # than the default, edit the following lines.
-#user=
+user=root
 #group=

・・・


 # Include another lot of configuration options.
 #conf-file=/etc/dnsmasq.more.conf
-#conf-dir=/etc/dnsmasq.d
+conf-dir=/etc/dnsmasq.d

設定を変更したらDockerfileを作成します。

FROM ubuntu:20.04

RUN apt-get update && apt-get install -y dnsmasq
VOLUME /etc/dnsmasq.d
VOLUME /var/lib/tftp

COPY etc/dnsmasq.conf /etc/dnsmasq.conf

CMD /usr/sbin/dnsmasq --conf-file=/etc/dnsmasq.conf && tail -f /dev/null

ポイントは/etc/dnsmasq.d/var/lib/tftpにアタッチポイントを作っておくところです。この後説明しますが、PXE用のdnsmasqの設定を後から/etc/dnsmasq.dに追加するのと、ブートローダを/var/lib/tftp配下に配置するのでここは必ず設定します。

後は先ほど変更したdnsmasq.confをCOPYでイメージ内に配置します。

最後に/usr/sbin/dnsmasqをdnsmasq.confを指定して起動します。ただ、この方法で起動するとバックグラウンドでプロセスを立ち上げてしまうためコンテナがすぐに終了してしまいます。

そのため最後にtailをフォアグラウンドプロセスとして立ち上げコンテナが落ちるのを防ぎます。

Dockerイメージの作成は以下のコマンドで行います。

# docker image build -t test-dnsmasq:1.0.0 .

Dockerコンテナ作成

次にdocker-composeを使用してコンテナを作成・管理したいと思います。

ディレクトリ構成は以下です。

/opt/pxe
├── dnsmasq
│   ├── etc
│   │   └── dnsmasq.d
│   │       └── pxe.conf
│   └── var
│       └── lib
│           └── tftp
│               ├── boot.img.gz
│               ├── ldlinux.c32
│               ├── mini.iso
│               ├── netboot.tar.gz
│               ├── pxelinux.0
│               ├── pxelinux.cfg
│               │   └── default
│               ├── ubuntu-installer
│               │   └── amd64
│               │       └── ...
│               └── xen
│                   └── ...
└── docker
    └── docker-compose.yml

まずはdnsmasqに設定を追加するため/opt/pxe/dnsmasq/etc/dnsmasq.d/pxe.confを作成して以下の設定を追記します。

#DHCP
interface=enp9s0,lo                          #インターフェス名を設定(今回はenp9s0という名前だったのでそれを設定しています)
bind-interfaces
dhcp-range=192.168.1.100,192.168.1.200,12h   #セグメントに沿ってレンジ設定(今回は192.168.1.0というネットワークでリース期間は12hを想定)
dhcp-option=option:netmask,255.255.255.0     #多分いらないと思うが、一応サブネットマスクを設定
dhcp-option=option:router,192.168.1.1        #これも多分いらないと思うがルータのIPを設定
dhcp-boot=pxelinux.0                         #ブートローダのファイル名

#TFTP
enable-tftp                                  #TFTP機能有効
tftp-root=/var/lib/tftp                      #TFTPのルートディレクトリ

/opt/pxe/dnsmasq/var/lib/tftp配下に以下のURLから資材を取得

http://archive.ubuntu.com/ubuntu/dists/focal/main/installer-amd64/current/legacy-images/netboot/

以下、docker-compose.ymlの設定です。

---
version: "3"
services:
  pxe_server:
    image: test-dnsmasq:1.0.0
    volumes:
      - /opt/pxe/dnsmasq/etc/dnsmasq.d:/etc/dnsmasq.d
      - /opt/pxe/dnsmasq/var/lib/tftp:/var/lib/tftp
    network_mode: "host"

以上まで準備ができたらコンテナを起動します。

# docker-compose up -d

これで普通ならうまくいくはずだったのですが、色んな要因が重なり多くの苦しみを味わう羽目になりました。

苦しみポイント1:netboot用資材が見つからない

gucci氏の記事ではUbuntu Server 18.04 LTSのインストールイメージで行っていたのでネットブート用の資材がISO内にあったのでしょうが、今回私が行ったUbuntu Server 20.04 LTSのISOには それがありませんでした・・・。

と言うわけで悶絶とまでは行かないまでもそれなりに調査に時間がかかりました。

苦しみポイント2:TFTPでブートローダが取得できない

Dockerコンテナを起動したので、いざOSインストール対象のPCを起動してみたのですが、以下のようなエラーが出てブートメニューが表示されません。

TFTP
PXE-E11: ARP timeout

どうやらTFTPでブートローダを落として読み込もうとしているのですが、アクセス対象のMACアドレスが解決できなくてエラーになっているようです。

これはなんだ?とずっと考えていたのですが、コンテナにarpコマンドを入れてarpテーブルを見てみたらなんとなく分かりました。以下が問題の箇所です。

Address                  HWtype  HWaddress           Flags Mask            Iface
192.168.11.29                    (incomplete)                              wlp7s0
192.168.1.112                    (incomplete)                              br-24cc64eb1e3c

・・・

Iface部分が本当は先程/opt/pxe/dnsmasq/etc/dnsmasq.d/pxe.confで設定したenp9s0になっていて欲しかったのですが、そうはなっていません。

ワイヤレスの方は正常に認識されているので、どうやらnetwork_mode: "host"によってコンテナに直接紐付けられたインターフェースはワイヤレスの方みたいです。これによりTFTPサーバへのアクセスができなかったのが原因だと考えます。

これを解決するため、docker-compose.ymlでインターフェースを指定できないか あれこれ調査しました。

苦しみポイント3:Dockerコンテナを起動するときにネットワークインターフェースを指定できない

という訳でDockerコンテナ起動時に紐付けるインターフェースを指定する方法を探したのですが、結論から言うと私は見つけることはできませんでした。

なので、複数の物理NICを持っているマシンでnetwork_mode: "host"を使用する時は思わぬ挙動になるため気をつけた方がよさそうというのが現時点での私の見解です。

以上から、当初想定していた環境の構築は抜本から考え直さないといけない状況になってしまいました。

そして改善へ

ひとしきり絶望した後、dnsmasqについてあれこれ調べていたらProxy DHCPという機能を見つけました。どうやらDHCPサーバが既に存在している環境においてPXEを提供するための機能らしいのでこれを使ってやってみることにしました。

やることは/opt/pxe/dnsmasq/etc/dnsmasq.d/pxe.confの設定変更で以下のように修正しました。

-#DHCP
-interface=enp9s0,lo
-bind-interfaces
-dhcp-range=192.168.1.100,192.168.1.200,12h
-dhcp-option=option:netmask,255.255.255.0
-dhcp-option=option:router,192.168.1.1
-dhcp-boot=pxelinux.0
+#Proxy DHCP
+port=0
+dhcp-range=192.168.11.0,proxy
+pxe-service=x86PC,"pxelinux",pxelinux

 #TFTP

・・・

これでコンテナを起動し直したらちゃんとブートメニューが表示されました。

まとめ

今回はDockerの勉強をしている過程で以下の知識を得ることができました。

  • Dockerコンテナに物理インターフェースを直接割り当てるにはnetwork_mode: "host"を使用する
  • 複数の物理NICを持っているマシンでDockerコンテナを起動する際network_mode: "host"を使用する場合はインターフェースを指定することができないので注意が必要
  • dnsmasqはDNSだけでなくDHCPとTFTPサーバとしても使える
  • Proxy DHCPという仕組みで既存のDHCPサーバがあるネットワーク環境下でPXEを追加で提供することができる

今回はgucci氏の記事を元にPXEサーバをdockerコンテナ化してみました。dockerをここまでしっかり触ったことがなかったので発見ばかりでしたが、とても苦しい・・・もとい、楽しい経験をしました。

今後はpreseedなどを駆使してOSのインストールも自動化できたら良いなと思ったので機会があったらやってみようと思います。

それでは。

Copyright © astamuse company, ltd. all rights reserved.