Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Kubernetes connector #434

Merged
merged 9 commits into from Oct 4, 2020
Merged

Conversation

skarsaune
Copy link
Contributor

To be reviewed after #431:
Support using Jolokia via kubernetes client

@rhuss
Copy link
Member

rhuss commented Mar 24, 2020

Thanks !

Good news: Looks like I can work on the integration to master towards the end of the week.

@skarsaune skarsaune force-pushed the kubernetes-connector branch 2 times, most recently from 9f7e854 to bbd595a Compare April 7, 2020 18:41
@skarsaune skarsaune marked this pull request as ready for review June 19, 2020 17:25
@skarsaune
Copy link
Contributor Author

@rhuss : Ready for review now that #431 is merged

@rhuss
Copy link
Member

rhuss commented Jun 22, 2020

Thanks @skarsaune ! I have a busy week ahead and will revisit this PR on friday. Maybe in the meantime you could give the error messages a review again and e.g. switch from the "I" perspective to a more neutral wording as in the previous PR ? mostly to align to the style of the other error messages ...

@skarsaune
Copy link
Contributor Author

Thanks @skarsaune ! I have a busy week ahead and will revisit this PR on friday. Maybe in the meantime you could give the error messages a review again and e.g. switch from the "I" perspective to a more neutral wording as in the previous PR ? mostly to align to the style of the other error messages ...

Have adapted error messages and corrected some javadoc.

@skarsaune skarsaune force-pushed the kubernetes-connector branch 3 times, most recently from 625fc9b to 6489844 Compare June 24, 2020 19:55
Copy link
Member

@rhuss rhuss left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for this connector, really nice idea !

Looks good in general except that I would not allow connecting to a pod when you find multiple matchings one:

  • More than one pod serves by a service and the connectors is in service mode
  • More than one pod selected by pod pattern

The reason is, that in every pod another JVM is running so when you access e.g. a service with multiple pods then ever Jolokia requests might hit another JVM, so that any result returned is really meaningless. JMX metrics are only useful in the context of a single JVM, so for accessing such a JVM you need to select a single pod.

Also I'm not clear what happens when a connected Pod dies. Does the connector then goes in an error state ? Or does it reconnect, then potentially connected to a totally different Pod ?

In short, I would not allow services to be specified and I would enforce a pod name to connect to. Maybe a pattern for pods, but then for a reconnect you can still get a different pod.

