<p>I'm curious about how ConfigMap and Deployment works in kubernetes. </p>

<p>I wanted to use the values in ConfigMap as arguments to my deployment pods. I've tried this with different images and found different behaviours when passing ConfigMap value as command arguments between containers that use <code>sh</code> as entry point and other commands as entry point.</p>

<p>Here is an example configuration to better illustrate my case:</p>

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

<pre><code>apiVersion: v1
kind: ConfigMap
metadata:
  name: app-envs
data:
  key: "value"
  BUCKET_NAME: "gs://bucket-name/"
  OUTPUT_PATH: "/data"
</code></pre>

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

<pre><code>apiVersion: extensions/v1beta1
kind: Deployment
spec:
  template:
    containers:
    - name: firstContainer
      image: busybox
      command: ["sh"]
      args: 
      - c
      - |
        echo $key
        echo ${BUCKET_NAME}
        echo $(OUTPUT_PATH)
      envFrom:
      - configMapRef:
          name: app-envs
    - name: secondContainer
      image: someImage
      args: [ "cmd", "${BUCKET_NAME}", "${OUTPUT_DATA}", "${key}" ] 
      envFrom:
      - configMapRef:
          name: app-envs
    - name: thirdContainer
      image: someImage
      args: [ "cmd", "$(BUCKET_NAME)", "$(OUTPUT_DATA)", "$(key)" ] 
      envFrom:
      - configMapRef:
          name: app-envs
</code></pre>

<p><code>someImage</code> is a docker image, which has certain bash script as its entry point that prints the environment values.</p>

<hr>

<p>The <code>firstContainer</code> and <code>thirdContainer</code> are able to print all the ConfigMap values correctly, meaning, all <code>value</code>, <code>gs://bucket-name/</code> and <code>/data</code> are received as input arguments.</p>

<p>However, the <code>secondContainer</code> is unable to print these values correctly. I tried to echo the received arguments, and it turned out that it receives:</p>

<blockquote>
  <p><code>${BUCKET_NAME}</code>, <code>${OUTPUT_DATA}</code>, and <code>${key}</code> literally as input
  arguments instead of the actual values from ConfigMaps.</p>
</blockquote>

<p>So after observing the above behaviours, here are my questions:</p>

<ol>
<li><p>What's the relationship between deployment and ConfigMap? Is there
some kind of order which specify how resources are created in a k8s pod/deployment (e.g., whether ConfigMap is loaded first, then the volumeMounts, and then the container or some kind of orderings)?</p></li>
<li><p>What's the difference between <code>${}</code> and <code>$()</code>? Why does the ConfigMap values are received as literal strings when using <code>${}</code> to a container that has different entry point than <code>bash</code> or <code>sh</code>?</p></li>
</ol>

<p>Thank you. Your help would be appreciated.</p>

<p>Kubernetes only directly understands environment variable references in parentheses <code>$(VAR)</code>; see for example the note in <a href="https://kubernetes.io/docs/tasks/inject-data-application/define-command-argument-container/#use-environment-variables-to-define-arguments" rel="nofollow noreferrer">Define a Command and Arguments for a Container</a>.</p>

<pre><code>args: [ "cmd", "$(BUCKET_NAME)", "$(OUTPUT_DATA)", "$(key)" ] 
</code></pre>

<p>Kubernetes itself knows what the environment variables are and does the substitution, so the container is launched as <code>cmd gs://bucket-name/ /data key</code>.</p>

<pre><code>command: ["sh"]
args: 
- c
- |
  echo $key
  echo ${BUCKET_NAME}
  echo $(OUTPUT_PATH)
</code></pre>

<p>Kubernetes expands <code>$(OUTPUT_PATH)</code> but doesn't understand any other form of braces, so the other strings get sent on as-is.  Since you're explicitly running this through a shell, though, both <code>$key</code> and <code>${BUCKET_NAME}</code> are standard shell variable expansions, so the shell expands these values.</p>

<pre><code>args: [ "cmd", "${BUCKET_NAME}", "${OUTPUT_DATA}", "${key}" ] 
</code></pre>

<p>Kubernetes doesn't expand things in curly braces, and there's no shell or anything else to expand these variables, so the variable strings (and not their contents) get passed along as-is.</p>
