Because of IP limitation, I cannot expose replicaset with LoadBalancer, so I decided to go with NodePort. I’m running on GKE 1.18 with Percona operator 1.9.0.
I got the CR here:
And expose replicaset only as follow (sharding disabled):
3 pods are created but restarts constantly with liveness failed: unreachable server error.
Operator logs show "msg":"failed to reconcile cluster","Request.Namespace":"percona-mongodb","Request.Name":"my-cluster-name","replset":"rs0","error":"dial:: failed to ping mongo: context deadline exceeded".
The operator seems to use <node_internal_ip>:<exposed_node_port_ip> as host name to connect to mongo instances. Which is somewhat expected, although I’d expect it to use the node’s external IP.
I tried to connect to one of the mongo pod with: kubectl exec --stdin --tty my-cluster-name-rs0-0 -- /bin/bash
Then tried to connect to the mongod running on the same pod with:
mongo --host <service_internal_ip> --port 27017 -u <username> -p <password> → This also worked.
mongo --host <cluster_internal_ip> --port <exposed_node_port> -u <username> -p <password> → This DOESN’T worked. I got a connection refused error.
The 2 first connection worked as expected but the last one didn’t. To be clear, the <cluster_internal_ip> is from the pod’s host IP (or from kubectl get nodes -owide) and the <exposed_node_port> is from the nodePort field in the pod’s service.
By curiosity, I tried to run a single percona server:
Then I tried all the connection above again. Now all of them worked as expected, including using node’s IP and node port.
So I don’t know why mongo instances in replicaset refused the nodeport connection but a standalone mongo instance did not. Anyway, because of the connectivity issue, the cluster was failed to be reconciled.
Have you ever experienced anything similar? What can be the cause of this?
I also noticed that the bug you mentioned had this PR merged. However, I am using the operator built from the main branch, not the earlier 1.9.0 tag. So the PR actually presents in my deployment.
But the ticket is still in progress, right? I can mention this post in the ticket, there are some extra information here.
I found something here. In the reconcile loop, the operator compare the last hash and service’s metadata with the current spec to decide whether it should update the service.
However in some cases, the NodePort service - after being created, will be populated with additional annotations. In my case it’s field.cattle.io/publicEndpoints which contains the public node’s IP and the nodeport. In consequence, the service’s metadata isn’t the same as the spec and then the service will be updated (while it shouldn’t), making constantly changing ports every time the operator fires a reconcile loop.
Also because of the changing port, connection error is inevitable.
Wow @vhphan, thank you for taking initiative and investigating the issue. AFAIU, that annotation is from Rancher but you’re using GKE. Any idea why that annotation is appended to the service on GKE?
BTW, that’s probably why I couldn’t reproduce the issue. I was trying on GKE.
I believe it’s because my GKE cluster was provisioned by a third-party job in my company, and they somehow mix some Rancher scheduler in there. But anw, I think comparing annotation like that leaves a potential bug in the future because extra annotations added by scheduler isn’t rare.
Secondly that annotation is calculated and dynamically injected, I cannot know beforehand what the host IP and port will be. So whatever I put in the CR will be replaced.
What we want to watch is essentially what users put in the CR, right? So I suggest, at least for reconciling service, that we can compare the annotation field from the CR. I suppose it can be done by comparing the current value with the old value in kubectl.kubernetes.io/last-applied-configuration.