<p>I'm doing a prototype where one service depends on an availability of other. Scenario:</p>

<ul>
<li>Service A is assumed to be already available in a local network. It was either deployed by K8S or manually (or even a managed one provided by AWS etc.).</li>
<li>Service B depends on environment variable <code>SERVICE_A_IP</code> and won't start without it. It's treated as a black box and can't be modified.</li>
</ul>

<p>I want to pass Service A IP to Service B through K8S YAML configuration file. Perfect syntax for this occasion:</p>

<pre><code>...
env:
  - name: SERVICE_A_IP
    valueFrom:
      k8sDeployment:
        name: service_a
        key: deploymentIP
...
</code></pre>

<p>During the prototyping stage Service A is an another K8S deployment but it might not be so in a production environment. Thus I need to decouple from <code>SERVICE_A_SERVICE_IP</code> that will be available to Service B (given it's deployed after Service A). I'm not into DNS discovery as well as it would require container modification which is far from a perfect solution.</p>

<p>If I would do it manually with <code>kubectl</code> (or with a shell script) it would be like the following:</p>

<pre><code>$ kubectl run service_a --image=service_a:latest --port=8080
$ kubectl expose deployment service_a
$ SERVICE_A_IP="$(kubectl describe service service_a | \
    grep IP: | \
    cut -f2 -d ':' | \
    xargs)"
$ kubectl run service_b --image=service_b:latest --port=8080 \
    --env="SERVICE_A_IP=${SERVICE_A_IP}"
</code></pre>

<p>It works. Though I want to do the same using YAML configuration without injecting <code>SERVICE_A_IP</code> into configuration file with shell (basically modifying the file).</p>

<p>Is there any way to do so? Please take the above setting as set in stone.</p>

<p><strong>UPDATE</strong></p>

<p>Not the best way though still:</p>

<pre><code>$ kubectl create -f service_a.yml
deployment "service_a" created
service "service_a" created
$ SERVICE_A_IP="$(kubectl describe service service_a | \
    grep IP: | \
    cut -f2 -d ':' | \
    xargs)"
$ kubectl create configmap service_a_meta \
    --from-literal="SERVICE_A_IP=${SERVICE_A_IP}"
</code></pre>

<p>And then in <code>service_b.yml</code>:</p>

<pre><code>...
env:
  - name: SERVICE_A_IP
    valueFrom:
      configMapKeyRef:
        name: service_a_meta
        key: SERVICE_A_IP
...
</code></pre>

<p>That will work but still involves some shell and generally feels way too hax.</p>

<p>You can use <a href="https://kubernetes.io/docs/tasks/configure-pod-container/attach-handler-lifecycle-event/" rel="nofollow noreferrer">attach handlers to lifecycle events</a> for update your environment variables on start.</p>

<p>Here is an example:
<code>
apiVersion: v1
kind: Pod
metadata:
  name: appB
spec:
  containers:
  - name: appB
    image: nginx
    lifecycle:
      postStart:
        exec:
          command: ["/bin/sh", "-c", "export SERVICE_B_IP=$(host &lt;SERVICE_B&gt;.&lt;SERVICE_B_NAMESPACE&gt;.svc.cluster.local)"]</code></p>

<p>Kubernetes will run <code>preStart</code> script each time when pod with your appB container is starting right in appB container before execution of the main application.</p>

<p>But, because of <a href="https://kubernetes.io/docs/concepts/containers/container-lifecycle-hooks/#container-hooks" rel="nofollow noreferrer">that description</a>:</p>

<blockquote>
  <p><strong>PostStart</strong></p>
  
  <p>This hook executes immediately after a container is created. However, there is no guarantee that the hook will execute before the container ENTRYPOINT. No parameters are passed to the handler.</p>
</blockquote>

<p>You need to add some <code>sleep</code> for your main app before the real start just to be sure that hook will be finished before application will be started.</p>
