【Proxmox】Ubuntu VMでmacvlanコンテナを作成し、物理ルータ経由でVLAN間通信を実現する方法
導入
仮想マシンだけで検証環境を増やしていくと、個人のラボ環境ではどうしてもリソースが不足しがちです。そこで今回は、より少ないリソースでセグメントを分けつつホストを量産する方法として、macvlanコンテナを使った構成を組んでみました。
本記事ではProxmox上の Ubuntu VMにVLANサブインターフェースを作成し、PodmanでmacvlanコンテナをVLAN100 / VLAN200の別セグメントで動作させ、物理ルータ経由でVLAN間通信を可能にする手順を解説します。
構成イメージは以下の通りです。
Ubuntu VM・コンテナA・コンテナB間でpingによる疎通確認ができる状態をゴールとします。

動作環境
以下の環境で動作を確認をしています。
- ハイパーバイザー
- Proxmox VE 9.0.3
- 物理・仮想ネットワークの接続
- Proxmoxでデフォルトで用意されているLinux Bridge(vmbr0)を使用
VLANのタグ処理はルータとUbuntu VMで行うこととする。
- Proxmoxでデフォルトで用意されているLinux Bridge(vmbr0)を使用
- 仮想マシン
- Ubuntu Server 24.04.3 LTS
- コンテナエンジン
- Podman
- コンテナ
- Ubuntu 22.04
- macvlanモード
- bridge
- 物理ルータ
- C891FJ-K9
物理ルータのインターフェイス設定は以下の通りです。
interface GigabitEthernet6
description ### Proxmox VE ###
switchport trunk native vlan 40
switchport trunk allowed vlan 1,2,40,100,200,1002-1005
switchport mode trunk
no ip address
!手順
必要パッケージのインストール
sudo apt update
sudo apt install -y iproute2 iputils-ping iputils-arping net-tools dnsutils traceroute curl podman chrony rsyslog snmp snmp-mibs-downloader bash-completion zshrootユーザーへの切り替え
gumio@ubuntu-server:~$ sudo passwd root
New password:
Retype new password:
passwd: password updated successfully
gumio@ubuntu-server:~$
gumio@ubuntu-server:~$ su
Password:
root@ubuntu-server:/home/gumio#時刻設定
root@ubuntu-server:/home/gumio# timedatectl set-timezone Asia/Tokyo
root@ubuntu-server:/home/gumio#
root@ubuntu-server:/home/gumio# timedatectl
Local time: Sat 2025-11-15 20:56:35 JST
Universal time: Sat 2025-11-15 11:56:35 UTC
RTC time: Sat 2025-11-15 11:56:35
Time zone: Asia/Tokyo (JST, +0900)
System clock synchronized: yes
NTP service: active
RTC in local TZ: no
root@ubuntu-server:/home/gumio#
root@ubuntu-server:/home/gumio# chronyc sources -v
.-- Source mode '^' = server, '=' = peer, '#' = local clock.
/ .- Source state '*' = current best, '+' = combined, '-' = not combined,
| / 'x' = may be in error, '~' = too variable, '?' = unusable.
|| .- xxxx [ yyyy ] +/- zzzz
|| Reachability register (octal) -. | xxxx = adjusted offset,
|| Log2(Polling interval) --. | | yyyy = measured offset,
|| \ | | zzzz = estimated error.
|| | | \
MS Name/IP address Stratum Poll Reach LastRx Last sample
===============================================================================
^- prod-ntp-3.ntp4.ps5.cano> 2 6 377 44 +4570us[+4570us] +/- 129ms
^- prod-ntp-5.ntp1.ps5.cano> 2 6 377 43 -7042us[-7042us] +/- 124ms
^- alphyn.canonical.com 2 6 377 45 -10ms[ -10ms] +/- 113ms
^- prod-ntp-4.ntp4.ps5.cano> 2 6 377 46 +3052us[+3052us] +/- 130ms
^* ntp1.hnd.jp.hojmark.net 2 6 377 47 -1443us[-2960us] +/- 24ms
^- vmi2899903.contaboserver> 4 6 353 107 +4820us[+3738us] +/- 176ms
^- 50.7.159.140 3 7 101 167 +2892us[ +282us] +/- 14ms
^- 138.3.209.153 2 6 373 47 -1253us[-1253us] +/- 110ms
root@ubuntu-server:/home/gumio#Netplan設定ファイルを作成・適用
サブインターフェイスを作成するため、Netplan設定ファイルを新規作成します。あわせて、今回は自動生成されているcloud-init用のファイルは無効化します。
cloud-initを無効化する理由については、こちらの過去記事をご参照ください。
root@ubuntu-server:/home/gumio# ls -al /etc/netplan/
total 12
drwxr-xr-x 2 root root 4096 Nov 14 16:15 .
drwxr-xr-x 115 root root 4096 Nov 15 20:55 ..
-rw------- 1 root root 235 Nov 14 16:15 50-cloud-init.yaml
root@ubuntu-server:/home/gumio#
root@ubuntu-server:/home/gumio# mv /etc/netplan/50-cloud-init.yaml /etc/netplan/50-cloud-init.yaml.disabled
root@ubuntu-server:/home/gumio#
root@ubuntu-server:/home/gumio# ls -al /etc/netplan/
total 12
drwxr-xr-x 2 root root 4096 Nov 15 21:10 .
drwxr-xr-x 115 root root 4096 Nov 15 20:55 ..
-rw------- 1 root root 235 Nov 14 16:15 50-cloud-init.yaml.disabled
root@ubuntu-server:/home/gumio#
root@ubuntu-server:/home/gumio# nano /etc/netplan/99-network.yaml
root@ubuntu-server:/home/gumio#
root@ubuntu-server:/home/gumio# ls -al /etc/netplan/
total 16
drwxr-xr-x 2 root root 4096 Nov 15 21:12 .
drwxr-xr-x 115 root root 4096 Nov 15 20:55 ..
-rw------- 1 root root 235 Nov 14 16:15 50-cloud-init.yaml.disabled
-rw-r--r-- 1 root root 366 Nov 15 21:12 99-network.yaml
root@ubuntu-server:/home/gumio#
root@ubuntu-server:/home/gumio# netplan apply
** (generate:6504): WARNING **: 21:20:05.154: Permissions for /etc/netplan/99-network.yaml are too open. Netplan configuration should NOT be accessible by others.
** (process:6502): WARNING **: 21:20:05.358: Permissions for /etc/netplan/99-network.yaml are too open. Netplan configuration should NOT be accessible by others.
** (process:6502): WARNING **: 21:20:05.408: Permissions for /etc/netplan/99-network.yaml are too open. Netplan configuration should NOT be accessible by others.
root@ubuntu-server:/home/gumio#99-network.yamlの中身には以下の内容を記述しています。
network:
version: 2
renderer: networkd
ethernets:
ens18:
dhcp6: false
dhcp4: false
addresses: [192.168.40.10/24]
routes:
- to: default
via: 192.168.40.99
nameservers:
addresses: [8.8.8.8, 1.1.1.1]
vlans:
ens18.100:
id: 100
link: ens18
ens18.200:
id: 200
link: ens18コンテナの参照DNSをホストと統一
DNSサーバ確認
■ホストのDNS
root@ubuntu-server:/home/gumio# cat /run/systemd/resolve/resolv.conf
# This is /run/systemd/resolve/resolv.conf managed by man:systemd-resolved(8).
# Do not edit.
#
# This file might be symlinked as /etc/resolv.conf. If you're looking at
# /etc/resolv.conf and seeing this text, you have followed the symlink.
#
# This is a dynamic resolv.conf file for connecting local clients directly to
# all known uplink DNS servers. This file lists all configured search domains.
#
# Third party programs should typically not access this file directly, but only
# through the symlink at /etc/resolv.conf. To manage man:resolv.conf(5) in a
# different way, replace this symlink by a static file or a different symlink.
#
# See man:systemd-resolved.service(8) for details about the supported modes of
# operation for /etc/resolv.conf.
nameserver 8.8.8.8
nameserver 1.1.1.1
search .
root@ubuntu-server:/home/gumio#
■コンテナのDNS
root@ubuntu-server:/home/gumio# cat /etc/resolv.conf
# This is /run/systemd/resolve/stub-resolv.conf managed by man:systemd-resolved(8).
# Do not edit.
#
# This file might be symlinked as /etc/resolv.conf. If you're looking at
# /etc/resolv.conf and seeing this text, you have followed the symlink.
#
# This is a dynamic resolv.conf file for connecting local clients to the
# internal DNS stub resolver of systemd-resolved. This file lists all
# configured search domains.
#
# Run "resolvectl status" to see details about the uplink DNS servers
# currently in use.
#
# Third party programs should typically not access this file directly, but only
# through the symlink at /etc/resolv.conf. To manage man:resolv.conf(5) in a
# different way, replace this symlink by a static file or a different symlink.
#
# See man:systemd-resolved.service(8) for details about the supported modes of
# operation for /etc/resolv.conf.
nameserver 127.0.0.53
options edns0 trust-ad
search .
root@ubuntu-server:/home/gumio#設定一致
root@ubuntu-server:/home/gumio# ln -sf /run/systemd/resolve/resolv.conf /etc/resolv.conf
root@ubuntu-server:/home/gumio#
root@ubuntu-server:/home/gumio# cat /etc/resolv.conf
# This is /run/systemd/resolve/resolv.conf managed by man:systemd-resolved(8).
# Do not edit.
#
# This file might be symlinked as /etc/resolv.conf. If you're looking at
# /etc/resolv.conf and seeing this text, you have followed the symlink.
#
# This is a dynamic resolv.conf file for connecting local clients directly to
# all known uplink DNS servers. This file lists all configured search domains.
#
# Third party programs should typically not access this file directly, but only
# through the symlink at /etc/resolv.conf. To manage man:resolv.conf(5) in a
# different way, replace this symlink by a static file or a different symlink.
#
# See man:systemd-resolved.service(8) for details about the supported modes of
# operation for /etc/resolv.conf.
nameserver 8.8.8.8
nameserver 1.1.1.1
search .
root@ubuntu-server:/home/gumio#macvlanネットワークを作成
作成コマンド
# VLAN100
podman network create \
--driver macvlan \
--subnet 192.168.100.0/24 \
--gateway 192.168.100.99 \
-o parent=ens18.100 macvlan100
# VLAN200
podman network create \
--driver macvlan \
--subnet 192.168.200.0/24 \
--gateway 192.168.200.99 \
-o parent=ens18.200 macvlan200確認コマンド
root@ubuntu-server:/home/gumio# podman network ls
NETWORK ID NAME DRIVER
b31d14129146 macvlan100 macvlan
14b0a7d1dcd2 macvlan200 macvlan
2f259bab93aa podman bridge
root@ubuntu-server:/home/gumio#コンテナ作成
作成コマンド
# コンテナA (VLAN100)
podman run -itd --name containerA \
--network macvlan100 \
--ip 192.168.100.10 \
--cap-add=NET_RAW \
--cap-add=NET_ADMIN \
docker.io/library/ubuntu:22.04 \
sleep infinity
# コンテナB (VLAN200)
podman run -itd --name containerB \
--network macvlan200 \
--ip 192.168.200.10 \
--cap-add=NET_RAW \
--cap-add=NET_ADMIN \
docker.io/library/ubuntu:22.04 \
sleep infinity確認コマンド
root@ubuntu-server:/home/gumio# podman ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
87273959f8ff docker.io/library/ubuntu:22.04 sleep infinity 17 seconds ago Up 17 seconds containerA
874bda1cc239 docker.io/library/ubuntu:22.04 sleep infinity 8 seconds ago Up 8 seconds containerB
root@ubuntu-server:/home/gumio#コンテナで必要パッケージをインストール
podman exec -it containerA apt update
podman exec -it containerA apt install -y iproute2 iputils-ping iputils-arping net-tools dnsutils traceroute curl chrony rsyslog snmp snmp-mibs-downloader bash-completion
podman exec -it containerB apt update
podman exec -it containerB apt install -y iproute2 iputils-ping iputils-arping net-tools dnsutils traceroute curl chrony rsyslog snmp snmp-mibs-downloader bash-completion
コンテナからGARP(Gratuitous ARP)を送信
物理ネットワーク上のルータのARPキャッシュを更新するため、コンテナ側からGARPを送信します。
root@ubuntu-server:/home/gumio# podman exec -it containerA arping -A -c 3 -I eth0 192.168.100.10
ARPING 192.168.100.10 from 192.168.100.10 eth0
Sent 3 probes (3 broadcast(s))
Received 0 response(s)
root@ubuntu-server:/home/gumio#
root@ubuntu-server:/home/gumio# podman exec -it containerB arping -A -c 3 -I eth0 192.168.200.10
ARPING 192.168.200.10 from 192.168.200.10 eth0
Sent 3 probes (3 broadcast(s))
Received 0 response(s)
root@ubuntu-server:/home/gumio#疎通確認
Ubuntuホスト→コンテナA・コンテナB
ping -c5 192.168.100.10
ping -c5 192.168.200.10コンテナA→Ubuntuホスト・コンテナB
podman exec -it containerA ping -c5 192.168.40.10
podman exec -it containerA ping -c5 192.168.200.10コンテナB→Ubuntuホスト・コンテナA
podman exec -it containerB ping -c5 192.168.40.10
podman exec -it containerB ping -c5 192.168.100.10Tips
その他コマンド
コンテナのIPアドレス・MACアドレス・ゲートウェイ・DNSサーバを確認
podman inspect -f '{{.Name}}: {{.NetworkSettings.Networks.macvlan100.IPAddress}}' containerA
podman inspect -f '{{.Name}}: {{.NetworkSettings.Networks.macvlan100.MacAddress}}' containerA
podman inspect -f '{{.NetworkSettings.Networks.macvlan100.Gateway}}' containerA
podman exec -it containerA cat /etc/resolv.confコンテナの停止・開始・削除(複数指定可)
podman stop containerA
podman start containerA
podman rm -f containerA containerB containerC ※-fオプション有りの場合、起動中でも削除可能macvlanの制限事項
macvlanをbridgeモードで使用する場合、ホスト(親インターフェース)とmacvlanコンテナ間では通信できないという制限があります。
今回の構成でいえば、Ubuntu VMのens18.100(親)と、その上に作成したmacvlan100コンテナの間では通信できません。そのため、そもそもサブインターフェイスにはIPアドレスをアサインしていません。
一方で、別のインターフェイス(例:ens18)とmacvlan100の間であれば通信は可能です。そのため、ホストとコンテナ間で相互通信を行いたい場合は、親インターフェースを分けてmacvlanを作成することで問題なく実現できます。
実行コマンドまとめ
sudo apt update
sudo apt install -y iproute2 iputils-ping iputils-arping net-tools dnsutils traceroute curl podman chrony rsyslog snmp snmp-mibs-downloader bash-completion zsh
sudo passwd root
su
timedatectl set-timezone Asia/Tokyo
timedatectl
chronyc sources -v
ls -al /etc/netplan/
mv /etc/netplan/50-cloud-init.yaml /etc/netplan/50-cloud-init.yaml.disabled
ls -al /etc/netplan/
nano /etc/netplan/99-network.yaml
network:
version: 2
renderer: networkd
ethernets:
ens18:
dhcp6: false
dhcp4: false
addresses: [192.168.40.10/24]
routes:
- to: default
via: 192.168.40.99
nameservers:
addresses: [8.8.8.8, 1.1.1.1]
vlans:
ens18.100:
id: 100
link: ens18
ens18.200:
id: 200
link: ens18
ls -al /etc/netplan/
netplan apply
cat /run/systemd/resolve/resolv.conf
cat /etc/resolv.conf
ln -sf /run/systemd/resolve/resolv.conf /etc/resolv.conf
cat /etc/resolv.conf
# VLAN100
podman network create \
--driver macvlan \
--subnet 192.168.100.0/24 \
--gateway 192.168.100.99 \
-o parent=ens18.100 macvlan100
# VLAN200
podman network create \
--driver macvlan \
--subnet 192.168.200.0/24 \
--gateway 192.168.200.99 \
-o parent=ens18.200 macvlan200
podman network ls
# コンテナA (VLAN100)
podman run -itd --name containerA \
--network macvlan100 \
--ip 192.168.100.10 \
--cap-add=NET_RAW \
--cap-add=NET_ADMIN \
docker.io/library/ubuntu:22.04 \
sleep infinity
# コンテナB (VLAN200)
podman run -itd --name containerB \
--network macvlan200 \
--ip 192.168.200.10 \
--cap-add=NET_RAW \
--cap-add=NET_ADMIN \
docker.io/library/ubuntu:22.04 \
sleep infinity
podman ps -a
podman exec -it containerA apt update
podman exec -it containerA apt install -y iproute2 iputils-ping iputils-arping net-tools dnsutils traceroute curl chrony rsyslog snmp snmp-mibs-downloader bash-completion
podman exec -it containerB apt update
podman exec -it containerB apt install -y iproute2 iputils-ping iputils-arping net-tools dnsutils traceroute curl chrony rsyslog snmp snmp-mibs-downloader bash-completion
podman exec -it containerA arping -A -c 3 -I eth0 192.168.100.10
podman exec -it containerB arping -A -c 3 -I eth0 192.168.200.10
ping -c5 192.168.100.10
ping -c5 192.168.200.10
podman exec -it containerA ping -c5 192.168.40.10
podman exec -it containerA ping -c5 192.168.200.10
podman exec -it containerB ping -c5 192.168.40.10
podman exec -it containerB ping -c5 192.168.100.10まとめ
今回の構成により、以下を実現できました。
- VLAN100 / VLAN200の独立したネットワークをmacvlanで再現
- Ubuntu VM 1台で複数セグメントの疎通検証が可能
- 物理ネットワーク側のL3機器を使ったVLAN間ルーティングが可能
- VMを増やさないため、全体のリソース消費を抑えられる
実際の現場の検証でも使用している構成のため、今後の検証環境やネットワーク設計においても幅広く応用できる仕組みです。
また、実際にはサーバを用意するというよりも、ノートPC内に仮想環境を構築し、外部ネットワークとトランク接続するケースの方が扱いやすく、より参考になるかと思います。そのため、Windows標準のHyper-Vを利用して同様の構成を構築する方法も別記事にて解説する予定です。
