Docker'da macvlan sürücüsü her container'a kendi MAC adresini verir ve container'ı yerel ağa fiziksel bir cihaz gibi bağlar; ipvlan sürücüsü ise container'lara ayrı MAC adresi vermeden, üst arayüzün (parent) MAC adresini paylaştırarak aynı fiziksel ağa ya da VLAN'lara bağlar. İkisinde de container fiziksel ağın alt ağından adres alır ve port eşlemeye gerek kalmaz. Docker belgelerine göre bulut sağlayıcılarının çoğu macvlan ağlarını engeller; bu sürücüler en çok ağ donanımına erişiminiz olan sunucularda ve yerel ağlarda işe yarar.

Bu yazıda iki sürücünün gereksinimlerini, macvlan'ın bridge ve 802.1Q trunk modlarını, ipvlan'ın L2 ve L3 modlarını, VLAN alt arayüzlerinin nasıl oluşturulup silindiğini, IPv6 kullanımını ve Compose ile macvlan ağı tanımlamayı ele alıyoruz. Sürücülerin genel karşılaştırması için Docker network türleri, tek sunucuda en yaygın seçenek için Docker bridge network yazısına bakın. Serinin tamamı Docker öğrenme rehberinde.

Macvlan ne zaman gerekir?

Macvlan ne zaman gerekir? Macvlan sürücüsü yalnızca Linux sunucularda çalışır; Mac ve Windows için Docker..., Bulut sağlayıcılarının çoğu macvlan ağını engeller; ağ donanımına...

Belgelere göre bazı uygulamalar, özellikle eski (legacy) uygulamalar ve ağ trafiğini izleyen uygulamalar, doğrudan fiziksel ağa bağlı olmayı bekler. Bu durumda macvlan her container'ın sanal ağ arayüzüne bir MAC adresi atar ve arayüz fiziksel ağa doğrudan bağlı fiziksel bir arayüz gibi görünür. Bunun için Docker sunucusunda macvlan'ın kullanacağı bir fiziksel arayüzü ve ağın alt ağı ile ağ geçidini belirtirsiniz. Farklı fiziksel arayüzler kullanarak macvlan ağlarını birbirinden de yalıtabilirsiniz. Belgeler macvlan'ı sanal makine düzeninden geçiş yapanlar ve container'ların ağda benzersiz MAC adresli fiziksel makineler gibi görünmesi gereken durumlar için en iyi seçenek olarak anar.

Platform desteği ve gereksinimler

  • Macvlan sürücüsü yalnızca Linux sunucularda çalışır; Mac ve Windows için Docker Desktop'ta ve Windows üzerindeki Docker Engine'de desteklenmez.
  • Bulut sağlayıcılarının çoğu macvlan ağını engeller; ağ donanımına fiziksel erişiminiz olması gerekebilir.
  • En az Linux çekirdeği 3.9 gerekir; 4.0 ve sonrası önerilir.
  • Macvlan sürücüsü rootless modda desteklenmez (rootless kurulum için Docker rootless mod yazısına bakın).

Dikkat edilmesi gerekenler

Belgeler macvlan kullanırken ağınızı istemeden kötüleştirebileceğiniz iki durumu sayar: IP adreslerinin tükenmesi ve "VLAN spread", yani ağda uygunsuz derecede çok sayıda benzersiz MAC adresi bulunması. Ağ donanımınızın tek bir fiziksel arayüze birden fazla MAC adresi atanmasına izin veren "promiscuous mode"u desteklemesi de gerekir. Uygulamanız bridge (tek sunucu) ya da overlay (birden fazla sunucu) ile çalışabiliyorsa belgeler bu çözümlerin uzun vadede daha iyi olabileceğini hatırlatır.

Macvlan seçenekleri ve modları

Macvlan ağı oluştururken --opt ile iki sürücü seçeneği verilir:

SeçenekVarsayılanAçıklama
macvlan_modebridgeMacvlan modu: bridge, vepa, passthru ya da private
parent-Kullanılacak üst arayüz

Bir macvlan ağı ya bridge modunda ya da 802.1Q trunk bridge modunda oluşturulur. Bridge modunda macvlan trafiği sunucudaki fiziksel bir aygıttan geçer. 802.1Q trunk bridge modunda ise trafik Docker'ın anında oluşturduğu bir 802.1Q alt arayüzünden geçer; belgelere göre bu, yönlendirme ve filtrelemeyi daha ince bir düzeyde denetlemenizi sağlar.

Bridge modu

