Getting Started with Kubernetes InitContainers and Volume pre-population
Tags: kubernetes, docker, systemadministration
Published: 2019-01-21 23:53:27

---
title: Getting Started with Kubernetes InitContainers and Volume pre-population
published: true
description: 
tags: kubernetes, docker, system-administration
---

[The `InitContainer` resource in Kubernetes](https://kubernetes.io/docs/concepts/workloads/pods/init-containers/) is an interesting, and very useful resource; in many cases, you'll see it used to do things like prepopulate data in a volume before creating the containers in a `Pod` deployment, so upon spinning up the containers, the volume data is already initialized.

In my case, I have a simple web frontend with a single static page, and it boots using the standard `nginx` Docker image to serve a manifest file:

```
﻿FROM nginx

COPY index.html /usr/share/nginx/html/index.html
COPY smartos.ipxe /usr/share/nginx/html/smartos.ipxe
```

This image builds and downloads very quickly, which is awesome, but partly because it's stateless; the the `smartos.ipxe` file, for example, makes reference to release data that, upon spinning up the app, needs to be available or else those references will not work as intended (abstracted as a `404` HTTP response):

```
#!ipxe
dhcp
set base-url http://sdc-ipxe.east.gourmet.yoga
kernel ${base-url}/smartos/smartos/platform/i86pc/kernel/amd64/unix -B smartos=true,console=ttyb,ttyb-mode="115200,8,n,1,-"
module ${base-url}/smartos/smartos/platform/i86pc/amd64/boot_archive type=rootfs name=ramdisk
boot
```

These files, however, are not part of the app image because, for example, it updates frequently, so each time we rollout a new version, we'd like the latest release available in the volume, and since we don't need to maintain these files in the image, or else it would be very large and costly to store in our registry, we can mount a Volume to the containers in the Pod to provide them.

So, basically, we need a way to pre-populate a volume we're mounting to `/usr/share/nginx/html/smartos`.

Using the `InitContainer` resource, we can specify a command to be run, and like any other container in a `Pod`, we can allocate a volume to be mounted, so let's start with a Kubernetes manifest like this:

```
apiVersion: apps/v1
kind: Deployment
metadata:
  name: sdc-ipxe-deployment
  labels:
    app: sdc-ipxe
spec:
  replicas: 2
  selector:
    matchLabels:
      app: sdc-ipxe
  template:
    metadata:
      labels:
        app: sdc-ipxe
    spec:
      initContainers:
      - name: config-data
        image: ubuntu:xenial
        command: ["/bin/sh","-c"]
        args: ["apt update; apt install -y wget tar; wget https://us-east.manta.joyent.com/Joyent_Dev/public/SmartOS/platform-latest.tgz; tar xvf platform-latest.tgz -C /data; mkdir /data/smartos; mv /data/platform* /data/smartos/platform"]
        volumeMounts:
        - mountPath: /data
          name: sdc-data
      volumes:
      - name: sdc-data
        hostPath:
          path: /mnt/kube-data/sdc-ipxe/
          type: DirectoryOrCreate

```

So, at this point, we're provisioning the volume `sdc-data`, mounting it to an `initContainer` called `config-data` at `/data`, and running:

```
"apt update; apt install -y wget tar; wget https://us-east.manta.joyent.com/Joyent_Dev/public/SmartOS/platform-latest.tgz; tar xvf platform-latest.tgz -C /data; mkdir /data/smartos; mv /data/platform* /data/smartos/platform"
```

to download and extract the data to the volume. Now, we we add a `containers:` key to the manifest, and attach that Volume again, the prepopulated data will be availabnle:

```
apiVersion: apps/v1
kind: Deployment
metadata:
  name: sdc-ipxe-deployment
  labels:
    app: sdc-ipxe
...
      containers:
      - name: sdc-ipxe
        image: coolregistryusa.bix/jmarhee/sdc-ipxe:latest
        imagePullPolicy: Always
        ports:
        - containerPort: 80
        volumeMounts:
        - mountPath: /usr/share/nginx/html/smartos
          name: sdc-data
...
```

with the volume mounted where the app in the container expects, `/usr/share/nginx/html/smartos` using the same `sdc-data` volume.

Other examples of this pattern being useful can be if your application relies on configurations with variable requirements; maybe you're issued a token, or an address is fairly dynamic, and this needs to be passed through files on disk, rather than the environment (i.e. a loadbalancer, or webserver, or database client with a configuration file, not easily handled through a Secret or ConfigMap because of how often they change), this provides a somewhat easily programmable interface for pre-populating or completing the templating of data handed to a container.

Further Reading
--
[Using InitContainers to pre-populate Volume data in Kubernetes](https://medium.com/@jmarhee/using-initcontainers-to-pre-populate-volume-data-in-kubernetes-99f628cd4519)