kubectl is the Kubernetes command line tool (CLI) that allows you to run commands against Kubernetes clusters. kubectl can be used to deploy applications, inspect and manage cluster resources, and view logs.
In a platform as large as Kubernetes, you will find commands that are similar but serve slightly different purposes. kubectl <terminal inline>apply<terminal inline> and <terminal inline>create<terminal inline> commands are two different approaches for creating Kubernetes resources. In this article, we will explore what these commands do, what the key differences between them are, and when to use each.
Imperative and Declarative
Before we discuss <terminal inline>apply<terminal inline> and <terminal inline>create<terminal inline>, it’s important to understand the difference between the imperative and declarative approaches.
In the imperative approach, we need to specify what and how to perform a task.
If the task is preparing a sandwich, for example, you would explain the items needed as well as the step-by-step instructions.
In the declarative approach, we need to specify what to do but not how to do it.
In this case, you would only explain the items needed for the sandwich, without the instructions.
Resource Creation
How do the imperative and declarative approaches fit into a Kubernetes context? <terminal inline>kubectl apply<terminal inline> and <terminal inline>kubectl create<terminal inline> are two different approaches in creating resources or updating resource configurations in the Kubernetes cluster environment.
Both these commands accept configuration changes either from the file or stdin, and both accept JSON and YAML file formats.
kubectl create
<terminal inline>kubectl create<terminal inline> is for imperative management. In this approach, you tell the Kubernetes API what you want to create, replace, or delete.
In simpler terms, <terminal inline>create<terminal inline> produces a new object (previously nonexistent or deleted). If a resource already exists, it will raise an error.
kubectl apply
<terminal inline>kubectl apply<terminal inline> is part of the declarative management approach in which changes that you may have applied to a live object (i.e., through scale) are “maintained” even if you apply other changes to the object.
<terminal inline>apply<terminal inline> makes incremental changes to an existing object by defining what we need. If a resource already exists, it will not raise an error.
apply vs create: Attributes
How They Work
For this example, let’s use the YAML file below to create a Kubernetes pod.
Now create the pod using the imperative approach with <terminal inline>kubectl create<terminal inline>:
Let’s verify the pod status along with labels:
Now we’ll edit the YAML file and add an extra label to it (environment: local):
Once again, use the imperative approach to apply the changes:
Note the error message saying the resource <terminal inline>kubectl-create-vs-apply-demo<terminal inline> already exists.
Now we’ll do the same operation using the declarative approach with <terminal inline>kubectl apply<terminal inline>:
This time, the resource was configured. Let’s verify the changes we made.
You can see that the new label <terminal inline>environment: local<terminal inline> has been applied to the pod.
CI/CD Issues
The differences between these commands can impact your CI/CD pipeline. As we saw above, <terminal inline>kubectl create<terminal inline> can only be used if there are no existing resources and you want to create new resources.
If the resource is already created and running, <terminal inline>create<terminal inline> will raise an error, thereby halting your CI/CD. To avoid that, use the <terminal inline>kubectl get<terminal inline> command to check if there is already an existing resource; then use <terminal inline>kubectl apply<terminal inline> to update to the latest configuration.
Shell Scripts
There will be many scenarios where you will want to execute shell scripts after the launch of the resource. You can provide shell scripts as part of your configuration file, which can be triggered just after the resource is created. These commands, once configured, cannot be updated when the resource is already running.
Be aware that these commands can be executed only via <terminal inline>kubectl create<terminal inline>. kubectl won’t allow you to update these commands via <terminal inline>kubectl apply<terminal inline> if the container is already running. We’ll use a simple example to demonstrate.
We will create a pod with a simple <terminal inline>echo<terminal inline> command.
Let’s create the pod using the above configuration.
Now update the <terminal inline>echo<terminal inline> command and apply the changes to the pod.
Apply the changes to the pod using the above configuration.
So <terminal inline>kubectl apply<terminal inline> failed with the stated reason that pod updates cannot change fields other than container specs.
Which Should You Use?
Choosing to use either <terminal inline>create<terminal inline> or <terminal inline>apply<terminal inline> depends on your particular use case.
If you want to add a version control to your Kubernetes object, then it’s better to use <terminal inline>kubectl apply<terminal inline>, which helps determine the accuracy of data in Kubernetes objects.
If you want to create a resource for troubleshooting, learning, or interactive experimentation, go with <terminal inline>kubectl create<terminal inline>.
Conclusion
Now you know what the difference is between imperative and declarative approaches and how they fit into the context of Kubernetes. You should also have a better sense of when to use kubectl <terminal inline>apply<terminal inline> and <terminal inline>create<terminal inline> and in what context. This will help you make more efficient use of your time and resources in Kubernetes and keep your CI/CD workflow at peak performance.