Back to blog
Guides & Tutorials

How a Simple ETL Job Turned Into a 5-Hour Kubernetes DNS Nightmare

How a Simple ETL Job Turned Into a 5-Hour Kubernetes DNS Nightmare blog cover image
learning-and-development
Burhanuddin Nahargarwala
Key takeaways
  • A simple ETL job broke into a 5-hour Kubernetes DNS nightmare. This blog walks through the symptoms, the chase, and the surprisingly simple fix.

“It was just supposed to be a simple ETL microservice. Fetch some data, transform it, and load it into Postgres. 30 minutes, tops.”

- Famous last words before a 5-hour DNS debugging marathon

The Setup That Should Have Been Simple

It’s a regular Tuesday afternoon, and I’m building what I thought would be a straightforward microservices setup in Kubernetes. Simple enough, right? A data loader microservice that fetches user data from an API, transforms it, and loads it into a PostgreSQL database. ConfigMaps for non-sensitive configs, Secrets for credentials, and textbook Kubernetes stuff.

Everything Was Going Fine… Until It Wasn’t

The architecture looked clean on paper:

  • Data Loader Microservice: Python app containerized and ready to roll
  • PostgreSQL Database: Running in its own pod with persistent storage
  • ConfigMaps: Handling API URLs, log levels, DB port, DB name
  • Secrets: Safeguarding DB credentials (properly base64 encoded, thank you very much)

I built my Docker image, configured my deployments, and applied my ConfigMaps and Secrets. The PostgreSQL pod started up beautifully. Green lights everywhere.

Then I deployed the ETL microservice and… 💥

Me: “That’s odd. Let me check the logs…”

ERROR:root:Error: could not translate host name 'postgres-service' to address:
Temporary failure in name resolution

The DNS Mystery Deepens

Wait, what? The service is right there! I can see it in kubectl get svc. The name is correct. The port is correct. What’s happening?

I tried the classic debugging move, checking if it’s an external network issue:

kubectl logs etl-deployment-7cd7bd469b-7dqfl
...
Failed to resolve 'random-data-api.com': Temporary failure in name resolution

Oh no. It’s not just the internal service. DNS is completely broken.

Time to investigate CoreDNS:

kubectl get pods -n kube-system -l k8s-app=kube-dns
NAME                       READY   STATUS             RESTARTS
coredns-668d6bf9bc-8xg47   0/1     CrashLoopBackOff   142

There it was. My DNS server was having an existential crisis, trapped in an infinite CrashLoopBackOff.


Down the Troubleshooting Rabbit Hole

Attempt #1: “Just Check the Logs”

kubectl logs -n kube-system coredns-668d6bf9bc-8xg47
Listen: listen tcp :53: bind: permission denied

Ah! A permission error. CoreDNS can’t bind to port 53. Easy fix; just add the ` NET_BIND_SERVICE` capability!

I edited the CoreDNS deployment:

securityContext:
  capabilities:
    add:
      - NET_BIND_SERVICE

Surely this would work… right?

Narrator: It did not work.

Attempt #2: “Maybe it needs allowPrivilegeEscalation?”

Added allowPrivilegeEscalation: true to the security context. Restarted CoreDNS.

kubectl get pods -n kube-system -l k8s-app=kube-dns
NAME                       READY   STATUS             RESTARTS
coredns-668d6bf9bc-tsn9r   0/1     CrashLoopBackOff   12

Still crashing. Still the same error.

Me, increasingly frustrated: “But ` NET_BIND_SERVICE` is literally right there in the deployment file!”

Attempt #3: “Let’s Try a Different Port!”

Okay, if port 53 is causing problems because it’s a privileged port (ports < 1024), let’s just use a non-privileged port instead!

I edited the CoreDNS ConfigMap and changed the port to 1053:

data:
  Corefile: |
    .:1053 {
      log
      errors
      health {
        lameduck 5s
      }
      ready
      kubernetes cluster.local in-addr.arpa ip6.arpa {
        pods insecure
        fallthrough in-addr.arpa ip6.arpa
        ttl 30
      }
      prometheus :9153
      forward . /etc/resolv.conf {
        max_concurrent 1000
      }
    }

