
September 10, 2026
12 min read
By Kokil Thapa | Last reviewed: September 2026
Your Laravel API passes every PHPUnit run on the laptop. Then it fails in staging because the Ingress path, probe timing, or ConfigMap key differs from Docker Compose. Local Kubernetes Dev with Tilt and Skaffold closes that gap. Both tools watch your source tree, rebuild images, and redeploy into a local cluster such as kind or Minikube. You exercise the same Deployments, Services, and Secrets you will ship. On production Laravel and booking systems I maintain, that mismatch between compose files and cluster manifests caused more late-night fixes than application bugs. This guide walks through a practical setup you can copy today.
What is Local Kubernetes Dev with Tilt and Skaffold?
Local Kubernetes development means running your application inside a real cluster on your machine. Docker Compose simulates services with containers on a single host. Kubernetes adds scheduling, Services, Ingress, and volume claims. Tools like Tilt and Skaffold remove the manual kubectl apply cycle after every code save.
Both sit between your editor and the cluster API. They detect file changes, build container images, push or load them into the cluster, and update running Pods. They also stream logs and expose port forwards. The goal is parity: what you test locally should match what GitOps deploys to staging.
A typical stack for a PHP team includes these pieces:
- A local cluster driver: kind, Minikube, k3d, or Docker Desktop Kubernetes.
- Container images built with Docker or BuildKit.
- Manifests in plain YAML, Kustomize overlays, or Helm charts.
- Skaffold or Tilt orchestrating the inner dev loop.
If you still run Laravel on Compose alone, read local Laravel dev with Sail and Docker first. Sail is excellent for feature work. Move to Kubernetes locally when ingress rules, sidecars, or multi-replica behaviour matter.
How do you set up a local Kubernetes cluster for development?
Before Tilt or Skaffold can deploy anything, you need a running cluster and kubectl context pointed at it. kind is my default on Ubuntu laptops. It spins up fast and tears down cleanly in CI.
Create a kind cluster with ingress
# Install kind (Linux amd64 example)
curl -Lo ./kind https://kind.sigs.k8s.io/dl/v0.26.0/kind-linux-amd64
chmod +x ./kind && sudo mv ./kind /usr/local/bin/kind
# Cluster config with extra port mappings for HTTP
cat > kind-config.yaml <<'EOF'
kind: Cluster
apiVersion: kind.x-k8s.io/v1alpha4
nodes:
- role: control-plane
kubeadmConfigPatches:
- |
kind: InitConfiguration
nodeRegistration:
kubeletExtraArgs:
node-labels: "ingress-ready=true"
extraPortMappings:
- containerPort: 80
hostPort: 8080
protocol: TCP
- containerPort: 443
hostPort: 8443
protocol: TCP
EOF
kind create cluster --name dev --config kind-config.yaml
kubectl cluster-info --context kind-dev
Minikube remains a solid choice when you want a built-in tunnel or driver abstraction. The comparison in our Minikube vs kind guide covers RAM usage and CI fit. Allocate at least 4 GB RAM and two CPU cores for a three-service app with MySQL.
Install ingress and metrics basics
kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/main/deploy/static/provider/kind/deploy.yaml
kubectl wait --namespace ingress-nginx \
--for=condition=ready pod \
--selector=app.kubernetes.io/component=controller \
--timeout=120s
Verify the cluster before adding Skaffold or Tilt. A broken context wastes an hour of cryptic build errors. Run kubectl get nodes and confirm Ready status.
How do you configure Skaffold for local Kubernetes development?
Skaffold reads a skaffold.yaml at the repo root. It defines build artifacts, deploy method, and optional file sync rules. Google maintains it. Teams that already use Cloud Build or GKE often adopt Skaffold because the same config runs in CI with skaffold run.
Minimal skaffold.yaml for a Laravel-style app
apiVersion: skaffold/v4beta11
kind: Config
metadata:
name: laravel-dev
build:
local:
push: false
artifacts:
- image: myapp/web
context: .
docker:
dockerfile: Dockerfile
sync:
manual:
- src: "app//*.php"
dest: /var/www/html/app
- src: "routes//*.php"
dest: /var/www/html/routes
- src: "resources/views/**/*.blade.php"
dest: /var/www/html/resources/views
- image: myapp/queue
context: .
docker:
dockerfile: Dockerfile.queue
deploy:
kubectl:
manifests:
- k8s/base/*.yaml
portForward:
- resourceType: service
resourceName: web
port: 80
localPort: 8080
Start the dev loop with one command:
skaffold dev --port-forward
Skaffold watches files, rebuilds when Docker layers change, and syncs PHP files without a full image rebuild when sync rules match. That mirrors how Docker Compose hot paths feel, but against real Deployments.
Skaffold profiles for staging parity
Use profiles when staging runs Helm but local dev uses plain manifests:
profiles:
- name: local
activation:
- command: dev
deploy:
kubectl:
manifests:
- k8s/overlays/local/*.yaml
- name: ci
activation:
- env: CI=true
build:
local:
push: true
deploy:
helm:
releases:
- name: myapp
chartPath: charts/myapp
Validate YAML syntax with our JSON and YAML formatter before debugging Skaffold parse errors. A trailing tab in skaffold.yaml fails silently until runtime.
How do you configure Tilt for local Kubernetes development?
Tilt uses a Tiltfile written in Starlark. It excels when you run five or more services and need one dashboard for logs, builds, and health. The web UI at localhost:10350 shows which resource is failing and why.
Example Tiltfile for web, queue, and Redis
# Tiltfile
allow_k8s_contexts('kind-dev')
docker_build('myapp/web', '.',
dockerfile='Dockerfile',
live_update=[
sync('./app', '/var/www/html/app'),
sync('./routes', '/var/www/html/routes'),
sync('./resources/views', '/var/www/html/resources/views'),
run('php artisan view:clear', trigger=['./resources/views']),
]
)
docker_build('myapp/queue', '.',
dockerfile='Dockerfile.queue',
live_update=[
sync('./app', '/var/www/html/app'),
]
)
k8s_yaml(['k8s/base/web.yaml', 'k8s/base/queue.yaml', 'k8s/base/redis.yaml'])
k8s_resource('web',
port_forwards=8080,
resource_deps=['redis'],
)
k8s_resource('queue',
resource_deps=['redis'],
)
Run tilt up in the repo root. Tilt builds images, loads them into kind, applies manifests, and opens the UI. Resource dependencies prevent the web Pod from starting before Redis is reachable.
For Laravel specifically, pair this with the patterns in Kubernetes for Laravel getting started. Set APP_KEY and database URLs through Secrets, not hard-coded env blocks in the Tiltfile.
Tilt extensions worth enabling
- helm_resource for charts you already ship to production.
- local_resource for asset builds when Vite 8.x runs on the host.
- ci_settings to disable the browser UI in headless pipelines.
I have used Tilt on multi-service booking platforms where web, worker, scheduler, and Redis each had separate Deployments. One screen beat four terminal panes of kubectl logs.
Tilt vs Skaffold: which tool fits your team?
Both solve Local Kubernetes Dev with Tilt and Skaffold as the headline workflow. They differ in config style, UI, and CI story. Neither replaces a production GitOps controller such as Argo CD.
| Criterion | Skaffold | Tilt |
|---|---|---|
| Config format | skaffold.yaml (YAML) | Tiltfile (Starlark/Python-like) |
| Developer UI | Terminal output; optional IDEs | Built-in web dashboard at :10350 |
| Deploy targets | kubectl, Kustomize, Helm, Cloud Run | kubectl, Helm, custom scripts |
| Live sync | manual sync rules in YAML | live_update blocks in Tiltfile |
| CI reuse | Strong: skaffold run / render | Possible; often dev-focused |
| Learning curve | Lower if team knows YAML | Steeper; pays off with many services |
| Best for | YAML-first teams, GKE pipelines | Polyglot monorepos, fast feedback |
Pick Skaffold when your platform team owns skaffold.yaml and wants identical render steps in GitLab CI. Pick Tilt when developers juggle many interdependent services and need visible build graphs. Running both in one repo is rare and usually a migration artifact, not a goal.
What are common gotchas when running apps locally on Kubernetes?
Local clusters expose problems that Compose hides. Treat these as normal learning steps, not signs the tooling failed.
Image pull and load failures
kind and Minikube often require push: false and local image load. Skaffold handles this when build.local.push is false. Tilt loads via docker_build defaults. If you see ImagePullBackOff, the tag in the Deployment does not match the built image name.
Probe timing during boot
Laravel containers need time for migrations and cache warmup. A readiness probe hitting / too early causes endless restarts. Tune initialDelaySeconds and align with resource limits and requests so PHP-FPM is not OOMKilled during composer install.
Volume permissions on Linux
Host-mounted volumes with www-data UID mismatches break file writes. On Ubuntu dev machines I set fsGroup in the Pod securityContext. This matches fixes I apply on production nodes during Linux server administration engagements.
Database seed data and migrations
Run migrations as a Kubernetes Job or an init container. Do not rely on artisan migrate inside the web container startup script without idempotency guards. Duplicate migrate calls from HPA scale events corrupt schema state.
When Pods still fail after config fixes, follow the steps in debug a CrashLoopBackOff and the broader Kubernetes troubleshooting field guide.
Bridging local dev to production pipelines
Local Kubernetes dev should feed the same manifests GitOps applies. A workable path looks like this:
- Develop with Tilt or Skaffold against k8s/overlays/local.
- Run skaffold render or kubectl kustomize build for staging output.
- Commit rendered manifests or Kustomize bases to Git.
- Let Argo CD or your CI pipeline deploy to staging clusters.
- Keep Compose or Sail for quick unit-test loops if the team prefers both.
On a Laravel eCommerce project like Quick And Easy Nepalese Grocery, delivery-zone logic lived in PHP. Running it behind real Ingress locally caught path-prefix bugs before QA. That saved a redeploy cycle staging would have paid for.
For API-heavy platforms, the same workflow pairs with API development practices: versioned OpenAPI specs, contract tests, and rate-limit headers enforced at the Ingress layer.
Teams building custom booking engines often ask whether local Kubernetes is worth the RAM cost. If you deploy to Kubernetes in production, the answer is yes. Compose cannot simulate pod anti-affinity, NetworkPolicy, or horizontal scaling behaviour. The hour spent on kind plus Skaffold pays back the first time a probe misconfiguration is caught locally.
Hardware matters on Nepal dev laptops with 8 GB RAM. Close browser tabs, cap cluster workers at one node, and run only the services you are editing. Use profiles to disable heavy dependencies like Elasticsearch until needed.
Compare this approach with Laravel Sail vs Docker Compose when pitching the stack to stakeholders. Sail stays cheaper for solo feature work. Tilt or Skaffold enters when staging mirrors production topology.
Enterprise clients evaluating microservices should read enterprise application development scope docs before mandating Kubernetes everywhere. A monolith on managed PHP hosting may outship a premature cluster.
The official Kubernetes documentation remains the reference for API objects you deploy through either tool. Neither Tilt nor Skaffold abstracts away understanding Deployments and Services.
Key Takeaways
- Local Kubernetes Dev with Tilt and Skaffold runs real manifests on kind or Minikube instead of compose-only approximations.
- Skaffold fits YAML-centric teams that want skaffold render output in CI; Tilt fits multi-service repos needing a live dependency dashboard.
- Configure live sync for PHP, Blade, and route files to avoid full image rebuilds on every save.
- Fix ImagePullBackOff, probe timing, and volume UID issues early—they dominate first-week setup time.
- Point local overlays at the same Kustomize or Helm bases GitOps deploys to staging and production.
- Keep Sail or Compose for fast unit tests; use Kubernetes locally when ingress, scaling, or policies matter.
People Also Ask
Do I need Kubernetes locally if I already use Docker Compose?
Not for every project. Compose is enough when production also runs Compose or plain VMs. You need local Kubernetes when production runs Kubernetes and you must test Ingress, Secrets, probes, or NetworkPolicy before merge.
Can Tilt and Skaffold work with kind on Apple Silicon and Linux?
Yes. kind supports arm64 and amd64. Build images for the node architecture or use buildx with the correct platform flag. Skaffold and Tilt both delegate to Docker or BuildKit for builds.
How much RAM does a local Kubernetes dev environment need?
Budget 4 GB for the cluster plus 2 GB for Docker builds on a three-service app. Add 1–2 GB per extra database or message broker. Close unused services through Skaffold profiles or commented k8s_resource blocks in Tilt.
Does local Kubernetes replace staging?
No. Local dev catches manifest and probe mistakes early. Staging still validates shared databases, TLS certificates, external webhooks, and load at scale. Treat local Kubernetes as the first gate, not the last.
Ship with confidence from laptop to cluster
Local Kubernetes Dev with Tilt and Skaffold turns manifest guesswork into a repeatable inner loop. Start with kind, add Skaffold or Tilt to match your team’s config style, and wire overlays into the same Git paths your pipeline already uses. If you want help designing that path for a Laravel, API, or booking platform, see the Adventure Third Pole Trek case study and reach out via contact us for architecture review. For broader context on my stack choices, visit about me or browse related posts on the blog.
Frequently Asked Questions
0 Comments
Leave a comment
Your email is not published. Comments appear once they have been read. Sign in to have your details filled in.

