A simple guide on how to setup a reverse proxy for your Kubernetes services on port 80 using Nginx on Kubernetes.
What will this achieve?
Say you have a service deployed on your Kubernetes cluster called
node-web-server, it exposes a port 300 and to keep this simple this is deployed in the
default namespace. This means that your other services can talk to this service on
node-web-server.default:3000 inside the cluster. Now you want to give external access to this service so that your friends or co-workers can access it, for example on
node-web-server.mydomain.com -> node-web-server.default:3000 using only YAML config.
Why did you create this guide, isn't this simple?
Most of the information I could find on the internet was using clusters deployed on GKE or AWS which allow you to deploy an Nginx Ingress as type
LoadBalancer. This means that the external GKE or AWS load balancer will do the heavy work of making your Ingress available on port 80. I was unable to find a simple guide that talked you through actually getting your Nginx to expose a port 80 on a bare metal cluster, they all seemed to leave me in this situation:
node-web-server.mydomain.com:32500 -> node-web-server.default:3000
Which quite frankly is ugly, I wanted to expose my app on port 80!
- Root access on the Kubernetes master node
- A domain with an A record setup to point to the IP address of one of the nodes in the Kubernetes cluster
These are the assumptions I have made in the article, you can simply replace this in any of the code/config listed on this page.
- You are using the
- The service you want to expose is called
node-web-serverand exposes a port
- The A-Record is setup on
The crucial step to all of this is giving your cluster permission to use a NodePort of port 80, beware when doing this as it does mean you are exposing services on privileged ports.
- SSH into the Kubernetes master
/etc/kubernetes/manifests/kube-apiserver.yamlfor editing with your favourite text editor:
nano, you decide!
- In the command section where there is a list of arguments, add to the bottom of that list
- Save and close the file
rebootthe Kubernetes master.
- Wait for it to come back online and for
kubectl get nodesto say it is ready again.
Deploying the Nginx instance
Now we've allowed services to run on a NodePort of 80 we can deploy the Nginx service! This will setup a default Nginx ingress based on:
Execute the following commands, this will setup a new namespace
ingress-nginx and setup the Nginx default config and a default HTTP backend in this namespace.
curl https://raw.githubusercontent.com/kubernetes/ingress-nginx/master/deploy/namespace.yaml \ | kubectl apply -f -
curl https://raw.githubusercontent.com/kubernetes/ingress-nginx/master/deploy/default-backend.yaml \ | kubectl apply -f -
curl https://raw.githubusercontent.com/kubernetes/ingress-nginx/master/deploy/configmap.yaml \ | kubectl apply -f -
curl https://raw.githubusercontent.com/kubernetes/ingress-nginx/master/deploy/tcp-services-configmap.yaml \ | kubectl apply -f -
curl https://raw.githubusercontent.com/kubernetes/ingress-nginx/master/deploy/udp-services-configmap.yaml \ | kubectl apply -f -
If you have RBAC setup on your cluster (most versions of Kubernetes >=1.7 do) then execute the following commands to deploy the Nginx instance:
curl https://raw.githubusercontent.com/kubernetes/ingress-nginx/master/deploy/rbac.yaml \ | kubectl apply -f -
curl https://raw.githubusercontent.com/kubernetes/ingress-nginx/master/deploy/with-rbac.yaml \ | kubectl apply -f -
For non-RBAC execute the following command:
curl https://raw.githubusercontent.com/kubernetes/ingress-nginx/master/deploy/without-rbac.yaml \ | kubectl apply -f -
Deploying the Nginx service
Now the most important step, this is my custom config which will allow you to expose the Nginx instance on port 80.
Save the following to a file
--- apiVersion: v1 kind: Service metadata: name: ingress-nginx namespace: ingress-nginx spec: type: NodePort ports: - name: http port: 80 targetPort: 80 nodePort: 80 protocol: TCP selector: app: ingress-nginx
Apply this to the cluster with
kubectl apply -f nginx-service.yml
Creating an ingress rule for your service
Save the following to a file named
--- apiVersion: extensions/v1beta1 kind: Ingress metadata: name: node-web-server namespace: default spec: rules: - host: node-web-server.mydomain.com http: paths: - path: "/" backend: serviceName: node-web-server servicePort: 3000
Apply this to the cluster with
kubectl apply -f ingress.yml
Exposing more services
To expose more services all you need to do is add another A record for that service e.g
service2.mydomain.com and then deploy another
ingress.yml (seen above) but with a different
spec.rules.host and different
I usually find it easier however to setup a wildcard, e.g for my
dev cluster I setup an A record for
*.dev.mydomain.com and then I can deploy Ingress rules using Ansible to automatically forward my new services!
If you have issues, I'm available by email.