Skip to content

Ingress Exposure

TinySystems components can expose HTTP endpoints to the internet via Kubernetes Ingress. This guide covers ingress configuration and common patterns.

Overview

+-----------------------------------------------------------------------------+
|                         INGRESS EXPOSURE                                     |
+-----------------------------------------------------------------------------+

  Internet                 Ingress Controller              Module Pods
      |                          |                             |
      |  https://api.example.com |                             |
      |  ----------------------> |                             |
      |                          |                             |
      |                          |  Route to Service           |
      |                          |  ----------------------->   |
      |                          |                             |
      |                          |           Load Balance      |
      |                          |  +------------------------->| Pod 1
      |                          |  |                          |
      |                          |  +------------------------->| Pod 2
      |                          |  |                          |
      |                          |  +------------------------->| Pod 3
      |                          |                             |

Basic Ingress Setup

Exposing a Port

go
func (s *Server) exposeHTTP(ctx context.Context, rm resource.Manager) error {
    return rm.ExposePort(ctx, resource.ExposePortRequest{
        Port:      s.currentPort,
        Hostnames: []string{"api.example.com"},
        TLS:       true,
    })
}

Generated Resources

Service:

yaml
apiVersion: v1
kind: Service
metadata:
  name: http-server-abc123
  namespace: tinysystems
spec:
  type: ClusterIP
  selector:
    app: http-module
  ports:
    - port: 8080
      targetPort: 8080

Ingress:

yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: http-server-abc123
  namespace: tinysystems
  annotations:
    cert-manager.io/cluster-issuer: letsencrypt-prod
spec:
  ingressClassName: nginx
  tls:
    - hosts:
        - api.example.com
      secretName: http-server-abc123-tls
  rules:
    - host: api.example.com
      http:
        paths:
          - path: /
            pathType: Prefix
            backend:
              service:
                name: http-server-abc123
                port:
                  number: 8080

TLS Configuration

Automatic Certificates

With cert-manager, certificates are provisioned automatically:

go
rm.ExposePort(ctx, resource.ExposePortRequest{
    Port:      8080,
    Hostnames: []string{"api.example.com"},
    TLS:       true,  // Triggers cert-manager
})

Custom Certificate

Use existing certificate:

go
rm.ExposePort(ctx, resource.ExposePortRequest{
    Port:          8080,
    Hostnames:     []string{"api.example.com"},
    TLS:           true,
    TLSSecretName: "my-existing-cert",
})

No TLS (HTTP only)

go
rm.ExposePort(ctx, resource.ExposePortRequest{
    Port:      8080,
    Hostnames: []string{"internal.example.com"},
    TLS:       false,
})

Multiple Hostnames

Expose same service on multiple domains:

go
rm.ExposePort(ctx, resource.ExposePortRequest{
    Port: 8080,
    Hostnames: []string{
        "api.example.com",
        "api.example.org",
        "api.example.net",
    },
    TLS: true,
})

Generated Ingress:

yaml
spec:
  tls:
    - hosts:
        - api.example.com
        - api.example.org
        - api.example.net
      secretName: http-server-abc123-tls
  rules:
    - host: api.example.com
      http:
        paths:
          - path: /
            backend:
              service:
                name: http-server-abc123
    - host: api.example.org
      http:
        paths:
          - path: /
            backend:
              service:
                name: http-server-abc123
    - host: api.example.net
      http:
        paths:
          - path: /
            backend:
              service:
                name: http-server-abc123

Path-Based Routing

Route different paths to different components:

yaml
# Manual ingress for advanced routing
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: multi-path-ingress
spec:
  rules:
    - host: api.example.com
      http:
        paths:
          - path: /users
            pathType: Prefix
            backend:
              service:
                name: user-service
                port:
                  number: 8080
          - path: /orders
            pathType: Prefix
            backend:
              service:
                name: order-service
                port:
                  number: 8080

Ingress Annotations

NGINX Ingress Controller

