<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Hilmi B</title>
    <description>The latest articles on DEV Community by Hilmi B (@hilmib).</description>
    <link>https://dev.to/hilmib</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4083351%2F85738ef2-8951-409f-bd6a-437f0fe7e0e7.png</url>
      <title>DEV Community: Hilmi B</title>
      <link>https://dev.to/hilmib</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/hilmib"/>
    <language>en</language>
    <item>
      <title>Kubernetes DNS was failing 33% of the time. CoreDNS was fine.</title>
      <dc:creator>Hilmi B</dc:creator>
      <pubDate>Thu, 20 Aug 2026 07:34:39 +0000</pubDate>
      <link>https://dev.to/hilmib/kubernetes-dns-was-failing-33-of-the-time-coredns-was-fine-221e</link>
      <guid>https://dev.to/hilmib/kubernetes-dns-was-failing-33-of-the-time-coredns-was-fine-221e</guid>
      <description>&lt;p&gt;A WordPress site on our platform started throwing &lt;code&gt;Error establishing a database connection&lt;/code&gt;. Not always — maybe one page load in three. Reload, and it worked. Reload again, broken.&lt;/p&gt;

&lt;p&gt;The obvious suspect is MySQL. It wasn't MySQL. It took us longer than it should have to stop looking there, so here is the whole path, including the two wrong turns.&lt;/p&gt;

&lt;h2&gt;
  
  
  The first wrong turn: blaming the database
&lt;/h2&gt;

&lt;p&gt;WordPress talks to MySQL through a hostname, not an IP. In our case the pod's config had:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;WORDPRESS_DB_HOST &lt;span class="o"&gt;=&lt;/span&gt; mysql.cdn.svc.cluster.local
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That single detail is the whole story, but we didn't see it yet. We went to MySQL first and checked whether we were simply out of connections:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;SHOW&lt;/span&gt; &lt;span class="k"&gt;GLOBAL&lt;/span&gt; &lt;span class="n"&gt;STATUS&lt;/span&gt; &lt;span class="k"&gt;LIKE&lt;/span&gt; &lt;span class="s1"&gt;'Connection_errors_max_connections'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Zero. No saturation, no slow queries, server healthy, direct connections from outside the cluster fine. So the database was answering everyone — just not always this pod.&lt;/p&gt;

&lt;h2&gt;
  
  
  The canary nobody reads
&lt;/h2&gt;

&lt;p&gt;WordPress does not log the DB connection failure when &lt;code&gt;WP_DEBUG&lt;/code&gt; is off. That's why this class of bug feels random: the failure is invisible in the application log.&lt;/p&gt;

&lt;p&gt;But the same pod ran Redis for object caching, and Redis &lt;strong&gt;does&lt;/strong&gt; log:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Redis::connect(): getaddrinfo for wp-redis-cache failed: Temporary failure in name resolution
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;getaddrinfo&lt;/code&gt; … &lt;code&gt;Temporary failure in name resolution&lt;/code&gt;. That's &lt;code&gt;EAI_AGAIN&lt;/code&gt; — a DNS timeout. Redis connects by hostname too, so it was failing for exactly the same reason as MySQL, and it was kind enough to say so out loud.&lt;/p&gt;

&lt;p&gt;If you take one thing from this post: when a hostname-based dependency fails intermittently and silently, go find a &lt;em&gt;noisier&lt;/em&gt; hostname-based dependency in the same pod and read its log.&lt;/p&gt;

&lt;h2&gt;
  
  
  The second wrong turn: blaming CoreDNS
&lt;/h2&gt;

&lt;p&gt;So it's DNS. The reflex is "CoreDNS is unhealthy" or "we need NodeLocal DNSCache." We reached for both, and both were wrong.&lt;/p&gt;

&lt;p&gt;CoreDNS pods were all &lt;code&gt;Running&lt;/code&gt;, all &lt;code&gt;Ready&lt;/code&gt;, no restarts, no errors in their logs. And the failure rate had a suspicious shape: roughly one in three.&lt;/p&gt;

&lt;p&gt;We had three CoreDNS endpoints.&lt;/p&gt;

&lt;p&gt;That ratio is not a coincidence, and it's the clue that changes the question from &lt;em&gt;"is CoreDNS broken?"&lt;/em&gt; to &lt;em&gt;"is one specific path to one specific CoreDNS pod broken?"&lt;/em&gt; A Service ClusterIP hides which backend answered you, so testing &lt;code&gt;mysql.cdn.svc.cluster.local&lt;/code&gt; in a loop just gives you a mushy ~33% failure rate with no information about &lt;em&gt;which&lt;/em&gt; backend is bad.&lt;/p&gt;

