Scenario
I’m using the CQRS pattern for REST services that deal with Sales as in the diagram below. (The question focuses on the REST services.)
On K8S I have:
- A microservice for GET endpoints (queries) that runs on a given pod.
- Another microservice for POST and PUT endpoints (commands) tat runs on a different pod.
Both operate on the same resource: Sales. The natural URL mapping would be:
- GET endpoints on
mydomain.com/api/sales/*
should go to the first pod. - POST and PUT endpoints on
mydomain.com/api/sales/*
should go to the second pod.
Ingress
To deploy these two microservices to a K8S cluster, I define a separate Service
and Deployment
for each. Then I create an Ingress
definition to route requests to the Services:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: my-ingress
spec:
rules:
- host: mydomain.com
http:
paths:
- path: /api/sales
pathType: Prefix
backend:
service:
name: sales-queries-service
port:
name: 80
- path: /api/sales
pathType: Prefix
backend:
service:
name: sales-commands-service
port:
name: 80
ingressClassName: ingress-nginx
Problem
The ingress definition above does not work because it has the mapping of the same path /api/sales
to two different services. As such, it’s non deterministic.
It’s a feature desired by many that the ingress spec can allow the specification of the HTTP methods. In fact, when I asked ChatGPT it suggested adding this snippet to my ingress yaml, but unfortunately it’s a parameter that doesn’t exist… yet.
httpMethods:
- GET
Is there any other option to specify the routing in a K8S cluster (without installing an API gateway product)?
2
Answers
I think it is better to route based on the URL (like /queries/xxxx and /commands/xxxx) and not on the HTTP verb/method because it might be useful to be able to do GET requests to the command service.
For example, you might want to do GET requests to the /health endpoint for health checks.
Or if you do want to do some specific READ queries against the write sides, yes, that is actually OK to do for some specific scenarios when you need an immediately consistent answer.
Just as Greg says:
"Your aggregate state IS a read model just one that often has a very short life time and is used to process transactions"
https://twitter.com/gregyoung/status/1275467796177137670
The key here is to be agile, flexible and don’t be too strict.
You can Install and Traefik and use IngressRoutes which supports Http method routing.
so you can Method() rule to point your requests toward desired services.