Using an ingress to expose and external service

Rationale TL;DR

Let’s suppose you would like to expose an external service by using a Kubernetes ingress. May be you want to expose a site hosted somewhere else using the nginx ingress as a proxy, for example.

The solution

First of all, we need to create an endpoint object. This object will present an endpoint which will be using an external IP as its upstream. This endpoint will work at the TCP/UDP level, simply forwarding the connection to the upstream host.

 ---
 kind: "Endpoints"
 apiVersion: "v1"
 metadata:
   name: "www"
 subsets:
   -
     addresses:
       - ip: "1.1.1.1"
     ports:
       -
         port: 443
         name: "www"
~

In this example, I’m defining an endpoint pointing to 1.1.1.1:443 (don’t try it at home, kids). After that, we can define a new service which will use that endpoint, this way we would be able to to expose the upstream service to the ingress controller (which needs a service):

After applying those manifests, we can describe the objects we just created:

# kubectl describe svc www
Name:              www
Namespace:         kube-system
Labels:            <none>
Annotations:       <none>
Selector:          <none>
Type:              ClusterIP
IP:                100.71.29.55
Port:              www  443/TCP
TargetPort:        443/TCP
Endpoints:         18.196.54.137:443
Session Affinity:  None
Events:            <none>

#kubectl describe ep www
Name:         www
Namespace:    kube-system
Labels:       <none>
Annotations:  <none>
Subsets:
  Addresses:          1.1.1.1
  NotReadyAddresses:  <none>
  Ports:
    Name  Port  Protocol
    ----  ----  --------
    www   443   TCP

Events:  <none>

Finally, we need to tell our ingress to expose that upstream service:

 apiVersion: extensions/v1beta1
 kind: Ingress
 metadata:
   annotations:
     nginx.ingress.kubernetes.io/proxy-read-timeout: "3600"
     nginx.ingress.kubernetes.io/proxy-send-timeout: "3600"
     kubernetes.io/ingress.class: nginx
     nginx.ingress.kubernetes.io/backend-protocol: "HTTPS"

   name: www-example-com
 spec:
   rules:
   - host: www.example.com
     http:
       paths:
       - backend:
           serviceName: www
           servicePort: 443
         path: /

In this example, I’m forcing the nginx ingress to talk to the upstream by using https. This is because my particular setup requires that, the upstream does a redirection to https when using plain old http.