kubectl Dry Run
On day-to-day operations in Kubernetes, I find myself frequently using the kubectl flag --dry-run=client
. I use it to generate definitions of objects in yaml by pairing it with -o yaml
. For example:
I learned this flag while studying for CKAD certification, and it was handy for the exam. However, I found it verbose at the time. “Why couldn’t I just pass --dry-run
?” I thought. 🤔 There were other arguments: none
and server
. I didn’t dive in much and either used the client
argument or didn’t specify the flag.
Fast forward to today, while watching the session The Hitchhiker’s Guide to Pod Security by Lachlan Evenson in KubeCon EU 2022, I found the usage of --dry-run
but this time with server
argument! 🤯 And it finally makes sense.
none, client and server⌗
--dry-run
supports three values. The help states the following:
--dry-run='none':
Must be "none", "server", or "client". If client strategy, only print the object that would be sent, without
sending it. If server strategy, submit server-side request without persisting the resource.
server⌗
In Lachlan’s talk, he uses the server
argument and not the client
one. Why? Because he wants to validate his object against the Pod Security admission controller1. That’s only possible if a request to the kube-apiserver goes through the typical stages up until persisting in storage.
Let’s repeat the same command I ran before, but this time with the server
argument:
As we can see, there is a lot more information, and it is similar to what we would persist if we created the resource without a dry run.
client⌗
On the other hand, with the client
argument, commands print the object’s definition, and there are no admission validations or mutations made to it.
Does this mean that whith this argument the command doesn’t communicate with the kube-apiserver at all? 🤔 Let’s find out!
Oops. It seems we can’t use client
argument without a kubeconfig/context set.
Now with a cluster running with kubeconfig and context set, let’s try to create a Service to expose a Deployment that does not exist:
No luck. Before generating the yaml for the Service, kubectl asks the kube-apiserver if the given Deployment we want to expose exists. I think we are convinced now.
Furthermore, I found that the result of --dry-run=client
is used when we opt for --dry-run=server
. We can observe this by increasing the verbosity level of kubectl.
Check the Request Body
of the truncated output. Sounds familiar, right? 😛
none⌗
Finally, none
is like not using the flag at all, meaning it’s not a dry run, and the request will be made and persisted if it succeeds.
Summarising⌗
To generate objects' definitions from commands like kubectl run
, kubectl expose
, kubectl create namespace
, or others, use --dry-run=client
.
To validate or observe mutations done by admission controllers and get more sense of how a given object would be stored, use --dry-run=server
.
Lastly, if we don’t want to do a dry run, we can either use --dry-run=none
or do not pass the flag.
-
You can read more about admission controllers in my previous post. ↩︎