
Pods
A pod is the smallest deployable unit in Kubernetes. It can contain one or more containers. Most of the time, we just need one container per pod. In some special cases, more than one container is included in the same pod, such as sidecar containers (http://blog.kubernetes.io/2015/06/the-distributed-system-toolkit-patterns.html). Containers in the same pod run in a shared context, on the same node, sharing the network namespace and shared volumes. Pods are also designed as mortal. When a pod dies for some reason, for example, if it's killed by Kubernetes controller if resources are lacking, it won't recover by itself. Instead, Kubernetes uses controllers to create and manage the desired state of pods for us.
We can use kubectl explain <resource> to get the detailed description of the resource by the command line. This will show the fields that the resource supports:
// get detailed info for `pods`
# kubectl explain pods
KIND: Pod
VERSION: v1
DESCRIPTION:
Pod is a collection of containers that can run on a host. This resource is
created by clients and scheduled onto hosts.
FIELDS:
apiVersion <string>
APIVersion defines the versioned schema of this representation of an
object. Servers should convert recognized schemas to the latest internal
value, and may reject unrecognized values. More info:
https://git.k8s.io/community/contributors/devel/api-conventions.md#resources
kind <string>
Kind is a string value representing the REST resource this object
represents. Servers may infer this from the endpoint the client submits
requests to. Cannot be updated. In CamelCase. More info:
https://git.k8s.io/community/contributors/devel/api-conventions.md#types-kinds
metadata <Object>
Standard object's metadata. More info:
https://git.k8s.io/community/contributors/devel/api-conventions.md#metadata
spec <Object>
Specification of the desired behavior of the pod. More info:
https://git.k8s.io/community/contributors/devel/api-conventions.md#spec-and-status
status <Object>
Most recently observed status of the pod. This data may not be up to date.
Populated by the system. Read-only. More info:
https://git.k8s.io/community/contributors/devel/api-conventions.md#spec-and-status
In the following example, we'll show how to create two containers in a pod, and demonstrate how they access each other. Please note that this is neither a meaningful nor a classic sidecar pattern example. Instead, it's just an example of how we can access other containers within a pod:
// an example for creating co-located and co-scheduled container by pod
# cat 3-2-1_pod.yaml
apiVersion: v1
kind: Pod
metadata:
name: example
spec:
containers:
- name: web
image: nginx
- name: centos
image: centos
command: ["/bin/sh", "-c", "while : ;do curl http://localhost:80/; sleep 10; done"]
The following diagram shows the relationship between containers in a Pod. They share the same network namespace:

This spec will create two containers, web and centos. Web is an nginx container (https://hub.docker.com/_/nginx/). The container port 80 is exposed by default. Since centos shares the same context as nginx, when using curl in http://localhost:80/, it should be able to access nginx.
Next, use the kubectl create command to launch the pod. The -f argument allows us to feed a configuration file to the kubectl command and creates the desired resources specified in the file:
// create the resource by `kubectl create` - Create a resource by filename or stdin
# kubectl create -f 3-2-1_pod.yaml pod "example" created
We can use the kubectl get <resource> command to get the current status of the object. In this case, we use the kubectl get pods command:
// get the current running pods
# kubectl get pods
NAME READY STATUS RESTARTS AGE
example 0/2 ContainerCreating 0 1s
// list pods in kube-system namespace
# kubectl get pods --namespace=kube-system
NAME READY STATUS RESTARTS AGE
coredns-99b9bb8bd-p2dvw 1/1 Running 0 1m
etcd-minikube 1/1 Running 0 47s
kube-addon-manager-minikube 1/1 Running 0 13s
kube-apiserver-minikube 1/1 Running 0 38s
kube-controller-manager-minikube 1/1 Running 0 32s
kube-proxy-pvww2 1/1 Running 0 1m
kube-scheduler-minikube 1/1 Running 0 26s
kubernetes-dashboard-7db4dc666b-f8b2w 1/1 Running 0 1m
storage-provisioner 1/1 Running 0 1m
The status of our example pod is ContainerCreating. In this phase, Kubernetes has accepted the request and is trying to schedule the pod and pull down the image. Zero containers are currently running.
After waiting a moment, we could get the status again:
// get the current running pods
# kubectl get pods
NAME READY STATUS RESTARTS AGE
example 2/2 Running 0 3s
We can see that two containers are currently running. The uptime is three seconds. Using kubectl logs <pod_name> -c <container_name> gets stdout for the container, similar to docker logs <container_name>:
// get stdout for centos
# kubectl logs example -c centos
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
...
centos in the pod shares the same networking with nginx via localhost. Kubernetes creates a network container along with the pod. One of the functions in the network container is to forward the traffic between containers within a pod. We'll learn more about this in Chapter 6, Kubernetes Network.
We could use kubectl describe <resource> <resource_name> to get detailed information about a resource:
// get detailed information for a pod
# kubectl describe pods example Name: example
Namespace: default
Priority: 0
PriorityClassName: <none>
Node: minikube/10.0.2.15
Start Time: Sun, 07 Oct 2018 15:15:36 -0400
Labels: <none>
Annotations: <none>
Status: Running
IP: 172.17.0.4
Containers: ...
At this point, we know which node this pod is running on. In minikube, we only get a single node so it won't make any difference. In the real cluster environment, knowing which node the pod is running on is useful for troubleshooting. We haven't associated any labels, annotations, or controllers for it:
web:
Container ID: docker://d8284e14942cbe0b8a91f78afc132e09c0b522e8a311e44f6a9a60ac2ca7103a
Image: nginx
Image ID: docker-pullable://nginx@sha256:9ad0746d8f2ea6df3a17ba89eca40b48c47066dfab55a75e08e2b70fc80d929e
Port: <none>
Host Port: <none>
State: Running
Started: Sun, 07 Oct 2018 15:15:50 -0400
Ready: True
Restart Count: 0
Environment: <none>
Mounts:
/var/run/secrets/kubernetes.io/serviceaccount from default-token-bm6vn (ro)
In the containers section, we'll see there are two containers included in this pod. We can see their states, source images, port mappings, and restart count:
Conditions:
Type Status
Initialized True
Ready True
ContainersReady True
PodScheduled True
A pod has PodStatus, which includes a map of array representations as PodConditions. The possible types of PodConditions are PodScheduled, Ready, Initialized, Unschedulable, and ContainersReady. The value will be true, false, or unknown. If the pod isn't created accordingly, PodStatus will give us a brief overview of which part failed. In the preceding example, we launched the pod successfully in each phase without any errors:
Volumes:
default-token-bm6vn:
Type: Secret (a volume populated by a Secret)
SecretName: default-token-bm6vn
Optional: false
A pod is associated with a service account that provides an identity for processes that are running the pod. It's controlled by service account and a token controller in the API Server.
It'll mount a read-only volume to each container under /var/run/secrets/kubernetes.io/serviceaccount in a pod that contains a token for API access. Kubernetes creates a default service account. We can use the kubectl get serviceaccounts command to list the service accounts:
QoS Class: BestEffort
Node-Selectors: <none>
Tolerations: node.kubernetes.io/not-ready:NoExecute for 300s
node.kubernetes.io/unreachable:NoExecute for 300s
We don't assign any selectors to this pod yet. Toleration is used to restrict how many pods a node can use. We'll learn more about this in Chapter 8, Resource Management and Scaling:
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal Scheduled 2m22s default-scheduler Successfully assigned default/example to minikube
Normal Pulling 2m21s kubelet, minikube pulling image "nginx"
Normal Pulled 2m8s kubelet, minikube Successfully pulled image "nginx"
Normal Created 2m8s kubelet, minikube Created container
Normal Started 2m8s kubelet, minikube Started container
Normal Pulling 2m8s kubelet, minikube pulling image "centos"
Normal Pulled 93s kubelet, minikube Successfully pulled image "centos"
Normal Created 92s kubelet, minikube Created container
Normal Started 92s kubelet, minikube Started container
By seeing the events, we can identify the steps required for Kubernetes to run a node. First, the scheduler assigns the task to a node, which here is called minikube. Then, kubelet starts pulling the first image and creates a container accordingly. After that, kubelet pulls down the second container and starts the container.