Introduction
Setting up a Kubernetes cluster on-premises (on-prem) or in a homelab environment can be a great way to learn and experiment with Kubernetes. However, one of the common challenges is exposing your services to the outside world. While cloud providers offer built-in solutions for external IP addresses, doing this on-prem or in a homelab requires a different approach. In this guide, we will explore various methods to get an external IP for your Kubernetes services in an on-prem setup. These methods include using MetalLB, NodePort, and an Ingress controller.
Using MetalLB for External IPs
MetalLB is a popular choice for providing LoadBalancer services in on-premises Kubernetes clusters. It allows you to assign external IPs to your services, just like in cloud environments.

Photo by admingeek from Infotechys
Installing MetalLB |
First, you need to install MetalLB. Apply the following commands to deploy MetalLB in your cluster:
kubectl apply -f https://raw.githubusercontent.com/metallb/metallb/v0.13.10/config/manifests/metallb-native.yamlnamespace/metallb-system created
customresourcedefinition.apiextensions.k8s.io/addresspools.metallb.io created
customresourcedefinition.apiextensions.k8s.io/bfdprofiles.metallb.io created
customresourcedefinition.apiextensions.k8s.io/bgpadvertisements.metallb.io created
customresourcedefinition.apiextensions.k8s.io/bgppeers.metallb.io created
customresourcedefinition.apiextensions.k8s.io/communities.metallb.io created
customresourcedefinition.apiextensions.k8s.io/ipaddresspools.metallb.io created
customresourcedefinition.apiextensions.k8s.io/l2advertisements.metallb.io created
serviceaccount/controller created
serviceaccount/speaker created
...omitted for brevity...Create a configuration map for MetalLB |
You’ll need to specify a pool of IP addresses that MetalLB can use for services. Create a file named metallb-config.yaml with the following content:
vim metallb-config.yamlCopy and paste the following in the file:
apiVersion: v1
kind: ConfigMap
metadata:
namespace: metallb-system
name: config
data:
config: |
address-pools:
- name: default
protocol: layer2
addresses:
- 192.168.1.240-192.168.1.250Apply this configuration:
kubectl apply -f metallb-config.yamlconfigmap/config createdExposing a Service Using MetalLB |
Now, you can expose a service using the LoadBalancer type. Create a service definition file named my-service.yaml:
apiVersion: v1
kind: Service
metadata:
name: my-service
spec:
selector:
app: my-app
ports:
- protocol: TCP
port: 80
targetPort: 8080
type: LoadBalancerApply the service definition:
kubectl apply -f my-service.yamlservice/my-service createdCheck the service status to see the assigned external IP:
kubectl get svc my-serviceNAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
my-service LoadBalancer 10.111.84.63 192.168.1.242 80:31252/TCP 47mNow, you will see that the EXTERNAL-IP status is 192.168.1.242, which can be accessed directly from outside the cluster without using NodePort or ClusterIP. Keep in mind that this IP, 192.168.1.242, is not assigned to any specific node. In this example, the service can be accessed via http://192.168.1.242.
Using NodePort for External Access
If you prefer not to use MetalLB, another option is to expose your service using the NodePort service type. This method will open a specific port on all nodes in your cluster, allowing external access.
Exposing a Service Using NodePort |
Edit your service definition to use NodePort. Create a file named my-service-nodeport.yaml:
apiVersion: v1
kind: Service
metadata:
name: my-service
spec:
selector:
app: my-app
ports:
- protocol: TCP
port: 80
targetPort: 8080
nodePort: 30007
type: NodePortApply service definition:
kubectl apply -f my-service-nodeport.yamlservice/my-service configuredAccess the service via NodeIP and NodePort:
kubectl get svc my-serviceNAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
my-service NodePort 10.111.84.63 <none> 80:30007/TCP 65mYour service will be accessible at http://<NodeIP>:30007. For example, if a node’s IP is 192.168.1.100, you can access the service at http://192.168.1.100:30007.
Using Ingress for Advanced Routing
For more complex setups or when managing multiple services, using an Ingress controller can be very effective. NGINX Ingress controller is a popular choice for on-premises environments.
Installing NGINX Ingress Controller |
Deploy the NGINX Ingress controller in your cluster:
kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/main/deploy/static/provider/cloud/deploy.yamlnamespace/ingress-nginx created
serviceaccount/ingress-nginx created
serviceaccount/ingress-nginx-admission created
role.rbac.authorization.k8s.io/ingress-nginx created
role.rbac.authorization.k8s.io/ingress-nginx-admission created
clusterrole.rbac.authorization.k8s.io/ingress-nginx created
clusterrole.rbac.authorization.k8s.io/ingress-nginx-admission created
rolebinding.rbac.authorization.k8s.io/ingress-nginx created
...omitted for brevity...Creating an Ingress Resource |
Create an Ingress resource to route traffic to your service. Save the following content to a file named my-ingress.yaml:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: my-ingress
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /
spec:
rules:
- host: myapp.local
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: my-service
port:
number: 80Apply the Ingress resource:
kubectl apply -f my-ingress.yamlConfiguring DNS |
Update your DNS or /etc/hosts file to point to the IP of the Ingress controller. For example, add the following line to your /etc/hosts file:
192.168.1.100 myapp.localFor on-premises or homelab Kubernetes clusters, using MetalLB to assign external IPs or using NodePort to expose services on node IPs and specific ports are common approaches. Additionally, setting up an Ingress controller provides more flexibility in managing external access to multiple services.
No comments:
Post a Comment