Restarted CoreDNS:

kubectl -n kube-system delete pod -l k8s-app=kube-dns

AND IT WORKED! CoreDNS was finally running!

kubectl get pods -n kube-system -l k8s-app=kube-dns
NAME                       READY   STATUS    RESTARTS
coredns-698f4cc5c9-xflhm   1/1     Running   0

Me: “YES! We did it! DNS is working now!”

But then I tested my ETL pod…

kubectl logs etl-deployment-7cd7bd469b-7dqfl
ERROR:root:Error: could not translate host name 'postgres-service' to address:
Temporary failure in name resolution

Me: “WHAT? How is it STILL broken?”

The problem? CoreDNS was now listening on port 1053, but all the pods were still configured to use port 53 for DNS lookups. I’d essentially moved the DNS server to a different address without telling anyone where it went.


The Nuclear Option: Full Minikube Reset

At this point, I was ready to throw my laptop out the window. Instead, I did the next best thing, nuked everything, and started fresh:

minikube delete
rm -rf ./minikube  # Clean slate, baby!
minikube start

Fresh install, clean DNS configuration, port 53 as intended. Everything should work now.

But still, the Same error. Same CrashLoopBackOff. Same “permission denied” message.

Me, on the verge of tears: “WHY?! It’s a fresh install! What is happening?!”


The Eureka Moment (Finally!)

After hours of debugging, countless chats with ChatGPT, Claude Code, and Gemini, and more coffee than is probably healthy, I finally understood the root cause:

Linux containers run as non-root users by default for security.

Port 53 is a privileged port that requires root access to bind to. Even with the NET_BIND_SERVICE` `` capability, even with allowPrivilegeEscalation: true` ``, CoreDNS running as a non-root user simply couldn’t bind to port 53.

The solution? Allow CoreDNS to run as root (in a controlled way):

kubectl patch deployment coredns -n kube-system \
  --type='json' \
  -p='[{"op": "add", "path": "/spec/template/spec/containers/0/securityContext/runAsUser", "value": 0}]'

This sets ` runAsUser: 0`, telling the container to run as root (UID 0).

I also enabled host networking to give CoreDNS direct access to the host’s network namespace:

kubectl patch deployment coredns -n kube-system \
  --type='json' \
  -p='[{"op": "add", "path": "/spec/template/spec/hostNetwork", "value": true}]'

Restarted CoreDNS one more time:

kubectl -n kube-system delete pod -l k8s-app=kube-dns

And then… silence. No crash. No errors.

kubectl get pods -n kube-system -l k8s-app=kube-dns
NAME                       READY   STATUS    RESTARTS
coredns-698f4cc5c9-xflhm   1/1     Running   0

I nervously checked the logs:

kubectl logs -n kube-system -l k8s-app=kube-dns
.:53
[INFO] plugin/reload: Running configuration SHA512 = b141a95c4ad45582b9d8d1be55241970...
CoreDNS-1.11.3
linux/amd64, go1.21.11, a6338e9
[INFO] 127.0.0.1:54374 - 17618 "HINFO IN 1085771236002924139.3914264802840083309...

It was actually working! Time to test DNS resolution:

kubectl run -it --rm dns-test --image=busybox:1.28 --restart=Never -- nslookup kubernetes.default
Server:    10.96.0.10
Address 1: 10.96.0.10 kube-dns.kube-system.svc.cluster.local

Name:      kubernetes.default
Address 1: 10.96.0.1 kubernetes.default.svc.cluster.local

âś… Internal DNS working!

kubectl run -it --rm dns-test --image=busybox:1.28 --restart=Never -- nslookup postgres-service
Server:    10.96.0.10
Address 1: 10.96.0.10 kube-dns.kube-system.svc.cluster.local

Name:      postgres-service
Address 1: 10.98.33.166 postgres-service.default.svc.cluster.local

âś… Service discovery working!

kubectl run -it --rm dns-test --image=busybox:1.28 --restart=Never -- nslookup random-data-api.com
Server:    10.96.0.10
Address 1: 10.96.0.10 kube-dns.kube-system.svc.cluster.local

Name:      random-data-api.com
Address 1: 67.205.161.199

