Skaffold is designed to make your Kubernetes development workflow feel less like a chore and more like, well, development. The core problem it solves is the friction between writing code and seeing it run live in your cluster. It automates the build, push, and deploy steps, so you can focus on writing your application.
Let’s see Skaffold in action. Imagine you have a simple Go web server in a file called main.go:
package main
import (
"fmt"
"net/http"
)
func main() {
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "Hello from Skaffold!")
})
fmt.Println("Server starting on port 8080")
http.ListenAndServe(":8080", nil)
}
And a Dockerfile to build it:
FROM golang:1.21-alpine
WORKDIR /app
COPY . .
RUN go build -o main
CMD ["/app/main"]
You’d typically build this, tag it, push it to a registry, and then apply a Kubernetes deployment manifest. With Skaffold, you just need a skaffold.yaml file:
apiVersion: skaffold.dev/v2beta20
kind: Config
build:
local:
push: false
artifacts:
- image: my-go-app
docker:
dockerfile: Dockerfile
deploy:
kubectl:
manifests:
- k8s/deployment.yaml
And a simple k8s/deployment.yaml:
apiVersion: apps/v1
kind: Deployment
metadata:
name: my-go-app
spec:
replicas: 1
selector:
matchLabels:
app: my-go-app
template:
metadata:
labels:
app: my-go-app
spec:
containers:
- name: my-go-app
image: my-go-app # Skaffold will tag this automatically
ports:
- containerPort: 8080
Now, from your terminal, run skaffold dev. Skaffold will:
- Build your Docker image.
- Tag it with a unique identifier (like a Git commit SHA or a timestamp).
- Deploy it to your Kubernetes cluster using
kubectl apply. - Port-forward the service so you can access it locally.
You’ll see output like this:
[...]
[my-go-app] Server starting on port 8080
[my-go-app] Forwarding from 127.0.0.1:8080 -> 8080
Press Ctrl+C to stop
Now, if you change main.go (e.g., change "Hello from Skaffold!" to "Hello again!"), save the file, Skaffold detects the change, rebuilds the image, redeploys, and your browser will automatically refresh to show the updated message. No manual docker build, docker push, kubectl apply, or kubectl port-forward needed. This is the "inner loop" – the rapid cycle of coding and testing.
Skaffold’s magic lies in its ability to manage the entire lifecycle. It integrates with various build tools (Docker, Jib, Bazel, etc.) and deployment strategies (kubectl, Helm, Kustomize, etc.). The skaffold.yaml is your central control panel, defining your build artifacts and how they should be deployed.
The build section specifies how your images are created. Here, local tells Skaffold to use your local Docker daemon, and push: false means it won’t push to a remote registry during dev mode (it tags them locally). You can configure different builders and push policies for different environments.
The deploy section tells Skaffold how to get your application running in Kubernetes. kubectl is the most straightforward, pointing to your manifest files. Skaffold will intelligently update the image tag in your deployment manifest before applying it.
What most people don’t realize is that Skaffold is not just about automation; it’s about intelligence. When you run skaffold dev, it doesn’t just blindly rebuild and redeploy everything on every change. It analyzes what has changed. If only your application code changed, it might only rebuild the affected image and redeploy the corresponding Kubernetes resources. If your Dockerfile changed, it will trigger a full rebuild. This granular understanding of dependencies is key to its speed.
The next step in mastering Skaffold is understanding how to manage multiple services and more complex deployment scenarios, often involving Helm charts or Kustomize overlays.