Bablu Ahmed
Bablu Ahmed

Reputation: 5020

Difference between initContainers and containers in Kubernetes

I noticed in a deployment file there are two fields for containers like initContainers and containers and looks confusing to me and I search through the internet but can't understand. Could anyone please tell me the difference between initContainers and containers and how we use them together?

For example

  containers:
  - name: php
    image: php:7-fpm
    volumeMounts:
    - name: dir
      mountPath: /dir
  initContainers:
  - name: install
    image: busybox
    volumeMounts:
    - name: dir
      mountPath: /dir
    command:
    - wget
    - "-O"
    - "/dir/index.php"
    - https://raw.githubusercontent.com/videofalls/demo/master/index.php

It's really appreciable and thanks in advance!!

Upvotes: 5

Views: 7970

Answers (2)

Will R.O.F.
Will R.O.F.

Reputation: 4128

About Containers:

Containers are a technology for packaging the (compiled) code for an application along with the dependencies it needs at run time. Each container that you run is repeatable; the standardization from having dependencies included means that you get the same behavior wherever you run it.

About InitContainer:

Init containers are exactly like regular containers, except:

  • Init containers always run to completion before the container execution.
  • Each initContainer must complete successfully before the next one starts.
  • If a Pod’s init container fails, Kubernetes repeatedly restarts the Pod until the init container succeeds. However, if the Pod has a restartPolicy of Never, Kubernetes does not restart the Pod.

Summarizing: Containers hosts your dockerized applications, initContainer run tasks that are required to run before the main Container execution.


One simple example is the code you provided:

  • You created a container with a php server, but you want the content of index.html to be always updated, without having to change the pod manifest itself.
  • So you added a initContainer to fetch the updated index.php and add to the container.
  • I've fixed your yaml with the volume parameters to add the emptyDir that will hold the downloaded file and changing the mountPath to the default html folder /var/www/html:
apiVersion: v1
kind: Pod
metadata:
  name: php-updated
spec:
  containers:
  - name: php
    image: php:7-fpm
    volumeMounts:
    - name: dir
      mountPath: /var/www/html/
  initContainers:
  - name: install
    image: busybox
    volumeMounts:
    - name: dir
      mountPath: /var/www/html/
    command:
    - wget
    - "-O"
    - "/var/www/html/index.php"
    - https://raw.githubusercontent.com/videofalls/demo/master/index.php
  volumes:
  - name: dir
    emptyDir: {}

POC:

$ kubectl apply -f php.yaml 
pod/php-updated created

$ kubectl get pod
NAME             READY   STATUS    RESTARTS   AGE
php-updated   1/1     Running   0          3s

$ kubectl exec -it php-updated -- /bin/bash
root@php-updated:/var/www/html# cat index.php 
<?php 
echo 'Demo Test';
  • As you can see the initContainer ran before the pod, downloaded the file to the mounted volume that is shared with the PHP server Container.

NOTE: The above webserver is not fully functional because the full php-fpm deployment is a little more complex, and it's not the core of this question, so I'll leave this tutorial for it: PHP-FPM, Nginx, Kubernetes, and Docker

One could argue that index.html is not a critical file for Pod initialization, and could be replaced during pod execution using Command so I'll leave here an answer I gave for persistently changing resolv.conf before pod initialization even after pod restart: DNS Config is Skipped in GKE.


Another great usage of initContainer is to make a pod wait for another resource in the cluster to be ready before initializing.

  • Here is a pod with a initContainer called init-mydb that waits and watched for a service called mydb to be on running state before allowing the container myapp-container start, imagine myapp-container is an app that requires the database connection before execution, otherwise it would fail repeatedly.

Reproduction:

  • here is the manifest my-app.yaml:
apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    run: my-app
  name: my-app
spec:
  replicas: 2
  selector:
    matchLabels:
      run: my-app
  template:
    metadata:
      labels:
        run: my-app
    spec:
      restartPolicy: Always
      containers:
      - name: myapp-container
        image: busybox:1.28
        command: ['sh', '-c', 'echo The app is running! && sleep 3600']
      initContainers:
      - name: init-mydb
        image: busybox:1.28
        command: ['sh', '-c', "until nslookup mydb.$(cat /var/run/secrets/kubernetes.io/serviceaccount/namespace).svc.cluster.local; do echo waiting for mydb; sleep 2; done"]
  • Now let's apply it see the status of the deployment:
$ kubectl apply -f my-app.yaml 
deployment.apps/my-app created

$ kubectl get pods
NAME                      READY   STATUS     RESTARTS   AGE
my-app-6b4fb4958f-44ds7   0/1     Init:0/1   0          4s
my-app-6b4fb4958f-s7wmr   0/1     Init:0/1   0          4s
  • The pods are hold on Init:0/1 status waiting for the completion of the init container.
  • Now let's create the service which the initContainer is waiting to be running before completing his task:
apiVersion: v1
kind: Service
metadata:
  name: mydb
spec:
  ports:
  - protocol: TCP
    port: 80
    targetPort: 9377
  • We will apply it and monitor the changes in the pods:
$ kubectl apply -f mydb-svc.yaml 
service/mydb created

$ kubectl get pods -w
NAME                      READY   STATUS     RESTARTS   AGE
my-app-6b4fb4958f-44ds7   0/1     Init:0/1   0          91s
my-app-6b4fb4958f-s7wmr   0/1     Init:0/1   0          91s
my-app-6b4fb4958f-s7wmr   0/1     PodInitializing   0          93s
my-app-6b4fb4958f-44ds7   0/1     PodInitializing   0          94s
my-app-6b4fb4958f-s7wmr   1/1     Running           0          94s
my-app-6b4fb4958f-44ds7   1/1     Running           0          95s
^C
$ kubectl get all
NAME                          READY   STATUS    RESTARTS   AGE
pod/my-app-6b4fb4958f-44ds7   1/1     Running   0          99s
pod/my-app-6b4fb4958f-s7wmr   1/1     Running   0          99s

NAME                 TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)   AGE
service/mydb         ClusterIP   10.100.106.67   <none>        80/TCP    14s

NAME                     READY   UP-TO-DATE   AVAILABLE   AGE
deployment.apps/my-app   2/2     2            2           99s

NAME                                DESIRED   CURRENT   READY   AGE
replicaset.apps/my-app-6b4fb4958f   2         2         2       99s

If you have any questions let me know in the comments!

Upvotes: 14

hoque
hoque

Reputation: 6471

Init Containers run before the main container runs. Normally init containers are used to ensure the server environment is ready for your application to start to run.

Go through the detailed official document for better understanding

Upvotes: 5

Related Questions