<p>A MCVE example is here: <a href="https://github.com/chrissound/k8s-metallb-nginx-ingress-minikube" rel="nofollow noreferrer">https://github.com/chrissound/k8s-metallb-nginx-ingress-minikube</a>
(just run <code>./init.sh</code> and <code>minikube addons enable ingress</code>).</p>

<p>The IP assigned to the ingress keeps getting reset, I don't know what is causing it? Do I need additional configuration perhaps?</p>

<pre><code>kubectl get ingress --all-namespaces                 
NAMESPACE       NAME          HOSTS         ADDRESS           PORTS     AGE
chris-example   app-ingress   example.com   192.168.122.253   80, 443   61m
</code></pre>

<p>And a minute later:</p>

<pre><code>NAMESPACE       NAME          HOSTS         ADDRESS   PORTS     AGE
chris-example   app-ingress   example.com             80, 443   60m
</code></pre>

<hr>

<p>In terms of configuration I've just applied:</p>

<pre><code># metallb
kubectl apply -f https://raw.githubusercontent.com/google/metallb/v0.7.3/manifests/metallb.yaml

# nginx
kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/master/deploy/static/mandatory.yaml
kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/master/deploy/static/provider/baremetal/service-nodeport.yaml
</code></pre>

<hr>

<p>ingress controller logs logs:</p>

<pre><code>I0714 22:00:38.056148       7 event.go:258] Event(v1.ObjectReference{Kind:"Ingress", Namespace:"chris-example", Name:"app-ingress", UID:"cbf3b5bf-a67a-11e9-be9a-a4cafa3aa171", APIVersion:"networking.k8s.io/v1beta1", ResourceVersion:"8681", FieldPath:""}): type: 'Normal' reason: 'UPDATE' Ingress chris-example/app-ingress
I0714 22:01:19.153298       7 event.go:258] Event(v1.ObjectReference{Kind:"Ingress", Namespace:"chris-example", Name:"app-ingress", UID:"cbf3b5bf-a67a-11e9-be9a-a4cafa3aa171", APIVersion:"networking.k8s.io/v1beta1", ResourceVersion:"8743", FieldPath:""}): type: 'Normal' reason: 'UPDATE' Ingress chris-example/app-ingress
I0714 22:01:38.051694       7 status.go:296] updating Ingress chris-example/app-ingress status from [{192.168.122.253 }] to []
I0714 22:01:38.060044       7 event.go:258] Event(v1.ObjectReference{Kind:"Ingress", Namespace:"chris-example", Name:"app-ingress", UID:"cbf3b5bf-a67a-11e9-be9a-a4cafa3aa171", APIVersion:"networking.k8s.io/v1beta1", ResourceVersion:"8773", FieldPath:""}): type: 'Normal' reason: 'UPDATE' Ingress chris-example/app-ingress
</code></pre>

<p>And the metallb controller logs:</p>

<pre><code>{"caller":"main.go:72","event":"noChange","msg":"service converged, no change","service":"kube-system/kube-dns","ts":"2019-07-14T21:58:39.656725017Z"}
{"caller":"main.go:73","event":"endUpdate","msg":"end of service update","service":"kube-system/kube-dns","ts":"2019-07-14T21:58:39.656741267Z"}
{"caller":"main.go:49","event":"startUpdate","msg":"start of service update","service":"chris-example/app-lb","ts":"2019-07-14T21:58:39.6567588Z"}
{"caller":"main.go:72","event":"noChange","msg":"service converged, no change","service":"chris-example/app-lb","ts":"2019-07-14T21:58:39.656842026Z"}
{"caller":"main.go:73","event":"endUpdate","msg":"end of service update","service":"chris-example/app-lb","ts":"2019-07-14T21:58:39.656873586Z"}
</code></pre>

<hr>

<p>As a test I deleted the deployment+daemonset relating to metallb:</p>

<pre><code>kubectl delete deployment -n metallb-system controller
kubectl delete daemonset -n metallb-system speaker
</code></pre>

<p>And after the external IP is set, it'll once again reset... </p>

<p>I was curious and recreated your case. I was able to properly expose the service.</p>
<p>First of all: you don't need to use minikube ingress addon when deploying your own NGINX. If you do, you have 2 ingress controllers in a cluster and it leads confusion later. Run: <code>minikube addons disable ingress</code></p>
<p>Sidenote: You can see this confusion in the IP your ingress got assigned: <code>192.168.122.253</code> which is not in CIDR range <code>192.168.39.160/28</code> you defined in <code>configmap-metallb.yaml</code>.</p>
<hr />
<p>You need to change service type of <code>ingress-nginx</code> to <code>LoadBalancer</code>. you can do this by running:</p>
<pre><code>kubectl edit -n ingress-nginx service ingress-nginx
</code></pre>
<p>Additionally, you can change <code>app-lb</code> service to <code>NodePort</code>, since it doesn't need to be exposed outside of the cluster - ingress controller will take care of it.</p>
<hr />
<h3>Explanation</h3>
<p>It's easier to think about <code>Ingress</code> object as of <code>ConfigMap</code>, rather than <code>Service</code>.</p>
<p>MetalLB takes configuration you provided in <code>ConfigMap</code> and waits for IP request API call. When it gets one it provides IP form the CIDR range you specified.</p>
<p>In a similar way, ingress controller (NGINX in your case) takes configuration described in <code>Ingress</code> object and uses it to rout traffic to desired place in the cluster.</p>
<p>Then <code>ingress-nginx</code> service is exposed outside of the cluster with assigned IP.</p>
<p>Inbound traffic is directed by Ingress controller (NGINX), based on rules described in <code>Ingress</code> object to a service in font of your application.</p>
<h3>Diagram</h3>
<pre><code>Inbound
traffic
   ++     +---------+
   ||     |ConfigMap|
   ||     +--+------+
   ||        |
   ||        | CIDR range to provision
   ||        v
   ||     +--+----------+
   ||     |MetalLB      |               +-------+
   ||     |Load balancer|               |Ingress|
   ||     +-+-----------+               +---+---+
   ||       |                               |
   ||       |  External IP assigned         |Rules described in spec
   ||       |  to service                   |
   ||       v                               v
   ||    +--+--------------------+      +---+------------------+
   ||    |                       |      |  Ingress Controller  |
   |----&gt;+ ingress-nginx service +-----&gt;+      (NGINX pod)     |
   +----&gt;|                       +-----&gt;+                      |
         +-----------------------+      +----------------------+
                                                    ||
                                                    VV
                                          +-----------------+
                                          | Backend service |
                                          | (app-lb)        |
                                          |                 |
                                          +-----------------+
                                                   ||
                                                   VV
                                          +--------------------+
                                          | Backend pod        |
                                          | (httpbin)          |
                                          |                    |
                                          +--------------------+
</code></pre>
