How to create a Docker macvlan with user defined IP and MAC address using Compose

PieterV picture PieterV · May 16, 2020 · Viewed 21.5k times · Source

I have a docker project that uses the MAC address for hardware license enforcement. I cannot change this, the ISV uses a hardware fingerprint that includes the MAC address.

I am trying to create a macvlan network, that will use the physical adapter and get an IP address from my network DHCP server, alternatively I will assign a static IP address manually. I must be able to set the MAC address manually such that it does not dynamically change and invalidate my license key.

Based on Docker docs the mac_address setting is deprecated, at least in v3 schema, but seems to be honored in v2 schemas.

I have a config that builds, using vanilla LSIO Nginx as test, but fails to run with an error stating that the MAC address cannot be assigned.

version: "2.1"

services:
  nginx:
    image: linuxserver/nginx
    container_name: nginx_macvlan
    environment:
      - TZ=Americas/Los_Angeles
    volumes:
      - .mount:/config
    ports:
      - 80:80
      - 443:443
    restart: unless-stopped
    mac_address: b7-48-d5-a6-d1-99
    networks: 
      nginx_vlan:
        ipv4_address: 192.168.1.10

networks:
  nginx_vlan:
    driver: macvlan
    ipam:
      driver: default
      config:
        - subnet: 192.168.1.0/24
PS C:\Users\piete\source\TestMacVlan> cd "c:\Users\piete\source\TestMacVlan"
PS C:\Users\piete\source\TestMacVlan> docker-compose -f "docker-compose-macvlan.yml" up -d --build
Creating network "testmacvlan_nginx_vlan" with driver "macvlan"
Creating nginx_macvlan ... error

ERROR: for nginx_macvlan  Cannot start service nginx: OCI runtime create failed: container_linux.go:349: starting container process caused "process_linux.go:449: container init caused \"process_linux.go:432: running prestart hook 0 caused \\\"error running hook: exit status 1, stdout: , stderr: time=\\\\\\\"2020-05-16T02:46:50Z\\\\\\\" level=fatal msg=\\\\\\\"failed to add interface veth2b7c9ef to sandbox: error setting interface \\\\\\\\\\\\\\\"veth2b7c9ef\\\\\\\\\\\\\\\" MAC to \\\\\\\\\\\\\\\"b7:48:d5:a6:d1:99\\\\\\\\\\\\\\\": cannot assign requested address\\\\\\\"\\\\n\\\"\"": unknown

ERROR: for nginx  Cannot start service nginx: OCI runtime create failed: container_linux.go:349: starting container process caused "process_linux.go:449: container init caused \"process_linux.go:432: running prestart hook 0 caused \\\"error running hook: exit status 1, stdout: , stderr: time=\\\\\\\"2020-05-16T02:46:50Z\\\\\\\" level=fatal msg=\\\\\\\"failed to add interface veth2b7c9ef to sandbox: error setting interface \\\\\\\\\\\\\\\"veth2b7c9ef\\\\\\\\\\\\\\\" MAC to \\\\\\\\\\\\\\\"b7:48:d5:a6:d1:99\\\\\\\\\\\\\\\": cannot assign requested address\\\\\\\"\\\\n\\\"\"": unknown
ERROR: Encountered errors while bringing up the project.
PS C:\Users\piete\source\TestMacVlan> 

I am testing on Win10 using Docker for Windows.

PS C:\Users\piete\source\TestMacVlan> docker --version
Docker version 19.03.1, build 5b38d82a-

PS C:\Users\piete\source\TestMacVlan> [Environment]::OSVersion               

Platform ServicePack Version      VersionString
-------- ----------- -------      -------------
 Win32NT             10.0.18363.0 Microsoft Windows NT 10.0.18363.0

How do I use macvlan in compose and set a MAC and IP or use DHCP for IP?

Answer

PieterV picture PieterV · May 17, 2020

I got it working on ubuntu 18 lts in a Hyper-V container.
You have to edit the Hyper-V guest network adapter to allow "enable mac address spoofing", this is under the advanced options.

When using compose, the version can't be greater than ~v2.1, when using current v3.7+ versions you'll get a gateway is unexpected error.

On Linux the host does not get traffic routed to the macvlan, so containers need to be on the same macvlan if they need to talk to each other.

There can only be one macvlan per subnet range, or one gateway per range, not sure what the cause is.

I could not get it working on Docker for Windows, specifically I do not know how to specify the parent adapter name. I tried the actual adapter name, did not work, "eth0" works for creating the macvlan, but no traffic flows. I don't know if it is because the adapter name is wrong, or something else.

I could not get network infrastructure DHCP working using macvlan, maybe this will require creating bridges on the host.

Here is working compose file running two nginx instances on two specific IP's with two specific MAC addresses, tested on Ubuntu 18.04 LTS running on Hyper-V. I have not yet tested bare metal.

version: "2.1"

services:
  nginx_10:
    image: linuxserver/nginx
    container_name: nginx_macvlan_10
    environment:
      - TZ=Americas/Los_Angeles
    ports:
      - 80:80
      - 443:443
    restart: unless-stopped
    mac_address: 02:42:c0:a8:84:22
    networks: 
      nginx_vlan:
        ipv4_address: 192.168.1.10

  nginx_45:
    image: linuxserver/nginx
    container_name: nginx_macvlan_45
    environment:
      - TZ=Americas/Los_Angeles
    ports:
      - 80:80
      - 443:443
    restart: unless-stopped
    mac_address: 02:42:c0:a8:84:23
    networks: 
      nginx_vlan:
        ipv4_address: 192.168.1.45

networks:
  nginx_vlan:
    driver: macvlan
    driver_opts:
      parent: eth0
    ipam:
      driver: default
      config:
        - subnet: 192.168.1.0/24
          gateway: 192.168.1.1

# docker-compose --file docker-compose-macvlan-ubuntu-multi.yml up --detach

I'd still like to know:

  • How to get this working with docker compose schema v3+.
  • How to get it working on Docker for Windows.
  • How to get DHCP working.