âś… External DNS working!


Victory at Last

I redeployed my ETL microservice and watched the logs with bated breath:

THE ETL JOB COMPLETED SUCCESSFULLY!


Wait, But Why Didn’t Port 1053 Work?

You might be wondering: “Port 1053 is non-privileged. CoreDNS was running. Why didn’t it work?”

The answer: It’s like changing your phone number without updating your contacts.

The DNS Resolution Chain

When a Kubernetes pod resolves a hostname:

  1. Pod reads ` /etc/resolv.conf` → points to 10.96.0.10:53
  2. Query sent to kube-dns Service on port 53
  3. Service forwards to CoreDNS on port 53 (defined in targetPort)
  4. CoreDNS responds

The problem? When I changed CoreDNS to port 1053, only step 4 changed. Steps 1-3 still expected port 53!

What Actually Needed to Change

Component What I Changed What I Missed
CoreDNS âś… Listening on 1053 -
kube-dns Service - ❌ Still forwarding to port 53
kubelet (all nodes) - ❌ Still configured for port 53
Pod resolv.conf - ❌ Still pointing to port 53

Result: CoreDNS was listening on the wrong port. It’s like moving apartments without telling the post office.


The Real Insight

Port 1053 solved the permission problem (CoreDNS could bind without root), but created a communication problem (nothing could reach it there).

Port 53 has been the DNS standard since 1987. Changing it means updating every component in the cluster, nodes, services, pods, everything.

The simpler fix? Let CoreDNS run as root (` runAsUser: 0`) and keep port 53. One change instead of cluster-wide reconfiguration.


The Takeaway

Three lessons from 5 hours of debugging:

  1. Privileged ports need root access - This is Linux security, not a bug
  2. System defaults exist for a reason - Port 53 is everywhere; changing it cascades
  3. Simple root cause fix beats complex workarounds - Sometimes “just run as root” is the right answer

Quick Debug Commands

If you hit CoreDNS issues:

# Check CoreDNS status
kubectl get pods -n kube-system -l k8s-app=kube-dns

# Check logs for errors
kubectl logs -n kube-system -l k8s-app=kube-dns

# Test DNS resolution
kubectl run -it --rm dns-test --image=busybox:1.28 --restart=Never -- nslookup kubernetes.default

Remember: Fix DNS first, everything else second.

Future of Data?
Discover how Enqurious helps deliver an end-to-end learning experience
Curious how we're reshaping the future of data? Watch our story unfold
Get Free Snowpro Core Certification Skill Path

You Might Also Like

Mounting ADLS in Databricks? Here's What You're Missing blog cover image
Guides & Tutorials
July 20, 2026
Mounting ADLS in Databricks? Here's What You're Missing

Storage account keys and mount points give every user in a Databricks workspace the same shared access to ADLS, with no audit trail. Here's why teams are moving to Storage Credentials and External Locations instead.

Sayli Sr. Data Engineer
AI-Ready Data: Why Enterprise AI Pilots Fail in Production blog cover image
Guides & Tutorials
July 2, 2026
AI-Ready Data: Why Enterprise AI Pilots Fail in Production

89% of enterprise AI pilots never reach production. Data integration, governance gaps, and silos are why. See how Snowflake Cortex AI fixes the root cause.

Rohit Data Engineer
Snowflake Cortex AI in 2026: 59x Cost Difference Explained blog cover image
Guides & Tutorials
June 15, 2026
Snowflake Cortex AI in 2026: 59x Cost Difference Explained

A Snowflake Summit 2026 benchmark revealed a 59x cost gap — open-source models at 440 credits vs. frontier models at 26,000 credits for identical workloads. Learn how CoCo, CoWork, AI Credits, and Cortex Training change enterprise AI strategy.

Rohit Data Engineer
What Happens When Claude Meets Databricks? blog cover image
Guides & Tutorials
June 5, 2026
What Happens When Claude Meets Databricks?

How a data engineering team replaced manual pipeline work with natural language prompts, using Claude Code and the Databricks AI Dev Kit.

Sayli Sr. Data Engineer
6 Errors I Hit Connecting Databricks Apps to Genie AI blog cover image
Guides & Tutorials
June 3, 2026
6 Errors I Hit Connecting Databricks Apps to Genie AI

