There are 3 main service types in a kubernetes deployment- ClusterIP
NodePort
LoadBalancer
. To expose services in production, using ClusterIP and NodePort is not a good practice. LoadBalancer can be used in this case. But using LoadBalancer service type in bare metal is problematic. We will explore around such a case in this blog post.
In the first place, we will deploy a Nginx image in service type ClusterIP. This is a basic nginx welcome page.
# nginx.yml
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
spec:
selector:
matchLabels:
app: nginx
replicas: 2
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:1.14.2
ports:
- containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
name: nginx-svc
spec:
ports:
- port: 80
targetPort: 80
selector:
app: nginx
So, let's apply it-
kubectl apply -f nginx.yml
So it launches 2 pods and a service of type ClusterIP. We can check it using-
$ kubectl get services
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
nginx-svc ClusterIP 10.18.0.242 <none> 80/TCP 2d11h
We can check the content served using cluster ip:
$ curl -D- 10.18.0.242
HTTP/1.1 200 OK
Server: nginx/1.14.2
kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/controller-v1.3.0/deploy/static/provider/cloud/deploy.yaml
This will create a new namespace ingress-nginx
. It will create 3 pods and 2 services. If we check the service now-
$ kubectl get service -n ingress-nginx
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/ingress-nginx-controller NodePort 10.18.0.66 <pending> 80:30243/TCP,443:32414/TCP 18h
we will see the external IP is in <pending>
state. This is due to our cloud provider doesn't provide load balancer.
Now, we will change the service type of ingress-nginx-controller
pod to NodePort
-
$ kubectl edit svc -n ingress-nginx ingress-nginx-controller
Change the type and save. If we check service now, we will see the external ip is now in <none>
stage from <pending>
.
$ kubectl get service -n ingress-nginx
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/ingress-nginx-controller NodePort 10.18.0.66 <none> 80:30243/TCP,443:32414/TCP 18h
Our nginx controller configration is done. Now it's time to create the rules for ingress resource.
In our ingress resource, we will serve our nginx welcome page which we deployed earlier using our hostname, e.g. web.shafinhasnat.me
, later we will make this public. Create the yml file below-
# ingress.yml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: minimal-ingress
annotations:
kubernetes.io/ingress.class: "nginx"
nginx.ingress.kubernetes.io/use-regex: "true"
nginx.ingress.kubernetes.io/rewrite-target: /
spec:
rules:
- host: web.shafinhasnat.me
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: nginx-svc
port:
number: 80
Apply using-
kubectl apply -f ingress.yml
It will create an ingress called minimal-ingress. We can check it using-
$ kubectl get ingress
NAME CLASS HOSTS ADDRESS PORTS AGE
minimal-ingress <none> web.shafinhasnat.me 10.18.0.66 80 10h
Now, if we resolve the dns to the address, we will be able to see the content served by nginx pod-
$ curl --resolve web.shafinhasnat.me:80:10.18.0.66 -D- http://web.shafinhasnat.me
HTTP/1.1 200 OK
...
This can be done by editing /etc/hosts
-
#add this line
10.18.0.66 web.shafinhasnat.me
We can check directly using the domain-
$ curl -D- web.shafinhasnat.me
HTTP/1.1 200 OK
...
So everything is working from the host machine. Now we will make this accessible from the internet.
Now, what we have to do is, reverse proxy incoming traffic to the ingress ip and port. Basically we will expose the reverse proxy service in the internet. We will use nginx in this case.
First we will create an .conf
file-
# nginx.conf
server {
listen 80;
server_name _;
location / {
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $remote_addr;
proxy_pass http://11.0.0.21:30243;
}
}
Now, we will create a docker-compose.yml
-
version: '3.8'
services:
nginx:
image: nginx
ports:
- 80:80
volumes:
- ./nginx.conf:/etc/nginx/conf.d/default.conf
Now simply deploy with-
docker-compose up -d
Make sure, this vm has internet connectivity and port 80
allowed in firewall.
Now, if we check resolving dns to the ip of the vm, we will see our nginx welcome page form our kubernetes cluster is up and running.
$ curl http://web.shafinhasnat.me/ --resolve web.shafinhasnat.me:80:<your_public_ip>
HTTP/1.1 200 OK
Server: nginx/1.23.1
...
To make it public, just simply add the public ip in the A records of your domain name provider manager dashboard.