Kubernetes: proxy requests without additional pods

Sometimes you need to provide a legacy access to various downloads or proxy some requests to a different endpoint, that might not be running in your cluster. One can natively redirect such requests with having to add additional deployments / containers to your Kubernetes cluster.

There is a special type of Kubernete’s service object that simply points any traffic to that external DNS name. This isn’t really document all too well but eventually you will find enough issues and pointers to frankenstein a solution together. For anybody else looking on how to do this correctly, here is run down with nginx-ingress-controller:0.19.0 that worked for me.

First we create a normal ingress object, that allows us to terminate the SSL and look into the path of the HTTP request and decide if this is a request that is relevant to be proxied. 

apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  annotations:
    kubernetes.io/ingress.class: nginx
    kubernetes.io/tls-acme: "true"
    nginx.ingress.kubernetes.io/rewrite-target: "<your-bucket-namespace>"
    nginx.ingress.kubernetes.io/secure-backends: "true"
  name: artifacts
spec:
  rules:
    - host: downloads.example.com
      http:
        paths:
          - path: "/artifacts/"
            backend:
              serviceName: proxy-artifacts
              servicePort: 443
  tls:
  - secretName: tls
    hosts:
    - downloads.example.com

Lets quickly take a look at what is going on here. We first configure our Ingress Controller to use nginx and enable automatic provisioning via our cluster ACME/cert-manager.

Then we instruct nginx to rewrite the target URL to add the bucket. This way, we can swap buckets without the user facing URL having to change. (Notice to not include leading or trailing slashes)

Lastly we tell nginx, that the backend it should be expecting also is using TLS.

The rest of the ingress object is pretty standard. Define the hostname, the path and point it towards our service, that we will take a look at next.

apiVersion: v1
kind: Service
spec:
  externalName: storage.googleapis.com
  type: ExternalName
metadata:
  name: proxy-artifacts

The service object is pretty standard. Notice that we don’t have to specify the port explicitly with this special kind of service. The externalName property simply is the hostname of what external system you want to talk to.

Deploy those two configurations and you should be all set. Once you have all the quirks figured out, this is actually really simple and saves you from operating any additional reverse proxies in- or outside your cluster. 

Published by

KB

I'm a student at TUM in Computer Science & Pizza eating. Passionate for SRE, beautiful Code and Club Mate.