&lt;h2&gt;
  
  
  The diagnostic that actually pinned it
&lt;/h2&gt;

&lt;p&gt;Stop querying the Service. Query each CoreDNS &lt;strong&gt;pod IP&lt;/strong&gt; individually, from a pod pinned to the affected node.&lt;/p&gt;

&lt;p&gt;Get the endpoints:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl &lt;span class="nt"&gt;-n&lt;/span&gt; kube-system get pods &lt;span class="nt"&gt;-l&lt;/span&gt; k8s-app&lt;span class="o"&gt;=&lt;/span&gt;kube-dns &lt;span class="nt"&gt;-o&lt;/span&gt; wide
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then run a debug pod on the node that's having trouble (&lt;code&gt;nodeName&lt;/code&gt; pins it — don't leave this to the scheduler, the whole point is which node you're testing from):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl run dnstest &lt;span class="nt"&gt;--image&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;busybox:1.36 &lt;span class="nt"&gt;--restart&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;Never &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--overrides&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'{"spec":{"nodeName":"&amp;lt;affected-node&amp;gt;"}}'&lt;/span&gt; &lt;span class="nt"&gt;--&lt;/span&gt; &lt;span class="nb"&gt;sleep &lt;/span&gt;3600
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And loop against each CoreDNS pod IP separately (IPs below are anonymised — use whatever the command above printed):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="k"&gt;for &lt;/span&gt;ip &lt;span class="k"&gt;in&lt;/span&gt; &amp;lt;coredns-ip-1&amp;gt; &amp;lt;coredns-ip-2&amp;gt; &amp;lt;coredns-ip-3&amp;gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;do
  &lt;/span&gt;&lt;span class="nv"&gt;ok&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;0&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nv"&gt;fail&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;0
  &lt;span class="k"&gt;for &lt;/span&gt;i &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;seq &lt;/span&gt;1 30&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;do
    if &lt;/span&gt;kubectl &lt;span class="nb"&gt;exec &lt;/span&gt;dnstest &lt;span class="nt"&gt;--&lt;/span&gt; nslookup mysql.cdn.svc.cluster.local &lt;span class="nv"&gt;$ip&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt;/dev/null 2&amp;gt;&amp;amp;1&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then
      &lt;/span&gt;&lt;span class="nv"&gt;ok&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="k"&gt;$((&lt;/span&gt;ok+1&lt;span class="k"&gt;))&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;else &lt;/span&gt;&lt;span class="nv"&gt;fail&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="k"&gt;$((&lt;/span&gt;fail+1&lt;span class="k"&gt;))&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;fi
  done
  &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$ip&lt;/span&gt;&lt;span class="s2"&gt; -&amp;gt; ok=&lt;/span&gt;&lt;span class="nv"&gt;$ok&lt;/span&gt;&lt;span class="s2"&gt; fail=&lt;/span&gt;&lt;span class="nv"&gt;$fail&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="k"&gt;done&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The output made it obvious:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;coredns-1 -&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;ok&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;30 &lt;span class="nv"&gt;fail&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;0
&lt;span class="gp"&gt;coredns-2 -&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;ok&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;0  &lt;span class="nv"&gt;fail&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;30
&lt;span class="gp"&gt;coredns-3 -&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;ok&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;30 &lt;span class="nv"&gt;fail&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;0
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;One endpoint, 30 out of 30 failures. The other two, perfect. &lt;code&gt;kube-dns&lt;/code&gt; round-robins across all three, so a third of every pod's lookups on that node went into a black hole.&lt;/p&gt;

&lt;p&gt;Then the confirmation step that tells you whether the &lt;em&gt;pod&lt;/em&gt; is broken or the &lt;em&gt;link&lt;/em&gt; is broken: repeat the same loop from a pod on a &lt;strong&gt;different&lt;/strong&gt; node. From elsewhere, the failing endpoint answered fine. So the CoreDNS pod was healthy. What was broken was the path between two specific nodes.&lt;/p&gt;

&lt;h2&gt;
  
  
  The actual cause
&lt;/h2&gt;

&lt;p&gt;We run Weave for the pod network. The control plane happily reported &lt;code&gt;established fastdp&lt;/code&gt; between the two nodes — the fast datapath was "up" as far as Weave's own status was concerned. But pod-to-pod traffic across that particular link was dropping 100%. A stale kernel datapath flow, reported healthy, forwarding nothing.&lt;/p&gt;