Fiziksel bir arayüzle köprü kuran bir macvlan ağı için docker network create komutuna --driver macvlan ve trafiğin sunucuda fiziksel olarak geçeceği arayüzü belirten parent seçeneği verilir:

bash
docker network create -d macvlan \
  --subnet=172.16.86.0/24 \
  --gateway=172.16.86.1 \
  -o parent=eth0 pub_net

Ağda zaten kullanılan bir adres gibi bazı IP adreslerini macvlan ağının dağıtımından çıkarmak için --aux-address kullanılır. Belgelerdeki örnek, container adreslerini --ip-range ile alt ağın üst yarısına sınırlar ve yönlendiricinin adresini ayırır:

bash
docker network create -d macvlan \
  --subnet=192.168.32.0/24 \
  --ip-range=192.168.32.128/25 \
  --gateway=192.168.32.254 \
  --aux-address="my-router=192.168.32.129" \
  -o parent=eth0 macnet32

Bu ayrım pratikte önemlidir: macvlan container'ları fiziksel ağın alt ağından adres aldığı için o alt ağdaki yönlendirici, yazıcı ya da başka sunucular gibi cihazların adresleriyle aynı havuzu paylaşır. Belgelerin yöntemi, container'lara --ip-range ile ayrı bir aralık vermek ve zaten kullanılan adresleri --aux-address ile dağıtımdan çıkarmaktır. Belgelerin uyardığı IP adresi tükenmesi riskini de bu aralığı gerçekçi boyutta tutarak azaltırsınız.

802.1Q trunk bridge modu

parent değerinde nokta içeren bir arayüz adı (örneğin eth0.50) verirseniz Docker bunu eth0'ın bir alt arayüzü olarak yorumlar ve alt arayüzü otomatik oluşturur:

bash
docker network create -d macvlan \
    --subnet=192.168.50.0/24 \
    --gateway=192.168.50.1 \
    -o parent=eth0.50 macvlan50

Container'ı inceleme

Belgelerdeki bridge modu örneğinde my-macvlan-net ağına bağlanan bir alpine container'ının docker container inspect çıktısında, Networks bölümünde container'a atanmış MAC adresi görülür. Belgede gösterilen kesit şöyledir:

json
"Networks": {
  "my-macvlan-net": {
    "Gateway": "172.16.86.1",
    "IPAddress": "172.16.86.2",
    "IPPrefixLen": 24,
    "MacAddress": "02:42:ac:10:56:02",
    ...
  }
}

Container içindeki yönlendirme tablosu da varsayılan yolun belirttiğiniz ağ geçidi üzerinden gittiğini gösterir (belgedeki çıktı):

bash
docker exec my-macvlan-alpine ip route

default via 172.16.86.1 dev eth0
172.16.86.0/24 dev eth0 scope link  src 172.16.86.2

IPvlan: MAC adresi paylaşan alternatif

IPvlan: MAC adresi paylaşan alternatif: L3 modu bütün broadcast ve multicast trafiğini düşürür; belgeler bunu büyük..., L3 ağı, varsayılan ad alanıyla farklı bir alt ağda...

Belgeler IPvlan'ı hafif bir ağ sanallaştırma tekniği olarak tanımlar. Geleneksel Linux bridge'i yalıtım için kullanmak yerine bir Linux Ethernet arayüzüne ya da alt arayüzüne bağlanır. Bridge'in atlanmasının performans açısından olumlu etkileri ve daha az hareketli parça bulunmasının getirdiği sadelik, belgelerin saydığı iki temel avantajdır. Container arayüzleri doğrudan sunucu arayüzüne bağlandığı için dışa dönük servislerde port eşleme gerekmez.

-o ipvlan_mode=l2 ile oluşturulan bir ipvlan ağı macvlan ağına benzer. Temel fark, ipvlan sürücüsünün her container'a bir MAC adresi atamamasıdır: ipvlan ağındaki aygıtlar L2 ağ yığınını paylaşır ve container'lar üst arayüzün MAC adresini kullanır. Ağ daha az MAC adresi görür ve sunucunun MAC adresi her container'ın IP adresiyle ilişkilendirilir. Belgeler, bir ağ arayüzüne ya da porta atanabilecek MAC adresi sayısında kısıtlama varsa ipvlan'ı düşünmenizi önerir ve seçim için Linux çekirdeği belgelerindeki karşılaştırmaya yönlendirir.

SeçenekVarsayılanAçıklama
ipvlan_model2Çalışma modu: l2, l3 ya da l3s
ipvlan_flagbridgeMod bayrağı: bridge, private ya da vepa
parent-Kullanılacak üst arayüz

