dependency injection

Context and problem

Dependency injection (DI) or "well known plugins" are a common and robust pattern in customization scenarios in the enterprise.

It's a pattern that has been used by ISVs to enable thier down stream users to customize products.

This can present challanges as ISVs modernize to containers because the ISVs want to deliver software in immutable containers but the requirement to customize by including libraries is still a concrete requirement.

Solution

Configure the application container at start up with an init container.

init diagram

The sample defines a disk volume that enables config to be passed from an initialization container to the main application container.

This scenario provides a pod definition a starting point that can be extended to meet the requirements.

In production this should be a persistent volume claim and NOT a hostPath as deployments will clobber each other

Issues and considerations

Loading libraries and config from an external source may require managing PATH priorities and loading orders that could potentially be brittle.

Areas of responsibility between vendor and client can become blurred although no worse that the virtual machine scenario.

When to use this scenario

This pattern is probably most relevent when moving from Rehost to Replatform.

Use this approach when you have additional configuration that needs to be deployed on a per container basis.

Example

apiVersion: v1
kind: Pod
metadata:
  name: di-pod
  labels:
    app.kubernetes.io/name: DiApp
spec:
  containers:
  # The main container that echos the file created by the init container.
  - name: app-container
    image: registry.access.redhat.com/ubi8/ubi-minimal
    command: ['sh', '-c', 'cat /usr/share/initfile && sleep 3600']
    volumeMounts:
    - name: shared-data
      mountPath: /usr/share
  initContainers:
  # A simple init container that echos a file into the shared data folder on startup
  - name: init-deps
    image: registry.access.redhat.com/ubi8/ubi-minimal
    volumeMounts:
    - name: shared-data
      mountPath: /pod-data
    command: ['sh', '-c', "echo Hello from the init container > /pod-data/initfile"]
    # defines a volume to enable config to be passed to the main container
    # In production this should be a persistent volume claim 
    # NOT a hostPath as deployments will clobber each other
  volumes :
      - hostPath:
          path: /tmp/di
          type: Directory
        name: shared-data

To run the scenario locally make sure you have podman installed and run the following commands:

  • Create a folder to match the volume definitions

    mkdir /tmp/di
    
  • Play the pod definition with podman

    podman play kube pod.yaml
    
  • Inspect the logs to see the main container has access to the file generated by the init container.

    podman logs di-pod-app-container
      Hello from the init container!
    
  • Clean up

    podman pod stop di-pod
    podman pod rm di-pod
    rm -fr /tmp/di
    

Streamline Builds