K8S deployment executing shell scripts reading configuration data

7/1/2018

In K8S, what is the best way to execute scripts in container (POD) once at deployment, which reads from confuguration files which are part of the deployment and seed ex mongodb once?

my project consist of k8s manifest files + configuration files

I would like to be able to update the config files locally and then redeploy via kubectl or helm

In docker-compose i could create a volume ponting at the directory where the config files resides and then in the command part execute bash -c cmds reading from the config files in the volume. How is this best done in K8S? I don't want to include the configuration files in a image via dockerfile, forcing me to rebuild the image before redeploying again via kubectl or helm

-- user9230212
deployment
kubernetes
manifest

1 Answer

7/1/2018

How is this best done in K8S?

There are several ways to skin a cat, but my suggestion would be to do the following:

  • Keep configuration in configMap and mount it as separate volume. Such a map is kept as k8s manifest, making all changes to it separate from docker build image - no need to rebuild or keep sensitive data within image. You can also use instead (or together with) secret in the same manner as configMap.
  • Use initContainers to do the initialization before main container is to be brought online, covering for your 'once on deployment' automatically. Alternatively (if init operation is not repeatable) you can use Jobs instead and start it when necessary.

Here is excerpt of example we are using on gitlab runner:

apiVersion: apps/v1beta1
kind: StatefulSet
metadata:
  name: ss-my-project
spec:
  ...
  template:
    ....
    spec:
      ...
      volumes:
      - name: volume-from-config-map-config-files
        configMap:
          name: cm-my-config-files
      - name: volume-from-config-map-script
        projected:
          sources:
          - configMap:
              name: cm-my-scripts
              items:
              - key: run.sh
                path: run.sh
                mode: 0755
      # if you need to run as non-root here is how it is done:
      securityContext:
        runAsNonRoot: true
        runAsUser: 999
        supplementalGroups: [999]
      containers:
      - image: ...
        name: ...
        command:
        - /scripts/run.sh
        ...
        volumeMounts:
        - name: volume-from-config-map-script
          mountPath: "/scripts"
          readOnly: true
        - mountPath: /usr/share/my-app-config/config.file
          name: volume-from-config-map-config-files
          subPath: config.file
      ...

You can, ofc, mount several volumes from config maps or combine them in one single, depending on frequency of your changes and affected parts. This is example with two separately mounted configMaps just to illustrate the principle (and mark script executable), but you can use only one for all required files, put several files into one or put single file into each - as per your need.

Example of such configMap is like so:

apiVersion: v1
kind: ConfigMap
metadata:
  name: cm-my-scripts
data:
  run.sh: |
    #!/bin/bash
    echo "Doing some work here..."

And example of configMap covering config file is like so:

kind: ConfigMap
apiVersion: v1
metadata:
  name: cm-my-config-files
data:
  config.file: |
     ---
     # Some config.file (example name) required in project
     # in whatever format config file actually is (just example)
     ... (here is actual content like server.host: "0" or EFG=True or whatever)

Playing with single or multiple files in configMaps can yield result you want, and depending on your need you can have as many or as few as you want.

In docker-compose i could create a volume ponting at the directory where the config files resides and then in the command part execute bash -c cmds reading from the config files in the volume.

In k8s equivalent of this would be hostPath but then you would seriously hamper k8s ability to schedule pods to different nodes. This might be ok if you have single node cluster (or while developing) to ease change of config files, but for actual deployment above approach is advised.

-- Const
Source: StackOverflow