Belgelere göre IPvlan için Linux çekirdeği 4.2 veya sonrası gerekir; daha eski çekirdeklerde destek vardır ama hatalıdır. Çekirdek sürümünüzü uname -r ile görebilirsiniz.

L2 modu

L2 modunda container, -o parent= ile verilen sunucu arayüzüyle aynı ağa bağlanır; --subnet olarak sunucu arayüzünün ağını kullanırsınız. Belgelerdeki örnekte üst arayüz eth0'ın adresi 192.168.1.250/24'tür:

bash
docker network create -d ipvlan \
    --subnet=192.168.1.0/24 \
    --gateway=192.168.1.1 \
    -o ipvlan_mode=l2 \
    -o parent=eth0 db_net

docker run --net=db_net -it --rm alpine /bin/sh

Belgelerin bu örnekteki notu önemlidir: container'lar alttaki sunucu arayüzlerine ping atamaz, çünkü bu trafik ek yalıtım için Linux tarafından kasıtlı olarak filtrelenir. Aynı ağa adla bağlanan iki container ise birbirini Docker'ın ad çözümlemesiyle bulabilir; belgelerdeki örnekte ikinci container ping -c 4 ipv1 ile ilkine ulaşır.

Mod verilmezse varsayılan l2 kullanılır. IPvlan sayfası ağ geçidi boş bırakılırsa ağın ilk kullanılabilir adresinin ağ geçidi yapıldığını söyler; ancak yukarıdaki notta belirtildiği gibi Engine 29.0.0 sürüm notları macvlan ve IPvlan L2 ağlarında açık bir --gateway verilmedikçe varsayılan ağ geçidi yapılandırılmadığını kaydeder. Engine 29 kullanıyorsanız ağ geçidini açıkça yazmak bu belirsizliği ortadan kaldırır.

Yalıtılmış ipvlan ağı: parent vermemek ya da --internal

Ağ yalıtımı üst arayüze sıkı sıkıya bağlı olduğu için -o parent= seçeneğini hiç vermemek, --internal vermekle aynı sonucu doğurur. Her iki durumda da sürücü kullanıcı için dummy türünde bir netlink arayüzü oluşturup bunu üst arayüz olarak kullanır ve ağ dışarıdan tamamen yalıtılır. Belgelere göre --subnet de boş bırakılırsa varsayılan IPAM bir alt ağ atar:

bash
docker network create -d ipvlan --subnet=192.168.10.0/24 isolated1
docker network create -d ipvlan --subnet=192.168.11.0/24 --internal isolated2
docker network create -d ipvlan isolated3

802.1Q VLAN alt arayüzleri

Bir VLAN etiketli Linux alt arayüzü önceden var olabilir ya da docker network create çağrıldığında oluşturulur. Sürücünün alt arayüzü ekleyip silebilmesi için ad biçimi arayüz_adı.vlan_etiketi olmalıdır; örneğin eth0.10, eth0'ın VLAN 10 ile etiketlenmiş alt arayüzüdür ve eşdeğer komut ip link add link eth0 name eth0.10 type vlan id 10'dur. docker network rm yalnızca alt arayüzleri siler; eth0 gibi üst arayüzler silinmez. Elle oluşturduğunuz alt arayüzler, adları ne olursa olsun, ağ silindiğinde silinmez; ağ oluşturulurken var ve açık olmaları yeterlidir:

bash
ip link add link eth0 name eth0.40 type vlan id 40
ip link set eth0.40 up

docker network create -d ipvlan \
    --subnet=192.168.40.0/24 \
    --gateway=192.168.40.1 \
    -o parent=eth0.40 ipvlan40

Farklı VLAN'lar arasında bir yönlendirici olmadan ping atılamaz. Belgelere göre ağ ekibinin verdiği VLAN numarası, alt ağ ve ağ geçidi değerleri doğrudan docker network create komutlarına yazılır; örneğin VLAN 10, alt ağ 172.16.80.0/24 ve ağ geçidi 172.16.80.1 için --subnet=172.16.80.0/24 --gateway=172.16.80.1 -o parent=eth0.10. Bu yapılandırmalar kalıcıdır ve Docker Engine her başladığında yeniden uygulanır.

L3 modu

