{"id":569,"date":"2018-04-03T07:36:25","date_gmt":"2018-04-03T15:36:25","guid":{"rendered":"http:\/\/andrewwippler.com\/?p=569"},"modified":"2018-04-02T08:16:45","modified_gmt":"2018-04-02T16:16:45","slug":"allowing-outside-access-to-home-kubernetes-cluster","status":"publish","type":"post","link":"https:\/\/andrewwippler.com\/2018\/04\/03\/allowing-outside-access-to-home-kubernetes-cluster\/","title":{"rendered":"Allowing outside access to Home Kubernetes Cluster"},"content":{"rendered":"

After I created a home kubernetes cluster, I immediately wanted to allow external access to pods\/services\/ingresses hosted inside the cluster. One must be aware that in bare metal environments, there is no receiver of an api call to create a load balancer. Since there is not a scriptable environment available to kubernetes, kubernetes cannot request external IP addresses or provision resources that one has come to expect in cloud environments such as AWS. This is a huge bummer – especially since dynamically built environments are fun to have.<\/p>\n

To route traffic to web services inside of kubernetes, you have to options available: ingress<\/code> and service<\/code>. Services can be exposed via NodePort<\/code>, LoadBalancer<\/code>, or ClusterIP<\/code>. In bare metal, LoadBalancer<\/code>\u00a0would never work (unless you coded your own API call to configure a load balancer outside of kubernetes). ClusterIP<\/code>\u00a0might work if you want to manage a routing table somewhere inside your network, and NodePort<\/code>\u00a0will work if you want to manage a port forwarding table on your router. None of these options are fun for home labs on bare metal. An Ingress<\/code>\u00a0is like a layer 7 firewall in that it reads the hostname and path of the incoming HTTP request and can route to applicable services. This works great for a dynamic environment where I am going to host multiple http endpoints.<\/p>\n

The overall view of this traffic is going to be: Internet<\/code>\u00a0> Router<\/code> > k8s Ingress<\/code>\u00a0> k8s Service<\/code>\u00a0> Pod(s)<\/code>.<\/p>\n

To create an ingress in kubernetes, you have to make it a Service<\/code>. In cloud environments, the Ingress<\/code>\u00a0is created as type LoadBalancer<\/code>\u00a0in home labs, we create this as type NodePort<\/code>\u00a0and port forward on the router to any node in the kubernetes cluster.<\/p>\n

$ kubectl get svc -n ingress-nginx\nNAME                   TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)                      AGE\ndefault-http-backend   ClusterIP   10.102.173.184           80\/TCP                       3d\ningress-nginx          NodePort    10.110.162.247           80:30746\/TCP,443:32641\/TCP   3d\n<\/code><\/pre>\n

In my home lab, I am port forwarding on my router 0.0.0.0:80 -> <any_node>:30746<\/code>\u00a0and 0.0.0.0:443 -> <any_node>:32641<\/code>.<\/p>\n

Since I have a non-traditional home router (a Linux server with two nics<\/a>), I had to either enter these into iptables<\/code>\u00a0or I could improve upon that by setting up a load balancer such as nginx<\/code>. nginx<\/code>\u00a0will allow me to port-forward load balance across all my nodes and have an easy config file to edit. Because I also want to use cert-manager<\/code>\u00a0with Let’s Encrypt free SSLs, I chose to use the TCP stream server of nginx<\/code>.<\/p>\n

Another hiccup (so to speak) in home based labs, is that ISPs give DHCP addresses. So when my internet IP changes, I need to update the DNS of all my http endpoints. Rather than doing that, I have all my home urls (*.wplr.rocks<\/code>) CNAME to a single hostname which I update with a script with the correct IP.<\/p>\n","protected":false},"excerpt":{"rendered":"

After I created a home kubernetes cluster, I immediately wanted to allow external access to pods\/services\/ingresses hosted inside the cluster. One must be aware that in bare metal environments, there is no receiver of an api call to create a load balancer. Since there is not a scriptable environment available to kubernetes, kubernetes cannot request […]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"advanced_seo_description":"","jetpack_seo_html_title":"","jetpack_seo_noindex":false,"footnotes":"","jetpack_publicize_message":"","jetpack_publicize_feature_enabled":true,"jetpack_social_post_already_shared":true,"jetpack_social_options":{"image_generator_settings":{"template":"highway","enabled":false}}},"categories":[6],"tags":[51,83,43],"jetpack_publicize_connections":[],"jetpack_featured_media_url":"","jetpack-related-posts":[],"jetpack_sharing_enabled":true,"jetpack_likes_enabled":true,"_links":{"self":[{"href":"https:\/\/andrewwippler.com\/wp-json\/wp\/v2\/posts\/569"}],"collection":[{"href":"https:\/\/andrewwippler.com\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/andrewwippler.com\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/andrewwippler.com\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/andrewwippler.com\/wp-json\/wp\/v2\/comments?post=569"}],"version-history":[{"count":1,"href":"https:\/\/andrewwippler.com\/wp-json\/wp\/v2\/posts\/569\/revisions"}],"predecessor-version":[{"id":570,"href":"https:\/\/andrewwippler.com\/wp-json\/wp\/v2\/posts\/569\/revisions\/570"}],"wp:attachment":[{"href":"https:\/\/andrewwippler.com\/wp-json\/wp\/v2\/media?parent=569"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/andrewwippler.com\/wp-json\/wp\/v2\/categories?post=569"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/andrewwippler.com\/wp-json\/wp\/v2\/tags?post=569"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}