Search code examples
kubernetesraspberry-pi3nginx-ingress

External ip always <none> or <pending> in kubernetes


Recently i started building my very own kubernetes cluster using a few Raspberry pi's.

I have gotten to the point where i have a cluster up and running!

Some background info on how i setup the cluster, i used this guide

But now, when i want to deploy and expose an application i encounter some issues...

Following the kubernetes tutorials i have made an deployment of nginx, this is running fine. when i do a port-forward i can see the default nginx page on my localhost.

Now the tricky part, creating an service and routing the traffic from the internet through an ingress to the service.

i have executed the following command's

kubectl expose deployment/nginx --type="NodePort" --port 80
kubectl expose deployment/nginx --type="Loadbalancer" --port 80

And these result in the following.

NAME         TYPE        CLUSTER-IP    EXTERNAL-IP   PORT(S)          AGE
kubernetes   ClusterIP   10.96.0.1     <none>        443/TCP          25h
nginx        NodePort    10.103.77.5   <none>        80:30106/TCP   7m50s
NAME         TYPE           CLUSTER-IP       EXTERNAL-IP   PORT(S)        AGE
kubernetes   ClusterIP      10.96.0.1        <none>        443/TCP        25h
nginx        LoadBalancer   10.107.233.191   <pending>     80:31332/TCP   4s

The external ip address never shows, which makes it quite impossible for me to access the application from outside of the cluster by doing curl some-ip:80 which in the end is the whole reason for me to setup this cluster.

If any of you have some clear guides or advice i can work with it would be really appreciated!

Note: I have read things about LoadBalancer, this is supposed to be provided by the cloud host. since i run on RPI i don't think this will work for me. but i believe NodePort should be just fine to route with an ingress.

Also i am aware of the fact that i should have an ingress-controller of some sort for ingress to work.

Edit

So i have the following now for the nodeport - 30168

$ kubectl get svc
NAME         TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)        AGE
kubernetes   ClusterIP   10.96.0.1       <none>        443/TCP        26h
nginx        NodePort    10.96.125.112   <none>        80:30168/TCP   6m20s

and for the ip address i have either 192.168.178.102 or 10.44.0.1

$ kubectl describe pod nginx-688b66fb9c-jtc98
Node:               k8s-worker-2/192.168.178.102
IP:                 10.44.0.1

But when i enter either of these ip addresses in the browser with the nodeport i still don't see the nginx page. am i doing something wrong?


Solution

  • Since you are not in a cloud provider, you need to use MetalLB to have the LoadBalancer features working.

    Kubernetes does not offer an implementation of network load-balancers (Services of type LoadBalancer) for bare metal clusters. The implementations of Network LB that Kubernetes does ship with are all glue code that calls out to various IaaS platforms (GCP, AWS, Azure…). If you’re not running on a supported IaaS platform (GCP, AWS, Azure…), LoadBalancers will remain in the “pending” state indefinitely when created.

    Bare metal cluster operators are left with two lesser tools to bring user traffic into their clusters, “NodePort” and “externalIPs” services. Both of these options have significant downsides for production use, which makes bare metal clusters second class citizens in the Kubernetes ecosystem.

    MetalLB aims to redress this imbalance by offering a Network LB implementation that integrates with standard network equipment, so that external services on bare metal clusters also “just work” as much as possible

    The MetalLB setup is very easy:

    kubectl apply -f https://raw.githubusercontent.com/google/metallb/v0.8.3/manifests/metallb.yaml

    This will deploy MetalLB to your cluster, under the metallb-system namespace

    You need to create a configMap with the ip range you want to use, create a file named metallb-cf.yaml:

    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.250 <= Select the range you want.
    

    kubectl apply -f metallb-cf.yaml

    That's all.

    To use on your services just create with type LoadBalancer and MetalLB will do the rest. If you want to customize the configuration see here

    MetalLB will assign a IP for your service/ingress, but if you are in a NAT network you need to configure your router to forward the requests for your ingress/service IP.

    EDIT:

    You have problem to get External IP with MetalLB running on Raspberry Pi, try to change iptables to legacy version:

    sudo sysctl net.bridge.bridge-nf-call-iptables=1
    sudo update-alternatives --set iptables /usr/sbin/iptables-legacy
    

    Reference: https://www.shogan.co.uk/kubernetes/building-a-raspberry-pi-kubernetes-cluster-part-2-master-node/

    I hope that helps.