Add Envkey to a Docker app in Kubernetes, without rebuilding the image

I’m a big fan of using Envkey to manage parameters and credentials across different services like AWS, GCP, Docker, and Kubernetes.

One minor drawback of Envkey is that the normal methods of integrating it require you to modify either your app code, to invoke the language-appropriate envkey library, or your Dockerfile, to download and run the envkey-source binary.

This makes it difficult to use community-maintained Docker images. If you want to use Envkey, you have to fork your own version of the Dockerfile, modify it to inject Envkey, then rebuild and host the modified image yourself.

On Kubernetes, however, I discovered a neat method to integrate Envkey with any unmodified Docker image. Kubernetes provides an initContainers feature that runs a separate container attached to your pod as it starts up. We can specify an initContainer that downloads Envkey and saves the environment variables in a place where the main container can pick them up.

The Deployment specification with Envkey looks like this:

spec:
    # create a volume to share between
    # envkey and the main container
    volumes:
      - name: envkey
        emptyDir: {}
     initContainers:
      # here is the Envkey container
      - name: envkey
        image: appropriate/curl
        command:
          - "sh"
          - "-c"
          # use curl to download, install, and run envkey
          - "curl -s \
          https://raw.githubusercontent.com/envkey/envkey-source/master/install.sh \
          | /bin/sh && envkey-source > /envkey/export-env && chmod -R 777 /envkey"
          # at this point, the variables will be in a file called
          # /envkey/export-env
          # chmod/chown may be necessary depending on the user
          # account under which the main container runs.
        volumeMounts:
          - name: envkey
            mountPath: "/envkey"
        env:
          # use a Kubernetes secret to hold the ENVKEY itself
          - name: ENVKEY
            valueFrom:
              secretKeyRef:
                key: ENVKEY
                name: my-envkey
containers:
      - name: my-main-container
        image: my-docker-image
        volumeMounts:
          - name: envkey
            mountPath: "/envkey"
        command:
          - "sh"
          - "-c"
          # note: you have to override the standard container
          # command here, to load the envkey variables first.
          # Check the Dockerfile for the appropriate CMD.
          - ". /envkey/export-env && \
          my-docker-image-entrypoint"

A couple of notes:

  • We have to load the Envkey variables into the main container’s process environment before invoking the standard entry point. This means we have to peek at the Dockerfile that was used to build the container so that we can duplicate the same command. (there does not seem to be a way to over-ride just part of the entry point).
  • This also requires that /bin/sh is available in the Docker container. Most public images do have this.
  • The environment variables won’t be updated while the container is running. This shouldn’t be an issue if you are following an immutable-infrastructure philosophy.
  • You need a way to carry the ENVKEY itself into the init container’s environment. A Kubernetes secret is a great way to do this.

Leave a Reply

Your email address will not be published. Required fields are marked *