Imperative: Execute a specific list of instructions to get a desired outcome. If one step fails in the process, the end result is likely to be incorrect or may error out.
Declarative: We don’t care about how the result is achieved, we give the necessary information to the software and it executes the steps under the hood to achieve the intended result.
In K8s, the imperative approach would be issuing commands to create resources through kubectl
. The declarative approach would be to create definition files and applying them using $ kubectl apply -f filename.yml
command.
- Imperative approach is difficult to use in a large, complex environment but they are quick. This is why creating K8s resources with object definition files, also known as manifest files, helps create exactly what we need the object to look like.
- These files can be stored in a repository through a change/review process. To make changes to these files, you can run the
$ kubectl edit deployment <object-name>
command.- This opens a YAML definition file, similar to ones used to create objects, but with some additional fields. For example,
$ kubectl edit deployment nginx
opensnginx.yaml
pod definition file within the editor. - The
status
field is used to store the status of the pod. - This file is not the file used to create the object, but a similar file with some additional fields.
- This opens a YAML definition file, similar to ones used to create objects, but with some additional fields. For example,
- To make changes to the live object, you can make changes to the local file, save and quit, and then run
$ kubectl replace -f nginx.yml
. - However, note that there is a difference between the live object and the definition file that you have locally.
- Changes made using the
$ kubectl edit
command are not recorded anywhere. So instead, a better way is to make changes to the local file and then run$ kubectl edit deployment <nginx>
, thenkubectl replace -f nginx.yml
.
What if you run the create command and the object already exists? It would fail with an error that says the pod already exists. Examples like this are why the imperative approach is taxing.
The declarative approach is where you use the same object configuration files but instead of create or replace commands we use the kubectl apply
command to manage objects.
- The
kubectl apply
command is intelligent enough to create an object if it doesn’t already exist. - If there are multiple object configuration files, as you usually would have, you can specify that directory instead of just one file.
- When changes are to be made, simply update the object configuration file and run
$ kubectl apply
command again. This time, it knows that the object exists, so it updates the object with the new changes. - TLDR: The
kubectl apply
command can be used to simultaneously update and create K8 resources in an entire directory.
So If you want to quickly create a resource or a deployment with a given image, take the imperative approach. If you have a complex requirement, use the declarative approach.
To expose a resource with a service, for example a pod, run $ kubectl expose pod nginx --port 80
.
- Another example: Create a Service named
redis-service
of type Cluster IP to expose a podredis
on port6379
. - Run
kubectl expose pod redis --port 6379 --name redis-service --dry-run=client -o yaml
. This will automatically set the pod’s labels as selectors. - Or use the command
$ kubectl create service clusterip redis --tcp=6379:6379 --dry-run=client -o yaml
.