1. Mục đích bài lab

Macvlan được sử dụng để tạo kết nối mạng cho các container sử dụng công nghệ ảo hóa LXC hoặc Docker. Bài lab này là bài lab cơ bản để thử nghiệm macvlan driver với chế độ bridge (một trong 4 chế độ hoạt động của macvlan) trên Docker.
Ghi chú: Docker là nền tảng ảo hóa lấy ý tưởng từ LXC (Linux Container), mục đích là để triển khai các ứng dụng trong một container cung cấp đầy đủ thư viện để chạy ứng dụng, sử dụng chung kernel với hệ điều hành chủ, giảm overhead, dễ dàng, thuận tiện khi triển khai, nâng cấp, hủy bỏ,... ứng dụng so với khi triển khai ứng dụng trên VM hay LXC.

2. Phân loại network trong Docker

Docker cung cấp các tùy chọn kết nối mạng tương tự như các nền tảng ảo hóa khác như các hypervisor của VMWare, Hyper-V, KVM, Xen, Virtualbox,... Tuy nhiên, cách tiếp cận của Docker có một chút khác biệt do các network driver mà nó cung cấp, gây khó hiểu đối với những người dùng mới đã quen thuộc với các khái niệm network trong các nền tảng ảo hóa khác. Bảng sau sẽ mô tả các chế độ network tương ứng với network driver mà docker cung cấp để tạo kết nối cho các container:
Các khái niệm trong ảo hóa mạng thông thường Docker network driver
NAT Network bridge
Bridge macvlan / ipvlan
Private/Host Only bridge
Overlay Network / VXLAN overlay

