<p>I have a <code>ConfigMap</code> with a variable for my domain:</p>

<pre><code>apiVersion: v1
kind: ConfigMap
metadata:
  name: config
data:
  MY_DOMAIN: mydomain.com
</code></pre>

<p>and my goal is to use the <code>MY_DOMAIN</code> variable inside my Ingress config</p>

<pre><code>apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: myingress
spec:
  tls:
    - hosts:
⮕       - config.MY_DOMAIN
      secretName: mytls
  rules:
⮕   - host: config.MY_DOMAIN
      http:
        paths:
          - backend:
              serviceName: myservice
              servicePort: 3000

</code></pre>

<p>But obviously the config above is not valid. So how can this be achieved?</p>

Florian Ludewig
<p>The <code>configMapRef</code> and <code>secretMapRef</code> for the <a href="https://gist.github.com/troyharvey/4506472732157221e04c6b15e3b3f094#file-deployment-yml-L25" rel="noreferrer">envFrom</a> and <a href="https://kubernetes.io/docs/tasks/configure-pod-container/configure-pod-configmap/#define-container-environment-variables-using-configmap-data" rel="noreferrer">valueFrom</a> functions are only available for environment variables which means they cannot be used in this context. The desired functionality is not available in vanilla Kubernetes as of 1.18.0. </p>

<p>However, it can be done. <a href="https://helm.sh/" rel="noreferrer">Helm</a> and <a href="https://kustomize.io/" rel="noreferrer">Kustomize</a> are probably the two best ways to accomplish this but it could also be done with <code>sed</code> or <code>awk</code>. Helm is a templating engine for Kubernetes manifests. Meaning, you create generic manifests, template out the deltas between your desired manifests with the generic manifests by variables, and then provide a variables file. Then, at runtime, the variables from your variables file are automatically injected into the template for you. </p>

<p>Another way to accomplish this is why Kustomize. Which is what I would personally recommend. Kustomize is like Helm in that it deals with producing customized manifests from generic ones, but it doesn't do so through templating. Kustomize is unique in that it performs merge patches between <a href="https://github.com/kubernetes-sigs/kustomize/blob/master/docs/glossary.md#patchstrategicmerge" rel="noreferrer">YAML</a> or <a href="https://github.com/kubernetes-sigs/kustomize/blob/master/docs/glossary.md#patchjson6902" rel="noreferrer">JSON</a> files at runtime. These patches are referred to as <a href="https://github.com/kubernetes-sigs/kustomize/blob/master/docs/glossary.md#overlay" rel="noreferrer">Overlays</a> so it is often referred to as an overlay engine to differentiate itself from traditional templating engines. Reason being Kustomize can be used with recursive directory trees of <a href="https://github.com/kubernetes-sigs/kustomize/blob/master/docs/glossary.md#base" rel="noreferrer">bases</a> and <a href="https://github.com/kubernetes-sigs/kustomize/blob/master/docs/glossary.md#overlay" rel="noreferrer">overlays</a>. Which makes it much more scalable for environments where dozens, hundreds, or thousands of manifests might need to be generated from boilerplate generic examples. </p>

<p>So how do we do this? Well, with Kustomize you would first define a <a href="https://github.com/kubernetes-sigs/kustomize/blob/master/docs/glossary.md#kustomization" rel="noreferrer">kustomization.yml</a> file. Within you would define your Resources. In this case, <code>myingress</code>:</p>

<pre><code>apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
    - myingress.yml
</code></pre>

<p>So create a <code>example</code> directory and make a subdirectory called <code>base</code> inside it. Create <code>./example/base/kustomization.yml</code> and populate it with the kustomization above. Now create a <code>./example/base/myingress.yml</code> file and populate it with the example <code>myingress</code> file you gave above.</p>

<pre><code>apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: myingress
spec:
  tls:
    - hosts:
      - config.MY_DOMAIN
      secretName: mytls
  rules:
     - host: config.MY_DOMAIN
        http:
          paths:
            - backend:
                serviceName: myservice
                servicePort: 3000
</code></pre>

