<p>I've been experimenting with <a href="https://github.com/heptio/contour" rel="nofollow noreferrer">contour</a> as an alternative ingress controller on a test GKE kubernetes cluster.</p>

<p>Following the contour <a href="https://github.com/heptio/contour/blob/master/docs/deploy-options.md" rel="nofollow noreferrer">deployment docs</a> with a few modifications, I've got a working setup serving test HTTP responses.</p>

<p>First, I created a "helloworld" pod that serves http responses, exposed via a NodePort service and an ingress:</p>

<pre><code>apiVersion: extensions/v1beta1
kind: Deployment
metadata:
    name: helloworld
spec:
  replicas: 4
  template:
    metadata:
      labels:
        app: helloworld
    spec:
      containers:
        - name: "helloworld-http"
          image: "nginxdemos/hello:plain-text"
          imagePullPolicy: Always
          resources:
            requests:
              cpu: 250m
              memory: 256Mi
      affinity:
        podAntiAffinity:
          preferredDuringSchedulingIgnoredDuringExecution:
          - weight: 100
            podAffinityTerm:
              labelSelector:
                matchExpressions:
                - key: app
                  operator: In
                  values:
                  - helloworld
              topologyKey: "kubernetes.io/hostname"
---
apiVersion: v1
kind: Service
metadata:
  name: helloworld-svc
spec:
  ports:
  - port: 80
    protocol: TCP
    targetPort: 80
  selector:
    app: helloworld
  sessionAffinity: None
  type: NodePort
---
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: helloworld-ingress
spec:
  backend:
    serviceName: helloworld-svc
    servicePort: 80
</code></pre>

<p>Then, I created a deployment for <code>contour</code> that's directly copied from their docs:</p>

<pre><code>apiVersion: v1
kind: Namespace
metadata:
  name: heptio-contour
---
apiVersion: v1
kind: ServiceAccount
metadata:
  name: contour
  namespace: heptio-contour
---
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
  labels:
    app: contour
  name: contour
  namespace: heptio-contour
spec:
  selector:
    matchLabels:
      app: contour
  replicas: 2
  template:
    metadata:
      labels:
        app: contour
      annotations:
        prometheus.io/scrape: "true"
        prometheus.io/port: "9001"
        prometheus.io/path: "/stats"
        prometheus.io/format: "prometheus"
    spec:
      containers:
      - image: docker.io/envoyproxy/envoy-alpine:v1.6.0
        name: envoy
        ports:
        - containerPort: 8080
          name: http
        - containerPort: 8443
          name: https
        command: ["envoy"]
        args: ["-c", "/config/contour.yaml", "--service-cluster", "cluster0", "--service-node", "node0", "-l", "info", "--v2-config-only"]
        volumeMounts:
        - name: contour-config
          mountPath: /config
      - image: gcr.io/heptio-images/contour:master
        imagePullPolicy: Always
        name: contour
        command: ["contour"]
        args: ["serve", "--incluster"]
      initContainers:
      - image: gcr.io/heptio-images/contour:master
        imagePullPolicy: Always
        name: envoy-initconfig
        command: ["contour"]
        args: ["bootstrap", "/config/contour.yaml"]
        volumeMounts:
        - name: contour-config
          mountPath: /config
      volumes:
      - name: contour-config
        emptyDir: {}
      dnsPolicy: ClusterFirst
      serviceAccountName: contour
      terminationGracePeriodSeconds: 30
      affinity:
        podAntiAffinity:
          preferredDuringSchedulingIgnoredDuringExecution:
          - weight: 100
            podAffinityTerm:
              labelSelector:
                matchLabels:
                  app: contour
              topologyKey: kubernetes.io/hostname
---
apiVersion: v1
kind: Service
metadata:
  name: contour
  namespace: heptio-contour
spec:
 ports:
 - port: 80
   name: http
   protocol: TCP
   targetPort: 8080
 - port: 443
   name: https
   protocol: TCP
   targetPort: 8443
 selector:
   app: contour
 type: LoadBalancer
---
</code></pre>

<p>The default and heptio-contour namespaces now look like this:</p>

<pre><code>$ kubectl get pods,svc,ingress -n default
NAME                              READY     STATUS    RESTARTS   AGE
pod/helloworld-7ddc8c6655-6vgdw   1/1       Running   0          6h
pod/helloworld-7ddc8c6655-92j7x   1/1       Running   0          6h
pod/helloworld-7ddc8c6655-mlvmc   1/1       Running   0          6h
pod/helloworld-7ddc8c6655-w5g7f   1/1       Running   0          6h

