I had a question about applications running within Docker containers and UUID generation.
Here’s our scenario:
Currently our applications are using an event driven framework.
For the events we generate the UUID’s based on mac address, pid,
time-stamp and counter.
For running containers on a distributed system like CoreOS (while a very very very low chance), there is no guarantee that all those parameters used to generate a UUID would be unique for each container as one container on one server in the cluster could generate a UUID using the same mac, pid, time-stamp and counter as another container on the cluster.
In essence if these two UUID’s were both to generate an event and send it to our messaging bus, then obviously there would be a conflict.
In our analysis, this scenario seems to boil down to the uniqueness of mac addresses on each Docker container.
So to be frank:
According to the v1. 7 documentation, all the Docker containers have the same prefix in their MAC addresses – '02:42:' if generated automatically. The remaining 4 octets of the MAC address is a container's IPv4 address printed in hex.
Docker Desktop currently supports macOS Catalina, macOS Big Sur, and macOS Monterey. At least 4 GB of RAM. VirtualBox prior to version 4.3.30 must not be installed as it is not compatible with Docker Desktop.
Docker image was built in only seven minutes on MacBook M1 Pro, which was even better than the build time on my new VPS. This is not surprising, I gave Docker quite a lot of resources. But it also shows that if there are not too many I/O disk operations, performance is quite good.
From my reading of generateMacAddr
function (edit: answer concerned 1.3.0-dev
, but is still correct for 17.05
), MAC addresses generated by docker
are essentially the IPv4
address of the container's interface on the docker0
bridge: they are guaranteed to be consistent with the IP address.
The docker0
bridge's subnet you have to operate in, usually 255.255.0.0
as per this example of 172.17.42.1/16
, has 65,534 routable addresses. This does reduce entropy for UUID generation, but MAC address collision isn't possible as IPs must be unique, and the scenario of identical MAC, PID, time and counter in two containers on the same docker server/CoreOS host should not be a possibility.
However two CoreOS hosts (each running one docker
server) could potentially choose the same random subnet, resulting in the possibility of duplicated MACs for containers on different hosts. You could evade this by setting a fixed CIDR for the docker
server on each host:
--fixed-cidr=CIDR
— restrict the IP range from the docker0 subnet, using the standard CIDR notation like172.167.1.0/28
. This range must be and IPv4 range for fixed IPs (ex:10.20.0.0/16
) and must be a subset of the bridge IP range (docker0
or set using--bridge
). For example with--fixed-cidr=192.168.1.0/25
, IPs for your containers will be chosen from the first half of192.168.1.0/24
subnet.
This should ensure unique MAC addresses across the cluster.
The original IEEE 802 MAC address comes from the original Xerox Ethernet addressing scheme. This 48-bit address space contains potentially 248 or 281,474,976,710,656 possible MAC addresses.
source
If you are concerned about lack of entropy (the IP to MAC mapping reduces it considerably), a better option may be to use a different mechanism for UUID generation. UUID versions 3, 4 and 5 do not take MAC address into account. Alternatively you could include the host machine's MAC in UUID generation.
Of course, whether this "considerable MAC space reduction" will have any impact of UUID generation should probably be tested before any code is changed.
Source linked to above:
// Generate a IEEE802 compliant MAC address from the given IP address.
//
// The generator is guaranteed to be consistent: the same IP will always yield the same
// MAC address. This is to avoid ARP cache issues.
func generateMacAddr(ip net.IP) net.HardwareAddr {
hw := make(net.HardwareAddr, 6)
// The first byte of the MAC address has to comply with these rules:
// 1. Unicast: Set the least-significant bit to 0.
// 2. Address is locally administered: Set the second-least-significant bit (U/L) to 1.
// 3. As "small" as possible: The veth address has to be "smaller" than the bridge address.
hw[0] = 0x02
// The first 24 bits of the MAC represent the Organizationally Unique Identifier (OUI).
// Since this address is locally administered, we can do whatever we want as long as
// it doesn't conflict with other addresses.
hw[1] = 0x42
// Insert the IP address into the last 32 bits of the MAC address.
// This is a simple way to guarantee the address will be consistent and unique.
copy(hw[2:], ip.To4())
return hw
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With