<p><strong>The dilemma</strong>: Deploy multiple app and database container pairs with identical docker image and code, but different config (different clients using subdomains).</p>

<p><em>What are some logical ways to approach this, as it doesn't seem kubernetes has an integration that would support this kind of setup?</em></p>

<p><strong>Possible Approaches</strong></p>

<ol>
<li>Use a single app service for all app deployments, a single database service for all database deployments. Have a single Nginx static file service and deployment running, that will serve static files from a static volume that is shared between the app deployments (all use the same set of static files). Whenever a new deployment is needed, have a bash script copy the app and database .yaml deployment files and sed text replace with the name of the client, and point to the correct configmap (which is manually written ofcourse) and kubectl apply them. A main nginx ingress will handle the incoming traffic and point to the correct pod through the app deployment service</li>
<li>Similar to the above except use a StatefulSet instead of separate deployments, and an init container to copy different configs to mounted volumes (only drawback is you cannot delete an item in the middle of a statefulset, which would be the case if you no longer need a specific container for a client, as well as this seems like a very hacky approach).</li>
</ol>

<p>Ideally if a StatefulSet could use the downward api to dynamically choose a configmap name based on the index of the stateful set that would resolve the issue (where you would basically make your config files manually with the index in the name, and it would be selected appropriately). Something like:</p>

<pre><code>env:
- name: POD_NAME
  valueFrom:
    fieldRef:
      fieldPath: metadata.name

envFrom:
- configMapRef:
  name: $(POD_NAME)-config
</code></pre>

<p>However that functionality isn't available in kubernetes.</p>

<p>A templating engine like <a href="https://helm.sh/" rel="nofollow noreferrer">Helm</a> can help with this.  (I believe <a href="https://kustomize.io/" rel="nofollow noreferrer">Kustomize</a>, which ships with current Kubernetes, can do this too, but I'm much more familiar with Helm.)  The basic idea is that you have a <em>chart</em> that contains the Kubernetes YAML files but can use a templating language (the Go <a href="https://godoc.org/text/template" rel="nofollow noreferrer"><code>text/template</code></a> library) to dynamically fill in content.</p>

<p>In this setup generally you'd have Helm create both the ConfigMap and the matching Deployment; in the setup you describe you'd install it separately (a Helm <em>release</em>) for each tenant.  Say the Nginx configurations were different enough that you wanted to store them in <a href="https://helm.sh/docs/chart_template_guide/accessing_files/" rel="nofollow noreferrer">external files</a>; the core parts of your chart would include</p>

<p><strong>values.yaml</strong> (overridable configuration, <code>helm install --set nginxConfig=bar.conf</code>):</p>

<pre class="lang-yaml prettyprint-override"><code># nginxConfig specifies the name of the Nginx configuration
# file to embed.
nginxConfig: foo.conf
</code></pre>

<p><strong>templates/configmap.yaml</strong>:</p>

<pre class="lang-yaml prettyprint-override"><code>apiVersion: v1
kind: ConfigMap
metadata:
  name: {{ .Release.Name }}-{{ .Chart.Name }}-config
data:
  nginx.conf: |-
{{ .Files.Get .Values.nginxConfig | indent 4 }}
</code></pre>

<p><strong>deployment.yaml</strong>:</p>

<pre class="lang-yaml prettyprint-override"><code>apiVersion: v1
kind: Deployment
metadata:
  name: {{ .Release.Name }}-{{ .Chart.Name }}-nginx
spec:
  ...
    volumes:
      - name: nginx-config
        configMap:
          name: {{ .Release.Name }}-{{ .Chart.Name }}-config
</code></pre>

<p>The <code>{{ .Release.Name }}-{{ .Chart.Name }}</code> is a typical convention that allows installing multiple copies of the chart in the same namespace; the first part is a name you give the <code>helm install</code> command and the second part is the name of the chart itself.  You can also directly specify the ConfigMap content, referring to other <code>.Values...</code> settings from the <code>values.yaml</code> file, use the ConfigMap as environment variables instead of files, and so on.</p>
