| created | Tue Dec 16 2025 00:00:00 GMT+0000 (Coordinated Universal Time) |
| modified | Tue Dec 16 2025 00:00:00 GMT+0000 (Coordinated Universal Time) |
| reviewed | Tue Dec 16 2025 00:00:00 GMT+0000 (Coordinated Universal Time) |
| name | skaffold-orbstack |
| description | OrbStack-optimized Skaffold workflows for local Kubernetes development without port-forward. Use when configuring Skaffold with OrbStack, accessing services via LoadBalancer or Ingress, or when the user mentions OrbStack, k8s.orb.local, service access, or eliminating port-forward. |
Skaffold with OrbStack - Port-Forward-Free Development
Overview
OrbStack provides superior local Kubernetes networking compared to other tools (minikube, kind, Docker Desktop). Services are accessible directly from macOS without port-forward.
Key OrbStack Advantages
| Feature | OrbStack | minikube/kind |
|---|---|---|
| LoadBalancer auto-provision | ✅ Yes | ❌ Needs MetalLB |
Wildcard DNS (*.k8s.orb.local) |
✅ Yes | ❌ No |
| cluster.local from host | ✅ Yes | ❌ No |
| Pod IP direct access | ✅ Yes | ❌ No |
| Auto HTTPS certificates | ✅ Yes | ❌ No |
Service Access Methods
Method 1: LoadBalancer Services (Simplest)
Change service type from ClusterIP to LoadBalancer:
apiVersion: v1
kind: Service
metadata:
name: my-app
spec:
type: LoadBalancer # OrbStack auto-provisions external IP
ports:
- port: 80
targetPort: 8080
selector:
app: my-app
Access: curl http://my-app.default.svc.cluster.local from macOS
Method 2: Ingress with Wildcard DNS (Recommended)
One-time setup - Install Ingress controller:
# Ingress-NGINX (recommended)
kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/controller-v1.8.1/deploy/static/provider/cloud/deploy.yaml
# OR Traefik
helm repo add traefik https://traefik.github.io/charts
helm install traefik traefik/traefik
Create Ingress for your service:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: my-app
spec:
ingressClassName: nginx
rules:
- host: my-app.k8s.orb.local
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: my-app
port:
number: 80
Access: http://my-app.k8s.orb.local (auto-resolves)
Method 3: Direct Service DNS (cluster.local)
OrbStack exposes cluster DNS to macOS:
# Access any service directly
curl http://my-app.default.svc.cluster.local:8080
# Full DNS pattern
curl http://<service>.<namespace>.svc.cluster.local:<port>
Skaffold Configuration for OrbStack
Minimal skaffold.yaml (No Port-Forward Needed)
apiVersion: skaffold/v4beta11
kind: Config
metadata:
name: my-app
build:
local:
push: false
useBuildkit: true
artifacts:
- image: my-app
docker:
dockerfile: Dockerfile
deploy:
kubeContext: orbstack
kubectl:
manifests:
- k8s/*.yaml
statusCheck: true
statusCheckDeadlineSeconds: 180
# Port-forward REMOVED - use LoadBalancer/Ingress instead
Profile: Local with Ingress
profiles:
- name: local-ingress
deploy:
kubeContext: orbstack
kubectl:
manifests:
- k8s/base/*.yaml
- k8s/ingress/*.yaml # Ingress resources
Profile: Services-Only (Frontend Local Dev)
profiles:
- name: services-only
build:
artifacts: [] # Don't build frontend
deploy:
kubeContext: orbstack
kubectl:
manifests:
- k8s/namespace.yaml
- k8s/database/*.yaml
- k8s/api/*.yaml
Access backend at http://api.k8s.orb.local while running npm run dev locally.
Kubernetes Manifest Templates
LoadBalancer Service Template
# k8s/service.yaml
apiVersion: v1
kind: Service
metadata:
name: {{ .name }}
labels:
app: {{ .name }}
spec:
type: LoadBalancer
ports:
- name: http
port: 80
targetPort: {{ .containerPort | default 8080 }}
selector:
app: {{ .name }}
Ingress Template
# k8s/ingress.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: {{ .name }}
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /
spec:
ingressClassName: nginx
rules:
- host: {{ .name }}.k8s.orb.local
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: {{ .name }}
port:
number: 80
Migration: Port-Forward to LoadBalancer
Before (Traditional)
# skaffold.yaml with port-forward
portForward:
- resourceType: service
resourceName: api
port: 8080
localPort: 8080
address: 127.0.0.1
- resourceType: service
resourceName: frontend
port: 3000
localPort: 3000
address: 127.0.0.1
skaffold dev # Services at localhost:8080, localhost:3000
After (OrbStack Native)
# k8s/services.yaml - Change service types
apiVersion: v1
kind: Service
metadata:
name: api
spec:
type: LoadBalancer # Changed from ClusterIP
ports:
- port: 8080
---
apiVersion: v1
kind: Service
metadata:
name: frontend
spec:
type: LoadBalancer # Changed from ClusterIP
ports:
- port: 3000
# skaffold.yaml - Remove portForward section entirely
deploy:
kubeContext: orbstack
kubectl:
manifests:
- k8s/*.yaml
# No portForward needed!
skaffold dev # Services at api.default.svc.cluster.local:8080
# frontend.default.svc.cluster.local:3000
Common Patterns
Database Access
# k8s/postgresql.yaml
apiVersion: v1
kind: Service
metadata:
name: postgresql
spec:
type: LoadBalancer # Access from local tools (DBeaver, pgAdmin)
ports:
- port: 5432
Connection string: postgres://user:pass@postgresql.default.svc.cluster.local:5432/db
Multi-Service Application
# k8s/ingress.yaml - Single Ingress for all services
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: app-ingress
spec:
ingressClassName: nginx
rules:
- host: api.k8s.orb.local
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: api
port:
number: 8080
- host: web.k8s.orb.local
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: frontend
port:
number: 3000
- host: admin.k8s.orb.local
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: admin-panel
port:
number: 8000
Security Considerations
Default: Localhost Only
OrbStack restricts services to localhost by default - safe on untrusted networks.
Expose to LAN (Use with Caution)
Settings → Kubernetes → "Expose services to local network devices"
Only enable when:
- Testing from mobile devices on same network
- Sharing local environment with team
- On trusted network
Troubleshooting
Service Not Accessible
- Check service type:
kubectl get svc - Verify LoadBalancer has EXTERNAL-IP (not
<pending>) - Test DNS:
nslookup my-app.default.svc.cluster.local
Ingress Not Working
- Verify Ingress controller is running:
kubectl -n ingress-nginx get pods - Check Ingress controller has LoadBalancer IP:
kubectl -n ingress-nginx get svc - Verify Ingress resource:
kubectl describe ingress my-app
DNS Resolution Issues
# Test cluster DNS from macOS
nslookup my-service.default.svc.cluster.local
# If short names fail, use full domain
# ❌ my-service.default.svc
# ✅ my-service.default.svc.cluster.local
Pod IP Direct Access (Debugging)
# Get pod IP
kubectl get pods -o wide
# Connect directly (OrbStack routes pod network to macOS)
curl http://10.42.0.15:8080
Quick Setup Checklist
- Install Ingress controller (one-time)
- Change service types to LoadBalancer
- Create Ingress resources for pretty URLs
- Remove
portForwardfrom skaffold.yaml - Set
kubeContext: orbstackin deploy config - Update local .env/config to use
.k8s.orb.localURLs
Commands Reference
# Start development (no --port-forward needed)
skaffold dev --kube-context=orbstack
# Run specific profile
skaffold dev -p services-only --kube-context=orbstack
# Check service accessibility
kubectl get svc -o wide
# Verify Ingress
kubectl get ingress