I have a kubernetes cluster which is spread across 2 zones- zone1 and zone2.
I have 2 applications- a web application and a database. The web application's configurations are stored in the database. Both the application as well as the database are deployed as stateful applications.
The idea is to deploy 2 replica sets for web application (application-0 and application-1) and 2 replica for database (database-0 and database-1). application-0 points to database-0, application-1 points to database-1.
Pod anti-affinity has been enabled. So preferably application-0 and application-1 will not be in same zone. Also database-0 and database-1 will not be in same zone.
I want to ensure application-0 and database-0 are in the same zone. And application-1 and database-1 are in another zone. So that the performance of the web application is not compromised. Is that possible?
For your database
metadata:
labels:
app: db
spec:
affinity:
podAntiAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
- labelSelector:
matchExpressions:
- key: app
operator: In
values:
- db
topologyKey: "kubernetes.io/hostname"
For your web-app
metadata:
labels:
app: web-app
spec:
affinity:
podAntiAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
- labelSelector:
matchExpressions:
- key: app
operator: In
values:
- web-app
topologyKey: "kubernetes.io/hostname"
In addition, you add podAffinity
to your web-app (not database) to co-locate it on nodes with your database.
With podAffinity
added for your web-app:
metadata:
labels:
app: web-app
spec:
affinity:
podAntiAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
- labelSelector:
matchExpressions:
- key: app
operator: In
values:
- web-app
topologyKey: "kubernetes.io/hostname"
podAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
- labelSelector:
matchExpressions:
- key: app
operator: In
values:
- db
topologyKey: "kubernetes.io/hostname"
Result
With both PodAntiAffinity
and PodAffinity
you will get web-app-X co-located with db-X.
web-app-1 web-app-2
db-1 db-2
See the Kubernetes documentation has an example to co-locate cache with app on nodes about PodAffinity
and ´PodAntiAffinity`.
To address one specific instance of a StatefulSet, create an Headless Service with ClusterIP: None
for each db replica. This allow your web-apps to connect to a specific instance.
Access the closest db instance
Now your web-apps can connect to db-0 and db-1 via the headless services. Let your web-apps connect to both initially, and use the one with shortest response time - that one is most likely the one on the same node.
Just like you used anti-affinity rules to avoid provisioning both apps in the same zone, you can use affinity to provision app-0 only in the zone where db-0 exists, technically that would mean that you could drop anti affinity from app completely as if you tell it to schedule only in the zone of db, and db is defined to spread zones with anti-affinity, you inherit the distribution from the database part.
If you want to have strict separation of the workloads over the two zones - I'd suggest using nodeSelector on a node's zone.
A similar result is possible with pod affinity but it's more complex and to get the clear split you describe. You'd need to use the requiredDuringScheduling / execution rules which are usually best avoided unless you really need them.