Mimir Won't Start With Predictable Interface Names (And There's No Common Config)
You set up a Mimir cluster. Everything looks good. You start the service. It dies.
The error message is unhelpful:
level=warn msg="error getting interface" inf=eth0 err="route ip+net: no such network interface"
level=warn msg="error getting interface" inf=en0 err="route ip+net: no such network interface"
level=error msg="error running application" err="No address found for [eth0 en0]"
If you’re running modern Linux with predictable interface names (which is everything since Ubuntu 15.04 and RHEL 7), your interface is called enp1s0 or ens192 or enx00e04b1a2c3d. Not eth0. Not en0.
So Mimir looks for eth0, doesn’t find it, looks for en0, doesn’t find that either, and gives up.
The Fix (That Shouldn’t Be This Hard)
Mimir has a config option called instance_interface_names that lets you specify which interface to use. The problem is that there’s no common section for it. Unlike Loki, which lets you set this once in the common config, Mimir requires you to repeat it in every single component’s ring configuration.
Here’s what that looks like for a full Mimir deployment:
distributor:
ring:
instance_interface_names:
- enp1s0
ingester:
ring:
instance_interface_names:
- enp1s0
frontend:
instance_interface_names:
- enp1s0
compactor:
sharding_ring:
instance_interface_names:
- enp1s0
store_gateway:
sharding_ring:
instance_interface_names:
- enp1s0
ruler:
ring:
instance_interface_names:
- enp1s0
alertmanager:
sharding_ring:
instance_interface_names:
- enp1s0
query_scheduler:
ring:
instance_interface_names:
- enp1s0
Eight components. Eight repetitions of the same line. One typo in any of them and you’ll spend an hour wondering why your cluster won’t form.
Why This Sucks
The instance_interface_names config exists because Mimir needs to know which network interface to advertise in the ring. When a component starts, it looks up the IP address of the specified interface and registers that as its instance address. If it can’t find the interface, it crashes.
This is a reasonable requirement. The unreasonable part is that there’s no way to set this once and have it apply to all components. Every ring module in Mimir has its own instance_interface_names config, and there’s no inheritance or common override.
Loki solved this by putting instance_interface_names in the common section. Mimir doesn’t have this. The GitHub issue tracking this has been open for a while. No one’s fixed it.
The Workaround
If you’re deploying Mimir via Helm or Ansible, you can automate this. Here’s a Jinja2 template snippet that generates the config for all components:
{% for component in ['distributor', 'ingester', 'ruler'] %}
{{ component }}:
ring:
instance_interface_names:
- {{ interface_name }}
{% endfor %}
{% for component in ['compactor', 'store_gateway', 'alertmanager'] %}
{{ component }}:
sharding_ring:
instance_interface_names:
- {{ interface_name }}
{% endfor %}
frontend:
instance_interface_names:
- {{ interface_name }}
query_scheduler:
ring:
instance_interface_names:
- {{ interface_name }}
This at least ensures consistency. But it’s a band-aid on a design flaw.
The Real Fix
Mimir should have a common.instance_interface_names config that applies to all ring modules. This is trivial to implement — each ring module already reads its own instance_interface_names config. Adding a fallback to a common value would be a few lines of code.
Until then, you’re stuck repeating the same config eight times. Or you’re stuck with eth0 and a whole lot of symlinks.