<p>I am currently using the following to attempt to spread Kubernetes pods in a given deployment across all Kubernetes nodes evenly:</p>
<pre class="lang-yaml prettyprint-override"><code>    spec:
      affinity:
        podAntiAffinity:
          preferredDuringSchedulingIgnoredDuringExecution:
          - weight: 100
            podAffinityTerm:
              topologyKey: kubernetes.io/hostname
              labelSelector:
                matchExpressions:
                - key: app
                  operator: In
                  values:
                  - api
</code></pre>
<p>However, I noticed that a new attribute <code>topologySpreadConstraints</code> was recently added to Kubernetes. What's the advantage of switching from using <code>affinity.podAntiAffinity</code> to <code>topologySpreadConstraints</code> in Kubernetes deployments? Any reasons to switch? What would that syntax look like to match what I am currently doing above?</p>

Justin
<h2>Summary</h2>
<p>TL;DR - The advantage of switching to <code>topologySpreadConstraints</code> is that you will be able to be more expressive about the <code>topology</code> or the <code>structure</code> of your underlying infrastructure for pod scheduling. Think of this is as a superset of what <code>affinity</code> can do.</p>
<p>One concept is not the replacement for the other, but both can be used for different purposes. You can combine <code>pod/nodeAffinity</code> with <code>topologySpreadConstraints</code> and they will be ANDed by the Kubernetes scheduler when scheduling pods. In short, <code>pod/nodeAffinity</code> is for <em>linear</em> topologies (all nodes on the same level) and <code>topologySpreadConstraints</code> are for <em>hierarchical</em> topologies (nodes spread across logical domains of topology). And when combined, the scheduler ensures that <em>both</em> are respected and <em>both</em> are used to ensure certain criteria, like high availability of your applications.</p>
<p>Keep on reading for more details!</p>
<h2>Affinities vs Topology Spread</h2>
<p>With <code>affinities</code> you can decide which <code>nodes</code> your <code>pods</code> are scheduled onto, based on a <code>node</code> <code>label</code> (in your case <code>kubernetes.io/hostname</code>).</p>
<p>With <code>topologySpreadConstraints</code> you can decide which <code>nodes</code> your <code>pods</code> are scheduled onto using a wider set of labels that define your <code>topology domain</code>. So, this is a generalisation of the simple <code>affinity</code> concept where all your nodes are &quot;on the same topology level&quot; - logically speaking - and on smaller scales, this is a simplified view of managing pod scheduling.</p>
<h2>An Example</h2>
<p>A <code>topology domain</code> is simply a logical unit of your infrastructure. Imagine you have a cluster with 10 nodes, that are logically on the same level and your <code>topology domain</code> represents simply a flat topology where all those nodes are at the same level.</p>
<pre><code>node1, node2, node3 ... node10
</code></pre>
<p>Now, imagine your cluster grows to have 20 nodes, 10 nodes in one Availability Zone (in your cloud provider) and 10 on another AZ. Now, your <code>topology domain</code> can be an Availability Zone and therefore, all the nodes are <em>not</em> at the same level, your topology has become &quot;multi-zonal&quot; now and instead of having 20 nodes in the same topology, you now have 20 nodes, 10 in <em>each</em> topological domain (AZ).</p>
<pre><code>AZ1 =&gt; node1, node2, node3 ... node10
AZ2 =&gt; node11, node12, node13 ... node20
</code></pre>
<p>Imagine it grows further to 40 nodes, 20 in each <code>region</code>, where each region can have 2 AZs (10 nodes each). A &quot;multi-regional&quot; topology with 2 types of <code>topology domains</code>, an AZ and a region. It now looks something like:</p>
<pre><code>Region1: =&gt; AZ1 =&gt; node1, node2, node3 ... node10
         =&gt; AZ2 =&gt; node11, node12, node13 ... node20
Region2: =&gt; AZ1 =&gt; node21, node22, node23 ... node30
         =&gt; AZ2 =&gt; node31, node32, node33 ... node40
</code></pre>
<p>Now, here's an idea. When scheduling your workload pods, you would like the scheduler to be aware of the topology of your underlying infrastructure that provides your Kubernetes nodes. This can be your own data center, a cloud provider etc. This is because you would like to ensure, for instance, that:</p>
<ol>
<li>You get an equal number of pods across regions, so your multi-regional application has similar capacities.</li>
<li>You can have an equal number of pods across AZs within a region, so AZs are not overloaded.</li>
<li>You have scaling constraints where you would like to prefer to scale an application equally across regions and so on.</li>
</ol>
<p>In order for the Kubernetes scheduler to be aware of this underlying topology that <em>you have setup</em>, you can use the <code>topologySpreadConstraints</code> to tell the scheduler how to interpret a &quot;list of nodes&quot; that it sees. Because remember, to the scheduler, all the nodes are just a flat list of nodes, there is no concept of a topology. You <em>can</em> build a topology by attaching special labels to nodes called <code>topologyKey</code> labels. For example, you will label <strong><em>each node</em></strong> in your cluster to make Kubernetes scheduler understand what kind of underlying &quot;topology&quot; you have. Like,</p>
<pre><code>node1 =&gt;  az: 1, region: 1
...
node11 =&gt; az: 2, region: 1
...
node21 =&gt; az: 1, region: 2
...
node31 =&gt; az: 2, region: 2
</code></pre>
<p>Now each node has been configured to be a part of &quot;two&quot; topological domains; each node must be in an <code>AZ</code> and in a <code>Region</code>. So, you can start configuring your <code>topologySpreadConstraints</code> to make the scheduler spread pods across regions, AZs etc. (your <code>topology domains</code>) and meet your requirements.</p>
<p>This is a very common use case that a lot of organisations implement with their workloads in order to ensure high availability of applications when they grow very large and become multi-regional, for instance. You can read more about <code>topologySpreadConstraints</code> <a href="https://kubernetes.io/docs/concepts/scheduling-eviction/topology-spread-constraints/" rel="noreferrer">here</a>.</p>