3. Lab tính năng macvlan bridge trong docker

  • 3.1. Topology



  • 3.2. Yêu cầu

    • Docker host cài đặt Ubuntu 14.04, phiên bản kernel yêu cầu thấp nhất là 3.9 (trong bài lab bản Ubuntu đã update kernel lên 4.x.x)
    • Docker host cài đặt docker phiên bản thấp nhất là 1.11 hoặc mới hơn(thời điểm bài lab thực hiện đang là phiên bản 1.12)
    • Docker host (lab trên VMware Workstation) có 1 card kết nối internet (chế độ bridge hoặc NAT), trong bài lab sử dụng card NAT dải 172.16.69.0/24.
  • 3.3. Cài đặt và cấu hình

    • Tạo macvlan network.

      Trong khi macvlan có 4 chế độ (VEPA, bridge, private, passthrough), thì Docker macvlan driver chỉ hỗ trợ macvlan bridge mode. Tiến hành tạo macvlan network mới tên là macvlan0 sử dụng lệnh sau:
          
      docker network create -d macvlan --subnet=172.16.69.0/24 --gateway=172.16.69.1 --ip-range=172.16.69.192/26 -o parent=eth0 macvlan0        
          
      
      Giải thích các tùy chọn:
      • -d: tùy chọn docker network driver (macvlan, bridge, overlay).
      • --subnet--gateway: subnet và gateway này trùng với subnet network và cấu hình gateway của lower device (ở đây là eth0) được chỉ định bởi tùy chọn parent.
      • --ip-range: dải địa chỉ cấp cho các container. Việc cấp IP cho các container không do external DHCP cung cấp mà nhờ IPAM driver đã cung cấp sẵn khi cài Docker.
      Các container sử dụng cấu hình DNS của Docker host nên không cần cấu hình tham số này cho macvlan network.
      Xác nhận macvlan network đã tạo:
          
      # liet ke danh sach cac macvlan network
      docker network ls | grep macvlan
      # ket qua tuong tu nhu sau
      8e93e9a79387        macvlan0            macvlan             local
          
      
      Xem chi tiết thông tin macvlan network macvlan0:
          
      # lenh kiem tra
      docker network inspect macvlan0
      # ket qua tra ve tuong tu nhu sau
      [
          {
              "Name": "macvlan0",
              "Id": "8e93e9a793879e2da2c22c9b2e7c10063e0daf3d443a23597b71e3170f59c77c",
              "Scope": "local",
              "Driver": "macvlan",
              "EnableIPv6": false,
              "IPAM": {
                  "Driver": "default",
                  "Options": {},
                  "Config": [
                      {
                          "Subnet": "172.16.69.0/24",
                          "IPRange": "172.16.69.192/26",
                          "Gateway": "172.16.69.1"
                      }
                  ]
              },
              "Internal": false,
              "Containers": {},
              "Options": {
                  "parent": "eth0"
              },
              "Labels": {}
          }
      ]
          
      
    • Tạo container mới tên alpine1 thuộc dải macvlan0:
          
      docker run --net=macvlan0 -itd --name='alpine1'  alpine /bin/sh
          
      
      Kiểm tra địa chỉ ip của alpine1:
          
      docker exec -ti alpine1 ip a
      # ket qua tuong tu nhu sau
      1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN
          link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
          inet 127.0.0.1/8 scope host lo
             valid_lft forever preferred_lft forever
          inet6 ::1/128 scope host
             valid_lft forever preferred_lft forever
      5: eth0@if2: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue state UNKNOWN
          link/ether 02:42:ac:10:45:c0 brd ff:ff:ff:ff:ff:ff
          inet 172.16.69.192/24 scope global eth0
             valid_lft forever preferred_lft forever
          inet6 fe80::42:acff:fe10:45c0/64 scope link
             valid_lft forever preferred_lft forever
          
      
      Ta thấy địa chỉ đầu tiên trong dải IP mà macvlan0 thiết lập được cấp cho container này. Kiểm tra thông tin network macvlan0 để xác nhận container đã được gắn vào macvlan network này:
          
      docker network inspect macvlan0
      # ket qua tuong tu nhu sau
      [
          {
              "Name": "macvlan0",
              "Id": "8e93e9a793879e2da2c22c9b2e7c10063e0daf3d443a23597b71e3170f59c77c",
              "Scope": "local",
              "Driver": "macvlan",
              "EnableIPv6": false,
              "IPAM": {
                  "Driver": "default",
                  "Options": {},
                  "Config": [
                      {
                          "Subnet": "172.16.69.0/24",
                          "IPRange": "172.16.69.192/26",
                          "Gateway": "172.16.69.1"
                      }
                  ]
              },
              "Internal": false,
              "Containers": {
                  "cf80975deb30c94ed65559e7e93fdd4de32263f98bbf6f7a9f07b22938e6fa2f": {
                      "Name": "alpine1",
                      "EndpointID": "ff6d54bdc31b56a608716c6883f10b8d45cd12c173ba94869d6d3fba9dee71ad",
                      "MacAddress": "02:42:ac:10:45:c0",
                      "IPv4Address": "172.16.69.192/24",
                      "IPv6Address": ""
                  }
              },
              "Options": {
                  "parent": "eth0"
              },
              "Labels": {}
          }
      ]
          
      
      Tiến hành ping thử ra gateway và ping ra internet kiểm tra kết nối:
          
      # ping ra gateway
      docker exec -ti alpine1 ping 172.16.69.1 -c 3
      # ket qua tuong tu nhu sau
      PING 172.16.69.1 (172.16.69.1): 56 data bytes
      64 bytes from 172.16.69.1: seq=0 ttl=128 time=0.759 ms
      64 bytes from 172.16.69.1: seq=1 ttl=128 time=0.593 ms
      64 bytes from 172.16.69.1: seq=2 ttl=128 time=0.868 ms
      
      --- 172.16.69.1 ping statistics ---
      3 packets transmitted, 3 packets received, 0% packet loss
      round-trip min/avg/max = 0.593/0.740/0.868 ms
      
      # ping ra internet
      docker exec -ti alpine1 ping google.com -c 3
      # ket qua tuong tu nhu sau
      PING google.com (216.58.199.14): 56 data bytes
      64 bytes from 216.58.199.14: seq=0 ttl=128 time=85.404 ms
      64 bytes from 216.58.199.14: seq=2 ttl=128 time=78.378 ms
      
      --- google.com ping statistics ---
      3 packets transmitted, 2 packets received, 33% packet loss
      round-trip min/avg/max = 78.378/81.891/85.404 ms
          
      
      Ping thử tới parent interface của network macvlan0, ta thấy kết quả ping thất bại:
          
      # kiem tra dia chi cua parent interface - eth0
      ip a | grep eth0
      # dia chi eth0
      2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
          inet 172.16.69.176/24 brd 172.16.69.255 scope global eth0
      
      # ping toi eth0
      docker exec -ti alpine1 ping 172.16.69.176 -c 3
      # ket qua tuong tu nhu sau
      PING 172.16.69.176 (172.16.69.176): 56 data bytes
      
      --- 172.16.69.176 ping statistics ---
      3 packets transmitted, 0 packets received, 100% packet loss
          
      
      Chú ý: đối với cả hai chế độ macvlanipvlan, ta đều không thê ping hay truyền thông với các địa chỉ thuộc default namespace (hay root namespace của hệ điều hành chủ, nơi các card mạng vật lý hoạt động). Ví dụ như ở đây ta ping giữa container alpine1 tới card eth0 của docker host bị thất bại. Lưu lượng đó đã bị lọc ngầm định bởi kernel module nhằm cung cấp khả năng bảo mật và cô lập về network.
    • Tạo thêm 1 container alpine2 và ping tới container alpine1 kiểm tra kết nối:
          
      # tao container
      docker run --net=macvlan0 -itd --name='alpine2'  alpine /bin/sh
      
      # kiem tra ip
      docker exec -ti alpine2 ip a
      # dia chi ip cua alpine2
      1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN
          link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
          inet 127.0.0.1/8 scope host lo
             valid_lft forever preferred_lft forever
          inet6 ::1/128 scope host
             valid_lft forever preferred_lft forever
      6: eth0@if2: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue state UNKNOWN
          link/ether 02:42:ac:10:45:c1 brd ff:ff:ff:ff:ff:ff
          inet 172.16.69.193/24 scope global eth0
             valid_lft forever preferred_lft forever
          inet6 fe80::42:acff:fe10:45c1/64 scope link
             valid_lft forever preferred_lft forever
      
      # ping toi alpine1 kiem tra ket noi
      docker exec -ti alpine2 ping 172.16.69.193 -c 3
      # ket qua ping 
      PING 172.16.69.193 (172.16.69.193): 56 data bytes
      64 bytes from 172.16.69.193: seq=0 ttl=64 time=0.206 ms
      64 bytes from 172.16.69.193: seq=1 ttl=64 time=0.150 ms
      64 bytes from 172.16.69.193: seq=2 ttl=64 time=0.433 ms
      
      --- 172.16.69.193 ping statistics ---
      3 packets transmitted, 3 packets received, 0% packet loss
      round-trip min/avg/max = 0.150/0.263/0.433 ms
          
      
      Kết quả ping thành công.