このガイドのゴール
AlmaLinux 9(ホスト)の上で、Podmanのコンテナが「SERVERセグメントに直接つながった本物のサーバー」のように振る舞える土台を作ります。完了すると、ホスト(192.168.2.3)からも、これから作る各コンテナ(192.168.2.11〜.17)からも、お互いに自由に通信できるようになります。これは今後のフェーズ全部の土台になるので、焦らず1ステップずつ確認しながら進めましょう。
0. まず概念を理解する(3分で読めます)
0-1. なぜ「NAT」ではなく「Macvlan」を使うのか
コンテナを作るとき、何も指定しなければ Podman は「NAT」というモードを使います。これは、コンテナたちをホストの内側に隠れたプライベートな小部屋(例:10.88.0.x)に押し込めるイメージです。外からアクセスするには、ホストの特定のポートを「転送(フォワード)」してあげる必要があります。
NATモードのイメージ
※ コンテナは「本物のサーバー」のようには見えない
Macvlanモードのイメージ
※ それぞれが「別のLANポートに挿さった本物のPC」のように見える
今回作りたいのは、DNSサーバーやHeadscaleサーバーが、まるでSERVERセグメントに直接挿さった独立した1台のサーバーであるかのように振る舞う環境です。そこで使うのが Macvlan です。
0-2. 立ちはだかる壁:「ホストとコンテナが会話できない」
ところが、Linuxカーネルの仕様(安全のための制限)により、同じ物理LANカードから分かれたMacvlanコンテナと、ホストOS自身は、直接パケットをやり取りできません。
物理NIC(eth0)を境にした断絶
同じeth0から分かれた者同士は、カーネルの仕様で直接会話できません。これでは、ホスト上で動かすAnsibleが各コンテナへSSHできません。そこで、ホストOS側にも「仮想的なLANカード(macv0)」をもう1枚作り、それを通じて会話する、というのが今回の作戦です。
0-3. もう1つの壁:「出口が2つあると、どちらを使うか迷う」
macv0 を作って 192.168.2.99 というIPを与えると、ホストの中に「192.168.2.0/24への出口」が2つできてしまいます(eth0 と macv0)。
ルート未設定の状態(まだ解決していない)
→ カーネルはどちらを使うべきか分からず、結局コンテナと話せないまま
ルート設定後(解決)
→ 迷いがなくなり、ホスト⇔コンテナ間で確実に通信できる
この迷いを解消するため、「コンテナ宛て(2.11〜2.17)の通信だけはピンポイントで macv0 を使う」という専用ルートを明示的に教えてあげます。これが今回の作業の核心です。
必要なもの
- AlmaLinux 9 が稼働しているサーバー(今回は 192.168.2.3)への管理者(sudo)アクセス
- FortiGate管理画面へのアクセス(あとでDHCP除外設定を行います)
構築手順
物理インターフェース名を確認する
作業を始める前に、自分のサーバーの「物理LANカードの名前」を確認します。環境によって eth0 だったり enp1s0 だったり様々です。
ip link show
1: lo: <LOOPBACK,UP,LOWER_UP> ...
2: enp1s0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 ...
この例では enp1s0 が物理LANカードです。以降のコマンドはすべて enp1s0 と仮定して書いていますが、ご自身の環境名に置き換えてください。
Podmanのインストールとmacvlanネットワークの作成
# パッケージ一覧を最新化し、Podmanをインストール
sudo dnf update -y
sudo dnf install -y podman
# Podman用のMacvlanネットワーク(local_lan)を作成
# -o parent=enp1s0 の部分を、ステップ0で確認した名前に置き換えてください
sudo podman network create -d macvlan --subnet=192.168.2.0/24 --gateway=192.168.2.1 -o parent=enp1s0 local_lan
sudo podman network ls
出力に local_lan が表示されていればOKです。出力の中の subnets(192.168.2.0/24か)、gateway(192.168.2.1か)、parent(ステップ0で確認した名前になっているか)を確認してください。
仮想インターフェース(macv0)の作成
# ホスト用の仮想LANカード(macv0)を、enp1s0を親として追加
sudo nmcli connection add type macvlan dev enp1s0 con-name macv0 ifname macv0 mode bridge
# macv0にホスト専用の予備IP(192.168.2.99)を割り当てる
sudo nmcli connection modify macv0 ipv4.addresses 192.168.2.99/24 ipv4.method manual
補足:ここではまだ nmcli connection up を実行しません。次のステップでルートも設定してから、まとめて起動します。
【最重要】コンテナ個別ルート(/32)の追加
ここが0-3で説明した「出口を2つから1つに絞り込む」作業です。/32 は「このIPアドレス1つだけ」を意味する、最も狭い指定方法です。
# 今後作成する予定の全コンテナIP(2.11〜2.17)へのルートを、macv0経由に固定
sudo nmcli connection modify macv0 +ipv4.routes "192.168.2.11/32"
sudo nmcli connection modify macv0 +ipv4.routes "192.168.2.12/32"
sudo nmcli connection modify macv0 +ipv4.routes "192.168.2.13/32"
sudo nmcli connection modify macv0 +ipv4.routes "192.168.2.14/32"
sudo nmcli connection modify macv0 +ipv4.routes "192.168.2.15/32"
sudo nmcli connection modify macv0 +ipv4.routes "192.168.2.16/32"
sudo nmcli connection modify macv0 +ipv4.routes "192.168.2.17/32"
運用ルール
今後コンテナを追加するたびに、この「採番表」と「ルート追加」をセットで更新してください。忘れると、新しいコンテナにだけ通信できない、という分かりにくい不具合になります。フェーズ6(Ansible)で、この作業自体も自動化します。
設定の反映
sudo nmcli connection reload
sudo nmcli connection up macv0
接続が正常にアクティベートされました(D-Bus アクティブパス: /org/freedesktop/NetworkManager/...)
本当に動くか証明する(疎通テスト)
設定が「正しく書けているか」と「実際に動くか」は別問題です。必ず実機で確認しましょう。
ip addr show macv0
state UP と 192.168.2.99/24 が表示されていればOKです。
参考:IPアドレスが異なっていた場合の修正方法
nmcli connection show macv0 | grep ipv4.method
nmcli connection show macv0 | grep ipv4.addresses
# ipv4.method: auto の場合、改めて設定し直す
sudo nmcli connection modify macv0 ipv4.method manual ipv4.addresses 192.168.2.99/24
# いったん落として上げ直せば反映される
sudo nmcli connection down macv0
sudo nmcli connection up macv0
ip route | grep macv0
192.168.2.11 dev macv0 scope link
192.168.2.12 dev macv0 scope link
...
このように7行(2.11〜2.17)表示されていれば成功です。
# 軽量なAlpine Linuxで、IP 192.168.2.11 のテストコンテナを起動
sudo podman run -it --rm --name test-ping --network local_lan --ip 192.168.2.11 docker.io/library/alpine:latest sh
実行するとコンテナの中(/ # というプロンプト)に入ります。
ping -c 3 192.168.2.99
ping -c 3 192.168.2.11
両方向とも 0% packet loss であればOKです。確認できたら、コンテナ側で exit と入力してテストを終了します(--rm オプションにより自動的に消えます)。
FortiGate側のDHCP除外設定(忘れずに)
192.168.2.99(macv0)と 192.168.2.11〜192.168.2.17(各コンテナ)が、将来DHCPで他の機器に払い出されてしまわないよう、FortiGateのDHCPサーバー設定で「除外範囲(Excluded Range)」に追加してください。
トラブルシューティング
| 症状 | 原因の可能性 | 対処法 |
|---|---|---|
ip route get 192.168.2.11 の結果が dev enp1s0 のまま | ルートが反映されていない | nmcli connection show macv0 で接続がactiveか確認し、nmcli connection down macv0 && nmcli connection up macv0 で再起動 |
nmcli connection add type macvlan でエラー | NetworkManagerのバージョンが古い、または該当プラグイン未導入 | nmcli --version を確認し、sudo dnf update NetworkManager を実施 |
| pingが片方向しか通らない | ファイアウォール(firewalld)がICMPをブロックしている可能性 | sudo firewall-cmd --list-all でICMP許可状況を確認 |
enp1s0 という名前が存在しない | 環境によって命名規則が異なる(ens18、eth0 など) | ステップ0の ip link show の結果を再確認し、全コマンド内の名前を実際の名前に置き換える |
| 再起動後にmacv0が消える/IPが消える | autoconnect が無効になっている | nmcli connection modify macv0 connection.autoconnect yes を実行 |
フェーズ1完了チェックリスト
ip link showで物理インターフェース名を確認したpodman network lsに local_lan が表示されるip addr show macv0で 192.168.2.99/24 が UP 状態ip route | grep macv0でコンテナ用ルート(2.11〜2.17)が7行表示される- テストコンテナとの双方向ping(ホスト⇔コンテナ)が両方とも成功した
- FortiGateのDHCP除外設定に .99 と .11〜.17 を追加した
すべてチェックできれば、フェーズ1は完了です。