5 minute read

Kubernetes Init Containers

Init Containers

Earlier, we saw that a Pod can have multiple containers running apps within it, but it can also have one or more init containers, which are run before the app containers are started.

Init containers are exactly like regular containers, except: Init containers always run to completion. Each init container must complete successfully before the next one starts.

If init container fails during startup of that Pod, Kubernetes treats the overall Pod as failed.

Here is an example with one InitContainer called wait-for-service which is basically looking for the presence of a service called my-service. It does this check by performing nslookup. Till the kebernetes service called my-service is present, the name resolution will not succeed and this initContainer will not be finishing. Once the service is created, the initContainer job is done and it proceeds to the main container, in this example, it is the ubuntu container.

pradeep@learnk8s$ more pod-with-init-container.yaml
apiVersion: v1
kind: Pod
metadata:
  name: pod-with-init-container
spec:
  containers:
  - name: ubuntu
    image: ubuntu
    command: ['sh', '-c', 'echo The ubuntu container is running! && sleep 3600']
  initContainers:
  - name: wait-for-service
    image: busybox:1.28
    command: ['sh', '-c', "until nslookup myservice.$(cat /var/run/secrets/kubernetes.io/serviceaccount/namespace).svc.cluster.local; do echo waiting for myservice; sleep 2; done"]
pradeep@learnk8s$ kubectl create -f pod-with-init-container.yaml
pod/pod-with-init-container created

Once we created the pod with initContainer, we can see the state as Init:0/1 meaning there is one init container but it is not yet ready.

pradeep@learnk8s$ kubectl get pods -o wide | grep init
pod-with-init-container     0/1     Init:0/1           0              7s    <none>        k8s       <none>           <none>

Waited for some more time, still it is in Init:0/1 state.

pradeep@learnk8s$ kubectl get pods -o wide | grep init
pod-with-init-container     0/1     Init:0/1           0                96s   10.244.0.15   k8s       <none>           <none>

Let us describe this pod to get additional details.

pradeep@learnk8s$ kubectl describe pods pod-with-init-container
Name:         pod-with-init-container
Namespace:    default
Priority:     0
Node:         k8s/192.168.177.29
Start Time:   Wed, 16 Feb 2022 07:48:13 +0530
Labels:       <none>
Annotations:  <none>
Status:       Pending
IP:
IPs:          <none>
Init Containers:
  wait-for-service:
    Container ID:
    Image:         busybox:1.28
    Image ID:
    Port:          <none>
    Host Port:     <none>
    Command:
      sh
      -c
      until nslookup myservice.$(cat /var/run/secrets/kubernetes.io/serviceaccount/namespace).svc.cluster.local; do echo waiting for myservice; sleep 2; done
    State:          Waiting
      Reason:       PodInitializing
    Ready:          False
    Restart Count:  0
    Environment:    <none>
apiVersion: v1
    Mounts:
      /var/run/secrets/kubernetes.io/serviceaccount from kube-api-access-7gp7r (ro)
Containers:
  ubuntu:
    Container ID:
    Image:         ubuntu
    Image ID:
    Port:          <none>
    Host Port:     <none>
    Command:
      sh
      -c
      echo The ubuntu container is running! && sleep 3600
    State:          Waiting
      Reason:       PodInitializing
    Ready:          False
    Restart Count:  0
    Environment:    <none>
    Mounts:
      /var/run/secrets/kubernetes.io/serviceaccount from kube-api-access-7gp7r (ro)
Conditions:
  Type              Status
  Initialized       False
  Ready             False
  ContainersReady   False
  PodScheduled      True
Volumes:
  kube-api-access-7gp7r:
    Type:                    Projected (a volume that contains injected data from multiple sources)
    TokenExpirationSeconds:  3607
    ConfigMapName:           kube-root-ca.crt
    ConfigMapOptional:       <nil>
    DownwardAPI:             true
QoS Class:                   BestEffort
Node-Selectors:              <none>
Tolerations:                 node.kubernetes.io/not-ready:NoExecute op=Exists for 300s
                             node.kubernetes.io/unreachable:NoExecute op=Exists for 300s
Events:
  Type    Reason     Age   From               Message
  ----    ------     ----  ----               -------
  Normal  Scheduled  17s   default-scheduler  Successfully assigned default/pod-with-init-container to k8s
  Normal  Pulling    14s   kubelet            Pulling image "busybox:1.28"

As seen above, Init Container is in Waiting state and overall Pod status is Pending.

To make the InitiContainer successful, let us create a service called myservice. Here is the sample definition of the service.

pradeep@learnk8s$ cat init-container-service.yaml
apiVersion: v1
kind: Service
metadata:
  name: myservice
spec:
  ports:
  - protocol: TCP
    port: 80
    targetPort: 9376

Create the myservice from the YAML file.

pradeep@learnk8s$ kubectl create -f init-container-service.yaml
service/myservice created

Once the service is created, verify if there is any change in the main Pod status. It seems there is a change.

pradeep@learnk8s$ kubectl get pods -o wide | grep init
pod-with-init-container     0/1     PodInitializing    0                108s   10.244.0.15   k8s       <none>           <none>

It is not yet in running state, it might take some more time. In the meanwhile, let us inspect the logs of the InitContainer that we created wait-for-service.

Remember the kubectl logs command?! and the -c option to specify a container name when there are multiple containers in a pod!

pradeep@learnk8s$ kubectl logs pod-with-init-container -c wait-for-service
Server:    10.96.0.10
Address 1: 10.96.0.10 kube-dns.kube-system.svc.cluster.local