yaml
metadata:
  annotations:
    # Timeouts
    nginx.ingress.kubernetes.io/proxy-connect-timeout: "60"
    nginx.ingress.kubernetes.io/proxy-send-timeout: "60"
    nginx.ingress.kubernetes.io/proxy-read-timeout: "60"

    # Body size
    nginx.ingress.kubernetes.io/proxy-body-size: "10m"

    # WebSocket support
    nginx.ingress.kubernetes.io/websocket-services: "http-server-abc123"

    # Rate limiting
    nginx.ingress.kubernetes.io/limit-rps: "100"

    # CORS
    nginx.ingress.kubernetes.io/enable-cors: "true"
    nginx.ingress.kubernetes.io/cors-allow-origin: "*"

Custom Annotations via Settings

go
type Settings struct {
    Hostnames          []string          `json:"hostnames"`
    TLS                bool              `json:"tls"`
    IngressAnnotations map[string]string `json:"ingressAnnotations,omitempty"`
}

rm.ExposePort(ctx, resource.ExposePortRequest{
    Port:        8080,
    Hostnames:   s.settings.Hostnames,
    TLS:         s.settings.TLS,
    Annotations: s.settings.IngressAnnotations,
})

WebSocket Support

Enable WebSocket upgrade:

yaml
metadata:
  annotations:
    nginx.ingress.kubernetes.io/proxy-http-version: "1.1"
    nginx.ingress.kubernetes.io/upstream-hash-by: "$request_uri"
    nginx.ingress.kubernetes.io/configuration-snippet: |
      proxy_set_header Upgrade $http_upgrade;
      proxy_set_header Connection "upgrade";

Health Checks

Readiness Probe

Ensure pods are ready before receiving traffic:

yaml
# In module Helm chart
spec:
  containers:
    - name: module
      readinessProbe:
        httpGet:
          path: /healthz
          port: 8080
        initialDelaySeconds: 5
        periodSeconds: 10

Backend Health

NGINX ingress checks backend health:

yaml
metadata:
  annotations:
    nginx.ingress.kubernetes.io/upstream-vhost: "api.example.com"
    nginx.ingress.kubernetes.io/health-check-path: "/healthz"

Load Balancing

Default (Round Robin)

Kubernetes Service distributes traffic evenly.

Session Affinity

Sticky sessions for stateful applications:

yaml
metadata:
  annotations:
    nginx.ingress.kubernetes.io/affinity: "cookie"
    nginx.ingress.kubernetes.io/session-cookie-name: "route"
    nginx.ingress.kubernetes.io/session-cookie-expires: "172800"

Monitoring Ingress

Check Ingress Status

bash
kubectl get ingress -n tinysystems
kubectl describe ingress http-server-abc123 -n tinysystems

View Logs

bash
# NGINX Ingress Controller logs
kubectl logs -n ingress-nginx -l app.kubernetes.io/name=ingress-nginx

Metrics

bash
# Prometheus metrics from ingress controller
curl http://ingress-controller:10254/metrics

Troubleshooting

Certificate Not Ready

bash
# Check cert-manager
kubectl get certificates -n tinysystems
kubectl describe certificate http-server-abc123-tls -n tinysystems

# Check challenges
kubectl get challenges -n tinysystems

502 Bad Gateway

  • Check pod readiness
  • Verify service selector matches pods
  • Check pod logs for errors
bash
kubectl get pods -n tinysystems -l app=http-module
kubectl logs -n tinysystems -l app=http-module

DNS Not Resolving

  • Verify DNS record exists
  • Check ingress host configuration
  • Ensure ingress controller has external IP
bash
kubectl get svc -n ingress-nginx
nslookup api.example.com

Best Practices

1. Use TLS in Production

go
rm.ExposePort(ctx, resource.ExposePortRequest{
    TLS: true,  // Always enable in production
})

2. Configure Timeouts

Match timeouts to your processing time:

yaml
nginx.ingress.kubernetes.io/proxy-read-timeout: "300"  # 5 minutes for long operations

3. Enable Rate Limiting

Protect against abuse:

yaml
nginx.ingress.kubernetes.io/limit-rps: "50"
nginx.ingress.kubernetes.io/limit-connections: "10"

4. Monitor Certificate Expiry

Set up alerts for certificate expiration:

yaml
# Prometheus rule
- alert: CertificateExpiringSoon
  expr: certmanager_certificate_expiration_timestamp_seconds - time() < 604800
  for: 1h

Next Steps

Build flow-based applications on Kubernetes