<p>Now we need to define our first overlay. We'll create two different domain configurations to provide an example of how overlays work. First create a <code>./example/overlays/domain-a</code> directory and create a <code>kustomization.yml</code> file within it with the following contents:</p>

<pre><code>apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
bases:
    - ../../../base/

patchesStrategicMerge:
    - ing_patch.yml

configMapGenerator:
    - name: config_a
      literals:
        - MY_DOMAIN='domain_a'
</code></pre>

<p>At this point we have defined <code>ing_patch.yml</code> and <code>config_a</code> in this file. <code>ing_patch.yml</code> will serve as our ingress Patch and <code>config_a</code> will serve as our <code>configMap</code>. However, in this case we'll be taking advantage of a Kustomize feature known as a <a href="https://github.com/kubernetes-sigs/kustomize/blob/master/examples/configGeneration.md" rel="noreferrer">configMapGenerator</a> rather than manually creating configMap files for single literal <code>key:value</code> pairs. </p>

<p>Now that we have done this, we have to actually make our first patch! Since the deltas in your ingress are pretty small, it's not that hard. Create <code>./example/overlays/domain_a/ing_patch.yml</code> and populate it with:</p>

<pre><code>apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: myingress
spec:
  tls:
    - hosts:
      - domain.a.com
  rules:
     - host: domain.a.com
</code></pre>

<p>Perfect, you have created your first overlay. Now you can use <code>kubectl</code> or <code>kustomize</code> to generate your resultant manifest to apply to the Kubernetes API Server. </p>

<ul>
<li><strong>Kubectl Build:</strong>   <code>kubectl kustomize ./example/overlays/domain_a</code> </li>
<li><strong>Kustomize Build:</strong> <code>kustomize build ./example/overlays/domain_a</code> </li>
</ul>

<p>Run one of the above Build commands and review the STDOUT produced in your terminal. Notice how it contains two files, <code>myingress</code> and <code>config</code>? And <code>myingress</code> contains the Domain configuration present in your overlay's patch? </p>

<p>So, at this point you're probably asking. Why does Kustomize exist if Kubectl supports the features by default? Well Kustomize started as an external project initially and the Kustomize binary is often running a newer release than the version available in Kubectl. </p>

<p>The next step is to create a second overlay. So go ahead and <code>cp</code> your first overlay over: <code>cp -r ./example/overlays/domain_a ./example/overlays/domain_b</code>.</p>

<p>Now that you have done that, open up <code>./example/overlays/domain_b/ing_patch.yml</code> up in a text editor and change the contents to look like so:</p>

<pre><code>apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: myingress
spec:
  tls:
    - hosts:
      - domain.b.com
  rules:
     - host: domain.b.com
</code></pre>

<p>Save the file and then build your two separate overlays:</p>

<pre><code>kustomize build ./example/overlays/domain_a
kustomize build ./example/overlays/domain_b
</code></pre>

<p>Notice how each generated stream of STDOUT varies based on the patch present in the Overlay directory? You can continue to abstract this pattern by making your Bases the Overlays for other bases. Or by making your Overlays the Bases for other Overlays. Doing so can allow you to scale this project in extremely powerful and efficient ways. Apply them to your API Server if you wish:</p>

<pre><code>kubectl apply -k ./example/overlays/domain_a
kubectl apply -k ./example/overlays/domain_b
</code></pre>

<p>This is only the beginning of Kustomize really. As you might have guessed after seeing the <code>configMapGenerator</code> field in the <code>kustomization.yml</code> file for each overlay, Kustomize has a LOT of features baked in. It can add <a href="https://github.com/kubernetes-sigs/kustomize/blob/master/docs/plugins/builtins.md#field-name-commonLabels" rel="noreferrer">labels</a> to all of your resources, it can override their <a href="https://github.com/kubernetes-sigs/kustomize/blob/master/docs/plugins/builtins.md#namespacetransformer" rel="noreferrer">namespaces</a> or container <a href="https://github.com/kubernetes-sigs/kustomize/blob/master/docs/plugins/builtins.md#imagetagtransformer" rel="noreferrer">image</a> information, etc. </p>

<p>I hope this helps. Let me know if you have any other questions. </p>
