Skip to main content

Services and Ingress

What You Will Learn

  • How traffic flows from users to Pods
  • What Services and Ingress do
  • The three-step chain: Pod, Service, Ingress

The Problem

Pods get random IP addresses. When a Pod restarts, it gets a new IP. If you have 3 copies of a Pod, you have 3 different IPs. You cannot give your users a random, changing IP address.

You need two things:

  1. A stable internal address that finds the right Pods (this is a Service)
  2. A public domain name that routes internet traffic in (this is an Ingress)

The Traffic Flow

Here is how a user's request reaches your app:

User's browser
    ↓
https://app.my-client.junovy.com
    ↓
┌─────────────────┐
│    Ingress       │  Routes the domain to a Service
└────────┬────────┘
         ↓
┌─────────────────┐
│    Service       │  Finds healthy Pods and load-balances
└────────┬────────┘
         ↓
┌────┐ ┌────┐ ┌────┐
│Pod1│ │Pod2│ │Pod3│   The actual containers running your app
└────┘ └────┘ └────┘

Services

A Service gives your Pods a stable address inside the cluster. It uses labels to find which Pods to route to.

apiVersion: v1
kind: Service
metadata:
  name: my-app               # the stable name other things use to find this
  namespace: hst-my-client
spec:
  type: ClusterIP             # only accessible inside the cluster
  selector:
    app: my-app               # finds Pods with this label (matches the Deployment)
  ports:
    - port: 80                # the port the Service listens on
      targetPort: 8080        # the port the Pod listens on (containerPort from Deployment)

The key line is selector: app: my-app. This tells the Service: "send traffic to any Pod that has the label app: my-app." That label matches the one in the Deployment template.

Ingress

An Ingress exposes a Service to the internet with a domain name and TLS (HTTPS). At Junovy, we use Traefik as the ingress controller. Traefik has a built-in ACME resolver that automatically gets TLS certificates from Let's Encrypt. We also use external-dns to automatically create DNS records.

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: my-app
  namespace: hst-my-client
  annotations:
    # Use Traefik's built-in ACME resolver for automatic TLS certificates
    traefik.ingress.kubernetes.io/router.tls.certresolver: letsencrypt
    traefik.ingress.kubernetes.io/router.entrypoints: websecure
    # Automatically create a DNS record for this domain
    external-dns.alpha.kubernetes.io/hostname: app.my-client.junovy.com
spec:
  ingressClassName: traefik-external
  tls:
    - hosts:
        - app.my-client.junovy.com      # the domain
      secretName: my-app-tls            # Traefik manages certificates internally via ACME
  rules:
    - host: app.my-client.junovy.com    # match this domain
      http:
        paths:
          - path: /                      # match all paths
            pathType: Prefix
            backend:
              service:
                name: my-app             # route to this Service
                port:
                  number: 80             # on this port

How They Connect

Object Points To Connected By
Ingress Service backend.service.name matches Service metadata.name
Service Pods selector matches Pod labels
Deployment Creates Pods template defines the Pod blueprint

This chain is the same for every application at Junovy. Once you learn it, you will see the same pattern everywhere.


Key Takeaways

  • A Service provides a stable internal address that finds Pods by label
  • An Ingress exposes a Service to the internet with a domain name and TLS
  • The chain is always: Ingress -> Service -> Pods

What Is Next

Next up: Namespaces where you will learn how Junovy isolates each client's environment.