
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
 <channel>
   <title>Incident on random thoughts</title>
   <link>https://blog.szuecs.net/tags/incident/</link>
   <description>Recent content in Incident on random thoughts</description>
   <generator>Hugo -- gohugo.io</generator>
   <language>en-us</language>
   <copyright>Copyright &amp;copy; 2025 - Sandor Szücs</copyright>
   <lastBuildDate>Thu, 09 Jul 2026 22:30:38 +0200</lastBuildDate>
   
       <atom:link href="https://blog.szuecs.net/tags/incident/index.xml" rel="self" type="application/rss+xml" />
   
   
     <item>
       <title>RFC9209 and the API of a 404</title>
       <link>https://blog.szuecs.net/posts/rfc9209-and-api-of-404/</link>
       <pubDate>Thu, 09 Jul 2026 22:30:38 +0200</pubDate>
       
       <guid>https://blog.szuecs.net/posts/rfc9209-and-api-of-404/</guid>
       <description>&lt;p&gt;We have an interesting &lt;a href=&#34;https://github.com/zalando/restful-api-guidelines/pull/869&#34;&gt;public debate&lt;/a&gt;on the status code 404 in Zalando&amp;rsquo;s API guidelines. I am a clearopponent to a change the proxy response from 404 to 5xx, but let&amp;rsquo;stry first to understand why they want to change.&lt;/p&gt;&lt;p&gt;The reason why this change proposal started was an incident, that our&lt;a href=&#34;https://github.com/zalando-incubator/kubernetes-on-aws/blob/dev/cluster/manifests/skipper/deployment.yaml#L4&#34;&gt;canary&lt;/a&gt;had some miss configuration. The canary is one pod in our Ingressfleet. This should mitigate the blast radius of updating our Ingressdata- and control-plane.  However the data-plane started successful,but had no routes created by &lt;a href=&#34;https://kubernetes.io/docs/concepts/services-networking/ingress/&#34;&gt;Kubernetes Ingress&lt;/a&gt;and &lt;a href=&#34;https://opensource.zalando.com/skipper/kubernetes/routegroup-crd/&#34;&gt;RouteGroup&lt;/a&gt;objects, so it responded 404 to all requests directed to applications.So as expected we had something like &lt;code&gt;&amp;lt;5%&lt;/code&gt; error rate responding 404instead of reaching the applications, until some other control loopdetected that we have no active applications anymore. The mentionedcontrol loop got the connection to the &lt;a href=&#34;https://opensource.zalando.com/skipper/kubernetes/ingress-controller/&#34;&gt;skipper-ingress&lt;/a&gt; that respondedwith 404, which lead to downtime for all applications within oneminute. Basically the API for the control loop was, that status code404 meant &amp;ldquo;application does not exist&amp;rdquo; or even better &amp;ldquo;application wasdeleted&amp;rdquo;, so it needed to act on this change and clean up resources.&lt;/p&gt;&lt;figure&gt;&lt;img src=&#34;https://blog.szuecs.net/posts/rfc9209-and-api-of-404/this_is_fine.jpeg&#34;    alt=&#34;This is fine meme&#34;&gt;&lt;figcaption&gt;      &lt;p&gt;This is fine&lt;/p&gt;    &lt;/figcaption&gt;&lt;/figure&gt;&lt;p&gt;Coming back to the pull request.&lt;/p&gt;&lt;p&gt;What do they want to change exactly?&lt;/p&gt;&lt;p&gt;Here is a cite, that shows what they want to change:&lt;/p&gt;&lt;blockquote&gt;&lt;p&gt;For instance, a Kubernetes Ingress router like&lt;a href=&#34;https://github.com/zalando/skipper&#34;&gt;https://github.com/zalando/skipper&lt;/a&gt; must be configured to returnthe status code {503}  instead of {404}, if there is no route for anapplication service endpoint available.&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;What is 503 and how it is supposed to be used?&lt;/p&gt;&lt;p&gt;503 is defined in&lt;a href=&#34;https://datatracker.ietf.org/doc/html/rfc9110#section-15.6.4&#34;&gt;rfc9110&lt;/a&gt;and is the status code for StatusServiceUnavailable, which sounds legit atfirst. However citing the RFC clarifies the intention of status code 503:&lt;/p&gt;&lt;blockquote&gt;&lt;p&gt;The 503 (Service Unavailable) status code indicates that the server is currently unable to handle the request due to a temporary overload or scheduled maintenance, which will likely be alleviated after some delay. The server MAY send a Retry-After header field (Section 10.2.3) to suggest an appropriate amount of time for the client to wait before retrying the request.&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;If you check when 503 status code is used today in http proxies, youwill find for example circuit breaker, load shedder or in some casesif the proxy could not reach the backend.  I think this is pretty muchinline with the RFC, for example load shedding and &amp;ldquo;temporaryoverload&amp;rdquo;. However a &amp;ldquo;route not found&amp;rdquo; case I don&amp;rsquo;t seerepresented. &amp;ldquo;Route not found&amp;rdquo; is not temporary, it&amp;rsquo;s theconfiguration, that might change after a deployment, but it is not theregular case.&lt;/p&gt;&lt;p&gt;Let&amp;rsquo;s understand the reasoning of the change proposal:&lt;/p&gt;&lt;blockquote&gt;&lt;p&gt;In particular, a middleware must not return a status code {404}, if theservice would have returned a different status code, as this could misleadclients into thinking that the resource does not exist when it actually does.&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;Note: In the case of the incident the proxy did know no backend service.&lt;/p&gt;&lt;blockquote&gt;&lt;p&gt;Clients can safely assume that {4xx} status codes are always authoritative andcomply with the end-to-end principle (see &amp;laquo;256&amp;raquo;). While a middleware canauthenticate a request and return {401} or {403} on behalf of the service, itmust never return a misleading status code, e.g. {404} or {410}, if the serviceis not configured or not responding.&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;They say that a client calling some URL should be able to use 404status code as the only thing it has to check for &amp;ldquo;an item does notexist&amp;rdquo;. So for &lt;code&gt;https://example.org/items/foo&lt;/code&gt; reponse 404 means fooitem does not exist.  This sounds also legit to me, even if I have adifferent opinion, because you can construct also weird examples like&lt;code&gt;https://example.org/items/foo/bar/qux&lt;/code&gt; , that does not exist, even if&lt;code&gt;/items/foo&lt;/code&gt; would exist. Normally you would get requests to some oldwordpress security vulnerability, so something like&lt;code&gt;&amp;lt;some-path&amp;gt;/foo.php&lt;/code&gt;. And yes, in this case they want to have a 5xxstatus code.&lt;/p&gt;&lt;p&gt;What is the definition of 404 status code?&lt;/p&gt;&lt;blockquote&gt;&lt;p&gt;15.5.5. 404 Not FoundThe 404 (Not Found) status code indicates that the origin server did not find a current representation for the target resource or is not willing to disclose that one exists. A 404 status code does not indicate whether this lack of representation is temporary or permanent; the 410 (Gone) status code is preferred over 404 if the origin server knows, presumably through some configurable means, that the condition is likely to be permanent.A 404 response is heuristically cacheable; i.e., unless otherwise indicated by the method definition or explicit cache controls (see Section 4.2.2 of [CACHING]).&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;So a middlebox which is a proxy cache can heuristically cache the404 response.  There is a status code 410 which should bepreferred for deleted resources. This would be in the case of theincident a possible way to differentiate between &amp;ldquo;deleted&amp;rdquo; and &amp;ldquo;doesnot exist&amp;rdquo; or &amp;ldquo;no matching route found&amp;rdquo;.&lt;/p&gt;&lt;p&gt;Why do I think a proxy that has no matching HTTP route for a givenHTTP request should return 404?&lt;/p&gt;&lt;p&gt;As a proxy to enable fast error detection you should indicate the mostlikely happening to guide your automations and investigators.  Giventhat availability tools respond with 503. Given if a backend does notlisten to a port and Linux kernel return connection refused (oom of anapplication instance for example), which proxies will turn toa 502. Given that a severe error of the proxy or the application willbe a 500. If you serve public endpoints then you know, if you everlooked into your access logs that a quite big fraction of traffic aresecurity scanners, scanning all day for old vulnerabilities. As aproxy you repond by 404 and it&amp;rsquo;s all good.&lt;/p&gt;&lt;p&gt;Why should we change a 404 to a 5xx?&lt;/p&gt;&lt;p&gt;The proposal says:&lt;/p&gt;&lt;blockquote&gt;&lt;p&gt;a middleware must always return a temporary, non-authoritative server-side status code, such as:&lt;/p&gt;&lt;/blockquote&gt;&lt;ul&gt;&lt;li&gt;&lt;code&gt;{502} — Bad Gateway&lt;/code&gt;,&lt;/li&gt;&lt;li&gt;&lt;code&gt;{503} — Service Unavailable&lt;/code&gt;, or&lt;/li&gt;&lt;li&gt;&lt;code&gt;{504} — Gateway Timeout&lt;/code&gt;.&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;While the RFC for 404 says:&lt;/p&gt;&lt;blockquote&gt;&lt;p&gt;A 404 status code does not indicate whether this lack of representation is temporary or permanent&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;So 404 could be temporary, which does not contradict what themiddleware responds.  Even worse a temporary 404 can not safelyassumed by the client that it is always authoritative.  This means wehave another clear contradiction to the proposed arguments about theend-to-end semantics.&lt;/p&gt;&lt;p&gt;The proposal also mentions:&lt;/p&gt;&lt;blockquote&gt;&lt;p&gt;The end-to-end semantics of HTTP status codes is a fundamental part of the API contract.&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;Given that 404 could be temporary and the RFC shows 410 as a moreclear permanent status code, maybe the guideline should rather clarifythe use of 404. Even better it could tell about 410 instead.&lt;/p&gt;&lt;p&gt;Why do I think 404 is the right status code for HTTP proxies that donot find a matching route?&lt;/p&gt;&lt;p&gt;A route can be created, update and deleted by someone any time, sotemporary miss configured route returns 404 and if fixed again itreturns again the result as expected. This seems to be reasonablebased on the RFC.&lt;/p&gt;&lt;p&gt;Another more practical reason is that the amount of crawlers,vulnerability scanners, &lt;code&gt;&amp;lt;bot-you-name-it&amp;gt;&lt;/code&gt; scan all the day your webpage every minute my tiny box hosting this blog gets traffic from someof these and I don&amp;rsquo;t care at all. Sometimes I name this &amp;ldquo;randominternet noise&amp;rdquo;.  I also stopped logging them, because I don&amp;rsquo;t want towaste disk for this garbage. Even better our default in our Kubernetesingress layer for logs is to disable logs for 2xx, 3xx, 404 and429, because it&amp;rsquo;s a waste of disk, money and compute. Even betterless people are distracted because someone started a vulnerabilityscanner against a proper zero trust architecture with defaultauthentication all over the place. In the last 10 years running likethis there was no finding at all.&lt;/p&gt;&lt;p&gt;Here 1d of status codes for my blog.szuecs.net (enabled for one day):&lt;/p&gt;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;$ awk &amp;#39;{print $9}&amp;#39; blog.szuecs.net/blog.szuecs.net_access.log.1 | sort | uniq -c    401 200     18 301      3 304    165 400   2226 404  &amp;lt;- 5x more than valid requests     17 405      1 408&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;So 5 times more traffic from vulnerability scanners, than fromgoogle-bot, bing-bot, &amp;hellip; and you reading this post!&lt;/p&gt;&lt;p&gt;Another reason why I think it does not even matter to identify anissue like this via status code is, that with the raise of Opentracingand the proper standard &lt;a href=&#34;https://opentelemetry.io/&#34;&gt;Open Telemetry&lt;/a&gt;(short: OTel), provides a proper tool that easily identifes that thecall chain of a 404 response ended at the HTTP proxy in case you needto know who responded during a failure analysis.&lt;/p&gt;&lt;p&gt;Even developers that run their workload behind a proxy layer will wantto have a 404 instead of 5xx response, if you tell them that theiralerting of 5xx will create false alerts by random internet noise.&lt;/p&gt;&lt;p&gt;/EOF&lt;/p&gt;</description>
     </item>
   
     <item>
       <title>Journey of Zone Aware Traffic</title>
       <link>https://blog.szuecs.net/posts/kubernetes-zone-aware-traffic/</link>
       <pubDate>Sat, 18 Apr 2026 20:02:25 +0200</pubDate>
       
       <guid>https://blog.szuecs.net/posts/kubernetes-zone-aware-traffic/</guid>
       <description>&lt;p&gt;Today, I want to share a bit of details in our steps to support zoneaware traffic in our &lt;a href=&#34;https://kubernetes-on-aws.readthedocs.io/en/latest/admin-guide/kubernetes-in-production.html&#34;&gt;Kubernetes infrastructure&lt;/a&gt;.&lt;/p&gt;&lt;p&gt;You can learn a bit of &lt;a href=&#34;https://kubernetes.io/&#34;&gt;Kubernetes&lt;/a&gt; and seeinteresting effects it can have. First I have to share something aboutthe environment.&lt;/p&gt;&lt;h3 id=&#34;starting-from-zero&#34;&gt;Starting from zero!&lt;/h3&gt;&lt;p&gt;There are basically two patterns in Kubernetes infrastructure deployments:&lt;/p&gt;&lt;ol&gt;&lt;li&gt;1 Kubernetes cluster per zone&lt;/li&gt;&lt;li&gt;1 Kubernetes cluster per region with multiple zones.&lt;/li&gt;&lt;/ol&gt;&lt;p&gt;In our case it&amp;rsquo;s the latter, a single Kubernetes cluster spansmultiple zones, 3 by default. The advantage is that you have moresimple availability guarantees, because all your applications run across 3 zonesby default. On the other hand, doing traffic engineering, so preferclose instances, is more complex. Before I tell about the problem spaceand our findings, let me share our basic &lt;a href=&#34;https://kubernetes.io/docs/concepts/services-networking/ingress/&#34;&gt;KubernetesIngress&lt;/a&gt;setup. It is a 2-layer load balancer infrastructure serving a largescale microservice environment.&lt;/p&gt;&lt;p&gt;In German there is a proverb that says one picture is better thanthousands of words, so let&amp;rsquo;s see figure 1. It&amp;rsquo;s a bit outdated,because we run AWS network load balancer (NLB) instead of ALB, butrest looks the same today.&lt;/p&gt;&lt;figure&gt;&lt;a href=&#34;https://opensource.zalando.com/skipper/kubernetes/ingress-controller/#aws-deployment&#34;&gt;&lt;img src=&#34;https://blog.szuecs.net/posts/kubernetes-zone-aware-traffic/ingress-traffic-flow-aws-technical.svg&#34;    alt=&#34;2-layer load balancer traffic flow from AWS ALB to skipper to application pods&#34;&gt;&lt;/a&gt;&lt;figcaption&gt;      &lt;p&gt;figure 1&lt;/p&gt;    &lt;/figcaption&gt;&lt;/figure&gt;&lt;p&gt;We terminate TLS in the cloud load balancer and the HTTP routing isdone in our HTTP proxy &lt;a href=&#34;https://github.com/zalando/skipper&#34;&gt;skipper&lt;/a&gt;.Cloud load balancers are managed by &lt;a href=&#34;https://github.com/zalando-incubator/kube-ingress-aws-controller&#34;&gt;kube-ingress-aws-controller&lt;/a&gt;and DNS by &lt;a href=&#34;https://github.com/kubernetes-sigs/external-dns&#34;&gt;external-dns&lt;/a&gt;.&lt;/p&gt;&lt;p&gt;We run this for about a decade since Kubernetes 1.3 and it evolvedquite a bit. If you want to lurk into our configuration, check it outin &lt;a href=&#34;https://github.com/zalando-incubator/kubernetes-on-aws/tree/dev/cluster/manifests/skipper&#34;&gt;kubernetes-on-aws&lt;/a&gt;.&lt;/p&gt;&lt;p&gt;In this environment zone aware traffic has 4 parts:&lt;/p&gt;&lt;ol&gt;&lt;li&gt;client to cloud load balancer&lt;/li&gt;&lt;li&gt;cloud load balancer to skipper-ingress (skipper-ingress is the application based on skipper that is the data-plane and control-plane of our http proxy layer)&lt;/li&gt;&lt;li&gt;skipper-ingress to backend pods&lt;/li&gt;&lt;li&gt;cluster internal clients to skipper-ingress through a service type ClusterIP&lt;/li&gt;&lt;/ol&gt;&lt;p&gt;Kube-ingress-aws-controller manages ALBs and NLBs, so 1. and 2. aredone, that one. You can set &lt;code&gt;-nlb-cross-zone=false&lt;/code&gt; to disable sendingtraffic cross zone from the load balancer TargetGroup toskipper-ingress.  If you set&lt;code&gt;--nlb-zone-affinity=availability_zone_affinity&lt;/code&gt; all clients runningin the same zone in any AWS account will resolve DNS to same zone. Soinstead of 3 IPs for NLB Listeners you will resolve only one. It doesnot matter if you have a client in the same or in another cluster.&lt;/p&gt;&lt;p&gt;Since&lt;a href=&#34;https://github.com/zalando/skipper/releases/tag/v0.24.22&#34;&gt;v0.24.22&lt;/a&gt;skipper supports zone aware traffic (3.) in its kubernetesdataclient. Dataclients are the way to fetch data, that skipper usesto create its routing table. If you run skipper-ingress with thekubernetes dataclient configured, every skipper-ingress pod will fetchall relevant Kubernetes objects to build its routing tree. In largerenvironments this is quite some load on the Kubernetes control planeand it&amp;rsquo;s easy to break Kubernetes control plane by scaling out. Theskipper way to control the load targeting the Kubernetes control planeis to run skipper&amp;rsquo;s &lt;code&gt;routesrv&lt;/code&gt;.&lt;a href=&#34;https://opensource.zalando.com/skipper/kubernetes/ingress-controller/#routesrv&#34;&gt;Routesrv&lt;/a&gt;is a skipper control plane component. It uses the Kubernetes dataclient to fetchrouting information and exposes an API endpoint to fetch eskiproutes. &lt;a href=&#34;https://pkg.go.dev/github.com/zalando/skipper/eskip&#34;&gt;Eskip&lt;/a&gt;is the skipper native routing language. Eskip has a set of paradigms:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;Routes match by &lt;a href=&#34;https://opensource.zalando.com/skipper/reference/predicates/&#34;&gt;&lt;code&gt;predicates&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;&lt;li&gt;Predicates can be combined by &lt;code&gt;&amp;amp;&amp;amp;&lt;/code&gt; (logical AND), if you need a logical OR, you have to create another route.&lt;/li&gt;&lt;li&gt;Features in the request or response path are implemented in &lt;a href=&#34;https://opensource.zalando.com/skipper/reference/filters/&#34;&gt;&lt;code&gt;filters&lt;/code&gt;&lt;/a&gt;.&lt;/li&gt;&lt;li&gt;&lt;a href=&#34;https://opensource.zalando.com/skipper/reference/backends/&#34;&gt;Backends&lt;/a&gt; are more than a list of load balancer pool members.&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;Eskip examples:&lt;/p&gt;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code class=&#34;language-eskip&#34; data-lang=&#34;eskip&#34;&gt;// syntaxrouteID: Predicate1 &amp;amp;&amp;amp; Predicate2 -&amp;gt; filter1 -&amp;gt; filter2 -&amp;gt; &amp;lt;backend&amp;gt;;r1: Path(&amp;#34;/resource/:id&amp;#34;) -&amp;gt; setRequestHeader(&amp;#34;X-Resource-Id&amp;#34;, &amp;#34;${id}&amp;#34;) -&amp;gt; clusterClientRatelimit(&amp;#34;resource&amp;#34;, 10, &amp;#34;1m&amp;#34;, &amp;#34;X-Resource-Id&amp;#34;) -&amp;gt; &amp;#34;https://backend.example.org&amp;#34;;r2: Host(&amp;#34;products.example.org&amp;#34;) &amp;amp;&amp;amp; Path(&amp;#34;/products/:productId&amp;#34;)    -&amp;gt; consistentHashKey(&amp;#34;${productId}&amp;#34;)    -&amp;gt; consistentHashBalanceFactor(1.25)    -&amp;gt; &amp;lt;consistentHash, &amp;#34;http://127.0.0.1:9998&amp;#34;, &amp;#34;http://127.0.0.1:9997&amp;#34;&amp;gt;;&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&#34;coming-back-to-zone-aware-traffic&#34;&gt;Coming back to zone aware traffic.&lt;/h3&gt;&lt;p&gt;If your data-plane skipper-ingress fetches routes from acontrol plane component like routesrv, the question is:&lt;/p&gt;&lt;p&gt;How does routesrv know where the skipper-ingress pod is running, that queries it?&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Astonishing: routesrv has no idea!&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;Routesrv just exposes route API endpoints, that are used by thedata-plane pods to fetch routes:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;code&gt;/routes&lt;/code&gt; fetch all routes&lt;/li&gt;&lt;li&gt;&lt;code&gt;/routes/:zone&lt;/code&gt; fetch zone aware routes&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;Skipper-ingress data plane pods know its zone by Kubernetes downwardsAPI. This makes it possible to pass Kubernetes metadata to the processby environment variables:&lt;/p&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-yaml&#34; data-lang=&#34;yaml&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;1&lt;/span&gt;&lt;span&gt;&lt;span style=&#34;color:#008000;font-weight:bold&#34;&gt;env&lt;/span&gt;:&lt;span style=&#34;color:#bbb&#34;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;2&lt;/span&gt;&lt;span&gt;- &lt;span style=&#34;color:#008000;font-weight:bold&#34;&gt;name&lt;/span&gt;:&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;KUBE_NODE_ZONE&lt;span style=&#34;color:#bbb&#34;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;3&lt;/span&gt;&lt;span&gt;&lt;span style=&#34;color:#bbb&#34;&gt;  &lt;/span&gt;&lt;span style=&#34;color:#008000;font-weight:bold&#34;&gt;valueFrom&lt;/span&gt;:&lt;span style=&#34;color:#bbb&#34;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;4&lt;/span&gt;&lt;span&gt;&lt;span style=&#34;color:#bbb&#34;&gt;    &lt;/span&gt;&lt;span style=&#34;color:#008000;font-weight:bold&#34;&gt;fieldRef&lt;/span&gt;:&lt;span style=&#34;color:#bbb&#34;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;5&lt;/span&gt;&lt;span&gt;&lt;span style=&#34;color:#bbb&#34;&gt;      &lt;/span&gt;&lt;span style=&#34;color:#008000;font-weight:bold&#34;&gt;fieldPath&lt;/span&gt;:&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;metadata.labels[&amp;#39;topology.kubernetes.io/zone&amp;#39;]&lt;span style=&#34;color:#bbb&#34;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Now you can use the environment variable in a flag to skipper like&lt;code&gt;-routes-urls=http://skipper-ingress-routesrv.kube-system.svc.cluster.local/routes/$(KUBE_NODE_ZONE)&amp;quot;&lt;/code&gt; to fetch zone aware routes.&lt;/p&gt;&lt;p&gt;Great, now we understand how we can do zone aware traffic 1.-3., but what about 4.?&lt;/p&gt;&lt;p&gt;Ok, 4. seems to be easy. You just plug an annotation&lt;code&gt;service.kubernetes.io/topology-mode: auto&lt;/code&gt; and kube-proxy will makesure your ClusterIP service is having a safe amount of Kubernetes podsin its layer 4 load balancer. We run this since more than 3 yearswithout an issue.  Before this annotation there was&lt;code&gt;service.kubernetes.io/topology-aware-hints&lt;/code&gt; annotation which didbasically the same thing. If you read the&lt;a href=&#34;https://kubernetes.io/docs/concepts/services-networking/topology-aware-routing/&#34;&gt;documentation&lt;/a&gt;,you see that there are some thoughts about safety, because you do notwant to create harm on a data-plane feature that every application hasto rely on.&lt;/p&gt;&lt;p&gt;As often in a life, things change. Sometimes implementation changes oryour monitoring adds more visibility. Your application requirements onthe infrastructure change or traffic patterns, because someonedeployed a new client to some service. Sometimes it&amp;rsquo;s a mixture of allof this visible in figure 2.&lt;/p&gt;&lt;p&gt;To understand better the zonal traffic in our clusters we created agraph how much requests by zone we have in skipper-ingressdata-plane. If we have some new data and it shows somethingunexpected, my first question is always: can we trust the data?Sometimes we do mistakes, like having a wrong unit or some selector isslightly wrong and you observe not exactly what you expected. So a bitof questioning your new data is always a great thing to find bugs.&lt;/p&gt;&lt;p&gt;However, in this case it seems we really were able to trust the data.During the last weeks we had some interesting effects in one of ourhigh traffic clusters. The effects are shown in figure 2. We can seethat within 1h there were 3 times a large share of throughput that hitonly one zone. After some minutes it was going back to normal.&lt;/p&gt;&lt;figure&gt;&lt;a href=&#34;https://opensource.zalando.com/skipper&#34;&gt;&lt;img src=&#34;https://blog.szuecs.net/posts/kubernetes-zone-aware-traffic/graph_split_traffic.png&#34;    alt=&#34;RPS traffic by zone and we can see a huge traffic split between these within 1-2 minutes and after a while it collapses again and it happened 3 times within 1 hour.&#34;&gt;&lt;/a&gt;&lt;figcaption&gt;      &lt;p&gt;figure 2 - RPS traffic by zone&lt;/p&gt;    &lt;/figcaption&gt;&lt;/figure&gt;&lt;p&gt;What we see is flapping of the traffic distribution, which sometimescaused an unexpected latency spike to one of our applications. Thisflapping was caused by kube-proxy, that thought it might makes senseto flap between zone aware and not zone aware traffic. If you check &lt;a href=&#34;https://kubernetes.io/docs/concepts/services-networking/topology-aware-routing/#safeguards&#34;&gt;safeguards&lt;/a&gt;,you can read:&lt;/p&gt;&lt;pre&gt;&lt;code&gt;4. One or more endpoints does not have a zone hint: When this  happens, the kube-proxy assumes that a transition from or to  Topology Aware Hints is underway. Filtering endpoints for a Service  in this state would be dangerous so the kube-proxy falls back to  using all endpoints.5. A zone is not represented in hints: If the kube-proxy is unable  to find at least one endpoint with a hint targeting the zone it  is running in, it falls back to using endpoints from all  zones. This is most likely to happen as you add a new zone into  your existing cluster.&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Basically what we see in figure 2 is that if zone hints are populated,kube-proxy will write layer 4 rules such that rules are zone aware andwe have this large unbalanced traffic split. Later zone hintsdisappear or are not available for one or more endpoints (4.) and itdecides that it is too dangerous and the rules will change to non-zoneaware traffic. I don&amp;rsquo;t know why these hints disappear, but I did notfind any when I checked. One of the interesting facts are that we havethis flapping all the day for some weeks and it&amp;rsquo;s most often not anissue, but sometimes a latency spike up to 250ms happened and this islarge enough for high traffic low latency applications to fail.&lt;/p&gt;&lt;p&gt;After discussing this in Kubernetes sig-network community channel wewill try to switch to a more persistent service type ClusterIPconfigurations by using &lt;code&gt;trafficDistribution: PreferSameZone&lt;/code&gt;, that isnow available in Kubernetes. It will provide no flapping for thetraffic distribution. I am looking forward to see the effects.&lt;/p&gt;&lt;h3 id=&#34;what-about-pods&#34;&gt;What about pods?&lt;/h3&gt;&lt;p&gt;One other important configuration is that you have a balanced spreadof pods for clients, proxy and backends. This you can influence by setting&lt;a href=&#34;https://kubernetes.io/docs/concepts/scheduling-eviction/topology-spread-constraints/&#34;&gt;&lt;code&gt;topologySpreadConstraints&lt;/code&gt;&lt;/a&gt;.The proxy and also application developers already enabled &lt;code&gt;topologySpreadConstraints&lt;/code&gt;,example:&lt;/p&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-yaml&#34; data-lang=&#34;yaml&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;topologySpreadConstraints&lt;/span&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        - &lt;span style=&#34;color:#f92672&#34;&gt;maxSkew&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          &lt;span style=&#34;color:#f92672&#34;&gt;topologyKey&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;topology.kubernetes.io/zone&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          &lt;span style=&#34;color:#f92672&#34;&gt;whenUnsatisfiable&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;DoNotSchedule&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          &lt;span style=&#34;color:#f92672&#34;&gt;labelSelector&lt;/span&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#f92672&#34;&gt;matchLabels&lt;/span&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;              &lt;span style=&#34;color:#f92672&#34;&gt;component&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;ingress&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;              &lt;span style=&#34;color:#f92672&#34;&gt;application&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;skipper-ingress&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This is configuration is important to not create too much of anunbalanced traffic by your clients. Also the targets of the proxy havealso to spread evenly so the horizontal pod autoscaling can do its joband keep the load of single pods in bounds.&lt;/p&gt;&lt;h3 id=&#34;one-last-thing&#34;&gt;One last thing&lt;/h3&gt;&lt;p&gt;Of course Kubernetes would not be Kubernetes, that everyone loves andhates, if there would not be a missing feature. Beware about the factthat there is no &lt;a href=&#34;https://github.com/kubernetes/kubernetes/issues/124149&#34;&gt;zone aware down scaling&lt;/a&gt;.&lt;/p&gt;&lt;p&gt;Kubernetes infrastructure is super interesting, often details matterand sometimes there are missing features, that make you wonder, butall in all I am very happy with it.&lt;/p&gt;&lt;p&gt;If you have any questions or anything to share let me know in &lt;a href=&#34;https://hachyderm.io/@sszuecs&#34;&gt;Mastodon&lt;/a&gt;.&lt;/p&gt;</description>
     </item>
   
     <item>
       <title>Hugo Tests</title>
       <link>https://blog.szuecs.net/posts/test-post/</link>
       <pubDate>Sat, 22 Nov 2025 19:55:23 +0100</pubDate>
       
       <guid>https://blog.szuecs.net/posts/test-post/</guid>
       <description>&lt;p&gt;Hello &amp;#x1f44b;&lt;/p&gt;&lt;p&gt;This is my first test post to test language rendering for Go and Bash and how to use pictures.&lt;/p&gt;&lt;p&gt;Something written in Go with highlights&lt;/p&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;display:grid;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;1&lt;/span&gt;&lt;span&gt;&lt;span style=&#34;color:#a2f;font-weight:bold&#34;&gt;package&lt;/span&gt;&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;main&lt;span style=&#34;color:#bbb&#34;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;2&lt;/span&gt;&lt;span&gt;&lt;span style=&#34;color:#bbb&#34;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex; background-color:#dfdfdf&#34;&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;3&lt;/span&gt;&lt;span&gt;&lt;span style=&#34;color:#a2f;font-weight:bold&#34;&gt;import&lt;/span&gt;&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color:#b44&#34;&gt;&amp;#34;fmt&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#bbb&#34;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;4&lt;/span&gt;&lt;span&gt;&lt;span style=&#34;color:#bbb&#34;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;5&lt;/span&gt;&lt;span&gt;&lt;span style=&#34;color:#a2f;font-weight:bold&#34;&gt;func&lt;/span&gt;&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color:#00a000&#34;&gt;main&lt;/span&gt;()&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;{&lt;span style=&#34;color:#bbb&#34;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex; background-color:#dfdfdf&#34;&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;6&lt;/span&gt;&lt;span&gt;&lt;span style=&#34;color:#bbb&#34;&gt;    &lt;/span&gt;&lt;span style=&#34;color:#a2f;font-weight:bold&#34;&gt;for&lt;/span&gt;&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;i&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color:#666&#34;&gt;:=&lt;/span&gt;&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color:#666&#34;&gt;0&lt;/span&gt;;&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;i&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;&amp;lt;&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color:#666&#34;&gt;3&lt;/span&gt;;&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;i&lt;span style=&#34;color:#666&#34;&gt;++&lt;/span&gt;&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;{&lt;span style=&#34;color:#bbb&#34;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex; background-color:#dfdfdf&#34;&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;7&lt;/span&gt;&lt;span&gt;&lt;span style=&#34;color:#bbb&#34;&gt;        &lt;/span&gt;fmt.&lt;span style=&#34;color:#00a000&#34;&gt;Println&lt;/span&gt;(&lt;span style=&#34;color:#b44&#34;&gt;&amp;#34;Value of i:&amp;#34;&lt;/span&gt;,&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;i)&lt;span style=&#34;color:#bbb&#34;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex; background-color:#dfdfdf&#34;&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;8&lt;/span&gt;&lt;span&gt;&lt;span style=&#34;color:#bbb&#34;&gt;    &lt;/span&gt;}&lt;span style=&#34;color:#bbb&#34;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;9&lt;/span&gt;&lt;span&gt;}&lt;span style=&#34;color:#bbb&#34;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Another thing written in Go without highlights&lt;/p&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;1&lt;/span&gt;&lt;span&gt;&lt;span style=&#34;color:#a2f;font-weight:bold&#34;&gt;package&lt;/span&gt;&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;foo&lt;span style=&#34;color:#bbb&#34;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;2&lt;/span&gt;&lt;span&gt;&lt;span style=&#34;color:#bbb&#34;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;3&lt;/span&gt;&lt;span&gt;&lt;span style=&#34;color:#a2f;font-weight:bold&#34;&gt;func&lt;/span&gt;&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color:#00a000&#34;&gt;Bar&lt;/span&gt;()&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;(&lt;span style=&#34;color:#0b0;font-weight:bold&#34;&gt;string&lt;/span&gt;,&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color:#0b0;font-weight:bold&#34;&gt;error&lt;/span&gt;)&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;{&lt;span style=&#34;color:#bbb&#34;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;4&lt;/span&gt;&lt;span&gt;&lt;span style=&#34;color:#bbb&#34;&gt;     &lt;/span&gt;&lt;span style=&#34;color:#a2f&#34;&gt;println&lt;/span&gt;(&lt;span style=&#34;color:#b44&#34;&gt;&amp;#34;Hello foo.Bar!&amp;#34;&lt;/span&gt;)&lt;span style=&#34;color:#bbb&#34;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;5&lt;/span&gt;&lt;span&gt;&lt;span style=&#34;color:#bbb&#34;&gt;     &lt;/span&gt;&lt;span style=&#34;color:#a2f;font-weight:bold&#34;&gt;return&lt;/span&gt;&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color:#b44&#34;&gt;&amp;#34;foo&amp;#34;&lt;/span&gt;,&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color:#a2f;font-weight:bold&#34;&gt;nil&lt;/span&gt;&lt;span style=&#34;color:#bbb&#34;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;6&lt;/span&gt;&lt;span&gt;}&lt;span style=&#34;color:#bbb&#34;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Now a little bit of bash:&lt;/p&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 1&lt;/span&gt;&lt;span&gt;&lt;span style=&#34;color:#a2f;font-weight:bold&#34;&gt;function&lt;/span&gt; foo &lt;span style=&#34;color:#666&#34;&gt;()&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;{&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 2&lt;/span&gt;&lt;span&gt;     &lt;span style=&#34;color:#a2f&#34;&gt;echo&lt;/span&gt; &lt;span style=&#34;color:#b44&#34;&gt;&amp;#34;Hello Bash!&amp;#34;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 3&lt;/span&gt;&lt;span&gt;&lt;span style=&#34;color:#666&#34;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 4&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 5&lt;/span&gt;&lt;span&gt;cat &lt;span style=&#34;color:#b44&#34;&gt;&amp;lt;&amp;lt;EOF&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 6&lt;/span&gt;&lt;span&gt;&lt;span style=&#34;color:#b44&#34;&gt;Hello World!&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 7&lt;/span&gt;&lt;span&gt;&lt;span style=&#34;color:#b44&#34;&gt;EOF&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 8&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 9&lt;/span&gt;&lt;span&gt;&lt;span style=&#34;color:#a2f;font-weight:bold&#34;&gt;while&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;[&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;1&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;]&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;10&lt;/span&gt;&lt;span&gt;&lt;span style=&#34;color:#a2f;font-weight:bold&#34;&gt;do&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;11&lt;/span&gt;&lt;span&gt;        &lt;span style=&#34;color:#a2f&#34;&gt;echo&lt;/span&gt; -n &lt;span style=&#34;color:#b44&#34;&gt;&amp;#34;.&amp;#34;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;12&lt;/span&gt;&lt;span&gt;        sleep 0.5&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;13&lt;/span&gt;&lt;span&gt;&lt;span style=&#34;color:#a2f;font-weight:bold&#34;&gt;done&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;A bit of goat&lt;/p&gt;&lt;div class=&#34;goat svg-container &#34;&gt;      &lt;svg      xmlns=&#34;http://www.w3.org/2000/svg&#34;      font-family=&#34;Menlo,Lucida Console,monospace&#34;              viewBox=&#34;0 0 352 57&#34;      &gt;      &lt;g transform=&#39;translate(8,16)&#39;&gt;&lt;path d=&#39;M 0,0 L 32,0&#39; fill=&#39;none&#39; stroke=&#39;currentColor&#39;&gt;&lt;/path&gt;&lt;path d=&#39;M 304,0 L 336,0&#39; fill=&#39;none&#39; stroke=&#39;currentColor&#39;&gt;&lt;/path&gt;&lt;path d=&#39;M 32,16 L 64,16&#39; fill=&#39;none&#39; stroke=&#39;currentColor&#39;&gt;&lt;/path&gt;&lt;path d=&#39;M 112,16 L 144,16&#39; fill=&#39;none&#39; stroke=&#39;currentColor&#39;&gt;&lt;/path&gt;&lt;path d=&#39;M 192,16 L 224,16&#39; fill=&#39;none&#39; stroke=&#39;currentColor&#39;&gt;&lt;/path&gt;&lt;path d=&#39;M 272,16 L 304,16&#39; fill=&#39;none&#39; stroke=&#39;currentColor&#39;&gt;&lt;/path&gt;&lt;path d=&#39;M 0,32 L 32,32&#39; fill=&#39;none&#39; stroke=&#39;currentColor&#39;&gt;&lt;/path&gt;&lt;path d=&#39;M 304,32 L 336,32&#39; fill=&#39;none&#39; stroke=&#39;currentColor&#39;&gt;&lt;/path&gt;&lt;path d=&#39;M 0,0 L 0,32&#39; fill=&#39;none&#39; stroke=&#39;currentColor&#39;&gt;&lt;/path&gt;&lt;path d=&#39;M 32,0 L 32,16&#39; fill=&#39;none&#39; stroke=&#39;currentColor&#39;&gt;&lt;/path&gt;&lt;path d=&#39;M 32,16 L 32,32&#39; fill=&#39;none&#39; stroke=&#39;currentColor&#39;&gt;&lt;/path&gt;&lt;path d=&#39;M 304,0 L 304,16&#39; fill=&#39;none&#39; stroke=&#39;currentColor&#39;&gt;&lt;/path&gt;&lt;path d=&#39;M 304,16 L 304,32&#39; fill=&#39;none&#39; stroke=&#39;currentColor&#39;&gt;&lt;/path&gt;&lt;path d=&#39;M 336,0 L 336,32&#39; fill=&#39;none&#39; stroke=&#39;currentColor&#39;&gt;&lt;/path&gt;&lt;polygon points=&#39;72.000000,16.000000 60.000000,10.400000 60.000000,21.600000&#39; fill=&#39;currentColor&#39; transform=&#39;rotate(0.000000, 64.000000, 16.000000)&#39;&gt;&lt;/polygon&gt;&lt;polygon points=&#39;120.000000,16.000000 108.000000,10.400000 108.000000,21.600000&#39; fill=&#39;currentColor&#39; transform=&#39;rotate(180.000000, 112.000000, 16.000000)&#39;&gt;&lt;/polygon&gt;&lt;polygon points=&#39;152.000000,16.000000 140.000000,10.400000 140.000000,21.600000&#39; fill=&#39;currentColor&#39; transform=&#39;rotate(0.000000, 144.000000, 16.000000)&#39;&gt;&lt;/polygon&gt;&lt;polygon points=&#39;200.000000,16.000000 188.000000,10.400000 188.000000,21.600000&#39; fill=&#39;currentColor&#39; transform=&#39;rotate(180.000000, 192.000000, 16.000000)&#39;&gt;&lt;/polygon&gt;&lt;polygon points=&#39;232.000000,16.000000 220.000000,10.400000 220.000000,21.600000&#39; fill=&#39;currentColor&#39; transform=&#39;rotate(0.000000, 224.000000, 16.000000)&#39;&gt;&lt;/polygon&gt;&lt;polygon points=&#39;280.000000,16.000000 268.000000,10.400000 268.000000,21.600000&#39; fill=&#39;currentColor&#39; transform=&#39;rotate(180.000000, 272.000000, 16.000000)&#39;&gt;&lt;/polygon&gt;&lt;path d=&#39;M 88,0 A 16,16 0 0,0 72,16&#39; fill=&#39;none&#39; stroke=&#39;currentColor&#39;&gt;&lt;/path&gt;&lt;path d=&#39;M 88,0 A 16,16 0 0,1 104,16&#39; fill=&#39;none&#39; stroke=&#39;currentColor&#39;&gt;&lt;/path&gt;&lt;path d=&#39;M 168,0 A 16,16 0 0,0 152,16&#39; fill=&#39;none&#39; stroke=&#39;currentColor&#39;&gt;&lt;/path&gt;&lt;path d=&#39;M 168,0 A 16,16 0 0,1 184,16&#39; fill=&#39;none&#39; stroke=&#39;currentColor&#39;&gt;&lt;/path&gt;&lt;path d=&#39;M 248,0 A 16,16 0 0,0 232,16&#39; fill=&#39;none&#39; stroke=&#39;currentColor&#39;&gt;&lt;/path&gt;&lt;path d=&#39;M 248,0 A 16,16 0 0,1 264,16&#39; fill=&#39;none&#39; stroke=&#39;currentColor&#39;&gt;&lt;/path&gt;&lt;path d=&#39;M 72,16 A 16,16 0 0,0 88,32&#39; fill=&#39;none&#39; stroke=&#39;currentColor&#39;&gt;&lt;/path&gt;&lt;path d=&#39;M 104,16 A 16,16 0 0,1 88,32&#39; fill=&#39;none&#39; stroke=&#39;currentColor&#39;&gt;&lt;/path&gt;&lt;path d=&#39;M 152,16 A 16,16 0 0,0 168,32&#39; fill=&#39;none&#39; stroke=&#39;currentColor&#39;&gt;&lt;/path&gt;&lt;path d=&#39;M 184,16 A 16,16 0 0,1 168,32&#39; fill=&#39;none&#39; stroke=&#39;currentColor&#39;&gt;&lt;/path&gt;&lt;path d=&#39;M 232,16 A 16,16 0 0,0 248,32&#39; fill=&#39;none&#39; stroke=&#39;currentColor&#39;&gt;&lt;/path&gt;&lt;path d=&#39;M 264,16 A 16,16 0 0,1 248,32&#39; fill=&#39;none&#39; stroke=&#39;currentColor&#39;&gt;&lt;/path&gt;&lt;text text-anchor=&#39;middle&#39; x=&#39;16&#39; y=&#39;20&#39; fill=&#39;currentColor&#39; style=&#39;font-size:1em&#39;&gt;A&lt;/text&gt;&lt;text text-anchor=&#39;middle&#39; x=&#39;88&#39; y=&#39;20&#39; fill=&#39;currentColor&#39; style=&#39;font-size:1em&#39;&gt;1&lt;/text&gt;&lt;text text-anchor=&#39;middle&#39; x=&#39;168&#39; y=&#39;20&#39; fill=&#39;currentColor&#39; style=&#39;font-size:1em&#39;&gt;2&lt;/text&gt;&lt;text text-anchor=&#39;middle&#39; x=&#39;248&#39; y=&#39;20&#39; fill=&#39;currentColor&#39; style=&#39;font-size:1em&#39;&gt;3&lt;/text&gt;&lt;text text-anchor=&#39;middle&#39; x=&#39;320&#39; y=&#39;20&#39; fill=&#39;currentColor&#39; style=&#39;font-size:1em&#39;&gt;B&lt;/text&gt;&lt;/g&gt;    &lt;/svg&gt;  &lt;/div&gt;&lt;p&gt;QR code:&lt;img src=&#34;https://blog.szuecs.net/qr_aa46e8ffae1a2ace.png&#34; width=&#34;720&#34; height=&#34;720&#34; alt=&#34;QR code of skipper user documentation&#34;&gt;&lt;/p&gt;&lt;p&gt;A bit of mathjax&lt;/p&gt;\[\begin{aligned}KL(\hat{y} || y) &amp;= \sum_{c=1}^{M}\hat{y}_c \log{\frac{\hat{y}_c}{y_c}} \\JS(\hat{y} || y) &amp;= \frac{1}{2}(KL(y||\frac{y+\hat{y}}{2}) + KL(\hat{y}||\frac{y+\hat{y}}{2}))\end{aligned}\]&lt;p&gt;A bit of inline mathjax \(a^*=x-b^*\) and \(\alpha \gt \beta\).&lt;/p&gt;&lt;p&gt;SVG with figure:&lt;figure class=&#34;ma0 w-75&#34;&gt;&lt;a href=&#34;https://github.com/brendangregg/FlameGraph&#34;&gt;&lt;img src=&#34;https://blog.szuecs.net/perf.svg&#34;    alt=&#34;A CPU flamegraph&#34;&gt;&lt;/a&gt;&lt;figcaption&gt;      &lt;p&gt;CPU flamegraph&lt;/p&gt;    &lt;/figcaption&gt;&lt;/figure&gt;&lt;/p&gt;&lt;p&gt;PNG figure:&lt;figure&gt;&lt;a href=&#34;https://opensource.zalando.com/skipper&#34;&gt;&lt;img src=&#34;https://blog.szuecs.net/posts/test-post/skipper.png&#34;    alt=&#34;Link to skipper as logo&#34;&gt;&lt;/a&gt;&lt;figcaption&gt;      &lt;p&gt;skipper logo&lt;/p&gt;    &lt;/figcaption&gt;&lt;/figure&gt;&lt;/p&gt;&lt;h2 id=&#34;tests&#34;&gt;Tests&lt;/h2&gt;&lt;p&gt;{{ $v1 := 6 }}{{ $v2 := 7 }}&lt;/p&gt;&lt;p&gt;The product of {{ $v1 }} and {{ $v2 }} is {{ mul $v1 $v2 }}.&lt;/p&gt;&lt;p&gt;{{ $d = time.ParseDuration &amp;ldquo;3.5h2.5m1.5s&amp;rdquo; }}{{ $d.Hours }}&lt;/p&gt;&lt;h2 id=&#34;resources&#34;&gt;Resources&lt;/h2&gt;&lt;p&gt;resources.Get (global assets){{ with resources.Get &amp;ldquo;perf.svg&amp;rdquo; }}&lt;img src=&#34;{{ .RelPermalink }}&#34; width=&#34;{{ .Width }}&#34; height=&#34;{{ .Height }}&#34; alt=&#34;&#34;&gt;{{ end }}&lt;/p&gt;&lt;p&gt;Resources.Get picture (per page) and try to render:&lt;/p&gt;&lt;p&gt;{{ $image := .Resources.Get &amp;ldquo;./skipper.png&amp;rdquo; }}{{ with $image }}&lt;img src=&#34;{{ .RelPermalink }}&#34; width=&#34;{{ .Width }}&#34; height=&#34;{{ .Height }}&#34;&gt;{{ end }}&lt;/p&gt;&lt;p&gt;{{ $image := .Resources.Get &amp;ldquo;skipper.png&amp;rdquo; }}{{ with $image }}![skipper logo markdown styl does not work]({{ .RelPermalink }}){{ end }}&lt;/p&gt;&lt;p&gt;end:) O:)&lt;/p&gt;</description>
     </item>
   
 </channel>
</rss>
