{"id":23251,"date":"2024-08-21T00:07:38","date_gmt":"2024-08-20T21:07:38","guid":{"rendered":"https:\/\/kifarunix.com\/?p=23251"},"modified":"2024-08-21T07:20:52","modified_gmt":"2024-08-21T04:20:52","slug":"kubernetes-ingress-explained-how-to-manage-external-access-to-your-services","status":"publish","type":"post","link":"https:\/\/kifarunix.com\/kubernetes-ingress-explained-how-to-manage-external-access-to-your-services\/","title":{"rendered":"Kubernetes Ingress Explained: How to Manage External Access to Your Services"},"content":{"rendered":"<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"978\" height=\"544\" src=\"https:\/\/kifarunix.com\/wp-content\/uploads\/2024\/08\/kubernetes-ingress.png?v=1724187696\" alt=\"Kubernetes Ingress Explained: How to Manage External Access to Your Services\" class=\"wp-image-23279\" title=\"\" srcset=\"https:\/\/kifarunix.com\/wp-content\/uploads\/2024\/08\/kubernetes-ingress.png?v=1724187696 978w, https:\/\/kifarunix.com\/wp-content\/uploads\/2024\/08\/kubernetes-ingress-768x427.png?v=1724187696 768w\" sizes=\"(max-width: 978px) 100vw, 978px\" \/><\/figure><\/div>\n\n\n<p>Welcome to our tutorial on how you can utilize Kubernetes Ingress to manage external access to your Kubernetes services. <a href=\"https:\/\/kubernetes.io\/docs\/concepts\/services-networking\/ingress\/\" target=\"_blank\" rel=\"noreferrer noopener\">Kubernetes Ingress<\/a> is a powerful tool that simplifies the management of external traffic to services running within a cluster. It acts as a reverse proxy, routing incoming requests to specific services based on defined rules. By utilizing Ingress, you can efficiently manage load balancing, SSL termination, and name-based virtual hosting.<\/p>\n\n\n\n<div class=\"wp-block-rank-math-toc-block\" id=\"rank-math-toc\"><h2>Table of Contents<\/h2><nav><ul><li><a href=\"#using-kubernetes-ingress-to-manage-external-access-to-services\">Using Kubernetes Ingress to Manage External Access to Services<\/a><ul><li><a href=\"#what-is-kubernetes-ingress\">What is Kubernetes Ingress?<\/a><\/li><li><a href=\"#key-components-of-kubernetes-ingress\">Key Components of Kubernetes Ingress<\/a><\/li><li><a href=\"#how-to-setup-kubernetes-ingress\">How to Setup Kubernetes Ingress<\/a><ul><li><a href=\"#installing-kubernetes-ingress-controller\">Installing Kubernetes Ingress Controller<\/a><\/li><li><a href=\"#create-a-deployment-and-service\">Create a Deployment and Service<\/a><\/li><li><a href=\"#create-an-ingress-resource\">Create an Ingress Resource<\/a><\/li><li><a href=\"#configure-dns-for-an-ingress-controller\">Configure DNS for an Ingress Controller<\/a><\/li><li><a href=\"#external-ip-for-local-on-premise-kubernetes-cluster-install-metal-lb\">External IP for Local\/On-Premise Kubernetes Cluster: Install MetalLB<\/a><\/li><li><a href=\"#configure-metal-lb-address-allocation\">Configure MetalLB Address Allocation<\/a><\/li><\/ul><\/li><li><a href=\"#conclusion\">Conclusion<\/a><\/li><\/ul><\/li><\/ul><\/nav><\/div>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"using-kubernetes-ingress-to-manage-external-access-to-services\">Using Kubernetes Ingress to Manage External Access to Services<\/h2>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"what-is-kubernetes-ingress\">What is Kubernetes Ingress?<\/h3>\n\n\n\n<p>So, how do I access Kubernetes service externally? Kubernetes Ingress is an API object resource that manages external access to services within a cluster. It provides HTTP and HTTPS routing, allowing you to define rules for how incoming traffic should be directed to different backend services in the cluster based on the request&#8217;s hostname or path.<\/p>\n\n\n\n<p>It can provide load balancing, SSL termination, and name-based virtual hosting. Essentially, it helps route traffic from outside the cluster to your services inside the cluster based on various rules.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"key-components-of-kubernetes-ingress\">Key Components of Kubernetes Ingress<\/h3>\n\n\n\n<p>What are the core components in Kubernetes Ingress?<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Ingress Resource<\/strong>: This is a Kubernetes configuration file that defines rules for routing external  HTTP\/HTTPS traffic to services within the cluster. At a high level, an Ingress resource is made up of the routing rules and configurations for the Ingress including:\n<ul class=\"wp-block-list\">\n<li><strong>Host<\/strong>: The domain name (e.g., <code>kifarunix.com<\/code>) that the rule applies to. If not specified, the rule applies to all hosts.<\/li>\n\n\n\n<li><strong>HTTP<\/strong>: Contains HTTP-specific routing information and includes:\n<ul class=\"wp-block-list\">\n<li><strong>Path<\/strong>: The URL path prefix (e.g., <code>\/about-us<\/code>). It is used to match incoming requests and route them to the appropriate backend.<\/li>\n\n\n\n<li><strong>PathType<\/strong>: Specifies how the path is matched. Common values include:\n<ul class=\"wp-block-list\">\n<li><strong>Prefix<\/strong> (match based on a path prefix). This is useful when you want to handle all paths that start with a specific prefix in the same way. It\u2019s common for serving content that falls under a certain category or section of a site e.g. \/about, about\/team, \/about\/history&#8230;<\/li>\n\n\n\n<li><strong>Exact<\/strong> (match based on the exact path). The <code>Exact<\/code> path type matches only the exact URL path specified. For instance, if you set a path <code>\/about-us<\/code> with <code>Exact<\/code>, it will only match requests to <code>\/about-us<\/code> and nothing else.<\/li>\n\n\n\n<li><strong>ImplementationSpecific:<\/strong> The default type, usually treated the same as Prefix. However, its behavior can vary depending on the Ingress controller implementation.<\/li>\n<\/ul>\n<\/li>\n\n\n\n<li><strong>Resource Backend<\/strong>: Defines the destination for the matched request and includes:\n<ul class=\"wp-block-list\">\n<li><strong>Service<\/strong>: The Kubernetes Service to which the request should be routed.<\/li>\n\n\n\n<li><strong>Port<\/strong>: The port on the Service that should receive the traffic.<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n<\/li>\n\n\n\n<li><strong>TLS<\/strong> (optional): Configures TLS\/SSL termination for the Ingress. This section includes:\n<ul class=\"wp-block-list\">\n<li><strong>Hosts<\/strong>: A list of hostnames that should be served over HTTPS.<\/li>\n\n\n\n<li><strong>SecretName<\/strong>: The name of the Kubernetes Secret that contains the TLS certificate and private key.<\/li>\n<\/ul>\n<\/li>\n\n\n\n<li><strong>Default Backend<\/strong>: The default backend is a Service that receives all traffic that doesn&#8217;t match any of the defined rules in the Ingress resource. It&#8217;s essentially a fallback option. This can be used to display a custom error page or redirect traffic to a specific service.<\/li>\n<\/ul>\n<\/li>\n\n\n\n<li><strong>Ingress Controller<\/strong>: This is a component that implements the Ingress rules defined. There are various <a href=\"https:\/\/kubernetes.io\/docs\/concepts\/services-networking\/ingress-controllers\/\" target=\"_blank\" rel=\"noreferrer noopener\">Ingress controllers<\/a> available (e.g., NGINX, Traefik, HAProxy).<\/li>\n\n\n\n<li><strong>Service<\/strong>: Represents a set of pods and a port for accessing them.<\/li>\n\n\n\n<li><strong>Ingress Class<\/strong>: This determines which Ingress controller should implement the rules. It\u2019s useful in environments where multiple controllers are used.<\/li>\n<\/ul>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"how-to-setup-kubernetes-ingress\">How to Setup Kubernetes Ingress<\/h3>\n\n\n\n<p>To setup Kubernetes Ingress, proceed as follows;<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Install Kubernetes Ingress Controller<\/li>\n\n\n\n<li>Create a Deployment and a Service to expose it within the cluster.<\/li>\n\n\n\n<li>Create an Ingress resource to expose the service externally<\/li>\n\n\n\n<li>Setup a DNS for your service<\/li>\n\n\n\n<li>Verify the Setup.<\/li>\n<\/ul>\n\n\n\n<h4 class=\"wp-block-heading\" id=\"installing-kubernetes-ingress-controller\">Installing Kubernetes Ingress Controller<\/h4>\n\n\n\n<p>To get started, you&#8217;ll need an Ingress controller. There are multiple Ingress controllers you can choose from based on your use cases. In this example guide, we will use the&nbsp;<a href=\"https:\/\/github.com\/kubernetes\/ingress-nginx\" target=\"_blank\" rel=\"noreferrer noopener\">NGINX Ingress Controller for Kubernetes<\/a>.<\/p>\n\n\n\n<p>Nginx Ingress controller can be deployed using <a href=\"https:\/\/kubernetes.github.io\/ingress-nginx\/deploy\/#quick-start\" target=\"_blank\" rel=\"noreferrer noopener\">different ways<\/a>. Since we are running a Kubeadm Kubernetes cluster, we will install Kubernetes Nginx ingress controller using its YAML file by running <strong>kubectl apply<\/strong> command as follows.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>kubectl apply -f https:\/\/raw.githubusercontent.com\/kubernetes\/ingress-nginx\/main\/deploy\/static\/provider\/cloud\/deploy.yaml<\/code><\/pre>\n\n\n\n<p>Sample installation output;<\/p>\n\n\n\n<pre class=\"scroll-box\"><code>namespace\/ingress-nginx created\nserviceaccount\/ingress-nginx created\nserviceaccount\/ingress-nginx-admission created\nrole.rbac.authorization.k8s.io\/ingress-nginx created\nrole.rbac.authorization.k8s.io\/ingress-nginx-admission created\nclusterrole.rbac.authorization.k8s.io\/ingress-nginx created\nclusterrole.rbac.authorization.k8s.io\/ingress-nginx-admission created\nrolebinding.rbac.authorization.k8s.io\/ingress-nginx created\nrolebinding.rbac.authorization.k8s.io\/ingress-nginx-admission created\nclusterrolebinding.rbac.authorization.k8s.io\/ingress-nginx created\nclusterrolebinding.rbac.authorization.k8s.io\/ingress-nginx-admission created\nconfigmap\/ingress-nginx-controller created\nservice\/ingress-nginx-controller created\nservice\/ingress-nginx-controller-admission created\ndeployment.apps\/ingress-nginx-controller created\njob.batch\/ingress-nginx-admission-create created\njob.batch\/ingress-nginx-admission-patch created\ningressclass.networking.k8s.io\/nginx created\nvalidatingwebhookconfiguration.admissionregistration.k8s.io\/ingress-nginx-admission created\n<\/code><\/pre>\n\n\n\n<p>This will deploy Ingress controller as a Deployment resource in the <strong>ingress-nginx<\/strong> namespace.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>kubectl get all -n ingress-nginx<\/code><\/pre>\n\n\n\n<pre class=\"scroll-box\"><code>NAME                                            READY   STATUS      RESTARTS   AGE\npod\/ingress-nginx-admission-create-kl4mr        0\/1     Completed   0          85s\npod\/ingress-nginx-admission-patch-4zqjb         0\/1     Completed   1          85s\npod\/ingress-nginx-controller-7d4db76476-5h4cq   1\/1     Running     0          85s\n\nNAME                                         TYPE           CLUSTER-IP      EXTERNAL-IP   PORT(S)                      AGE\nservice\/ingress-nginx-controller             LoadBalancer   10.108.54.181   &lt;pending&gt;     80:30580\/TCP,443:30896\/TCP   86s\nservice\/ingress-nginx-controller-admission   ClusterIP      10.103.61.173   &lt;none&gt;        443\/TCP                      85s\n\nNAME                                       READY   UP-TO-DATE   AVAILABLE   AGE\ndeployment.apps\/ingress-nginx-controller   1\/1     1            1           85s\n\nNAME                                                  DESIRED   CURRENT   READY   AGE\nreplicaset.apps\/ingress-nginx-controller-7d4db76476   1         1         1       85s\n\nNAME                                       STATUS     COMPLETIONS   DURATION   AGE\njob.batch\/ingress-nginx-admission-create   Complete   1\/1           5s         85s\njob.batch\/ingress-nginx-admission-patch    Complete   1\/1           6s         85s\n<\/code><\/pre>\n\n\n\n<p>To render the controller details;<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>kubectl describe deployment ingress-nginx-controller -n ingress-nginx<\/code><\/pre>\n\n\n\n<pre class=\"scroll-box\"><code>\nName:                   ingress-nginx-controller\nNamespace:              ingress-nginx\nCreationTimestamp:      Mon, 19 Aug 2024 19:35:45 +0000\nLabels:                 app.kubernetes.io\/component=controller\n                        app.kubernetes.io\/instance=ingress-nginx\n                        app.kubernetes.io\/name=ingress-nginx\n                        app.kubernetes.io\/part-of=ingress-nginx\n                        app.kubernetes.io\/version=1.11.2\nAnnotations:            deployment.kubernetes.io\/revision: 1\nSelector:               app.kubernetes.io\/component=controller,app.kubernetes.io\/instance=ingress-nginx,app.kubernetes.io\/name=ingress-nginx\nReplicas:               1 desired | 1 updated | 1 total | 1 available | 0 unavailable\nStrategyType:           RollingUpdate\nMinReadySeconds:        0\nRollingUpdateStrategy:  1 max unavailable, 25% max surge\nPod Template:\n  Labels:           app.kubernetes.io\/component=controller\n                    app.kubernetes.io\/instance=ingress-nginx\n                    app.kubernetes.io\/name=ingress-nginx\n                    app.kubernetes.io\/part-of=ingress-nginx\n                    app.kubernetes.io\/version=1.11.2\n  Service Account:  ingress-nginx\n  Containers:\n   controller:\n    Image:           registry.k8s.io\/ingress-nginx\/controller:v1.11.2@sha256:d5f8217feeac4887cb1ed21f27c2674e58be06bd8f5184cacea2a69abaf78dce\n    Ports:           80\/TCP, 443\/TCP, 8443\/TCP\n    Host Ports:      0\/TCP, 0\/TCP, 0\/TCP\n    SeccompProfile:  RuntimeDefault\n    Args:\n      \/nginx-ingress-controller\n      --publish-service=$(POD_NAMESPACE)\/ingress-nginx-controller\n      --election-id=ingress-nginx-leader\n      --controller-class=k8s.io\/ingress-nginx\n      --ingress-class=nginx\n      --configmap=$(POD_NAMESPACE)\/ingress-nginx-controller\n      --validating-webhook=:8443\n      --validating-webhook-certificate=\/usr\/local\/certificates\/cert\n      --validating-webhook-key=\/usr\/local\/certificates\/key\n      --enable-metrics=false\n    Requests:\n      cpu:      100m\n      memory:   90Mi\n    Liveness:   http-get http:\/\/:10254\/healthz delay=10s timeout=1s period=10s #success=1 #failure=5\n    Readiness:  http-get http:\/\/:10254\/healthz delay=10s timeout=1s period=10s #success=1 #failure=3\n    Environment:\n      POD_NAME:        (v1:metadata.name)\n      POD_NAMESPACE:   (v1:metadata.namespace)\n      LD_PRELOAD:     \/usr\/local\/lib\/libmimalloc.so\n    Mounts:\n      \/usr\/local\/certificates\/ from webhook-cert (ro)\n  Volumes:\n   webhook-cert:\n    Type:          Secret (a volume populated by a Secret)\n    SecretName:    ingress-nginx-admission\n    Optional:      false\n  Node-Selectors:  kubernetes.io\/os=linux\n  Tolerations:     &lt;none&gt;\nConditions:\n  Type           Status  Reason\n  ----           ------  ------\n  Available      True    MinimumReplicasAvailable\n  Progressing    True    NewReplicaSetAvailable\nOldReplicaSets:  &lt;none&gt;\nNewReplicaSet:   ingress-nginx-controller-7d4db76476 (1\/1 replicas created)\nEvents:\n  Type    Reason             Age    From                   Message\n  ----    ------             ----   ----                   -------\n  Normal  ScalingReplicaSet  3m49s  deployment-controller  Scaled up replica set ingress-nginx-controller-7d4db76476 to 1\n<\/code><\/pre>\n\n\n\n<h4 class=\"wp-block-heading\" id=\"create-a-deployment-and-service\">Create a Deployment and Service<\/h4>\n\n\n\n<p>In our environment, we have a custom web app with an <strong>home<\/strong> page and an <strong>about-us<\/strong> page running under <strong>ingress<\/strong> namespace.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>cat deployment.yaml<\/code><\/pre>\n\n\n\n<pre class=\"scroll-box\"><code>apiVersion: apps\/v1\nkind: Deployment\nmetadata:\n  name: nginx-deployment\n  namespace: ingress\nspec:\n  replicas: 1\n  selector:\n    matchLabels:\n      app: nginx\n  template:\n    metadata:\n      labels:\n        app: nginx\n    spec:\n      containers:\n      - name: nginx\n        image: nginx:latest\n        volumeMounts:\n        - name: nginx-conf\n          mountPath: \/etc\/nginx\/conf.d\n        - name: index-html\n          mountPath: \/usr\/share\/nginx\/html\n        - name: about-us-html\n          mountPath: \/usr\/share\/nginx\/html\/about\n      volumes:\n      - name: nginx-conf\n        configMap:\n          name: nginx.conf\n      - name: index-html\n        configMap:\n          name: index.html\n      - name: about-us-html\n        configMap:\n          name: about-us.html          \n---\napiVersion: v1\nkind: Service\nmetadata:\n  name: nginx-service\n  namespace: ingress\nspec:\n  selector:\n    app: nginx\n  ports:\n    - protocol: TCP\n      port: 80\n      targetPort: 80\n  type: LoadBalancer\n<\/code><\/pre>\n\n\n\n<p>The deployment is exposed via a Load balancer service type.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>kubectl get all -n ingress<\/code><\/pre>\n\n\n\n<pre class=\"scroll-box\"><code>NAME                                    READY   STATUS    RESTARTS   AGE\npod\/nginx-deployment-78c6f7dd66-qxdsr   1\/1     Running   0          10s\n\nNAME                    TYPE           CLUSTER-IP      EXTERNAL-IP   PORT(S)        AGE\nservice\/nginx-service   LoadBalancer   10.100.105.43   &lt;pending&gt;     80:31617\/TCP   10s\n\nNAME                               READY   UP-TO-DATE   AVAILABLE   AGE\ndeployment.apps\/nginx-deployment   1\/1     1            1           10s\n\nNAME                                          DESIRED   CURRENT   READY   AGE\nreplicaset.apps\/nginx-deployment-78c6f7dd66   1         1         1       10s\n<\/code><\/pre>\n\n\n\n<p>As you can see, the external IP is still pending.<\/p>\n\n\n\n<p>Within the cluster, we can access the web pages mentioned above as;<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>curl 10.100.105.43<\/code><\/pre>\n\n\n\n<pre class=\"scroll-box\"><code>&lt;!DOCTYPE html&gt;\n&lt;html&gt;\n&lt;head&gt;\n    &lt;title&gt;Home Page&lt;\/title&gt;\n&lt;\/head&gt;\n&lt;body&gt;\n    &lt;h1&gt;Welcome to the Home Page!&lt;\/h1&gt;\n    &lt;p&gt;This is the default custom page served at the root path.&lt;\/p&gt;\n    &lt;a href=\"\/about-us\"&gt;About Us&lt;\/a&gt;\n&lt;\/body&gt;\n&lt;\/html&gt;\n<\/code><\/pre>\n\n\n\n<pre class=\"wp-block-code\"><code>curl 10.100.105.43\/about-us<\/code><\/pre>\n\n\n\n<pre class=\"scroll-box\"><code>&lt;!DOCTYPE html&gt;\n&lt;html&gt;\n&lt;head&gt;\n    &lt;title&gt;About Us&lt;\/title&gt;\n&lt;\/head&gt;\n&lt;body&gt;\n    &lt;h1&gt;About Us&lt;\/h1&gt;\n    &lt;p&gt;This is the custom About Us page.&lt;\/p&gt;\n    &lt;a href=\"\/\"&gt;Home&lt;\/a&gt;\n&lt;\/body&gt;\n&lt;\/html&gt;\n<\/code><\/pre>\n\n\n\n<h4 class=\"wp-block-heading\" id=\"create-an-ingress-resource\">Create an Ingress Resource<\/h4>\n\n\n\n<p>Next, we\u2019ll define an Ingress resource to expose the web server service. This resource will route external traffic to the Nginx service through the load balancer IP.<\/p>\n\n\n\n<p>You can create an Ingress controller via declarative method using a manifest YAML file or imperatively using <strong>kubect create ingress<\/strong> command. Imperative method however does not offer flexibility provided by the declarative method.<\/p>\n\n\n\n<p>To use a declarative method, proceed as follows.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>cat ingress-resource.yaml<\/code><\/pre>\n\n\n\n<pre class=\"scroll-box\"><code>apiVersion: networking.k8s.io\/v1\nkind: Ingress\nmetadata:\n  name: nginx-ingress-resource\n  namespace: ingress\nspec:\n  rules:\n  - host: kifarunix-demo.com\n    http:\n      paths:\n      - path: \/\n        pathType: Exact\n        backend:\n          service:\n            name: nginx-service\n            port:\n              number: 80\n      - path: \/about-us\n        pathType: Exact\n        backend:\n          service:\n            name: nginx-service\n            port:\n              number: 80\n<\/code><\/pre>\n\n\n\n<p>Apply;<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>kubectl apply -f ingress-resource.yaml<\/code><\/pre>\n\n\n\n<p>If you want to create the ingress via command line, the command line syntax is;<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>kubectl create ingress NAME --rule=host\/path=service:port&#91;,tls&#91;=secret]]  &#91;options]<\/code><\/pre>\n\n\n\n<p>For example, to create an ingress like the above via command line;<\/p>\n\n\n\n<pre class=\"scroll-box\"><code>kubectl create ingress nginx-ingress-resource -n ingress \\\n\t--rule=\"kifarunix-demo.com\/*=nginx-service:80\" \\\n\t--rule=\"kifarunix-demo.com\/about-us=nginx-service:80\"\n<\/code><\/pre>\n\n\n\n<p>Read more on <strong>kubectl create ingress &#8211;help<\/strong>.<\/p>\n\n\n\n<p>List Ingress resources on your namespace;<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>kubectl get ingress -n ingress\n<\/code><\/pre>\n\n\n\n<p><strong>-n ingress<\/strong> specifies our namespace.<\/p>\n\n\n\n<pre class=\"scroll-box\"><code>NAME                     CLASS    HOSTS                ADDRESS   PORTS   AGE\nnginx-ingress-resource   &lt;none&gt;   kifarunix-demo.com             80      15s\n<\/code><\/pre>\n\n\n\n<h4 class=\"wp-block-heading\" id=\"configure-dns-for-an-ingress-controller\">Configure DNS for an Ingress Controller<\/h4>\n\n\n\n<p>For the Ingress resource to work, you need to point the domain of your application to the external IP address of your Ingress controller.<\/p>\n\n\n\n<p>To find the external IP address assigned to your Ingress Controller service, run the following command to list the services in the <strong>ingress-nginx<\/strong> namespace.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>kubectl get service -n ingress-nginx<\/code><\/pre>\n\n\n\n<pre class=\"scroll-box\"><code>NAME                                 TYPE           CLUSTER-IP      EXTERNAL-IP   PORT(S)                      AGE\ningress-nginx-controller             LoadBalancer   10.108.54.181   &lt;pending&gt;     80:30580\/TCP,443:30896\/TCP   36m\ningress-nginx-controller-admission   ClusterIP      10.103.61.173   &lt;none&gt;        443\/TCP                      36m\n<\/code><\/pre>\n\n\n\n<p>From the output;<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>NAME<\/strong>: This column shows the name of the Kubernetes service.\n<ul class=\"wp-block-list\">\n<li><strong><code>ingress-nginx-controller<\/code><\/strong>: This is the primary service for the Ingress Controller. It\u2019s responsible for handling incoming HTTP\/HTTPS traffic and routing it based on Ingress rules.<\/li>\n\n\n\n<li><strong><code>ingress-nginx-controller-admission<\/code><\/strong>: This service is typically used for admission control purposes, such as validating or mutating Ingress resources before they are applied.<\/li>\n<\/ul>\n<\/li>\n\n\n\n<li><strong>TYPE<\/strong>: This indicates the type of the service, which determines how it is exposed.\n<ul class=\"wp-block-list\">\n<li><strong><code>LoadBalancer<\/code><\/strong>: This type of service provisions a load balancer in cloud environments (like AWS, Azure, GCP) that provides an external IP address to route traffic to your service.<\/li>\n\n\n\n<li><strong><code>ClusterIP<\/code><\/strong>: This type of service is only accessible within the Kubernetes cluster. It is not exposed to the outside world.<\/li>\n<\/ul>\n<\/li>\n\n\n\n<li><strong>CLUSTER-IP<\/strong>: This is the internal IP address assigned to the service within the Kubernetes cluster.\n<ul class=\"wp-block-list\">\n<li><code><strong>10.108.54.181<\/strong><\/code>: This is the internal IP address for the <code>ingress-nginx-controller<\/code> service.<\/li>\n\n\n\n<li><strong><code>10.103.61.173<\/code><\/strong>: This is the internal IP address for the <code>ingress-nginx-controller-admission<\/code> service.<\/li>\n<\/ul>\n<\/li>\n\n\n\n<li><strong>EXTERNAL-IP<\/strong>: This is the IP address that is exposed outside the Kubernetes cluster (for LoadBalancer services).\n<ul class=\"wp-block-list\">\n<li><strong><code>&lt;pending&gt;<\/code><\/strong>: Indicates that an external IP address has not yet been assigned. This usually happens when the cloud provider has not yet provisioned the load balancer or assigned an IP. The external IP will be populated once the load balancer is set up. If you are running a local\/on-premise K8S cluster, you won&#8217;t get an external IP out of the box.<\/li>\n\n\n\n<li><strong><code>&lt;none&gt;<\/code><\/strong>: This indicates that the service does not have an external IP because it is a <code>ClusterIP<\/code> service and is only accessible within the cluster.<\/li>\n<\/ul>\n<\/li>\n\n\n\n<li><strong>PORT(S)<\/strong>: Lists the ports that the service is listening on and the corresponding node ports (for <code>LoadBalancer<\/code> type services).\n<ul class=\"wp-block-list\">\n<li><strong><code>80:30580\/TCP<\/code><\/strong>: The service is exposing port 80 internally and mapping it to port 30270 on the node.<\/li>\n\n\n\n<li><strong><code>443:30896\/TCP<\/code><\/strong>: The service is exposing port 443 internally and mapping it to port 32487 on the node.<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n\n\n\n<p>So, you would typically set the DNS entry of the application domain to point to the value of the EXTERNAL_IP address.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\" id=\"external-ip-for-local-on-premise-kubernetes-cluster-install-metal-lb\">External IP for Local\/On-Premise Kubernetes Cluster: Install MetalLB<\/h4>\n\n\n\n<p>If you&#8217;re running a non-cloud (on-premises or bare-metal) Kubernetes cluster, you won\u2019t have a cloud provider\u2019s load balancer automatically provisioning an external IP address for your <code>LoadBalancer<\/code> service. Instead, you can use NodePort service type to expose your Ingress controller or simply use <strong><a href=\"https:\/\/metallb.universe.tf\/\" data-type=\"link\" data-id=\"https:\/\/metallb.universe.tf\/\" target=\"_blank\" rel=\"noreferrer noopener\">MetalLB<\/a><\/strong>, a load-balancer implementation for bare metal&nbsp;Kubernetes&nbsp;clusters.<\/p>\n\n\n\n<p>In this demo, we will use <strong>MetalLB<\/strong>. MetalLB allows you to create Kubernetes services of type&nbsp;<code>LoadBalancer<\/code>&nbsp;in clusters that don\u2019t run on a cloud provider.<\/p>\n\n\n\n<p>Before you can proceed, check the <strong>kube-proxy<\/strong> mode from the cluster. <strong>iptables<\/strong> is the default mode. For example, run this command on the master node;<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>curl localhost:10249\/proxyMode<\/code><\/pre>\n\n\n\n<p>Sample output in my case shows, <strong>iptables<\/strong>. If the output is IPVS, it shows you are using IPVS to manage and distribute network traffic.<\/p>\n\n\n\n<p>If IPVS is enabled, you have to edit the <strong>kube-proxy<\/strong> to and set strict ARP mode to true.<\/p>\n\n\n\n<pre class=\"scroll-box\"><code>kubectl get configmap kube-proxy -n kube-system -o yaml | \\\nsed -e \"s\/strictARP: false\/strictARP: true\/\" | \\\nkubectl apply -f - -n kube-system\n<\/code><\/pre>\n\n\n\n<p>Next, proceed to install MetalLB using manifest. Just get the <a href=\"https:\/\/metallb.universe.tf\/release-notes\/#version-0-14-8\" target=\"_blank\" rel=\"noreferrer noopener\">current release version<\/a> and replace the value of VER below;<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>VER=v0.14.8<\/code><\/pre>\n\n\n\n<pre class=\"wp-block-code\"><code>kubectl apply -f https:\/\/raw.githubusercontent.com\/metallb\/metallb\/${VER}\/config\/manifests\/metallb-native.yaml<\/code><\/pre>\n\n\n\n<p>Sample installation output;<\/p>\n\n\n\n<pre class=\"scroll-box\"><code>namespace\/metallb-system created\ncustomresourcedefinition.apiextensions.k8s.io\/bfdprofiles.metallb.io created\ncustomresourcedefinition.apiextensions.k8s.io\/bgpadvertisements.metallb.io created\ncustomresourcedefinition.apiextensions.k8s.io\/bgppeers.metallb.io created\ncustomresourcedefinition.apiextensions.k8s.io\/communities.metallb.io created\ncustomresourcedefinition.apiextensions.k8s.io\/ipaddresspools.metallb.io created\ncustomresourcedefinition.apiextensions.k8s.io\/l2advertisements.metallb.io created\ncustomresourcedefinition.apiextensions.k8s.io\/servicel2statuses.metallb.io created\nserviceaccount\/controller created\nserviceaccount\/speaker created\nrole.rbac.authorization.k8s.io\/controller created\nrole.rbac.authorization.k8s.io\/pod-lister created\nclusterrole.rbac.authorization.k8s.io\/metallb-system:controller created\nclusterrole.rbac.authorization.k8s.io\/metallb-system:speaker created\nrolebinding.rbac.authorization.k8s.io\/controller created\nrolebinding.rbac.authorization.k8s.io\/pod-lister created\nclusterrolebinding.rbac.authorization.k8s.io\/metallb-system:controller created\nclusterrolebinding.rbac.authorization.k8s.io\/metallb-system:speaker created\nconfigmap\/metallb-excludel2 created\nsecret\/metallb-webhook-cert created\nservice\/metallb-webhook-service created\ndeployment.apps\/controller created\ndaemonset.apps\/speaker created\nvalidatingwebhookconfiguration.admissionregistration.k8s.io\/metallb-webhook-configuration created\n<\/code><\/pre>\n\n\n\n<p>As you can see, the LoadBalancer is installed in a separate namespace, <strong>metallb-system<\/strong>.<\/p>\n\n\n\n<p>The MetalLB components that are deployed include:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>The&nbsp;<code>metallb-system\/controller<\/code>&nbsp;deployment which is the cluster-wide controller that handles IP address assignments.<\/li>\n\n\n\n<li>The&nbsp;<code>metallb-system\/speaker<\/code>&nbsp;daemonset which is the component that speaks the protocol(s) of your choice to make the services reachable.<\/li>\n\n\n\n<li>Service accounts for the controller and speaker, along with the RBAC permissions that the components need to function.<\/li>\n<\/ul>\n\n\n\n<pre class=\"wp-block-code\"><code>kubectl get pods -n metallb-system<\/code><\/pre>\n\n\n\n<pre class=\"scroll-box\"><code>NAME                          READY   STATUS    RESTARTS   AGE\ncontroller-6dd967fdc7-brn6z   1\/1     Running   0          24s\nspeaker-cqms7                 1\/1     Running   0          24s\nspeaker-f4d2t                 1\/1     Running   0          24s\nspeaker-hjnhq                 1\/1     Running   0          24s\nspeaker-lxpts                 1\/1     Running   0          24s\nspeaker-wprwg                 1\/1     Running   0          24s\nspeaker-xk4rg                 1\/1     Running   0          24s\n<\/code><\/pre>\n\n\n\n<h4 class=\"wp-block-heading\" id=\"configure-metal-lb-address-allocation\">Configure MetalLB Address Allocation<\/h4>\n\n\n\n<p><em>By default, MetalLB will allocate IPs from any configured address pool with free addresses.<\/em> As such, you need to configure it to use a pool of IP addresses for load balancing through the use of <strong>IPAddressPool<\/strong> resource.<\/p>\n\n\n\n<p>You also need to define an <strong><code>L2Advertisement<\/code><\/strong> resource to allow <strong>MetalLB<\/strong> to broadcast the presence of services with assigned external IPs to devices on the same local network.<\/p>\n\n\n\n<p>We will create these resources via YAML files as follows;<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>cat metallb-resources.yaml<\/code><\/pre>\n\n\n\n<pre class=\"scroll-box\"><code>apiVersion: metallb.io\/v1beta1\nkind: IPAddressPool\nmetadata:\n  name: demo-pool\n  namespace: metallb-system\nspec:\n  addresses:\n  - 192.168.122.245-192.168.122.250\n---\napiVersion: metallb.io\/v1beta1\nkind: L2Advertisement\nmetadata:\n  name: demo-l2\n  namespace: metallb-system\nspec:\n  ipAddressPools:\n    - demo-pool\n<\/code><\/pre>\n\n\n\n<p>Adjust the name and address space for the pool as well as the <strong>L2Advertisement<\/strong> name.<\/p>\n\n\n\n<p>Let&#8217;s apply the resources;<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>kubectl apply -f metallb-resources.yaml<\/code><\/pre>\n\n\n\n<p>Now, if you check our Nginx ingress controller LoadBalancer, it should be having an EXTERNAL IP;<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>kubectl get service -n ingress-nginx<\/code><\/pre>\n\n\n\n<pre class=\"scroll-box\"><code>NAME                                 TYPE           CLUSTER-IP      EXTERNAL-IP       PORT(S)                      AGE\ningress-nginx-controller             LoadBalancer   10.108.54.181   192.168.122.246   80:30580\/TCP,443:30896\/TCP   21h\ningress-nginx-controller-admission   ClusterIP      10.103.61.173   &lt;none&gt;            443\/TCP                      21h\n<\/code><\/pre>\n\n\n\n<p>Similarly, our deployment service should also be having an EXTERNAL IP;<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>kubectl get service -n ingress<\/code><\/pre>\n\n\n\n<pre class=\"scroll-box\"><code>NAME            TYPE           CLUSTER-IP      EXTERNAL-IP       PORT(S)        AGE\nnginx-service   LoadBalancer   10.100.105.43   192.168.122.245   80:31617\/TCP   21h\n<\/code><\/pre>\n\n\n\n<p>So, to externally access our Nginx app via ingress controller, we need to use our app service external IP.<\/p>\n\n\n\n<p>We have mapped it locally to the domain;<\/p>\n\n\n\n<p>Accessing home page;<\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"1393\" height=\"384\" src=\"https:\/\/kifarunix.com\/wp-content\/uploads\/2024\/08\/ingress-controller-external-ip-access.png?v=1724184508\" alt=\"Kubernetes Ingress Explained\" class=\"wp-image-23276\" title=\"\" srcset=\"https:\/\/kifarunix.com\/wp-content\/uploads\/2024\/08\/ingress-controller-external-ip-access.png?v=1724184508 1393w, https:\/\/kifarunix.com\/wp-content\/uploads\/2024\/08\/ingress-controller-external-ip-access-768x212.png?v=1724184508 768w\" sizes=\"(max-width: 1393px) 100vw, 1393px\" \/><\/figure>\n\n\n\n<p>Accessing about-us page;<\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"1423\" height=\"441\" src=\"https:\/\/kifarunix.com\/wp-content\/uploads\/2024\/08\/ingress-controller-external-ip-access-2.png?v=1724184523\" alt=\"Kubernetes Ingress Explained\" class=\"wp-image-23277\" title=\"\" srcset=\"https:\/\/kifarunix.com\/wp-content\/uploads\/2024\/08\/ingress-controller-external-ip-access-2.png?v=1724184523 1423w, https:\/\/kifarunix.com\/wp-content\/uploads\/2024\/08\/ingress-controller-external-ip-access-2-768x238.png?v=1724184523 768w\" sizes=\"(max-width: 1423px) 100vw, 1423px\" \/><\/figure>\n\n\n\n<p>And that is it!<\/p>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"conclusion\">Conclusion<\/h3>\n\n\n\n<p>Kubernetes Ingress is a powerful tool for managing external access to your services, offering flexible routing based on hostnames and URL paths. By following the steps outlined above, you can set up Ingress, expose your services, and leverage advanced features like TLS termination and path-based routing.<\/p>\n\n\n\n<p>Read more about Kubernetes Ingress controller:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><a href=\"https:\/\/github.com\/kubernetes\/ingress-nginx\" target=\"_blank\" rel=\"noreferrer noopener\">https:\/\/github.com\/kubernetes\/ingress-nginx<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/kubernetes.io\/docs\/concepts\/services-networking\/ingress\/\" target=\"_blank\" rel=\"noreferrer noopener\">https:\/\/kubernetes.io\/docs\/concepts\/services-networking\/ingress\/<\/a><\/li>\n<\/ul>\n","protected":false},"excerpt":{"rendered":"<p>Welcome to our tutorial on how you can utilize Kubernetes Ingress to manage external access to your Kubernetes services. Kubernetes Ingress is a powerful tool<\/p>\n","protected":false},"author":10,"featured_media":23279,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"rank_math_lock_modified_date":false,"footnotes":""},"categories":[1076,121,1668],"tags":[7580,7578,7581],"class_list":["post-23251","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-containers","category-howtos","category-kubernetes","tag-ingress-controller-metallb-2","tag-kubernetes-ingress","tag-loadbalancer-type","generate-columns","tablet-grid-50","mobile-grid-100","grid-parent","grid-50","resize-featured-image"],"_links":{"self":[{"href":"https:\/\/kifarunix.com\/wp-json\/wp\/v2\/posts\/23251"}],"collection":[{"href":"https:\/\/kifarunix.com\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/kifarunix.com\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/kifarunix.com\/wp-json\/wp\/v2\/users\/10"}],"replies":[{"embeddable":true,"href":"https:\/\/kifarunix.com\/wp-json\/wp\/v2\/comments?post=23251"}],"version-history":[{"count":17,"href":"https:\/\/kifarunix.com\/wp-json\/wp\/v2\/posts\/23251\/revisions"}],"predecessor-version":[{"id":23283,"href":"https:\/\/kifarunix.com\/wp-json\/wp\/v2\/posts\/23251\/revisions\/23283"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/kifarunix.com\/wp-json\/wp\/v2\/media\/23279"}],"wp:attachment":[{"href":"https:\/\/kifarunix.com\/wp-json\/wp\/v2\/media?parent=23251"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/kifarunix.com\/wp-json\/wp\/v2\/categories?post=23251"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/kifarunix.com\/wp-json\/wp\/v2\/tags?post=23251"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}