Now that we know what a Pod is and how it works,
let's create one by ourselves. We have seen
previously, that there are two ways to create any
object in Kubernetes, imperative and declarative.
To make sure that we cover both of these ways, we
have two terminals open side by side. In one
terminal, we'll create a Pod imperatively,
whereas on the other terminal, we will create the
pod declaratively. We have these terminals side
by side so that we can compare them once both of
them are created. Let's start with the imperative one.
For creating a Pod imperatively, we need to
provide all of the specifications through either a
command or a YAML file, we will choose yaml this time.
Let's write a file called imperative-pod.yaml.
We are using nano as our text editor, but you
can use any text editor which you want. The basics
of the YAML file remains the same as Docker Compose.
Only difference would be the fields,
which would be indicated as key value pairs.
With that said, let's get started. Our first field or
first key value pair is API version. This field is
used to let Kubernetes know which version of API
is being used to create this object. For more
information about the API versions, and which
version to use for which object, you can follow
the official Kubernetes documentation by going to
the following link. Next up, we have kind,
kind specifies which kind or which type of object is to
be created using this file, we want to create a
Pod. So our kind field or kind key, will have
the value Pod. Next up we have metadata. It does
what its name suggests, it is data about the
object which is going to be created. Typically,
metadata would contain fields like names, labels,
and so on. The primary use of metadata in
Kubernetes is for us and the Kubernetes itself to
identify, group and sort the Pods. We want to name
the Pod as imp, or imp-pod, and we want to
give a label, which says app equals myapp.
You may have noticed that labels are a key value pair.
For now, let's not dwell too deep into labels and
let's go further. Next up we have spec field,
which stands for specifications. You can consider
spec as the most important field of this file.
And why is that? Well, the reason is quite obvious.
Specs are used to provide object configuration
information, which means that here, spec field
will provide information and configurations about
the Pod itself. Our first spec is containers.
Unlike Docker, containers are just a specification
or a field of the parent object, which is Pod.
Specifications may vary with objects, which means
that different objects may have different
specifications and different fields to provide
them. Our next entry under the containers spec is
the name of the container. It is different from
the name of the Pod. In theory, you can keep both
of them same, but keeping them different makes
things simpler. Next up, we have image field image
field describes the image which is going to be
used to run this container. By default, Kubernetes
uses images from Docker Hub, but if we want to use
other registries, we need to provide specific URL,
but we will get into that later. Next up we have
command this one is quite simple to comprehend.
We are asking our container to run shell command and
echo a string called 'Welcome to Container
MasterClass by CeruleanCanvas'
and sleep for 60 seconds. We have mentioned all of
the required specifications to create this Pod.
Let's save our file and exit the text editor
Parallely, we are also writing another file called
declarative-pod.yaml. And as you can see,
they're also providing similar fields as previous
file in this one such as API version, kind, and
metadata. To distinguish this Pod from previous
Pod, we are giving it a different name, but both of
the pods will contain same label. Next up, we have
specifications. Again, the name of the container
is changing but the image is remaining the same.
And this time, we are asking it to print the same
string but sleep for 60 more seconds. Let's save
this and exit as well. Let's go back to our left
hand terminal and write the command kubectl create -f
imperative-pod.yaml. We are
asking kubectl to create an object from this
particular file. As a nod to success of this
command, we receive the notification of imp-pod
having been created. Let's go back to right
hand side terminal. Unlike imperative way, we will
write the command kubectl apply and mentioned the
file using -f flag, and the Pod is created
as well. In this case, even if we had wanted to
delete or scale the Pod, the command would have
been the same Kubernetes or kubectl would have
figured it out by itself. What do we want to
convey through the file, whereas in case of
imperative command, we specifically had to tell
Kubernetes to create an object. In any case, both
our imperative and declarative Pods are created.
So let's see if they are running or not.
Like kubectl get pods, we will be using this command a
lot in future demos. It gives a well arranged list
of Pods along with a few more attributes, like how
many of the listed Pods are ready, what is the
status of each and every Pod, whether there was any
restarts during the runtime of the Pod, and since
how long is the Pod running, we can see both
imperative and declarative pod having been
created. Now let's dig deeper into both of the
Pods by writing the command kubectl describe pods,
followed by the name of the Pod, which in
this case, is imp-pod. We will also run the same
command on the right hand side or declare to terminal as well.
Now we have descriptions of both
of the Pods, so we can make a fair comparison.
Let's start from the top. First of all, we have
Name of both of the parts, which are unique.
Then, we can see that both of the Pods are allotted to
the same Namespace, which is default Namespace.
Our imperative Pod is scheduled on node-2,
whereas declarative Pod is scheduled on node-1.
We also have that starting timestamps and their
labels, which is common. As for the differences,
our imperative Pod doesn't have any annotations,
whereas the declarative pod has quite a few of
them. The reason behind that is, kubectl has used
the configuration which were provided by us to
create the Pod in case of imperative Pod. Whereas
in case of declarative Pod, it has used a specified
Pod template, and has just filled in or replaced
the information which we have provided.
Moving further, we have IP for both of the Pods, but
we'll get into that later. Next up, we have
Container information. As you can see, both of the
container have different Names and different
Container IDs. But the container Image and the
Image IDs are same. We also have the command which
is going to be executed by both of the containers,
and it has a slight difference as we had mentioned.
Moving further, we have the state of
the container which is running in both of the cases.
And we also have the starting timestamp of
the container, which means that this is the point
where the container went from Created state to
Started state. Our first container, which is
imperative or imp container has already exited or
terminated because it was completed. Whereas same
is not the case with the other one because the
sleeping period was a bit longer.
Next up, we have Mount and Volume information,
but we don't need to dwell too deep into that right now.
We will look into them when we study volumes for Kubernetes.
My personal favorite part about the
description of the containers is the events. This
is different from how we used to inspect our
containers using Docker. Kubernetes gives us a
short and sweet summary of events, which were
really important. We can see that both of the
containers went through a bunch of events,
including their scheduling, pulling an image,
containers having been created, and finally started.
So this is how we can create and
distinguish imperative and declarative Pods.