Six errors, 6 hours of debugging, and the permission checklist that finally made Databricks Apps + Genie work. The full lessons-learned guide.

Mansi AI & ML Engineer
Where Did My Claude Code Session Go? How to Find Any Lost Session blog cover image
Guides & Tutorials
June 2, 2026
Where Did My Claude Code Session Go? How to Find Any Lost Session

Your Claude Code session isn't lost. It's on disk, in a folder /resume isn't scanning. Here's how to find any session in 30 seconds, with the exact commands.

Mansi AI & ML Engineer
What is Scenario Based Learning for Data Teams? blog cover image
Guides & Tutorials
May 15, 2026
What is Scenario Based Learning for Data Teams?

Scenario based learning replaces tutorials with realistic operational scenarios where engineers develop the hands on judgment classroom instruction cannot produce. How it works and why it matters.

Mandar Sr. Data Analyst
Data Engineering Roadmap 2026: What Companies Actually Hire blog cover image
Guides & Tutorials
May 5, 2026
Data Engineering Roadmap 2026: What Companies Actually Hire

The 2026 data engineering roadmap. SQL, Python, cloud, Airflow, dbt, streaming. What companies actually hire for and how to build a portfolio that gets shortlisted.

Mandar Sr. Data Analyst
Medallion Architecture: Why Most Data Pipelines Break Without It blog cover image
Guides & Tutorials
April 30, 2026
Medallion Architecture: Why Most Data Pipelines Break Without It

Medallion Architecture splits your data pipeline into Bronze, Silver, and Gold layers so a small business change never forces a full rebuild. Here's why it works.

Divyanshi Data Engineer
An Advanced Git Tutorial: Lessons from a Real-World Versioning Crisis blog cover image
Guides & Tutorials
March 7, 2026
An Advanced Git Tutorial: Lessons from a Real-World Versioning Crisis

I was working on a large content repository on Windows, and I needed to version some new work — campaign assets, workshop content, LinkedIn job descriptions, and some file deletions. Simple enough, right? What followed was a two-day journey through some of Git's more obscure corners.

Amit Co-founder & CEO
The Docker Playground: Learning Without Fear blog cover image
Guides & Tutorials
January 29, 2026
The Docker Playground: Learning Without Fear

New engineers shouldn't learn Docker like they're defusing a bomb. Here's how we created a fear-free learning environment—and cut training time in half." (165 characters)

Burhanuddin DevOps Engineer
Data Quality Explained: Challenges, Best Practices, and Complete 2026 Guide blog cover image
Guides & Tutorials
January 23, 2026
Data Quality Explained: Challenges, Best Practices, and Complete 2026 Guide

A complete beginner’s guide to data quality, covering key challenges, real-world examples, and best practices for building trustworthy data.

Divyanshi Data Engineer
Data Lakehouse Demystified: Unlocking Databricks’ Hidden Powers in 2025 blog cover image
Guides & Tutorials
December 29, 2025
Data Lakehouse Demystified: Unlocking Databricks’ Hidden Powers in 2025

Explore the power of Databricks Lakehouse, Delta tables, and modern data engineering practices to build reliable, scalable, and high-quality data pipelines."

Divyanshi Data Engineer
My Three-Hour Terraform Task That Took Three Days (And Seven Errors) blog cover image
Guides & Tutorials
December 21, 2025
My Three-Hour Terraform Task That Took Three Days (And Seven Errors)

A real-world Terraform war story where a “simple” Azure SQL deployment spirals into seven hard-earned lessons, covering deprecated providers, breaking changes, hidden Azure policies, and why cloud tutorials age fast. A practical, honest read for anyone learning Infrastructure as Code the hard way.

Burhanuddin DevOps Engineer
Data Doesn’t Wait Anymore: A Guide to Streaming with Azure Databricks blog cover image
Guides & Tutorials
December 15, 2025
Data Doesn’t Wait Anymore: A Guide to Streaming with Azure Databricks

Data doesn’t wait - and neither should your insights. This blog breaks down streaming vs batch processing and shows, step by step, how to process real-time data using Azure Databricks.

