-
Notifications
You must be signed in to change notification settings - Fork 304
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
Use official Kubernetes python client #41
Conversation
Thank you for working on this! This looks great, am reviewing it now. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It looks ok to me, but I'd like the following changes:
- Make using kubernetes client be a separate commit from adding more features. Ideally the new features would be a different PR, but separate commits are also ok. This makes it easier to merge, review and test.
- Fix the tests.
This is great work - thanks for taking it on!
kubespawner/objects.py
Outdated
pod.metadata = V1ObjectMeta() | ||
pod.metadata.name = name | ||
pod.metadata.labels = {} | ||
pod.metadata.labels.update({"name": name}) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why not just have this be one line?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
pod.metadata.labels = labels.copy()
pod.metadata.labels['name'] = name
seems clearer and possibly faster?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, thats better. Done
kubespawner/objects.py
Outdated
@@ -11,13 +33,15 @@ def make_pod_spec( | |||
run_as_uid, | |||
fs_gid, | |||
env, | |||
node_selector, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you split out the additional features into separate commits (or even a separate PR) so it's easier to review? I'll leave commnets about them here too tho
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I have removed the node_selector
things I will make another PR for that.
kubespawner/objects.py
Outdated
notebook_container.resources = V1ResourceRequirements() | ||
notebook_container.resources.requests = {"cpu": cpu_guarantee, "memory": mem_guarantee} | ||
notebook_container.resources.limits = {"cpu": cpu_limit, "memory": mem_limit} | ||
# notebook_container.liveness_probe = V1Probe() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's get the commented code out? Also would be nice if it were a separate commit :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, i wanted to have it there temporally in case you wanted it on this PR. It's gone.
kubespawner/spawner.py
Outdated
) | ||
|
||
working_dir = Unicode( | ||
"/home", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think the default should be None, which should make it use whatever is specified in the Docker image (which is the current default). Should probably be called singleuser_working_dir as well (I've been trying to do that for all new properties)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah yes, I agree that its a better default. Also renamed the property to singleuser_working_dir
.
kubespawner/spawner.py
Outdated
@@ -109,6 +108,26 @@ def _namespace_default(self): | |||
""" | |||
).tag(config=True) | |||
|
|||
|
|||
node_selector = Dict( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can this be a separate commit / PR? We need to be careful to support both simple property based selectors and more complex ones...
I have fixed the tests and removed the You can probably Squash and Merge this one if you want to keep history clean about changes. |
kubespawner/spawner.py
Outdated
@@ -109,6 +108,13 @@ def _namespace_default(self): | |||
""" | |||
).tag(config=True) | |||
|
|||
singleuser_working_dir = Unicode( | |||
help=""" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
set the default explicitly to None and also allow_none?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
(I'll take a more detailed look + test on Monday!) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
More minor changes that I missed on first round - sorry about that! Otherwise it looks good, and I want us to test this on a couple of different k8s clusters before merging. What cluster have you been testing this against? GKE or minikube?
kubespawner/objects.py
Outdated
notebook_container.ports.append(port_) | ||
notebook_container.env = [] | ||
for key, value in env.items(): | ||
env_ = V1EnvVar() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This could just be:
notebook_container.env = [V1EnvVar(k, v) for k, v in env.items()]
no? https://github.com/kubernetes-incubator/client-python/blob/84bf6cc9dc206cb3314a5b4d2fa1a9c2fa2c5137/kubernetes/client/models/v1_env_var.py#L24 says it takes the properties as params to init
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, thats good. Done
kubespawner/spawner.py
Outdated
@@ -433,6 +442,15 @@ def _hub_connect_port_default(self): | |||
""" | |||
) | |||
|
|||
user_storage_match_labels = Dict( | |||
help=""" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What's the default for this? I'm trying to understand what exactly this feature does - does it allow binding to an existing PVC that isn't created by this? Under what circumstances would I use this?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So by default its nothing so the default behavior should be the same.
No, it still creates a PVC spec as it was doing before. This new property basically it just passes the matchLabels
field from the PVC spec so its possible to filter between existing PV. Lets say you have multiple PV you can select which one you want.
From: https://kubernetes.io/docs/concepts/storage/persistent-volumes/ - PersistentVolumeClaims section.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah, so is it for the case where the PV is not dynamically created by using a StorageClass?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ok! I think we should set the default explicitly, and explain why you should use this and when in the help. The current help text isn't sufficient, IMO.
Also in the future, it'd be nice to have these as a separate PR, rather than as part of one :) Makes it easier to review.
I'll do some testing and try to get this merged tomorrow!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The more I think about it, the more I think we should take it out now. I think way to include this would be:
- Write a 'LabelSelector' trait type, that can be used to express both matchLabels and matchExpressions
- Use that for this and for nodeSelectors
I think that's the cleanest and most future compatible way of doing this. what do you think?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It should probably also support expanding {username} and friends in the label values, to provide more targeted matching. Let's definitely get it out of this PR?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok, its gone now. Yes, it was for that case where you already had existing PVs. This is the way I have always used PV + PVC, more manual than the automatic creation.
# This makes sure that we don't accidentally give access to the whole | ||
# kubernetes API to the users in the spawned pods. | ||
# See https://github.com/kubernetes/kubernetes/issues/16779#issuecomment-157460294 | ||
hack_volumes = [{ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this belongs here, and not in the make_pod_spec. We could add an option to allow service account access in here when it's here, and this also keeps the make_pod_spec agnostic about what we do. Someone has actually forked this to make this disabling optional, and that's easier to do when this is here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes I agree with keeping make_pod_spec
independent of the hack i just wanted to keep the kubernetes_client
code in one place. I put it back now.
cmd=real_cmd, | ||
run_as_uid=singleuser_uid, | ||
fs_gid=singleuser_fs_gid, | ||
env=self.get_env(), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Passing named args is much cleaner, thank you for moving it!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍
kubespawner/objects.py
Outdated
|
||
pod.spec.containers = [] | ||
|
||
notebook_container = V1Container() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We could also construct notebook_container this way (passing params to init) since that supports it too (https://github.com/kubernetes-incubator/client-python/blob/84bf6cc9dc206cb3314a5b4d2fa1a9c2fa2c5137/kubernetes/client/models/v1_container.py). I'm not super attached to it here, though - because there's a lot more params.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes I agree, personally I don't like to pass 3+ params to a function.
This changes I have only tested on minikube but I still yet to see something in k8s that doesn't work from minukube to GCP. |
kubespawner/spawner.py
Outdated
@@ -433,6 +442,15 @@ def _hub_connect_port_default(self): | |||
""" | |||
) | |||
|
|||
user_storage_match_labels = Dict( | |||
help=""" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The more I think about it, the more I think we should take it out now. I think way to include this would be:
- Write a 'LabelSelector' trait type, that can be used to express both matchLabels and matchExpressions
- Use that for this and for nodeSelectors
I think that's the cleanest and most future compatible way of doing this. what do you think?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Tested locally, is ok! \o/
Thank you for the patch! |
I'm going to test this now with https://github.com/jupyterhub/helm-chart |
I filed #43 with further options on how to move forward getting rid of our custom code in favor of the official client. |
This PR changes the
objects.py
to use the official python kubernetes client. Hopefully this makes k8s specs creation a little easier by adding a pure python dependency.This also solves #6 by adding a simple
nodeSelector
to the Pod spec.I also tried to solve #1 but using
/user/{userid}
as a path for liveliness return a 404 because of Hub redirects or something (not 100% sure) any other ideas on how to check status of the Notebook server?