<p>I have the following anti-affinity rule configured in my k8s Deployment:</p>
<pre><code>spec:
  ...
  selector:
    matchLabels:
      app: my-app
      environment: qa
  ...
  template:
    metadata:
      labels:
        app: my-app
        environment: qa
        version: v0
    spec:
      affinity:
        podAntiAffinity:
          requiredDuringSchedulingIgnoredDuringExecution:
          - labelSelector:
              matchExpressions:
              - key: app
                operator: In
                values:
                - my-app
            topologyKey: kubernetes.io/hostname
</code></pre>
<p>In which I say that I do not want any of the Pod replica to be scheduled on a node of my k8s cluster in which is already present a Pod of the same application. So, for instance, having:</p>
<pre><code>nodes(a,b,c) = 3
replicas(1,2,3) = 3
</code></pre>
<p><strong>replica_1</strong> scheduled in <strong>node_a</strong>, <strong>replica_2</strong> scheduled in <strong>node_b</strong> and <strong>replica_3</strong> scheduled in <strong>node_c</strong></p>
<p>As such, I have each Pod scheduled in different nodes.</p>
<p>However, I was wondering if there is a way to specify that: &quot;I want to spread my Pods in at least 2 nodes&quot; to guarantee high availability without spreading all the Pods to other nodes, for example:</p>
<pre><code>nodes(a,b,c) = 3
replicas(1,2,3) = 3
</code></pre>
<p><strong>replica_1</strong> scheduled in <strong>node_a</strong>, <strong>replica_2</strong> scheduled in <strong>node_b</strong> and <strong>replica_3</strong> scheduled (<strong>again</strong>) in <strong>node_a</strong></p>
<p>So, to sum up, I would like to have a softer constraint, that allow me to guarantee high availability spreading Deployment's replicas across at least 2 nodes, without having to launch a node for each Pod of a certain application.</p>
<p>Thanks!</p>

Luca Tartarini
<p>I think I found a solution to your problem. Look at this example yaml file:</p>
<pre><code>spec:
  topologySpreadConstraints:
  - maxSkew: 1
    topologyKey: kubernetes.io/hostname
    whenUnsatisfiable: DoNotSchedule
    labelSelector:
    matchLabels:
      example: app
  affinity:
    nodeAffinity:
      requiredDuringSchedulingIgnoredDuringExecution:
        nodeSelectorTerms:
        - matchExpressions:
          - key: kubernetes.io/hostname
            operator: In
            values:
            - worker-1
            - worker-2
      preferredDuringSchedulingIgnoredDuringExecution:
      - weight: 50
        preference:
          matchExpressions:
          - key: kubernetes.io/hostname
            operator: In
            values:
            - worker-1
</code></pre>
<p><strong>Idea of this configuration:</strong>
I'm using nodeAffinity here to indicate on which nodes pod can be placed:</p>
<pre><code>- key: kubernetes.io/hostname
</code></pre>
<p>and</p>
<pre><code>values:
- worker-1
- worker-2
</code></pre>
<p>It is important to set the following line:</p>
<pre><code>- maxSkew: 1
</code></pre>
<p>According to the <a href="https://kubernetes.io/docs/concepts/workloads/pods/pod-topology-spread-constraints/#spread-constraints-for-pods" rel="nofollow noreferrer">documentation</a>:</p>
<blockquote>
<p><strong>maxSkew</strong> describes the degree to which Pods may be unevenly distributed. It must be greater than zero.</p>
</blockquote>
<p>Thanks to this, the difference in the number of assigned feeds between nodes will always be maximally equal to 1.</p>
<p>This section:</p>
<pre><code>      preferredDuringSchedulingIgnoredDuringExecution:
      - weight: 50
        preference:
          matchExpressions:
          - key: kubernetes.io/hostname
            operator: In
            values:
            - worker-1
</code></pre>
<p>is optional however, it will allow you to adjust the feed distribution on the free nodes even better. <a href="https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/#node-affinity" rel="nofollow noreferrer">Here</a> you can find a description with differences between: <code>requiredDuringSchedulingIgnoredDuringExecution</code> and <code>preferredDuringSchedulingIgnoredDuringExecution</code>:</p>
<blockquote>
<p>Thus an example of <code>requiredDuringSchedulingIgnoredDuringExecution</code> would be &quot;only run the pod on nodes with Intel CPUs&quot; and an example <code>preferredDuringSchedulingIgnoredDuringExecution</code> would be &quot;try to run this set of pods in failure zone XYZ, but if it's not possible, then allow some to run elsewhere&quot;.</p>
</blockquote>
