In the last part we created a few pods using the run command and by accident created some other things also, deployment, replicaset.

Pods, deployments, replicasets are all kubernetes (k8s) resources. The idea here is they are available for you to use. Many resources, such as pods and replicasets are available to you out-of-the-box. Later in this course we play with creating our own Custom Resources.

All resources are configurable and you specify the configuration with a Resource Definition. Lets see a definition for a Pod

apiVersion: "v1"
kind: Pod
metadata:
  name: ubuntu-pod
  labels:
    app: ubuntu-pod
    version: v1
    role: backend
spec:
  containers:
  - name: ubuntu-container
    image: ubuntu
    command: ["/bin/bash"]
    args: ["-c", "while [ \"a\" = \"a\" ]; do echo \"Hi\"; sleep 5; done" ]

The structure here will mostly be the same. The above is a yaml file so spaces matter, if you don’t like adhering to spaces (and love ‘ ” ‘, ‘{}’s and ‘,’s) you can specify the same as json (yuck!).

{
"apiVersion": "v1",
"kind": "Pod",
"metadata": {
  "name": "ubuntu-pod",
  "labels": {
    "app": "ubuntu-pod",
    "version": "v1",
    "role": "backend"
  }
},
"spec": {
  "containers": [{
  "name": "ubuntu-container",
  "image": "ubuntu",
  "command": ["/bin/bash"],
  "args": ["-c", "while [ \"a\" = \"a\" ]; do echo \"Hi\"; sleep 5; done" ]
  }]
}
}

apiVersion: This is the api version you want to avail of. Different api versions give you different resources that you can create. v1 is the base version, most of the standard resources such as pods, deployments, services are in the v1 api. To find out which api version the resource is in, a google of
“kubernetes <type of resource>”
should get you the needed information. I tend to rely on kubernetes.io for this kind of information.

kind: is the type of resource you want to create. In this case Pod. Please note that kind is case-sensitive.

metadata: This, as the name suggests is about the resource instance you are creating. name is mandatory, labels are optional and both key and value are defined by you.

spec: This is the actual configuration for the resource. This changes depending on the resource you are creating. In this example we specify the array of containers and the container specifications.

Creating resources

In the case of run, you can actually specify many of these on the command line. For example in the last post we specified the image on the command line. For a list of all options, just do

kubectl run --help

This is not recommended though! The best practice is to write the definition in a file and apply or create it.

kubectl apply -f resource.json
kubectl create -f resource.json
kubectl apply -f resource.yaml
kubectl create -f resource.yaml

Difference between apply and create

create: Create this resource. If it exists throw an error. It doesn’t care about a change in config. It only looks for the name.

apply: update the resource with this definition. If it doesn’t exist create it.

Lets change the definition of the pod slightly. Changing ‘Hi’ to ‘Bye’ on the last line.

apiVersion: "v1"
kind: Pod
metadata:
  name: ubuntu-pod
  labels:
    app: ubuntu-pod
    version: v1
    role: backend
spec:
  containers:
  - name: ubuntu-container
    image: ubuntu
    command: ["/bin/bash"]
    args: ["-c", "while [ \"a\" = \"a\" ]; do echo \"Bye\"; sleep 5; done" ]

I already have ubuntu-pod running. Now lets try to create it.

$ kubectl get pods
NAME         READY   STATUS    RESTARTS   AGE
ubuntu-pod   1/1     Running   0          23m
$ kubectl create -f ubuntuPod.yml
Error from server (AlreadyExists): error when creating "ubuntuPod.yml": pods "ubuntu-pod" already exists

As expected it failed as the resource already exists.

Now lets try to apply it

$ kubectl apply -f ubuntuPod.yml

Warning: kubectl apply should be used on resource created by either kubectl create --save-config or kubectl apply

The Pod "ubuntu-pod" is invalid: spec: Forbidden: pod updates may not change fields other than `spec.containers[*].image`, `spec.initContainers[*].image`, `spec.activeDeadlineSeconds` or `spec.tolerations` (only additions to existing tolerations)

One warning, one error here!. Lets tackle the warning

Warning: kubectl apply should be used on resource created by either kubectl create --save-config or kubectl apply

The reason this warning exists is because if you try to edit a pod created in some other way, the resource that created the pod in the first place may change it back or end up in a wierd state. Remember, resources need not be directly created by you, resources can create more resources. You might also have the wrong config completely!

Now the error

The Pod "ubuntu-pod" is invalid: spec: Forbidden: pod updates may not change fields other than `spec.containers[*].image`, `spec.initContainers[*].image`, `spec.activeDeadlineSeconds` or `spec.tolerations` (only additions to existing tolerations)

This error tells us that you can only change certain fields in the specification. Lets reedit to change only the image. Lets use a better OS, move ubuntu to more hardened and secure centos.

apiVersion: "v1"
kind: Pod
metadata:
  name: ubuntu-pod
  labels:
    app: ubuntu-pod
    version: v1
    role: backend
spec:
  containers:
  - name: ubuntu-container
    image: centos
    command: ["/bin/bash"]
    args: ["-c", "while [ \"a\" = \"a\" ]; do echo \"Hi\"; sleep 5; done" ]

Now the excerpt of the output of kubectl get pod/ubuntu-pod -oyaml after apply.

spec:
  containers:
  - args:
    - -c
    - while [ "a" = "a" ]; do echo "Hi"; sleep 5; done
    command:
    - /bin/bash
    image: centos

Now lets check the Uptime of the pod with kubectl get pod/ubuntu-pod

$ kubectl get pod/ubuntu-pod 
NAME         READY   STATUS    RESTARTS   AGE
ubuntu-pod   1/1     Running   0          48m

Wow! it says no restarts and age 48m. We changed the operating system for gods sake!!!!! This doesn’t make sense! But after a while…

$ kubectl get pod/ubuntu-pod 
NAME         READY   STATUS    RESTARTS   AGE
ubuntu-pod   1/1     Running   1          56m

As usual patience is virtue. This is better, so now we had 1 Restart but the pod has been up for 56 minutes (this is the time since first creation). This definitely makes more sense.

Learnings

kubectl commands may take time to execute.

If it doesn’t make sense, then either your mental model is wrong or your observation. Patience pays.

Learning is the process of firming up your mental model so that it reflects reality.

differences between create and apply.

Conclusion

In this post we learnt to define and create resources. We didn’t talk much about resource behaviour. Resources have a behaviour as well as being things. These behaviours could be interaction with other resources or things that resource does on its own. For example, a pod runs the containers it holds. What happens if a container inside it crashes ? Does the pod restart ? or is that container only restarted ?