Setting Up a Reverse Proxy for Kubernetes Migration
Migrating my old server to Kubernetes has been on my mind for a while. The last couple of months were spent on setting up the general structure of my cluster. I got a bunch of neat tools set up on the cluster, like: ArgoCD, Cilium, External DNS, NGINX Ingress Controller and a ton more. I also figured out how I could do some GitOps, with an App of Apps and an ApplicationSet for some neat Kustomize stuff to boot. That meant that it was time to get stuff hosted on there, except for one issue: I have just the one IP available, and I have a server and a cluster serving websites.
At first, I checked out CloudFlare’s cloudflared, which is nice, but it does have several limitations. It doesn’t allow WebSocket POSTs, and in my opinion it’s not great for non-HTTP(S)-related tasks (e.g., SSH). So I checked what I could do with the cluster I had available. At this point I’m not yet fully familiar with all that’s available in this ecosystem, so I figured that I could do something with an NGINX reverse proxy.
Considering I already had NGINX Ingress Controller set up, I figured it would be wise to see if I could solve this with an Ingress. I was only used to configuring Ingresses to use Services that use labels to send traffic to Deployments/Statefulsets/etc. A quick search yielded some neat options, including a helpful blog post by Kristina Devochko that had exactly what I needed. I could link a Service to an Endpoints resource or EndpointSlice, or I could change the Service’s type to ExternalName.
I created a proxy service that routes traffic to an external service (legacy-server.example.com
) using the ExternalName
service type:
apiVersion: v1
kind: Service
metadata:
name: legacy-server
spec:
type: ExternalName
externalName: legacy-server.example.com
Note that the externalName
points to a DNS name, not an IP address.
The Ingress handles the traffic and sends it to the service. Many hosts can be added, even wildcards (which might be a security issue by exposing too many services):
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
annotations:
nginx.ingress.kubernetes.io/backend-protocol: HTTPS
name: legacy-server
namespace: proxy-legacy-server
spec:
rules:
- host: example.com
http:
paths:
- backend:
service:
name: legacy-server
port:
number: 443
path: /
pathType: Prefix
- host: registry.example.com
http:
paths:
- backend:
service:
name: legacy-server
port:
number: 443
path: /
pathType: Prefix
tls:
- hosts:
- example.com
- registry.example.com
secretName: example-com-tls
Note that this example assumes the legacy-server
endpoint expects traffic on port 443
using the HTTPS
protocol. If HTTPS isn’t needed, remove the annotation and update the port to match the service’s expected port.
Now that this part is sorted, I can gradually migrate services to the cluster without impacting DNS or requiring third-party services, and I can easily revert to the legacy setup if things go awry.