&lt;p&gt;The fix was almost insultingly small — delete the &lt;code&gt;weave-net&lt;/code&gt; pod on the affected node and let the DaemonSet recreate it, which rebuilds the datapath flows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl &lt;span class="nt"&gt;-n&lt;/span&gt; kube-system delete pod weave-net-xxxxx
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Back in about sixteen seconds. DNS 30/30 from every endpoint. The WordPress errors stopped.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why NodeLocal DNSCache didn't save us
&lt;/h2&gt;

&lt;p&gt;The instinctive hardening move here is &lt;code&gt;nodelocaldns&lt;/code&gt;: cache DNS on every node, stop crossing the overlay for every lookup. We tried it as a canary on one node and rolled it back, because in this topology it makes things worse in two ways:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The &lt;code&gt;node-cache&lt;/code&gt; runs on &lt;code&gt;hostNetwork&lt;/code&gt; and still has to reach the &lt;code&gt;kube-dns-upstream&lt;/code&gt; ClusterIP over the same overlay — so it inherits exactly the network fault we were trying to route around.&lt;/li&gt;
&lt;li&gt;It inherits the black-holed upstream endpoint too. Now you've cached your way to a node whose only path to some upstreams is broken.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;NodeLocal DNSCache reduces DNS &lt;em&gt;load&lt;/em&gt; and &lt;em&gt;latency&lt;/em&gt;. It is not a fix for a broken overlay link, and if you deploy it while an overlay link is broken, you can hand yourself a node where DNS is worse than before.&lt;/p&gt;

&lt;h2&gt;
  
  
  What we changed
&lt;/h2&gt;

&lt;p&gt;Two things, one tactical and one structural.&lt;/p&gt;

&lt;p&gt;Tactically, for anything where a hostname buys you nothing, we stopped depending on DNS. A managed database that lives at a stable ClusterIP does not need to be resolved on every connection:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;WORDPRESS_DB_HOST &lt;span class="o"&gt;=&lt;/span&gt; 10.107.207.215
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Less elegant, and you must remember it if the Service is ever recreated. But it removes a whole class of intermittent failure from the request path, and for a customer's site that's the right trade.&lt;/p&gt;

&lt;p&gt;Structurally, the honest lesson is about our own topology. Our cluster is stretched — nodes in Istanbul and nodes at a European provider, on one overlay. That's a deliberate choice for &lt;a href="https://cdn.com.tr/en" rel="noopener noreferrer"&gt;the platform we run&lt;/a&gt;, and it works, but a stretched overlay means the &lt;em&gt;link&lt;/em&gt; is a first-class failure domain, not just the node and the pod. We now treat "which node pair" as a thing to test explicitly, and per-endpoint DNS probing is a standing runbook step rather than something we invent under pressure.&lt;/p&gt;

&lt;h2&gt;
  
  
  The three-line version
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Intermittent &lt;code&gt;Error establishing a database connection&lt;/code&gt; with no MySQL symptoms is usually DNS, and WordPress won't tell you — read the log of any other hostname-based client in the pod.&lt;/li&gt;
&lt;li&gt;A failure rate that matches &lt;code&gt;1/n&lt;/code&gt; where &lt;code&gt;n&lt;/code&gt; is your endpoint count means "one endpoint," not "the service." Probe pod IPs individually, from a pod pinned to the affected node.&lt;/li&gt;
&lt;li&gt;"Established" in a network overlay's own status output is a claim, not a measurement. Verify it with traffic.&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;&lt;em&gt;I work on &lt;a href="https://cdn.com.tr/en" rel="noopener noreferrer"&gt;cdn.com.tr&lt;/a&gt;, a CDN and managed container platform run out of Istanbul. Most of what I write about is whatever broke that week.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>kubernetes</category>
      <category>devops</category>
      <category>networking</category>
      <category>debugging</category>
    </item>
    <item>
      <title>how to make a wordpress site faster?</title>
      <dc:creator>Hilmi B</dc:creator>
      <pubDate>Tue, 18 Aug 2026 13:15:08 +0000</pubDate>
      <link>https://dev.to/hilmib/how-to-make-a-wordpress-site-faster-3f32</link>
      <guid>https://dev.to/hilmib/how-to-make-a-wordpress-site-faster-3f32</guid>
      <description>&lt;p&gt;We have many websites which uses wordpress as management engine. But wordpress is heavy, especially after a few plugins... which you can't do without them. &lt;/p&gt;

&lt;p&gt;I started using cdntr plugin lately to test website optimization status. It has page control tool whihc says whats wrong in the page for cdn cache optimization. &lt;/p&gt;

&lt;p&gt;It seems infrastracture is going to singularity.. in the end, everything will be perfect :) "joking..."&lt;/p&gt;

</description>
    </item>
  </channel>
</rss>
