Open LanDinh opened 2 years ago
Thank you for your message.
It is currently possible to manually create a Service to target the primary and replicas pods, as follows:
apiVersion: v1
kind: Service
metadata:
name: my-postgres
namespace: default
labels:
app: my-postgres
spec:
clusterIP: None
ports:
- protocol: TCP
port: 5432
selector:
app: my-postgres
Please let me know if that helps.
I mean, sure, this would work. But it also means that whenever I want to change something in my configuration (e.g. labels, namespace, ports, whatever), I would have to change it both in that file, as well as the kubegres resource - on top of that, it would mean that I depend on kubegres internals (e.g. I would depend on how the pods currently get created etc). It is never a good idea to have users depend on implementation details, especially not if the whole point of this project is to abstract away such details :) Hence the feature request.
The service example in my previous message assumed that you called your Postgres cluster "my-postgres" in the YAML of kind: Kubegres
.
The name of a resource is not an implementation details but part of the Kubernetes API recommendations. If you create a service which targets a resource by its name, it's an acceptable approach API point of view.
Moreover, Kubegres guarantees that the resource's name will not change.
What I recommend to do is either of the following options: 1) you can submit a PR with the feature that you suggested 2) you can create a service as I mentioned in my previous message 3) you can modify you client application so that the client calls randomly a connection on either the primary and replica services for read requests and calls the primary for write requests.
All the 3 options above are acceptable as a good practice.
Personally, I would go with the option 3 because the client application is already aware that it needs to call a Primary service for write requests. The logic to randomise the read requests between Primary and Replica service would be an easy and good solution to implement.
I think that there's a misunderstanding here. The fact that a resource has some kind of name is part of the Kubernetes API, yes. But the specific name kubegres chooses to give to the deployment it creates is an implementation detail - it could be the name that I specified, but it could also in the future change to only contain this as a prefix and add some other thing, etc (e.g. there could be multiple deployments that get created, in which case the prefix-approach would make sense - but as a user of kubegres, I should not need to know what it creates underneath, I should only need to know about the kubegres resource)
So I guess what I'm trying to say is: it should not be up to the user to know about anything hidden away behind the kubegres resource, which means that option 2) would be depending on the implementation details of kubegres = the implementation details of a third party dependency outside of the user's control.
The reason that makes option 1 difficult is that I'm exactly 0 familiar with golang :D
And option 3 is not necessarily easy do implement - most modern applications don't build database connections directly, but use ORMs to handle that for them. In my case, e.g., I use Django - there, it's easy to specify a single connection for reads, and a single connection for writes. But adding this randomized approach would mean:
I hope it makes more sense now why I posted this as feature request?^^
I disagree with your statement:
the specific name kubegres chooses to give to the deployment it creates is an implementation detail
Kubegres guarantees the backwards compatibility of all future versions with the name of a resource. That's because in the Kubernetes world a resource name is its identifier.
I hope that helps.
Yes, the name is the identifier in Kubernetes.
But the way kubegres (or any operator, for that matter) works is: you offer some kind of "Kubegres API" via the Kubegres resource. Which means that in order to interact with Kubegres, this Kubegres resource is the interface for it.
Why would a user need to know that Kubegres just so happens to create a single deployment only, and choose to use the same name for that deployment as was specified as name in the Kubegres resource? It could very well create multiple deployments per Kubegres resource - this is what I meant by implementation detail. Just like it e.g. creates multiple services already (for the master, and for the replicas). These services are required for connecting to postgres, in other words, they hide away any deployment / pod that they connect to - that's the whole point of using services, to not have to know implementation details like the number of pods in a deployment. There could be 1 pod, there could be 100 pods, in a single deployment. As a user of a service, we don't care, be cause the service handles all of that for us.
Similarly to not having to worry about the number of pods in a deployment by using a service, I don't want to worry about anything like deployments etc. created when using kubegres - otherwise, I could just create those deployments myself, right? (Sure, this is a huge simplification, as there's other things, too, that kubegres does, like handling replication etc - but it doesn't change the fact that the deployments are implementation details).
As an example: the kubegres documentation states:
The documentation doesn't state:
e.g. what if, at some point in the future, there will be the option to add some cronjob options to the kubegres resource to perform regular tasks? (think stuff like data retention, cleanup work, dumping the postgres logs, rather than just creating data backups, etc) This cronjob will need some pods to run, too. How will there be guarantee that the labels attached to the kubegres resource won't clash with that cronjob? Those cronjob pods will need to be tied to the kubegres resource somehow. Which means that my intuitive thinking would be that they, too would get all of the labels specified on the kubegres resource. But then, kubegres must be able to distinguish between the cronjob pods and the server pods, so that cleanup by the cronjob resource doesn't accidentally clean up the server, too, and vice-versa - so it will probably add some additional labels on top of that, etc. And suddenly, selecting by pods by only labels provided in the kubegres resource won't work anymore.
So what I'm trying to say here: there must be a clear line between "this is the API that kubegres offers", and "this is an implementation detail of kubegres". This is essential for any kind of API. This line is not at all clear as it is right now, and that's why I formed this feature request :)
Thanks a ton for this project! I have a feature request :)
According to the documentation, the following services get created:
<service>
pointing to the master<service>-replica
pointing to the replicasI however have the following use case: There are many read, but very, very few write operations. So I could of course simply use
<service>-replica
for the read operations to have multiple instances serving read-only data, but that would mean that there's one idle instance - the current master.In my case, I absolutely don't care who ends up serving read requests, but I want to save resources by distributing these requests among all instances that can serve them - meaning that I would need a service targeting both the master and the replicas :)
I hope that this feature will make it in at some point :)