Quick start: Tạo Docker Macvlan và gán IP tĩnh trong 5 phút
Hệ thống tổng đài Asterisk hoặc FreePBX chạy trong Docker bridge rất hay gặp lỗi: máy nhánh chỉ nghe được một chiều, rớt cuộc gọi sau 30 giây hoặc không nhận diện được gói SIP SDP do vướng NAT. Các gói broadcast/multicast từ IP phone vật lý ngoài switch cũng không thể định tuyến vào bridge network của Docker.
Cách giải quyết nhanh nhất là đưa container ra thẳng lớp mạng LAN vật lý bằng driver macvlan. Khi đó, container hoạt động độc lập và có MAC address riêng ngang hàng với mọi thiết bị trong mạng.
Trước tiên, xác định card mạng đang nối ra router và thông số IP trên server:
ip -br addr show
# Ví dụ output: eth0 UP 192.168.1.50/24
# Gateway hiện tại: 192.168.1.1
# Subnet mạng nội bộ: 192.168.1.0/24
Tạo một Docker network với driver macvlan gắn vào interface eth0:
docker network create -d macvlan \
--subnet=192.168.1.0/24 \
--gateway=192.168.1.1 \
--ip-range=192.168.1.200/28 \
-o parent=eth0 \
lan_macvlan
Khởi chạy container với IP tĩnh 192.168.1.202 nằm trong dải vừa cấp:
docker run -d \
--name voip-service \
--net=lan_macvlan \
--ip=192.168.1.202 \
--restart=always \
nginx:alpine
Từ một máy tính khác trong cùng dải mạng LAN, kiểm tra kết nối:
ping -c 4 192.168.1.202
curl -I http://192.168.1.202
Ping phản hồi ngay với RTT dưới 1ms. Container đã có địa chỉ MAC riêng và bắt trọn traffic trực tiếp trên Layer 2 mà không cần đi qua tầng NAT trung gian.
Bản chất Docker Macvlan vận hành ra sao?
Ở chế độ bridge mặc định, Docker dựng bridge ảo docker0 và dùng iptables MASQUERADE để dịch địa chỉ (NAT). Switch và router ngoài hệ thống chỉ nhìn thấy duy nhất MAC và IP của máy host. Cơ chế này tiện lợi nhưng làm tê liệt các giao thức phụ thuộc broadcast hoặc multicast như DHCP relay, VoIP (SIP/RTP), mDNS của Home Assistant hay luồng stream camera ONVIF.
Cơ chế ảo hóa sub-interface
Macvlan xử lý vấn đề này ở tầng liên kết dữ liệu (Layer 2). Driver tạo các sub-interface ảo gắn trực tiếp vào card mạng cha (parent interface) của máy host. Mỗi container được cấp một địa chỉ MAC ngẫu nhiên theo chuẩn IEEE 802:
- MAC address độc lập: Switch nhận diện container như một máy chủ vật lý cắm dây trực tiếp vào port mạng.
- Không qua NAT: Container hứng trực tiếp traffic gửi đến IP của nó. Không phát sinh độ trễ định tuyến hay phụ thuộc vào bảng conntrack của Linux kernel.
- Loại bỏ Port Mapping: Bạn không cần khai báo
-p 80:80. Điều này xóa bỏ nguy cơ xung đột port giữa nhiều service chạy song song trên cùng một host.
Ý nghĩa các tham số mạng cần nhớ
--subnet: Bắt buộc khớp với subnet của router LAN (ví dụ192.168.1.0/24).--gateway: Địa chỉ IP của Default Gateway (thường là router192.168.1.1).--ip-range: Giới hạn vùng IP Docker được phép cấp. Ví dụ192.168.1.200/28chỉ cho phép Docker sử dụng 16 địa chỉ (từ.200đến.215), tránh tranh chấp với DHCP server của văn phòng.-o parent: Tên card mạng vật lý đang kết nối (nhưeth0,ens18hoặcenp3s0).
Triển khai bằng Docker Compose và xử lý lỗi Host – Container
File docker-compose.yml hoàn chỉnh
Với Compose hiện đại, bạn không cần khai báo dòng version: đã lỗi thời. Cấu hình triển khai Pi-hole kèm Macvlan viết như sau:
services:
dns-server:
image: pihole/pihole:latest
container_name: local-pihole
environment:
TZ: 'Asia/Ho_Chi_Minh'
WEBPASSWORD: 'AdminSecurePassword123'
networks:
lan_net:
ipv4_address: 192.168.1.205
restart: unless-stopped
networks:
lan_net:
name: lan_macvlan
driver: macvlan
driver_opts:
parent: eth0
ipam:
config:
- subnet: 192.168.1.0/24
ip_range: 192.168.1.200/28
gateway: 192.168.1.1
Khắc phục lỗi: Máy host không ping được container
Bạn sẽ gặp ngay hiện tượng này: các máy tính khác trong LAN truy cập container bình thường, nhưng chính máy host gõ ping 192.168.1.205 thì nhận 100% packet loss. Đây là thiết kế bảo mật có chủ đích của Linux kernel. Kernel cấm giao tiếp trực tiếp giữa card cha (parent) và các sub-interface macvlan con ở chế độ bridge.
Giải pháp chuẩn xác là tạo một interface macvlan đóng vai trò cầu nối (shim interface) ngay trên host:
# 1. Tạo bridge macvlan ảo trên host
sudo ip link add macvlan-shim link eth0 type macvlan mode bridge
# 2. Gán một IP chưa sử dụng cho shim interface
sudo ip addr add 192.168.1.210/32 dev macvlan-shim
# 3. Bật interface
sudo ip link set macvlan-shim up
# 4. Định tuyến toàn bộ dải IP container qua shim này
sudo ip route add 192.168.1.200/28 dev macvlan-shim
Chạy xong 4 lệnh trên, host ping thẳng tới container ngay lập tức mà không cần khởi động lại dịch vụ.
3 lưu ý quan trọng khi chạy trên Production
- Bật Promiscuous Mode trên hypervisor: Nếu máy host là VM chạy trên VMware ESXi hoặc Proxmox VE, bạn phải bật
Promiscuous Mode,MAC Address ChangesvàForged Transmitsthành Accept trên vSwitch/Linux Bridge. Nếu tắt, hypervisor sẽ drop mọi gói tin mang MAC address lạ của container. - Quy hoạch dải IP cẩn thận: Đừng để Docker đụng dải cấp phát tự động của Router. Bạn nên cấu hình Router DHCP chỉ phát từ
192.168.1.10đến192.168.1.150, dành riêng đoạn192.168.1.200/28cho Docker Macvlan. - Lưu cấu hình shim interface khi reboot: Các lệnh
ip linkvàip routesẽ mất trắng khi server khởi động lại. Bạn nên gom các lệnh này vào một file systemd service hoặc cấu hình trực tiếp vào Netplan/NetworkManager để tự chạy khi boot server.