NAME                     TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)        AGE
service/helloworld-svc   NodePort    10.59.240.105   &lt;none&gt;        80:31481/TCP   34m
service/kubernetes       ClusterIP   10.59.240.1     &lt;none&gt;        443/TCP        7h

NAME                                    HOSTS     ADDRESS         PORTS     AGE
ingress.extensions/helloworld-ingress   *         y.y.y.y   80        34m

$ kubectl get pods,svc,ingress -n heptio-contour
NAME                          READY     STATUS    RESTARTS   AGE
pod/contour-9d758b697-kwk85   2/2       Running   0          34m
pod/contour-9d758b697-mbh47   2/2       Running   0          34m

NAME              TYPE           CLUSTER-IP     EXTERNAL-IP     PORT(S)                      AGE
service/contour   LoadBalancer   10.59.250.54   x.x.x.x   80:30882/TCP,443:32746/TCP   34m
</code></pre>

<p>There's 2 publicly routable IP addresses:</p>

<ul>
<li>x.x.x.x - a GCE TCP load balancer that forwards to the contour pods</li>
<li>y.y.y.y - a GCE HTTP load balancer that forwards to the helloworld pods via the helloworld-ingress</li>
</ul>

<p>A <code>curl</code> on both public IPs returns a valid HTTP response from the helloworld pods.</p>

<pre><code># the TCP load balancer
$ curl -v x.x.x.x
* Rebuilt URL to: x.x.x.x/  
*   Trying x.x.x.x...
* TCP_NODELAY set
* Connected to x.x.x.x (x.x.x.x) port 80 (#0)
&gt; GET / HTTP/1.1
&gt; Host: x.x.x.x
&gt; User-Agent: curl/7.58.0
&gt; Accept: */*
&gt;
&lt; HTTP/1.1 200 OK
&lt; server: envoy
&lt; date: Mon, 07 May 2018 14:14:39 GMT
&lt; content-type: text/plain
&lt; content-length: 155
&lt; expires: Mon, 07 May 2018 14:14:38 GMT
&lt; cache-control: no-cache
&lt; x-envoy-upstream-service-time: 1
&lt;
Server address: 10.56.4.6:80
Server name: helloworld-7ddc8c6655-w5g7f
Date: 07/May/2018:14:14:39 +0000
URI: /
Request ID: ec3aa70e4155c396e7051dc972081c6a

# the HTTP load balancer
$ curl http://y.y.y.y 
* Rebuilt URL to: y.y.y.y/
*   Trying y.y.y.y...
* TCP_NODELAY set
* Connected to y.y.y.y (y.y.y.y) port 80 (#0)
&gt; GET / HTTP/1.1
&gt; Host: y.y.y.y
&gt; User-Agent: curl/7.58.0
&gt; Accept: */*
&gt; 
&lt; HTTP/1.1 200 OK
&lt; Server: nginx/1.13.8
&lt; Date: Mon, 07 May 2018 14:14:24 GMT
&lt; Content-Type: text/plain
&lt; Content-Length: 155
&lt; Expires: Mon, 07 May 2018 14:14:23 GMT
&lt; Cache-Control: no-cache
&lt; Via: 1.1 google
&lt; 
Server address: 10.56.2.8:80
Server name: helloworld-7ddc8c6655-mlvmc
Date: 07/May/2018:14:14:24 +0000
URI: /
Request ID: 41b1151f083eaf30368cf340cfbb92fc
</code></pre>

<p>Is it by design that I have two public IPs? Which one should I use for customers? Can I choose based on my preference between a TCP and HTTP load balancer? </p>

James Healy
<p>Probably you have GLBC ingress configured (<a href="https://github.com/kubernetes/ingress-gce/blob/master/docs/faq/gce.md#how-do-i-disable-the-gce-ingress-controller" rel="nofollow noreferrer">https://github.com/kubernetes/ingress-gce/blob/master/docs/faq/gce.md#how-do-i-disable-the-gce-ingress-controller</a>)</p>

<p>Could you try using following ingress definition?</p>

<pre><code>apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  annotations:
    kubernetes.io/ingress.class: "contour"
  name: helloworld-ingress
spec:
  backend:
    serviceName: helloworld-svc
    servicePort: 80
</code></pre>

<p>If you would like to be sure that your traffic goes via contour you should use <code>x.x.x.x</code> ip.</p>
