<p>I'm migrating an application to Docker/Kubernetes. This application has 20+ well-known ports it needs to be accessed on. It needs to be accessed from outside the kubernetes cluster. For this, the application writes its public accessible IP to a database so the outside service knows how to access it. The IP is taken from the downward API (<code>status.hostIP</code>). </p>

<p>One solution is defining the well-known ports as (static) nodePorts in the service, but I don't want this, because it will limit the usability of the node: if another service has started and incidentally taken one of the known ports the application will not be able to start. Also, because Kubernetes opens the ports on all nodes in the cluster, I can only run 1 instance of the application per cluster.</p>

<p>Now I want to make the application aware of the port mappings done by the NodePort-service. How can this be done? As I don't see a hard link between the <code>Service</code> and the <code>Statefulset</code> object in Kubernetes.</p>

<p>Here is my (simplified) Kubernetes config: </p>

<pre><code>apiVersion: v1
kind: Service
metadata:
  name: my-app-svc
  labels:
    app: my-app
spec:
  ports:
    - port: 6000
      targetPort: 6000
      protocol: TCP
      name: debug-port
    - port: 6789
      targetPort: 6789
      protocol: TCP
      name: traffic-port-1
  selector:
    app: my-app
  type: NodePort

---
apiVersion: apps/v1
kind: StatefulSet
metadata:
    name: my-app-sf
spec:
    serviceName: my-app-svc
    replicas: 1
    selector:
      matchLabels:
        app: my-app
    template:
      metadata:
        labels:
          app: my-app
      spec:
          containers:
            - name: my-app
              image: my-repo/myapp/my-app:latest
              imagePullPolicy: Always
              env:
                - name: K8S_ServiceAccountName
                  valueFrom:
                    fieldRef:
                      fieldPath: spec.serviceAccountName
                - name: K8S_ServerIP
                  valueFrom:
                    fieldRef:
                      fieldPath: status.hostIP
                - name: serverName
                  valueFrom:
                    fieldRef:
                      fieldPath: metadata.name
              ports:
              - name: debug
                containerPort: 6000
              - name: traffic1
                containerPort: 6789
</code></pre>

<p>This can be done with an initContainer. </p>

<p>You can define an initContainer to get the nodeport and save into a directory that shared with the container, then container can get the nodeport from that directory later, a simple demo like this:</p>

<pre><code>apiVersion: v1
kind: Pod
metadata:
  name: my-app
spec:
  containers:
  - name: my-app
    image: busybox
    command: ["sh", "-c", "cat /data/port; while true; do sleep 3600; done"]
    volumeMounts:
    - name: config-data
      mountPath: /data
  initContainers:
  - name: config-data
    image: tutum/curl
    command: ["sh", "-c", "TOKEN=`cat /var/run/secrets/kubernetes.io/serviceaccount/token`; curl -kD - -H \"Authorization: Bearer $TOKEN\" https://kubernetes.default:443/api/v1/namespaces/test/services/app 2&gt;/dev/null | grep nodePort | awk '{print $2}' &gt; /data/port"]
    volumeMounts:
    - name: config-data
      mountPath: /data
  volumes:
  - name: config-data
    emptyDir: {}
</code></pre>
