From c749699a2f6ad55e3313efbf1603a867079cee4f Mon Sep 17 00:00:00 2001 From: Junwei Zhao Date: Mon, 12 Jan 2026 10:04:59 +1100 Subject: [PATCH] Use endpointslice to proxy internal non k8s services --- archive/nginx-proxy-manager.yaml | 241 ++++++++++++++++++------------- external-service-template.yaml | 225 +++++++++++++++++++++++++++++ home-apps/ext-up.yaml | 82 +++++++++++ 3 files changed, 445 insertions(+), 103 deletions(-) create mode 100644 external-service-template.yaml create mode 100644 home-apps/ext-up.yaml diff --git a/archive/nginx-proxy-manager.yaml b/archive/nginx-proxy-manager.yaml index 3296008..bef92b8 100644 --- a/archive/nginx-proxy-manager.yaml +++ b/archive/nginx-proxy-manager.yaml @@ -1,22 +1,25 @@ +# Nginx Proxy Manager Data PersistentVolume apiVersion: v1 kind: PersistentVolumeClaim metadata: + name: nginx-proxy-manager-data-pvc namespace: home-apps - name: nginx-proxy-pvc spec: accessModes: - ReadWriteOnce storageClassName: nfs-client resources: requests: - storage: 5Gi + storage: 3Gi --- +# Nginx Proxy Manager Letsencrypt PersistentVolume + apiVersion: v1 kind: PersistentVolumeClaim metadata: + name: nginx-proxy-manager-letsencrypt-pvc namespace: home-apps - name: nginx-letsencrypt-pvc spec: accessModes: - ReadWriteOnce @@ -26,119 +29,151 @@ spec: storage: 2Gi --- -apiVersion: apps/v1 -kind: Deployment -metadata: - name: nginx-proxy - namespace: home-apps - labels: - app: nginx-proxy -spec: - replicas: 1 - revisionHistoryLimit: 2 - selector: - matchLabels: - app: nginx-proxy - template: - metadata: - labels: - app: nginx-proxy - name: nginx-proxy - spec: - containers: - - name: nginx-proxy - image: jc21/nginx-proxy-manager:latest - imagePullPolicy: IfNotPresent - ports: - - containerPort: 80 - name: web - protocol: TCP - - containerPort: 81 - name: admin - protocol: TCP - env: - - name: TZ - value: "Australia/Melbourne" - volumeMounts: - - name: data - mountPath: "/data" - - name: nginx-letsencrypt-pvc - mountPath: "/etc/letsencrypt" - resources: - requests: - cpu: 200m - memory: 512Mi - limits: - cpu: 400m - memory: 1Gi - volumes: - - name: data - persistentVolumeClaim: - claimName: nginx-proxy-pvc - - name: nginx-letsencrypt-pvc - persistentVolumeClaim: - claimName: nginx-letsencrypt-pvc - ---- - +# Nginx Proxy Manager Service apiVersion: v1 kind: Service metadata: - name: nginx-proxy - labels: - name: nginx-proxy + name: nginx-proxy-manager + namespace: home-apps spec: type: ClusterIP - selector: - app: nginx-proxy ports: - - name: nginx-proxy - targetPort: web - port: 80 - protocol: TCP - - name: nginx-proxy-admin - targetPort: admin - port: 81 - protocol: TCP - + - name: http + port: 80 + targetPort: 80 + - name: admin + port: 81 + targetPort: 81 + selector: + app: nginx-proxy-manager --- +# Nginx Proxy Manager Deployment +apiVersion: apps/v1 +kind: Deployment +metadata: + name: nginx-proxy-manager + namespace: home-apps +spec: + selector: + matchLabels: + app: nginx-proxy-manager + replicas: 1 + strategy: + type: Recreate + template: + metadata: + labels: + app: nginx-proxy-manager + spec: + nodeSelector: + kubernetes.io/hostname: server-3 + securityContext: + fsGroup: 0 + runAsUser: 0 + runAsNonRoot: false + containers: + - name: nginx-proxy-manager + image: jc21/nginx-proxy-manager:latest + ports: + - containerPort: 80 + - containerPort: 443 + - containerPort: 81 + env: + - name: PUID + value: "1000" + - name: PGID + value: "1000" + - name: TZ + value: "Australia/Melbourne" + - name: DB_POSTGRES_HOST + value: "192.168.1.2" + - name: DB_POSTGRES_PORT + value: "5432" + - name: DB_POSTGRES_USER + valueFrom: + secretKeyRef: + name: postgres-credential + key: username + - name: DB_POSTGRES_PASSWORD + valueFrom: + secretKeyRef: + name: postgres-credential + key: password + - name: DB_POSTGRES_NAME + value: "nginx_proxy_manager" + volumeMounts: + - name: data + mountPath: /data + - name: letsencrypt + mountPath: /etc/letsencrypt + resources: + requests: + cpu: 100m + memory: 256Mi + limits: + cpu: 500m + memory: 512Mi + volumes: + - name: data + persistentVolumeClaim: + claimName: nginx-proxy-manager-data-pvc + - name: letsencrypt + persistentVolumeClaim: + claimName: nginx-proxy-manager-letsencrypt-pvc +--- + +# Wildcard Ingress for *.r.junv.cc (proxied services) apiVersion: networking.k8s.io/v1 kind: Ingress metadata: - name: nginx-proxy-ingress + name: nginx-proxy-manager-wildcard-ingress + namespace: home-apps annotations: - kubernetes.io/ingress.class: "nginx" - kubernetes.io/tls-acme: "true" cert-manager.io/cluster-issuer: "letsencrypt-prod" - nginx.ingress.kubernetes.io/auth-url: "https://id.junv.me/oauth2/auth" - nginx.ingress.kubernetes.io/auth-signin: "https://id.junv.me/oauth2/start?rd=https%3A%2F%2F$host$request_uri" spec: + ingressClassName: nginx tls: - - hosts: - - proxy.junv.me - secretName: nginx-proxy-tls-new - - hosts: - - proxy-admin.junv.me - secretName: nginx-proxy-admin-tls-new + - hosts: + - "*.r.junv.cc" + secretName: nginx-proxy-manager-wildcard-tls rules: - - host: proxy.junv.me - http: - paths: - - backend: - service: - name: nginx-proxy - port: - number: 80 - path: / - pathType: Prefix - - host: proxy-admin.junv.me - http: - paths: - - backend: - service: - name: nginx-proxy - port: - number: 81 - path: / - pathType: Prefix + - host: "*.r.junv.cc" + http: + paths: + - backend: + service: + name: nginx-proxy-manager + port: + number: 80 + path: / + pathType: Prefix +--- + +# Ingress for Admin Interface (port 81) +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + name: nginx-proxy-manager-admin-ingress + namespace: home-apps + annotations: + cert-manager.io/cluster-issuer: "letsencrypt-prod" + nginx.ingress.kubernetes.io/auth-url: "https://pass.junv.cc/oauth2/auth" + nginx.ingress.kubernetes.io/auth-signin: "https://pass.junv.cc/oauth2/start?rd=https://$host$escaped_request_uri" +spec: + ingressClassName: nginx + tls: + - hosts: + - npm-admin.junv.cc + secretName: nginx-proxy-manager-admin-tls + rules: + - host: npm-admin.junv.cc + http: + paths: + - backend: + service: + name: nginx-proxy-manager + port: + number: 81 + path: / + pathType: Prefix diff --git a/external-service-template.yaml b/external-service-template.yaml new file mode 100644 index 0000000..f664a1c --- /dev/null +++ b/external-service-template.yaml @@ -0,0 +1,225 @@ +# Template for Exposing External Services (Outside K8s) +# +# Use this template when you have services running on your local network +# (e.g., http://192.168.1.4:3031) and want to expose them with: +# - A custom domain (e.g., myapp.junv.cc) +# - Automatic HTTPS certificate from Let's Encrypt +# - Through your existing NGINX Ingress Controller +# +# HOW TO USE: +# 1. Copy this template +# 2. Replace ALL_CAPS placeholders with your values +# 3. Save as home-apps/SERVICENAME.yaml +# 4. Apply: kubectl apply -f home-apps/SERVICENAME.yaml +# +# EXAMPLE: +# Service: http://192.168.1.4:3031 → https://myapp.junv.cc +# +--- +# Service without selector (no pods, points to external endpoint) +apiVersion: v1 +kind: Service +metadata: + name: SERVICENAME # e.g., home-assistant, grafana-external + namespace: home-apps +spec: + ports: + - name: http + port: 80 # Port exposed within cluster + targetPort: EXTERNAL_PORT # e.g., 3031, 8080, 9090 + protocol: TCP +--- +# Manual EndpointSlice pointing to external IP +apiVersion: discovery.k8s.io/v1 +kind: EndpointSlice +metadata: + name: SERVICENAME # MUST match Service name exactly + namespace: home-apps + labels: + kubernetes.io/service-name: SERVICENAME # Required: links EndpointSlice to Service +addressType: IPv4 +endpoints: + - addresses: + - EXTERNAL_IP # e.g., 192.168.1.4 +ports: + - name: http # Should match Service port name + port: EXTERNAL_PORT # e.g., 3031 + protocol: TCP +--- +# Ingress with automatic TLS certificate +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + name: SERVICENAME-ingress + namespace: home-apps + annotations: + cert-manager.io/cluster-issuer: "letsencrypt-prod" + # Optional: Add OAuth2 protection (uncomment to enable) + # nginx.ingress.kubernetes.io/auth-url: "https://pass.junv.cc/oauth2/auth" + # nginx.ingress.kubernetes.io/auth-signin: "https://pass.junv.cc/oauth2/start?rd=https://$host$escaped_request_uri" + # Optional: Proxy settings for specific backends + # nginx.ingress.kubernetes.io/proxy-body-size: "100m" + # nginx.ingress.kubernetes.io/proxy-read-timeout: "3600" + # nginx.ingress.kubernetes.io/proxy-send-timeout: "3600" + # Optional: Websocket support (for apps like Home Assistant) + # nginx.ingress.kubernetes.io/websocket-services: "SERVICENAME" +spec: + ingressClassName: nginx + tls: + - hosts: + - DOMAIN.junv.cc # e.g., homeassistant.junv.cc, grafana.junv.cc + secretName: SERVICENAME-tls # cert-manager will create this automatically + rules: + - host: DOMAIN.junv.cc + http: + paths: + - path: / + pathType: Prefix + backend: + service: + name: SERVICENAME + port: + number: 80 + +--- +# ============================================================================ +# REAL WORLD EXAMPLE 1: Home Assistant on 192.168.1.4:8123 +# ============================================================================ +# apiVersion: v1 +# kind: Service +# metadata: +# name: home-assistant-external +# namespace: home-apps +# spec: +# ports: +# - name: http +# port: 80 +# targetPort: 8123 +# protocol: TCP +# --- +# apiVersion: discovery.k8s.io/v1 +# kind: EndpointSlice +# metadata: +# name: home-assistant-external +# namespace: home-apps +# labels: +# kubernetes.io/service-name: home-assistant-external +# addressType: IPv4 +# endpoints: +# - addresses: +# - 192.168.1.4 +# ports: +# - name: http +# port: 8123 +# protocol: TCP +# --- +# apiVersion: networking.k8s.io/v1 +# kind: Ingress +# metadata: +# name: home-assistant-external-ingress +# namespace: home-apps +# annotations: +# cert-manager.io/cluster-issuer: "letsencrypt-prod" +# nginx.ingress.kubernetes.io/websocket-services: "home-assistant-external" +# spec: +# ingressClassName: nginx +# tls: +# - hosts: +# - ha.junv.cc +# secretName: home-assistant-external-tls +# rules: +# - host: ha.junv.cc +# http: +# paths: +# - path: / +# pathType: Prefix +# backend: +# service: +# name: home-assistant-external +# port: +# number: 80 + +--- +# ============================================================================ +# REAL WORLD EXAMPLE 2: Proxmox Web UI on 192.168.1.5:8006 +# ============================================================================ +# apiVersion: v1 +# kind: Service +# metadata: +# name: proxmox-external +# namespace: home-apps +# spec: +# ports: +# - name: https +# port: 8006 +# targetPort: 8006 +# protocol: TCP +# --- +# apiVersion: discovery.k8s.io/v1 +# kind: EndpointSlice +# metadata: +# name: proxmox-external +# namespace: home-apps +# labels: +# kubernetes.io/service-name: proxmox-external +# addressType: IPv4 +# endpoints: +# - addresses: +# - 192.168.1.5 +# ports: +# - name: https +# port: 8006 +# protocol: TCP +# --- +# apiVersion: networking.k8s.io/v1 +# kind: Ingress +# metadata: +# name: proxmox-external-ingress +# namespace: home-apps +# annotations: +# cert-manager.io/cluster-issuer: "letsencrypt-prod" +# # Backend uses HTTPS, tell NGINX to use it +# nginx.ingress.kubernetes.io/backend-protocol: "HTTPS" +# # Skip TLS verification (self-signed cert on backend) +# nginx.ingress.kubernetes.io/proxy-ssl-verify: "false" +# spec: +# ingressClassName: nginx +# tls: +# - hosts: +# - proxmox.junv.cc +# secretName: proxmox-external-tls +# rules: +# - host: proxmox.junv.cc +# http: +# paths: +# - path: / +# pathType: Prefix +# backend: +# service: +# name: proxmox-external +# port: +# number: 8006 + +--- +# ============================================================================ +# COMPARISON: NPM vs Native Kubernetes +# ============================================================================ +# +# Nginx Proxy Manager (*.r.junv.cc): +# ✅ Web UI - easy to add services +# ✅ Good for non-technical users +# ❌ Extra hop (NGINX Ingress → NPM → External Service) +# ❌ More resources (NPM pod + database) +# ❌ Not GitOps - config stored in database +# +# Native K8s (this template): +# ✅ GitOps - version controlled YAML +# ✅ Native K8s - no extra components +# ✅ Direct routing (NGINX Ingress → External Service) +# ✅ Automatic cert renewal via cert-manager +# ❌ Must write/copy YAML for each service +# ❌ No web UI +# +# RECOMMENDATION: +# - Use NPM (*.r.junv.cc) for quick ad-hoc services or non-tech users +# - Use this template for permanent services you want in GitOps diff --git a/home-apps/ext-up.yaml b/home-apps/ext-up.yaml new file mode 100644 index 0000000..ced95d2 --- /dev/null +++ b/home-apps/ext-up.yaml @@ -0,0 +1,82 @@ +# Template for Exposing External Services (Outside K8s) +# +# Use this template when you have services running on your local network +# (e.g., http://192.168.1.4:3031) and want to expose them with: +# - A custom domain (e.g., myapp.junv.cc) +# - Automatic HTTPS certificate from Let's Encrypt +# - Through your existing NGINX Ingress Controller +# +# HOW TO USE: +# 1. Copy this template +# 2. Replace ALL_CAPS placeholders with your values +# 3. Save as home-apps/up.yaml +# 4. Apply: kubectl apply -f home-apps/up.yaml +# +# EXAMPLE: +# Service: http://192.168.1.4:3031 → https://myapp.junv.cc +# +--- +# Service without selector (no pods, points to external endpoint) +apiVersion: v1 +kind: Service +metadata: + name: up # e.g., home-assistant, grafana-external + namespace: home-apps +spec: + ports: + - name: http + port: 80 # Port exposed within cluster + targetPort: 3031 # e.g., 3031, 8080, 9090 + protocol: TCP +--- +# Manual EndpointSlice pointing to external IP +apiVersion: discovery.k8s.io/v1 +kind: EndpointSlice +metadata: + name: up # MUST match Service name exactly + namespace: home-apps + labels: + kubernetes.io/service-name: up # Required: links EndpointSlice to Service +addressType: IPv4 +endpoints: + - addresses: + - 192.168.1.4 # e.g., 192.168.1.4 +ports: + - name: http # Should match Service port name + port: 3031 # e.g., 3031 + protocol: TCP +--- +# Ingress with automatic TLS certificate +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + name: up-ingress + namespace: home-apps + annotations: + cert-manager.io/cluster-issuer: "letsencrypt-prod" + # Optional: Add OAuth2 protection (uncomment to enable) + nginx.ingress.kubernetes.io/auth-url: "https://pass.junv.cc/oauth2/auth" + nginx.ingress.kubernetes.io/auth-signin: "https://pass.junv.cc/oauth2/start?rd=https://$host$escaped_request_uri" + # Optional: Proxy settings for specific backends + # nginx.ingress.kubernetes.io/proxy-body-size: "100m" + # nginx.ingress.kubernetes.io/proxy-read-timeout: "3600" + # nginx.ingress.kubernetes.io/proxy-send-timeout: "3600" + # Optional: Websocket support (for apps like Home Assistant) + # nginx.ingress.kubernetes.io/websocket-services: "up" +spec: + ingressClassName: nginx + tls: + - hosts: + - up.junv.cc # e.g., homeassistant.junv.cc, grafana.junv.cc + secretName: up-tls # cert-manager will create this automatically + rules: + - host: up.junv.cc + http: + paths: + - path: / + pathType: Prefix + backend: + service: + name: up + port: + number: 80