L3 modunda Docker sunucusu, container'larda yeni ağlar başlatan bir yönlendiriciye çok benzer. Sürücü yalnızca L3 portunu kurar ve container'ı arayüze bağlar; yolların küme içinde dağıtılması bu tek sunuculu sürücünün kapsamı dışındadır. Belgelerin vurguladığı özellikler şunlardır:

  • L3 modu bütün broadcast ve multicast trafiğini düşürür; belgeler bunu büyük ölçek ve öngörülebilir ağ bütünleşmesi arayanlar için bir avantaj olarak sunar.
  • L3 ağı, varsayılan ad alanıyla farklı bir alt ağda olmalıdır; örnekte eth0 192.168.1.0/24 üzerindeyken Docker ağı başka alt ağlardadır.
  • L2 modunun aksine farklı alt ağlar, aynı -o parent= arayüzünü paylaştıkları sürece birbirine ping atabilir.
  • Broadcast olmadığı için klasik ağ geçidi anlamını yitirir; container'ın varsayılan yolu default dev eth0 olur ve --gateway verilse bile yok sayılır.
  • Mod varsayılan l2 olduğundan -o ipvlan_mode=l3 açıkça yazılmalıdır.
  • Uzak bir sunucunun container'a ulaşması ya da container'ın uzak bir sunucuya ulaşması için aradaki ağın, container'ın Docker sunucusunun IP adresini gösteren bir yola sahip olması gerekir.
bash
docker network create -d ipvlan \
    --subnet=192.168.214.0/24 \
    --subnet=10.1.214.0/24 \
    -o ipvlan_mode=l3 ipnet210

IPv6 ile macvlan ve ipvlan

Daemon IPv6'ya izin verecek şekilde yapılandırıldıysa çift yığınlı (IPv4/IPv6) macvlan ve ipvlan ağları oluşturabilirsiniz. Belgelerdeki macvlan örneği iki IPv4 alt ağı ve bir IPv6 alt ağını VLAN 218 üzerinde tanımlar:

bash
docker network create -d macvlan \
    --subnet=192.168.216.0/24 --subnet=192.168.218.0/24 \
    --gateway=192.168.216.1 --gateway=192.168.218.1 \
    --subnet=2001:db8:abc8::/64 --gateway=2001:db8:abc8::10 \
     -o parent=eth0.218 \
     -o macvlan_mode=bridge macvlan216

IPv6 adreslerini Docker'ın IPAM'ı yerine üst ağdaki bir yönlendiriciden durumsuz adres otomatik yapılandırmasıyla (SLAAC) almak da mümkündür. Ancak ağda IPv6 alt ağı yoksa Docker container arayüzünde IPv6'yı kapatır ve arayüz SLAAC'ın dayandığı yönlendirici duyurularını kabul edemez. IPv6'yı yeniden açmak için container'ı ağa bağlarken arayüzün disable_ipv6 sysctl değerini 0 yaparsınız:

bash
docker network connect \
    --driver-opt="com.docker.network.endpoint.sysctls=net.ipv6.conf.IFNAME.disable_ipv6=0" \
    my-macvlan-net my-container

Sysctl adındaki IFNAME harfi harfine yazılır; Docker bunu container'ın bu ağdaki arayüz adıyla değiştirir. disable_ipv6 arayüz başına bir ayar olduğu için docker run --sysctl ile değil, endpoint.sysctls sürücü seçeneğiyle verilmelidir. Aynı yöntem ipvlan ağlarında da geçerlidir. Belgeler ipvlan L3 modunda belirli bir --ip6 adresiyle oluşturulan bir container silinip aynı adresle yenisi başlatıldığında adresin havuza düzgün geri verilmemesi ve Address already in use hatası alınması gibi olası bir hatayı da not eder. Docker'da IPv6'nın genel yapılandırması Docker IPv6 yapılandırma yazısında.

Compose ile macvlan ağı

Compose dosyasında macvlan ağı, üst düzey networks altında driver: macvlan, driver_opts ile parent ve ipam ile alt ağ tanımlanarak kurulur. Servise sabit adres vermek için ipv4_address kullanılır; Compose başvurusuna göre bu adresi kapsayan bir ipam alt ağ yapılandırması bulunmalıdır. Aşağıdaki dosya yukarıdaki macnet32 örneğinin Compose karşılığıdır ve Docker CLI 29.8.1, Docker Compose v5.5.1 ile docker compose config --quiet doğrulamasından geçmiştir:

yaml
services:
  legacy:
    image: example/legacy-app:latest
    networks:
      lan:
        ipv4_address: 192.168.32.140

networks:
  lan:
    driver: macvlan
    driver_opts:
      parent: eth0
    ipam:
      config:
        - subnet: 192.168.32.0/24
          ip_range: 192.168.32.128/25
          gateway: 192.168.32.254
          aux_addresses:
            my-router: 192.168.32.129

