Using Kubernetes ConfigMaps As Code

Photo by Ryan Moulton on Unsplash

A ConfigMap is a set of named bits of data. They allow Kubernetes operators to supply additional runtime configuration to the images they are spinning. They can be the source of environment variables. They can even be the source of files on-disk.

Consider the nginx image on Docker Hub. This is an excellent example of a generic container, ready to be plumbed into a wider deployment. The image itself runs the nginx master process and as many workers as you configure. Out of the box, it ships with a sane configuration that serves static files from /usr/share/nginx/html.

We can use a ConfigMap to put files in that directory, for nginx to serve up!

---apiVersion: v1
kind: ConfigMap
metadata:
  name: static-files
data:
  index.html: |
    <html><head><title>End of the Internet</title></head>
    <body><h1>The End of the Internet</h1>
    <p>You have reached the end of the Internet.
    Feel free to go outside now.</p>
    </body></html>
---
apiVersion: v1
kind: Pod
metadata:
  name: website
spec:
  volumes:
    - name: static-files
      configMap:
        name: static-files
  containers:
    - name: nginx
      image: nginx
      volumeMounts:
        - name: static-files
          mountPath: /usr/share/nginx/html

Once that’s applied, you can port-forward your way into nginx, without much fuss:

$ kubectl port-forward website 8008:80
Forwarding from 127.0.0.1:8008 -> 80
Forwarding from [::1]:8008 -> 80

Head on over to http://localhost:8008, and you should see the following:

So, ConfigMaps can let you inject arbitrary files into a container.

In UNIX, everything is a file, including the programs we run.

That means we should be able to inject arbitrary files into a container, using a ConfigMap…

---
apiVersion: v1
kind: ConfigMap
metadata:
  name: bins
data:
  hello: |
    #!/bin/sh
    echo "Hello, ConfigMap!"
    exec sleep 86400
---
apiVersion: v1
kind: Pod
metadata:
  name: hiya
spec:
  volumes:
    - name: bins
      configMap:
        name: bins
  containers:
    - name: hiya
      image: alpine
      volumeMounts:
        - name: bins
          mountPath: /usr/local/bin
      command:
        - /usr/local/bin/hello

However, if you run that, the hiya pod will fail to start. Somewhere in the kubectl describe output, you should see an error like this:

starting container process caused "exec: \"/usr/local/bin/hello\": permission denied": unknown

By default, ConfigMaps mount in as non-executable. That makes sense, given that they are normally used for things like configuration files, data files, etc. What we’re doing is a bit unusual, but we have some options.

The first option is to change the command on the hiya container from this:

      command:
        - /usr/local/bin/hello

to this:

      command:
        - /bin/sh
        - /usr/local/bin/hello

That passes the script to /bin/sh as an argument, skipping the part where Linux tries to figure out how to run the script via the #!/... shebang at the top.

Note: this also means that whatever you do put in the shebang is ignored. This script will always run under the Bourne shell, /bin/sh. The shebang is now a comment.

Another way to fix this, that lets us avoid committing to an executor in the command: section is to mount the ConfigMap in with a different defaultMode.

  volumes:
    - name: bins
      configMap:
        name: bins
defaultMode: 0755

This new defaultMode: 0755 bit is set on the bins volume, and instructs Kubernetes to change the permissions on all of the files (but not the directories!) to have the executable bit turned on for all parties.

Next Steps

Using ConfigMaps to insert arbitrary executable scripts (safely!) into upstream container images can be super useful in a variety of circumstances, like:

  1. Not having to chain a bunch of commands together with &&
  2. Not having to build a custom image with a few shell scripts added
  3. Using a single (possibly bespoke) container and augmenting behavior with plugins

Spread the word

twitter icon facebook icon linkedin icon