{"id":34,"date":"2025-10-24T12:00:00","date_gmt":"2025-10-24T12:00:00","guid":{"rendered":"https:\/\/rezachegini.com\/?p=34"},"modified":"2026-10-30T06:38:54","modified_gmt":"2026-10-30T06:38:54","slug":"understanding-kubernetes-services-building-multi-tier-applications","status":"publish","type":"post","link":"https:\/\/rezachegini.com\/?p=34","title":{"rendered":"Understanding Kubernetes Services &#8211; Building Multi-Tier Applications"},"content":{"rendered":"<p class=\"wp-block-paragraph\">Today I want to share what I learned about Kubernetes Services and how they solve networking challenges in containerized applications.<\/p>\n\n<h3 class=\"wp-block-heading\">What is a Service?<\/h3>\n\n<p class=\"wp-block-paragraph\">A Service is a Kubernetes abstraction that provides stable networking and load balancing for Pods. Think of it as a permanent address and phone number for your application. While Pods come and go with changing IP addresses, Services give you a fixed way to reach them. Services solve the critical problem of how frontend applications can reliably find and communicate with backend applications.<\/p>\n\n<h3 class=\"wp-block-heading\">Complete Multi-Tier Application YAML File<\/h3>\n\n<p class=\"wp-block-paragraph\">Here is the complete file that creates a two-tier application with both ClusterIP and NodePort Services:<\/p>\n\n<pre class=\"wp-block-code\"><code># Backend Deployment\napiVersion: apps\/v1\nkind: Deployment\nmetadata:\n  name: backend-restapp\n  labels:\n    app: backend-restapp\n    tier: backend\nspec:\n  replicas: 3\n  selector:\n    matchLabels:\n      app: backend-restapp\n  template:\n    metadata:\n      labels:\n        app: backend-restapp\n        tier: backend\n    spec:\n      containers:\n      - name: backend-restapp\n        image: backendapp\n        ports:\n        - containerPort: 8080\n\n---\n\n# Backend ClusterIP Service\napiVersion: v1\nkind: Service\nmetadata:\n  name: my-backend-service\n  labels:\n    app: backend-restapp\n    tier: backend\nspec:\n  # type: ClusterIP is default (internal only)\n  selector:\n    app: backend-restapp\n  ports:\n  - name: http\n    port: 8080\n    targetPort: 8080\n\n---\n\n# Frontend Deployment\napiVersion: apps\/v1\nkind: Deployment\nmetadata:\n  name: frontend-nginxapp\n  labels:\n    app: frontend-nginxapp\n    tier: frontend\nspec:\n  replicas: 3\n  selector:\n    matchLabels:\n      app: frontend-nginxapp\n  template:\n    metadata:\n      labels:\n        app: frontend-nginxapp\n        tier: frontend\n    spec:\n      containers:\n      - name: frontend-nginxapp\n        image: sfrontendapp\n        ports:\n        - containerPort: 80\n\n---\n\n# Frontend NodePort Service\napiVersion: v1\nkind: Service\nmetadata:\n  name: frontend-nginxapp-nodeport-service\n  labels:\n    app: frontend-nginxapp\n    tier: frontend\nspec:\n  type: NodePort\n  selector:\n    app: frontend-nginxapp\n  ports:\n  - name: http\n    port: 80\n    targetPort: 80\n    nodePort: 31234<\/code><\/pre>\n\n<h3 class=\"wp-block-heading\">Breaking Down the Complete File<\/h3>\n\n<p class=\"wp-block-paragraph\">The Backend Deployment Section:<\/p>\n\n<pre class=\"wp-block-code\"><code>apiVersion: apps\/v1              # Uses apps API for Deployments\nkind: Deployment                # Creates a Deployment controller\nmetadata:\n  name: backend-restapp         # Backend application name\n  labels:\n    app: backend-restapp        # Application identifier\n    tier: backend              # Tier classification\nspec:\n  replicas: 3                  # Run 3 backend instances\n  selector:\n    matchLabels:\n      app: backend-restapp     # Manages Pods with this label\n  template:\n    metadata:\n      labels:\n        app: backend-restapp   # Pod labels for Service discovery\n        tier: backend         # Tier information\n    spec:\n      containers:\n      - name: backend-restapp          # Container name\n        image: backendapp  # REST API image\n        ports:\n        - containerPort: 8080          # Backend listens on port 8080<\/code><\/pre>\n\n<p class=\"wp-block-paragraph\">The Backend ClusterIP Service Section:<\/p>\n\n<pre class=\"wp-block-code\"><code>apiVersion: v1                    # Core Kubernetes API\nkind: Service                     # Creates a Service resource\nmetadata:\n  name: my-backend-service        # Service name (becomes DNS name)\n  labels:\n    app: backend-restapp          # Service labels\n    tier: backend                 # Tier classification\nspec:\n  # type: ClusterIP (default)     # Internal access only\n  selector:\n    app: backend-restapp          # Routes to Pods with this label\n  ports:\n  - name: http                    # Port name\n    port: 8080                    # Service port (what clients use)\n    targetPort: 8080              # Container port (where traffic goes)<\/code><\/pre>\n\n<p class=\"wp-block-paragraph\">What ClusterIP Service does:<\/p>\n\n<ul class=\"wp-block-list\"><li>Internal Only &#8211; Accessible only within the Kubernetes cluster<\/li><li>Stable IP &#8211; Gets a permanent cluster-internal IP address<\/li><li>DNS Name &#8211; Accessible via service name my-backend-service<\/li><li>Load Balancing &#8211; Distributes traffic across all 3 backend Pods<\/li><li>Security &#8211; Not exposed to external networks<\/li><\/ul>\n\n<p class=\"wp-block-paragraph\">The Frontend Deployment Section:<\/p>\n\n<pre class=\"wp-block-code\"><code>apiVersion: apps\/v1              # Uses apps API for Deployments\nkind: Deployment                # Creates a Deployment controller\nmetadata:\n  name: frontend-nginxapp       # Frontend application name\n  labels:\n    app: frontend-nginxapp      # Application identifier\n    tier: frontend             # Tier classification\nspec:\n  replicas: 3                  # Run 3 frontend instances\n  selector:\n    matchLabels:\n      app: frontend-nginxapp   # Manages Pods with this label\n  template:\n    metadata:\n      labels:\n        app: frontend-nginxapp # Pod labels for Service discovery\n        tier: frontend        # Tier information\n    spec:\n      containers:\n      - name: frontend-nginxapp        # Container name\n        image: frontendapp  # Nginx frontend\n        ports:\n        - containerPort: 80            # Frontend listens on port 80<\/code><\/pre>\n\n<p class=\"wp-block-paragraph\">The Frontend NodePort Service Section:<\/p>\n\n<pre class=\"wp-block-code\"><code>apiVersion: v1                              # Core Kubernetes API\nkind: Service                               # Creates a Service resource\nmetadata:\n  name: frontend-nginxapp-nodeport-service  # Service name\n  labels:\n    app: frontend-nginxapp                  # Service labels\n    tier: frontend                          # Tier classification\nspec:\n  type: NodePort                            # External access type\n  selector:\n    app: frontend-nginxapp                  # Routes to frontend Pods\n  ports:\n  - name: http                              # Port name\n    port: 80                                # Service port (internal)\n    targetPort: 80                          # Container port\n    nodePort: 31234                         # External port on nodes<\/code><\/pre>\n\n<p class=\"wp-block-paragraph\">What NodePort Service does:<\/p>\n\n<ul class=\"wp-block-list\"><li>External Access &#8211; Accessible from outside the cluster<\/li><li>Port on Every Node &#8211; Opens port 31234 on all cluster nodes<\/li><li>Also ClusterIP &#8211; Gets internal IP for cluster communication<\/li><li>Load Balancing &#8211; Distributes traffic across all 3 frontend Pods<\/li><li>User Access &#8211; External users can reach the application<\/li><\/ul>\n\n<p class=\"wp-block-paragraph\">How the Multi-Tier Application Works:<\/p>\n\n<ol class=\"wp-block-list\"><li>External User accesses <a href=\"http:\/\/NODE_IP:31234\">http:\/\/NODE_IP:31234<\/a><\/li><li>NodePort Service receives traffic and load balances to frontend Pods<\/li><li>Frontend Pod serves the web page and makes API calls to backend<\/li><li>Frontend calls backend using DNS name: <a href=\"http:\/\/my-backend-service:8080\">http:\/\/my-backend-service:8080<\/a><\/li><li>ClusterIP Service receives internal requests and routes to backend Pods<\/li><li>Backend Pod processes API request and returns data<\/li><li>Response flows back through Services to user<\/li><\/ol>\n\n<p class=\"wp-block-paragraph\">Why This Architecture Matters:<\/p>\n\n<ul class=\"wp-block-list\"><li>Separation of Concerns &#8211; Frontend handles UI, backend handles logic<\/li><li>Internal Security &#8211; Backend not exposed externally<\/li><li>Scalability &#8211; Each tier can scale independently<\/li><li>Service Discovery &#8211; Frontend finds backend using DNS name<\/li><li>Load Distribution &#8211; Traffic spreads across multiple Pod instances<\/li><\/ul>\n\n<h3 class=\"wp-block-heading\">How to Deploy and Manage This Application<\/h3>\n\n<p class=\"wp-block-paragraph\">Step 1: Deploy the Complete Application<\/p>\n\n<pre class=\"wp-block-code\"><code>kubectl apply -f multi-tier-app.yaml<\/code><\/pre>\n\n<p class=\"wp-block-paragraph\">Step 2: Check All Deployments<\/p>\n\n<pre class=\"wp-block-code\"><code>kubectl get deployments\nkubectl get deploy -l tier=backend\nkubectl get deploy -l tier=frontend<\/code><\/pre>\n\n<p class=\"wp-block-paragraph\">Step 3: Check All Services<\/p>\n\n<pre class=\"wp-block-code\"><code>kubectl get services\nkubectl get svc -l tier=backend\nkubectl get svc -l tier=frontend<\/code><\/pre>\n\n<p class=\"wp-block-paragraph\">Step 4: Verify Backend Service and Endpoints<\/p>\n\n<pre class=\"wp-block-code\"><code># Check backend service details\nkubectl describe service my-backend-service\n\n# Check backend endpoints (should show 3 Pod IPs)\nkubectl get endpoints my-backend-service<\/code><\/pre>\n\n<p class=\"wp-block-paragraph\">Step 5: Verify Frontend Service and Endpoints<\/p>\n\n<pre class=\"wp-block-code\"><code># Check frontend service details\nkubectl describe service frontend-nginxapp-nodeport-service\n\n# Check frontend endpoints\nkubectl get endpoints frontend-nginxapp-nodeport-service<\/code><\/pre>\n\n<p class=\"wp-block-paragraph\">Step 6: Test Backend Service Internally<\/p>\n\n<pre class=\"wp-block-code\"><code># Create test Pod to check backend\nkubectl run test-backend --image=busybox --rm -it --restart=Never -- sh\n\n# Inside test Pod:\nwget -qO- http:\/\/my-backend-service:8080\nexit\n\n# Or use one-liner\nkubectl run test --image=busybox --rm -it --restart=Never \\\n  -- wget -qO- http:\/\/my-backend-service:8080<\/code><\/pre>\n\n<p class=\"wp-block-paragraph\">Step 7: Access Frontend Application Externally<\/p>\n\n<pre class=\"wp-block-code\"><code># Get node IP\nkubectl get nodes -o wide\n\n# Access application at: http:\/\/NODE_IP:31234\n# For Docker Desktop: http:\/\/localhost:31234\n# For minikube: minikube service frontend-nginxapp-nodeport-service<\/code><\/pre>\n\n<p class=\"wp-block-paragraph\">Step 8: Test Service Discovery<\/p>\n\n<pre class=\"wp-block-code\"><code># Test DNS resolution\nkubectl run dnstest --image=busybox --rm -it --restart=Never \\\n  -- nslookup my-backend-service\n\n# Should return the ClusterIP of backend service<\/code><\/pre>\n\n<p class=\"wp-block-paragraph\">Step 9: Test Load Balancing<\/p>\n\n<pre class=\"wp-block-code\"><code># Make multiple requests to see different Pods responding\nfor i in {1..10}; do\n  curl http:\/\/localhost:31234\n  echo \"Request $i completed\"\n  sleep 1\ndone<\/code><\/pre>\n\n<p class=\"wp-block-paragraph\">Step 10: Monitor Pod Logs<\/p>\n\n<pre class=\"wp-block-code\"><code># Watch backend Pod logs\nkubectl logs -f -l app=backend-restapp\n\n# Watch frontend Pod logs\nkubectl logs -f -l app=frontend-nginxapp\n\n# You'll see requests being distributed across different Pods<\/code><\/pre>\n\n<p class=\"wp-block-paragraph\">Step 11: Test Service Self-Healing<\/p>\n\n<pre class=\"wp-block-code\"><code># Delete a backend Pod\nkubectl delete pod -l app=backend-restapp | head -1\n\n# Check endpoints - Pod IP removed and new one added\nkubectl get endpoints my-backend-service\n\n# Service continues working while Pod is replaced<\/code><\/pre>\n\n<p class=\"wp-block-paragraph\">Step 12: Scale Services<\/p>\n\n<pre class=\"wp-block-code\"><code># Scale backend up\nkubectl scale deployment backend-restapp --replicas=5\n\n# Watch endpoints update\nkubectl get endpoints my-backend-service\n\n# Scale frontend down\nkubectl scale deployment frontend-nginxapp --replicas=2\n\n# Services automatically adapt to new Pod counts<\/code><\/pre>\n\n<p class=\"wp-block-paragraph\">Step 13: View Service Types<\/p>\n\n<pre class=\"wp-block-code\"><code># Compare service types\nkubectl get services -o wide\n\n# ClusterIP: only cluster-internal IP\n# NodePort: gets both cluster IP and node port<\/code><\/pre>\n\n<p class=\"wp-block-paragraph\">Step 14: Test Inter-Service Communication<\/p>\n\n<pre class=\"wp-block-code\"><code># Get into frontend Pod\nkubectl exec -it &lt;frontend-pod-name&gt; -- \/bin\/sh\n\n# Test calling backend from frontend\ncurl http:\/\/my-backend-service:8080\n\n# This is how frontend communicates with backend\nexit<\/code><\/pre>\n\n<p class=\"wp-block-paragraph\">Step 15: Clean Up Resources<\/p>\n\n<pre class=\"wp-block-code\"><code>kubectl delete -f multi-tier-app.yaml\n\n# Or delete individually:\n# kubectl delete deployment backend-restapp frontend-nginxapp\n# kubectl delete service my-backend-service frontend-nginxapp-nodeport-service<\/code><\/pre>\n\n<p class=\"wp-block-paragraph\">Understanding Services is essential for junior DevOps engineers because:<\/p>\n\n<ul class=\"wp-block-list\"><li>Real Applications are almost always multi-tier (frontend, backend, database)<\/li><li>Service Discovery is how microservices find and communicate with each other<\/li><li>Load Balancing ensures applications can handle traffic and failures<\/li><\/ul>","protected":false},"excerpt":{"rendered":"<p>Today I want to share what I learned about Kubernetes Services and how they solve networking challenges in containerized applications. What is&hellip;<\/p>\n","protected":false},"author":2,"featured_media":36,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_rezaops_part":"4","_rezaops_linkedin_url":"https:\/\/www.linkedin.com\/pulse\/understanding-kubernetes-services-building-reza-chegini-5y5zc\/","footnotes":""},"categories":[10,9],"tags":[13,8,5,3,7,6],"series":[11],"class_list":["post-34","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-devops","category-kubernetes","tag-deployments","tag-devops","tag-kubectl","tag-kubernetes","tag-kubernetes-services","tag-yaml","series-understanding-kubernetes"],"jetpack_featured_media_url":"https:\/\/rezachegini.com\/wp-content\/uploads\/2026\/10\/understanding-kubernetes-services-cover.png","_links":{"self":[{"href":"https:\/\/rezachegini.com\/index.php?rest_route=\/wp\/v2\/posts\/34","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/rezachegini.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/rezachegini.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/rezachegini.com\/index.php?rest_route=\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/rezachegini.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=34"}],"version-history":[{"count":1,"href":"https:\/\/rezachegini.com\/index.php?rest_route=\/wp\/v2\/posts\/34\/revisions"}],"predecessor-version":[{"id":35,"href":"https:\/\/rezachegini.com\/index.php?rest_route=\/wp\/v2\/posts\/34\/revisions\/35"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/rezachegini.com\/index.php?rest_route=\/wp\/v2\/media\/36"}],"wp:attachment":[{"href":"https:\/\/rezachegini.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=34"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/rezachegini.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=34"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/rezachegini.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=34"},{"taxonomy":"series","embeddable":true,"href":"https:\/\/rezachegini.com\/index.php?rest_route=%2Fwp%2Fv2%2Fseries&post=34"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}