client/kubernetes/pom.xml Outdated Show resolved Hide resolved
String actualNamespace = null;
String actualName = null;
for (final V1Service service : api
.listServiceForAllNamespaces(null, null, false, null, null, null, null, 5, null)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This can be a potentially very expensive operation. There is definitely a service list command which already restricts to a certain namespace (which I think is the usual case).

Tbh, for a service I wouldn't allow pattern matching as the service is user managed (not so much for a pod). I would require the service + namespace as mandatory.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

btw, the fabric8 client doesn't have this ugly, 9 params arguments method style (which is also why I would prefer the fabric8 client)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I can make namespace mandatory

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you could default to the "current" namespace if the namespace is not given. Not sure how to model 'optional' parameters in the JMX connector URL.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok, I'm used to always specify namespace in operations or --all-namespaces. Wondering if using default namespace will be a source of confusion. If for instance test and prod run in the same cluster I'm inclined to make namespace mandatory.

CoreV1Api api) throws MalformedURLException {
try {
for (V1Pod pod : api
.listNamespacedPod(actualNamespace, false, null, null, null, null, null, null, 5, false)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

there is definitely a way to query pods directly by using the service selector directly for a query.

.getItems()) {
for (V1OwnerReference ref : pod.getMetadata().getOwnerReferences()) {
//pod that references the service
if (ref.getName().equals(actualName)) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A Pod is not owned by a Service but by e..g a Deployment, StatefulSet or a Job. So this will be true only if the deployment is called like the service which by no means is a given.

Another reason to select the pods directly with the service's label selector to find the affected pods.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Returning randomly any of the pods backing a service is very dangerous. See the review comment for why using a service for a connector is generally a bad idea.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am aware of this, and we can document it. It is basically the same problem as when accessing Jolokia over a load balancer. It is not optimal, and can be confusing, but if it is the only way then I can still be valuable if you know what you are doing. Use cases such as executing an operation where you are not concerned with what pod you hit. But I guess the argument is that if you have access to services you also have access to pods, hence the load balancer comparison is not really justified. In light of that service support should perhaps be dropped.

String actualNamespace = null;
String actualPodName = null;
for (final V1Pod pod : api
.listPodForAllNamespaces(null, null, false, null, null, null, null, 5, null)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same argument above: In order to find a specific pod without any ambiguity, you shouldn't use patterns or at least throw an error if multiple are found. And is you don't have a pattern you can do a direct select. Listing all pods in all namespaces is a quite expensive operation.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There are 2 usecases.

  1. You want to connect to a specific pod for investigation. Use the exact pod name.
  2. You want to connect to any given pod of a service, as they typically display the same behaviour. One pod will be selected at connect time. When disconnected it will naturally stop working, but it depends a bit on the tool behaves, whether stats are not updated or you get explicit errors. A reconnect will connect to the first matching pod.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

2. as they typically display the same behaviour

Are you sure ? As pods are spread over different nodes and since metric information is stateful, I don't regard the pods as interchangeable wrt/ to metrics. Consider os information from MBean, MBeans that access file systems etf. In a multi-arch cluster the different pods can even run on different architectures (arm vs i86 etc)

Wouldn't a user be surprised that the memory graph make a jump in jconsole if a reconnection happens ? There is no indication by JMX that it is now connected to another JVM.

However, I see your use case in favor of convenience. One idea could be that only when going over a service or deployment the JMX connector URL that kind of roulette applies. That way a user has to know what she does. However when using the 'pod' variant of the URL, then a single pod has to be selected. (that would require to also allow a "deployment", "replicaset" (or "rs"), "statefulset" and "job" kind of JMX connectors (but happy to start with service and deployment as they are probably the most common).

wdyt ?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the risks of using wildcards in pod url can be documented. In my current project the last 2 years shows very homogenous behavior over pods and setup is identical, so personally I would like the convenience of a URL that you can store across deploys. For instance if I inspect a pod or port forward, I tend to pick the top of the list. For JMC specifically I am thinking of both wizard / browser to interactively connect to pods, and alternatively probe pods in cluster for Jolokia (if user has configured it to). I could look at the possibility of interactively or always hard wire to a given pod.

public class KubernetesJmxConnector extends JolokiaJmxConnector {

private static Pattern POD_PATTERN = Pattern
.compile("/api/v1/namespaces/([^/]+)/pods/([^/]+)/proxy/(.+)");
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe instead of exposing the K8A API path literally a more concise and shorter JMX connector URL would make sense, something like service:jmx:kubernetes:pod/mynamespace/mypodname:port/path and service:jmx:kubernetes:service/mynamespace/mysvname:port/path and then translate that to the full K8s API path ?

This might be more convenient for the user on expense to be less flexible (but I'm pretty sure that the API path format won't change any time soon for Kubernetes)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice input. Will think about it.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Have done some investigation. Can drop the /api/v1 and proxy from the path to reduce the boilerplate. Apart from that I have not come up with any more intuitive path. The result would be service:jmx:kubernetes:/namespaces/myns/pods/mypod/path

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Still, wondering if we should also drop "namespaces" and "pods" , it becomes less self documenting but briefer?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, if we skip the connection to the K8s API syntax, then I don't see a reason why not make it even shorter (as you can't reverse the path parts anyway, that style of 'named' arguments doesn't make much sense imo)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So service:jmx:kubernetes:///mynamespace/mypod/path then? Sure, can change.

@skarsaune skarsaune force-pushed the kubernetes-connector branch 2 times, most recently from 46b44ee to 4e8171c Compare August 30, 2020 17:57
…seful connections, example activemq, jvms with jvm agent
String namespace = matcher.group(1);
String podPattern = matcher.group(2);
String path = matcher.group(3);
String namespace = matcher.group("namespace");
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note, this requires Java 1.7 , I can happily replace with numeric groups, however was not sure if Java 1.6 is feasible anymore (?)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We abandoned Java 1.6 already afair (my gosh, really not deep in Jolokia anymore :(.

Lets keep it ...

@skarsaune
Copy link
Contributor Author

With the last 2 additions my use cases work satisfactory now. Things that would be good for review.

  • Authorization through proxy with custom header - any more elegant ideas? I did a quick PoC on using cookies, however that turned out very hard with the http client setup in fabric8
  • Enable specifying port - whether the JMX url still is intuitive

No further changes in the pipeline, apart from review input.

@rhuss
Copy link
Member

rhuss commented Aug 31, 2020

Cool, thanks @skarsaune ! Let me try to get this in over the week and then do a release afterwards (finally)

@skarsaune
Copy link
Contributor Author

@rhuss : As far as I can see everything should be resolved now, but the varying conversations overlap. Should I mark them as resolved? Or is there a status on what remains to proceed?

@rhuss
Copy link
Member

rhuss commented Oct 4, 2020

@skarsaune I would say, let's merge see it and next weekend I can make a new release then. Currently I'm more in feedback-only mode with Jolokia, so happy to release and work on any feedback that is coming up then.

@rhuss rhuss merged commit a8bf5f1 into jolokia:master Oct 4, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

2 participants