-
-
Notifications
You must be signed in to change notification settings - Fork 1.9k
Feat: Run inside a cluster by evaluating incluster config #3088
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
base: master
Are you sure you want to change the base?
Conversation
c3b44c3
to
067ee0e
Compare
@derailed Hi. Do you need some more information from my side regarding 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.
@blaubaer Thank you for this update!
I think this needs a bit of TLC. Also we need docs to show users how to correctly configure and deploy their k9s pod and note that any context related actions are off the table.
Also we need to think about what happens when you run k9s in a pod related to any k9s customizations i.e skins, plugins, aliases, etc... How would one configure/load those in a given cluster and potentially reuse those across clusters?
internal/client/config.go
Outdated
} | ||
|
||
func (c *Config) isIncluster(cfg api.Config) bool { | ||
if (cfg.CurrentContext == "" || cfg.CurrentContext == incluster) && |
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.
Might as well return the bool expression. Also we could use a helper to check for empty i.e isEmpty(*string) bool
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.
internal/client/config.go
Outdated
func (c *Config) newInclusterContext() *api.Context { | ||
ns, _, _ := c.clientConfig().Namespace() | ||
if ns == "" { | ||
ns = "default" |
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.
Use const DefaultNamespace
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.
internal/client/config.go
Outdated
if ns == "" { | ||
ns = "default" | ||
} | ||
nc := api.NewContext() |
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.
nit: could just build the object and return it i.e return api.Context{Cluster: inCluster, Namespace: ns, ...}
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.
internal/client/config.go
Outdated
@@ -23,6 +23,8 @@ const ( | |||
|
|||
// UsePersistentConfig caches client config to avoid reloads. | |||
UsePersistentConfig = true | |||
|
|||
incluster = "incluster" |
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.
nit: inClusterConfig
vs incluster
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.
internal/client/config.go
Outdated
if c, ok := cfg.Contexts[n]; ok { | ||
return c, nil | ||
} | ||
|
||
if n == incluster { | ||
nc := c.newInclusterContext() |
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.
no need to create a var here just return 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.
Ok.
Kubernetes itself documents everything required on the Service Account documentation page. I would link to this site. This change of the code just makes k9s works like every other library which is using the go kubernetes SDK. k9s is just special because of the context switch stuff, which leads to that this does not work in the first place. With this adjustments it should work transparently, like a kubeconfig with just once context inside. I've added a proposal to the |
Good question. I suppose this is like running k9s inside a Docker container. Context: Currently I work in environments where people are creating base images (like with kubectl and customized ones with k9s, because k9s does currently not support incluster) with all common stuff are already added to the customized image. Everyone who is accessing them have all those configuration and features are available. Nothing is persisted, like on a local computer - with intention. The people should rely on to have always a fresh and proofed environment. Therefore, the most recommend way might be the same here, for me: Build a derivate of the image with all customizations the people want and/or (if this is really required) mount persistent storage. Did I address your point, or did I get something wrong? |
Background
Assuming you want to execute k9s inside a POD directly inside the Kubernetes cluster you want to manage with k9s, currently you need to create a dedicated kubeconfig file for this.
But if the POD (k9s is running inside) is configured with a ServiceAccount, also the incluster config is available. If the Go client library is used (as k8s does), this is also automatically evaluated.
k9s has the feature to switch contexts. For this internal/client/config.go is doing currently some non standard logic to makes this possible. It assumes that the fields
Clusters
,AuthInfos
,Contexts
andCurrentContext
ofk8s.io/client-go/tools/clientcmd/api.Config
has always values, which is not the case in case of incluster config; the same applies for mostly all fields ofk8s.io/cli-runtime/genericclioptions/ConfigFlags
.Summary of changes
This adjustment detect if all of those fields are empty and creates in this case a kind of mock context to be compatible with the regular behavior of k9s. It is important to note: The Go client library only offers the possibility to either run with a regular kubeconfig file OR incluster config; it cannot both together.
Note on testing
The Go client library evaluates the fixed environment variables
KUBERNETES_SERVICE_HOST
andKUBERNETES_SERVICE_PORT
, this is not a problem to set inside tests. But it also evaluates the following files:/var/run/secrets/kubernetes.io/serviceaccount/ca.crt
/var/run/secrets/kubernetes.io/serviceaccount/token
/var/run/secrets/kubernetes.io/serviceaccount/namespace
(in some cases also environment variablePOD_NAMESPACE
applies)... the problem with this files, for regular testing they're located in areas where a regular user cannot write to and tests cannot be executed concurrently - and you cannot changes this location, they are hardcoded. Therefore I've tested everything locally and ensured all the other behaviors (with kubeconfig files) works as before.
User noticeable change
As a consequence, if now k9s is started inside a POD which does have a correct configured ServiceAccount, it works without any configurations.