Divyanshi Data Engineer
Unity Catalog Just Leveled Up: Meet your Data’s New Bodyguards blog cover image
Guides & Tutorials
December 8, 2025
Unity Catalog Just Leveled Up: Meet your Data’s New Bodyguards

This blog talks about Databricks’ Unity Catalog upgrades -like Governed Tags, Automated Data Classification, and ABAC which make data governance smarter, faster, and more automated.

Divyanshi Data Engineer
"Yeh Dosti" of AI: Claude & Nano Banana as Jai & Veeru! blog cover image
Guides & Tutorials
December 6, 2025
"Yeh Dosti" of AI: Claude & Nano Banana as Jai & Veeru!

Tired of boring images? Meet the 'Jai & Veeru' of AI! See how combining Claude and Nano Banana Pro creates mind-blowing results for comics, diagrams, and more.

Burhanuddin DevOps Engineer
A Week-Long Journey Through Deployment Errors and RBAC Implementation blog cover image
Guides & Tutorials
December 2, 2025
A Week-Long Journey Through Deployment Errors and RBAC Implementation

What I thought would be a simple RBAC implementation turned into a comprehensive lesson in Kubernetes deployment. Part 1: Fixing three critical deployment errors. Part 2: Implementing namespace-scoped RBAC security. Real terminal outputs and lessons learned included

Burhanuddin DevOps Engineer
The Day I Discovered Databricks Connect  blog cover image
Guides & Tutorials
December 1, 2025
The Day I Discovered Databricks Connect

This blog walks you through how Databricks Connect completely transforms PySpark development workflow by letting us run Databricks-backed Spark code directly from your local IDE. From setup to debugging to best practices this Blog covers it all.

Divyanshi Data Engineer
Building Bronze Layer: Using COPY INTO in Databricks blog cover image
Guides & Tutorials
September 12, 2025
Building Bronze Layer: Using COPY INTO in Databricks

Master the bronze layer foundation of medallion architecture with COPY INTO - the command that handles incremental ingestion and schema evolution automatically. No more duplicate data, no more broken pipelines when new columns arrive. Your complete guide to production-ready raw data ingestion

Sayli Sr. Data Engineer
Understanding the Power Law Distribution blog cover image
Guides & Tutorials
January 3, 2025
Understanding the Power Law Distribution

This blog talks about the Power Law statistical distribution and how it explains content virality

Amit Co-founder & CEO
How Apache Airflow Helps Manage Tasks, Just Like an Orchestra blog cover image
Guides & Tutorials
September 16, 2024
How Apache Airflow Helps Manage Tasks, Just Like an Orchestra

This blog explains how Apache Airflow orchestrates tasks like a conductor leading an orchestra, ensuring smooth and efficient workflow management. Using a fun Romeo and Juliet analogy, it shows how Airflow handles timing, dependencies, and errors.

Burhanuddin DevOps Engineer
Basics of Langchain blog cover image
Guides & Tutorials
December 16, 2023
Basics of Langchain

The blog contains the journey of ChatGPT, and what are the limitations of ChatGPT, due to which Langchain came into the picture to overcome the limitations and help us to create applications that can solve our real-time queries

Burhanuddin DevOps Engineer
An L&D Strategy to achieve 100% Certification clearance blog cover image
Guides & Tutorials
December 6, 2023
An L&D Strategy to achieve 100% Certification clearance

An account of experience gained by Enqurious team as a result of guiding our key clients in achieving a 100% success rate at certifications

Amit Co-founder & CEO
Calendar Events Automation: Streamline Your Life with App Script Automation blog cover image
Guides & Tutorials
October 10, 2023
Calendar Events Automation: Streamline Your Life with App Script Automation

This blog delves into the capabilities of Calendar Events Automation using App Script.

Burhanuddin DevOps Engineer
A Journey Through Extraction, Transformation, and Loading blog cover image
Guides & Tutorials
September 7, 2023
A Journey Through Extraction, Transformation, and Loading

Dive into the fundamental concepts and phases of ETL, learning how to extract valuable data, transform it into actionable insights, and load it seamlessly into your systems.

Burhanuddin DevOps Engineer