Skip to content

Internal Service Patterns

How to expose K8s services for internal/LAN-only access without external DNS or SSL complications.

The Problem

Services exposed via Ingress with *.bogocat.com domains: - Require external DNS resolution - Get HSTS/SSL enforcement from browsers - May route through VPS before reaching local cluster

For internal-only services (dashboards, control panels, dev tools), this is overkill.

Solutions

Gets a dedicated internal IP from MetalLB pool. Clean, HA, no port numbers.

apiVersion: v1
kind: Service
metadata:
  name: my-service
  namespace: my-namespace
spec:
  type: LoadBalancer
  ports:
    - port: 80
      targetPort: 3000
  selector:
    app: my-app

After applying, check assigned IP:

kubectl get svc -n my-namespace
# EXTERNAL-IP column shows the assigned IP

Access: http://10.89.97.xxx

Current internal services: | Service | IP | DNS | Port | |---------|-----|-----|------| | music-control | 10.89.97.218 | hifi.internal | 80 | | longhorn-ui | 10.89.97.210 | | 80 | | grafana | 10.89.97.211 | | 80 | | kubernetes-dashboard | 10.89.97.212 | | 443 | | alertmanager | 10.89.97.217 | | 9093 |

Option 2: NodePort

Exposes on a high port (30000-32767) on ALL nodes. HA but ugly URLs.

apiVersion: v1
kind: Service
metadata:
  name: my-service
  namespace: my-namespace
spec:
  type: NodePort
  ports:
    - port: 80
      targetPort: 3000
      nodePort: 30080  # optional, auto-assigned if omitted
  selector:
    app: my-app

Access: http://<any-node-ip>:30080 - 10.89.97.201:30080 - 10.89.97.202:30080 - 10.89.97.203:30080

All work - K8s routes to pod regardless of which node you hit.

Option 3: Ingress with Local Domain

Use ingress but with a .local domain that doesn't have HSTS baggage.

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: my-service
  namespace: my-namespace
  annotations:
    nginx.ingress.kubernetes.io/ssl-redirect: "false"
spec:
  ingressClassName: nginx
  rules:
    - host: myservice.local
      http:
        paths:
          - path: /
            pathType: Prefix
            backend:
              service:
                name: my-service
                port:
                  number: 80

Requires adding DNS override in OPNsense/router:

myservice.local → 10.89.97.220

Access: http://myservice.local

When to Use Each

Scenario Recommendation
Internal dashboard/control panel LoadBalancer
Quick dev/test access NodePort
Need pretty URL, no external access Ingress + .local domain
External access required Standard Ingress + bogocat.com

MetalLB IP Pool

Current pool: 10.89.97.210-10.89.97.230

To check available IPs:

kubectl get svc -A -o wide | grep LoadBalancer | awk '{print $5}'