🚀 Executive Summary
TL;DR: The article addresses critical container networking issues in Docker and Kubernetes, specifically DNS resolution failures where services cannot find each other. It provides three distinct solutions, ranging from quick development hacks to robust production-ready configurations, to ensure reliable service discovery and prevent system outages.
🎯 Key Takeaways
- Container network isolation is a fundamental feature, not a bug, meaning containers on Docker’s default `bridge` network cannot resolve each other by name without explicit configuration.
- User-defined Docker networks are the recommended permanent solution, offering a built-in DNS server that allows containers on the same network to resolve each other using their container names as hostnames.
- The `–add-host` flag (Docker) or `hostAliases` (Kubernetes) provides a quick, temporary fix by manually injecting IP-to-name mappings into `/etc/hosts`, but it is brittle and unsuitable for production due to dynamic IP changes.
Struggling with container networking and service discovery? Senior DevOps Engineer Darian Vance demystifies why your services can’t find each other and provides three real-world fixes, from quick dev hacks to production-ready solutions.
My Container Can’t Find Your Service: A Guide to Fixing DNS in Docker & K8s
I was scrolling through Reddit the other day and saw a thread titled “Best Niches & Networks for Affiliate Marketing in 2026?”. It got me thinking. It’s funny, but that’s our job in a nutshell, isn’t it? We’re constantly trying to connect a service (the “niche”) to the right endpoint (the “network”). Get it wrong, and you’re just shouting into the void, getting zero conversions—or in our case, a whole lot of `ConnectionRefusedError`. This reminded me of a 2 AM PagerDuty alert that nearly broke me. A new `payment-gateway` service went live. All green in CI/CD. An hour later, the whole checkout system was timing out. The logs were screaming `UnknownHostException: prod-auth-db-01`. The database was up, I could ping it from the host, but our shiny new container might as well have been on another planet. It was on the wrong “network,” and it had no idea how to find its “niche.”
The “Why”: You’re Not in Kansas Anymore
Here’s the thing that trips up everyone at some point: a container is not just a process, it’s a self-contained universe. It has its own network stack, its own IP address, and its own `localhost`. When your application code inside a container tries to connect to `localhost:5432`, it’s looking for a Postgres server inside that same container, not on the Docker host machine you’re running it on. This network isolation is a feature, not a bug! It prevents port conflicts and keeps things clean. But it also means that containers on Docker’s default `bridge` network can’t resolve each other by name out of the box. They’re like houses on the same street with no addresses.
The Fixes: From Duct Tape to a Solid Foundation
Look, there are a few ways to solve this. The one you choose depends on whether you need to stop the immediate bleeding or build a system that won’t give you a 2 AM wakeup call ever again.
1. The Quick Fix: The `/etc/hosts` Hack
This is the digital equivalent of putting a sticky note on your monitor. You are manually telling one container the exact IP address of another. It’s brittle because IPs can change, but for local development or a five-alarm fire, it gets the job done instantly.
In Docker, you use the --add-host flag. This injects an entry into the container’s internal `/etc/hosts` file, mapping a name to an IP.
# First, get the IP address of your database container
# docker inspect -f '{{range.NetworkSettings.Networks}}{{.IPAddress}}{{end}}' prod-auth-db-01
# Let's say it returns 172.17.0.2
# Now, run your app container and inject that mapping
docker run --add-host=prod-auth-db-01:172.17.0.2 my-payment-gateway-image
In Kubernetes, the equivalent is using `hostAliases` in your Pod specification. It’s just as hacky and just as effective in a pinch.
Pro Tip: This is a temporary solution, not an architecture. Relying on this in production is just asking for trouble when a container gets rescheduled and comes back with a new IP. Use it to get your dev environment working, then move on to a real fix.
2. The Permanent Fix: Use a User-Defined Network
This is the right way to do it. Instead of letting your containers float around on the default network, you create your own custom bridge network. The magic of a user-defined network is that it comes with a built-in DNS server. Containers on the same custom network can find each other simply by using their container names as hostnames.
It’s a two-step process:
- Create the network:
docker network create checkout-system-net - Attach your services to it:
# Start the database first docker run -d --name prod-auth-db-01 --network=checkout-system-net postgres:14 # Now start your application docker run -d --name payment-gateway --network=checkout-system-net my-payment-gateway-image
That’s it. Now, from inside the `payment-gateway` container, your connection string can simply point to `prod-auth-db-01`, and the Docker DNS will resolve it to the correct internal IP. No more manual IP management. In Kubernetes, this is the default behavior—Services provide a stable DNS name for a set of Pods, and CoreDNS handles the resolution automatically. This is the pattern you should always aim for.
3. The ‘Nuclear’ Option: Host Networking
Sometimes, you need to break the rules. The “nuclear” option is to completely remove the network isolation between your container and the host. By using host networking, the container shares the host’s network stack. Your container’s `localhost` is now the host’s `localhost`, and it can see every port on the host machine.
docker run --net=host my-payment-gateway-image
This solves the resolution problem, but it’s a massive trade-off. You lose all the benefits of isolation. If your containerized app needs port 8080, it will conflict with anything else running on port 8080 on the host. It’s also a significant security risk, as a compromised container has direct access to the host’s network interfaces.
Warning: Use this with extreme caution. It’s useful for very specific high-performance applications that need to minimize network overhead or for legacy apps that are a nightmare to containerize properly. For 99% of microservice use cases, this is the wrong tool for the job.
Comparison at a Glance
To make it simple, here’s how I decide which tool to use:
| Solution | Best For | Pros | Cons |
| 1. Quick Fix (`–add-host`) | Local development, emergencies | Simple, direct, no setup | Brittle, manual IP management |
| 2. Permanent Fix (Custom Network) | All environments (Prod included) | Scalable, secure, automatic DNS | Requires minimal setup |
| 3. ‘Nuclear’ Option (`–net=host`) | High-performance or tricky legacy apps | Maximum network throughput | Insecure, port conflicts, no isolation |
At the end of the day, our job is about building reliable paths. Whether it’s a marketer finding a customer or a service finding a database, a broken link means failure. Don’t let a simple networking oversight be the reason your system goes down. Start with the right foundation, and you won’t have to duct tape it together at 2 AM.
🤖 Frequently Asked Questions
âť“ Why do my Docker containers on the default bridge network fail to resolve each other by name?
Containers on Docker’s default `bridge` network operate in isolation, each with its own network stack, and this network lacks a built-in DNS server for name resolution between containers. They are like houses on the same street with no addresses.
âť“ How do user-defined Docker networks compare to Kubernetes Services for service discovery?
User-defined Docker networks provide a built-in DNS server for containers within that network to resolve each other by name. Kubernetes Services offer a more advanced and stable mechanism, providing a consistent DNS name for a set of Pods, with CoreDNS automatically handling resolution, which is the default and preferred pattern in K8s.
âť“ What is a common implementation pitfall when using the `/etc/hosts` hack for service discovery?
A common pitfall is relying on the `/etc/hosts` hack (`–add-host` in Docker or `hostAliases` in K8s) in production. This approach is brittle because container IP addresses can change when containers are rescheduled, leading to `UnknownHostException` errors if the manual IP mapping is not updated.
Leave a Reply