compose config doğrulaması yalnızca dosyanın yapısını denetler; eth0 arayüzünün var olup olmadığını ya da ağınızın macvlan'a izin verip vermediğini bilemez. Bunlar ancak docker compose up sırasında, Docker Engine ağı oluştururken ortaya çıkar. Compose ağ başvurusuna göre belirttiğiniz sürücü platformda yoksa Compose hata döndürür.

Macvlan, ipvlan ve bridge karşılaştırması

Macvlan, ipvlan ve bridge karşılaştırması: Container başına MAC, Sunucu ile doğrudan iletişim, Broadcast/multicast, Port eşleme
Özellikmacvlanipvlan L2ipvlan L3bridge
Container başına MACEvetHayır, üst arayüzün MAC adresiHayırDış ağ yalnızca sunucunun adresini görür
Sunucu ile doğrudan iletişimHayır (çekirdek kısıtı)Hayır, filtrelenirHayır, varsayılan ad alanına ulaşılamazEvet
Broadcast/multicastVarVarDüşürülürVar
Port eşlemeGerekmezGerekmezGerekmezGerekir
Docker güvenlik duvarı kurallarıOluşturulmazOluşturulmazOluşturulmazOluşturulur
Dış ağın bilmesi gerekenAlt ağ ve ağ geçidiAlt ağ ve ağ geçidiContainer ağlarına giden yollarHiçbir şey, NAT kullanılır

Tablodaki güvenlik duvarı satırı özellikle önemlidir: Docker belgelerine göre ipvlan ve macvlan ağları için Docker hiçbir güvenlik duvarı kuralı oluşturmaz. Container doğrudan ağa açık bir adres aldığı için erişim denetimini ağ donanımınızda ya da container'ın kendisinde yapmanız gerekir. Bridge ağlarındaki kurallar Docker iptables ve UFW yazısında.

Sık yapılan hatalar

  • Bulut VPS'te macvlan beklemek: belgelere göre çoğu bulut sağlayıcısı macvlan ağını engeller; tek bir VPS'te bridge ağı kullanın.
  • Sunucudan macvlan container'ına ping atamamayı hata sanmak: bu Linux çekirdeğinin kısıtlamasıdır; bridge ağı ekleyin ya da sunucuda bir macvlan arayüzü oluşturun.
  • DHCP aralığıyla çakışan alt ağ vermek: --ip-range ve --aux-address ile Docker'ın dağıtacağı adresleri ayırın.
  • Engine 29'da ağ geçidini yazmamak: macvlan ve IPvlan L2 ağlarında açık --gateway olmadan varsayılan ağ geçidi yapılandırılmaz.
  • L3 modunda ipvlan_mode yazmayı unutmak: varsayılan l2'dir.
  • Rootless modda macvlan denemek: desteklenmez.

Sık Sorulan Sorular

Macvlan ile ipvlan arasındaki temel fark nedir?

Macvlan her container'a ayrı bir MAC adresi verir; ipvlan ise container'ların üst arayüzün MAC adresini paylaşmasını sağlar. Ağdaki MAC adresi sayısı sınırlıysa ipvlan tercih edilir.

Macvlan container'ına neden sunucudan erişemiyorum?

Belgelere göre macvlan ağına bağlı container'lar Linux çekirdeğindeki bir kısıtlama nedeniyle sunucuyla doğrudan haberleşemez. Container'ı bir bridge ağına da bağlamak ya da sunucuda aynı üst arayüzde bir macvlan arayüzü oluşturmak çözüm yoludur.

ipvlan için parent vermezsem ne olur?

Sürücü bir dummy arayüz oluşturup üst arayüz olarak kullanır ve ağ dışarıdan tamamen yalıtılır; sonuç --internal ile aynıdır.

VLAN alt arayüzünü Docker mı oluşturur?

parent değeri eth0.50 gibi arayüz.vlan biçimindeyse Docker alt arayüzü oluşturur ve ağ silinince siler. Elle oluşturduğunuz alt arayüzler ağ silindiğinde silinmez.

Marka adları sahiplerine aittir. Bu yazı bağımsız bir teknik rehberdir; adı geçen kuruluşlarla bayilik veya ortaklık ilişkisi bulunduğu anlamına gelmez.

İlgili içerikler: Docker öğrenme rehberi · Docker network türleri · Docker bridge network · Docker IPv6 · Docker iptables ve UFW · Docker rootless mod