nslookup: can't resolve 'myservice.default.svc.cluster.local'
waiting for myservice
Server:    10.96.0.10
Address 1: 10.96.0.10 kube-dns.kube-system.svc.cluster.local

waiting for myservice
nslookup: can't resolve 'myservice.default.svc.cluster.local'
Server:    10.96.0.10
nslookup: can't resolve 'myservice.default.svc.cluster.local'
Address 1: 10.96.0.10 kube-dns.kube-system.svc.cluster.local

<SNIP>

nslookup: can't resolve 'myservice.default.svc.cluster.local'
waiting for myservice
Server:    10.96.0.10
Address 1: 10.96.0.10 kube-dns.kube-system.svc.cluster.local

Name:      myservice.default.svc.cluster.local
Address 1: 10.111.136.80 myservice.default.svc.cluster.local

A lot of similar output is omitted for brevity, but we can clearly see that this container is continuosly checking for the resolution of myservice.default.svc.cluster.local but nslookup: can’t resolve it.

Finally, after we created the myservice Service, name resolution was successful ( the last line). It (myservice.default.svc.cluster.local) is resolved to the IP address of 10.111.136.80.

This is nothing but the ClusterIP assigned to the myservice.

pradeep@learnk8s$ kubectl get svc
NAME         TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)   AGE
kubernetes   ClusterIP   10.96.0.1       <none>        443/TCP   19h
myservice    ClusterIP   10.111.136.80   <none>        80/TCP    9m13s

Going back to the main Pod, we can see it is in Running State.

pradeep@learnk8s$ kubectl get pods -o wide | grep init
pod-with-init-container     1/1     Running            0               12m   10.244.0.15   k8s       <none>           <none>

If we describe it one more time, Init Container is in Terminated State with Reason as Completed. And the Ubuntu container is Running.

pradeep@learnk8s$ kubectl describe pods pod-with-init-container
Name:         pod-with-init-container
Namespace:    default
Priority:     0
Node:         k8s/192.168.177.29
Start Time:   Wed, 16 Feb 2022 07:48:13 +0530
Labels:       <none>
Annotations:  <none>
Status:       Running
IP:           10.244.0.15
IPs:
  IP:  10.244.0.15
Init Containers:
  wait-for-service:
    Container ID:  docker://8b5668914aeef2c9c43eebf3ebf7b7289eff4efa96166198fc0c6db8cdfd358b
    Image:         busybox:1.28
    Image ID:      docker-pullable://busybox@sha256:141c253bc4c3fd0a201d32dc1f493bcf3fff003b6df416dea4f41046e0f37d47
    Port:          <none>
    Host Port:     <none>
    Command:
      sh
      -c
      until nslookup myservice.$(cat /var/run/secrets/kubernetes.io/serviceaccount/namespace).svc.cluster.local; do echo waiting for myservice; sleep 2; done
    State:          Terminated
      Reason:       Completed
      Exit Code:    0
      Started:      Wed, 16 Feb 2022 07:48:52 +0530
      Finished:     Wed, 16 Feb 2022 07:49:52 +0530
    Ready:          True
    Restart Count:  0
    Environment:    <none>
    Mounts:
      /var/run/secrets/kubernetes.io/serviceaccount from kube-api-access-7gp7r (ro)
Containers:
  ubuntu:
    Container ID:  docker://60caee7150e608901a2fda93fdc6758c8aa5208ec69320ed8c7982d57efde9fb
    Image:         ubuntu
    Image ID:      docker-pullable://ubuntu@sha256:669e010b58baf5beb2836b253c1fd5768333f0d1dbcb834f7c07a4dc93f474be
    Port:          <none>
    Host Port:     <none>
    Command:
      sh
      -c
      echo The ubuntu container is running! && sleep 3600
    State:          Running
      Started:      Wed, 16 Feb 2022 07:59:33 +0530
    Ready:          True
    Restart Count:  0
    Environment:    <none>
    Mounts:
      /var/run/secrets/kubernetes.io/serviceaccount from kube-api-access-7gp7r (ro)
Conditions:
  Type              Status
  Initialized       True
  Ready             True
  ContainersReady   True
  PodScheduled      True
Volumes:
  kube-api-access-7gp7r:
    Type:                    Projected (a volume that contains injected data from multiple sources)
    TokenExpirationSeconds:  3607
    ConfigMapName:           kube-root-ca.crt
    ConfigMapOptional:       <nil>
    DownwardAPI:             true
QoS Class:                   BestEffort
Node-Selectors:              <none>
Tolerations:                 node.kubernetes.io/not-ready:NoExecute op=Exists for 300s
                             node.kubernetes.io/unreachable:NoExecute op=Exists for 300s
Events:
  Type    Reason     Age   From               Message
  ----    ------     ----  ----               -------
  Normal  Scheduled  12m   default-scheduler  Successfully assigned default/pod-with-init-container to k8s
  Normal  Pulling    12m   kubelet            Pulling image "busybox:1.28"
  Normal  Pulled     11m   kubelet            Successfully pulled image "busybox:1.28" in 35.840326348s
  Normal  Created    11m   kubelet            Created container wait-for-service
  Normal  Started    11m   kubelet            Started container wait-for-service
  Normal  Pulling    10m   kubelet            Pulling image "ubuntu"
  Normal  Pulled     50s   kubelet            Successfully pulled image "ubuntu" in 9m39.673051136s
  Normal  Created    50s   kubelet            Created container ubuntu
  Normal  Started    50s   kubelet            Started container ubuntu
Back to Top ↑