Skaffold profiles let you switch between different development, staging, and production configurations for your Kubernetes applications without copying and pasting YAML.
Here’s Skaffold in action, building and deploying a simple Go web app to a local Kubernetes cluster using different profiles.
First, let’s set up a basic Go web application.
// main.go
package main
import (
"fmt"
"net/http"
)
func handler(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "Hello from Skaffold! Environment: %s\n", getEnv())
}
func getEnv() string {
// In a real app, this would come from environment variables or config files
// For demonstration, we'll hardcode it, but Skaffold profiles will override this.
return "default"
}
func main() {
http.HandleFunc("/", handler)
fmt.Println("Server starting on port 8080")
// Skaffold's port forwarding will expose this to your local machine.
http.ListenAndServe(":8080", nil)
}
Now, we need a skaffold.yaml file to define our build and deploy process. We’ll start with a default configuration and then add profiles.
# skaffold.yaml (initial version)
apiVersion: skaffold/v2beta10
kind: Config
metadata:
name: my-go-app
build:
local:
# Use Docker to build the image.
push: false
artifacts:
- image: my-go-app
context: .
docker:
dockerfile: Dockerfile
deploy:
kubectl:
# Deploy to the default Kubernetes context.
manifests:
- k8s/deployment.yaml
- k8s/service.yaml
We’ll also need a Dockerfile and Kubernetes manifests.
# Dockerfile
FROM golang:1.21-alpine
WORKDIR /app
COPY . .
RUN go build -o main .
EXPOSE 8080
CMD ["/app/main"]
# 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 # This will be replaced by the built image tag
ports:
- containerPort: 8080
# k8s/service.yaml
apiVersion: v1
kind: Service
metadata:
name: my-go-app-service
spec:
selector:
app: my-go-app
ports:
- protocol: TCP
port: 80
targetPort: 8080
type: ClusterIP # For local development, ClusterIP is fine.
With this setup, running skaffold dev would build the image and deploy the application to your Kubernetes cluster. The getEnv() function in our Go app would return "default" because we haven’t configured any environment-specific settings yet.
Now, let’s introduce Skaffold profiles. We want a dev profile for local development and a staging profile.
Here’s how we modify skaffold.yaml to include profiles:
# skaffold.yaml (with profiles)
apiVersion: skaffold/v2beta10
kind: Config
metadata:
name: my-go-app
# Default configuration (applies if no profile is active or matches)
build:
local:
push: false
artifacts:
- image: my-go-app
context: .
docker:
dockerfile: Dockerfile
deploy:
kubectl:
manifests:
- k8s/deployment.yaml
- k8s/service.yaml
# Define profiles
profiles:
- name: dev
# For development, we want to enable debugging and maybe a different image tag.
build:
local:
push: false
artifacts:
- image: my-go-app-dev
context: .
docker:
dockerfile: Dockerfile
deploy:
kubectl:
# Override manifests for dev. For example, maybe we want a LoadBalancer service.
manifests:
- k8s/deployment.yaml
- k8s/service-dev.yaml
- name: staging
# For staging, we'll push to a registry and use a specific tag.
build:
artifacts:
- image: my-docker-registry/my-go-app
context: .
docker:
dockerfile: Dockerfile
# For staging, we want to push to a registry.
local:
push: true
deploy:
kubectl:
# Staging might use a different set of manifests or configurations.
manifests:
- k8s/deployment-staging.yaml
- k8s/service.yaml
# We can also set image tags explicitly for a profile.
images:
- my-docker-registry/my-go-app=my-docker-registry/my-go-app:v1.0.0
And let’s create the new Kubernetes manifests referenced in the dev and staging profiles.
# k8s/service-dev.yaml
apiVersion: v1
kind: Service
metadata:
name: my-go-app-service-dev
spec:
selector:
app: my-go-app
ports:
- protocol: TCP
port: 80
targetPort: 8080
type: LoadBalancer # Expose externally for easier local testing.
# k8s/deployment-staging.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: my-go-app-staging
spec:
replicas: 3 # More replicas for staging
selector:
matchLabels:
app: my-go-app
template:
metadata:
labels:
app: my-go-app
spec:
containers:
- name: my-go-app
image: my-docker-registry/my-go-app:v1.0.0 # Explicitly use the staging tag
ports:
- containerPort: 8080
With profiles, you can now run Skaffold with a specific profile using the -p flag.
To use the dev profile:
skaffold dev -p dev
This command will:
- Build the
my-go-app-devimage using theDockerfilein the current context. - Deploy using
k8s/deployment.yamlandk8s/service-dev.yaml. Theservice-dev.yamlusestype: LoadBalancer, which your local Kubernetes environment (like Minikube or Kind) will typically provision with a NodePort or an IP address you can access. - Skaffold will then port-forward to the
my-go-appdeployment, allowing you to access it locally.
To use the staging profile:
skaffold dev -p staging
This command will:
- Build the
my-docker-registry/my-go-appimage andpush: truewill upload it to your configured Docker registry. - Deploy using
k8s/deployment-staging.yamlandk8s/service.yaml. Thedeployment-staging.yamlspecifiesreplicas: 3and uses the explicit image tagmy-docker-registry/my-go-app:v1.0.0.
The build and deploy sections within a profile override the top-level build and deploy configurations. This means you don’t have to repeat common settings. For instance, in the dev profile, we only specify image: my-go-app-dev and manifests: - k8s/service-dev.yaml because the rest of the build and deploy configuration (like context: . and dockerfile: Dockerfile) is inherited from the top level.
One of the most powerful, yet often overlooked, aspects of Skaffold profiles is their ability to modify environment variables passed into your application containers. While not explicitly shown in the skaffold.yaml above, you can add an envTemplate section to your deployment manifests or directly within the Skaffold deploy configuration. For example, you could add this to the dev profile’s deploy section:
deploy:
kubectl:
manifests:
- k8s/deployment.yaml
- k8s/service-dev.yaml
envTemplate:
configs:
- image: my-go-app # The image to apply env vars to
env:
- name: APP_ENV
value: development
This allows you to inject environment-specific variables into your running application, enabling you to easily switch behavior (like logging levels, feature flags, or configuration sources) based on the active Skaffold profile without rebuilding or redeploying your application’s code itself.
The next step is to explore how Skaffold profiles interact with Skaffold’s build.tagPolicy and how to manage multiple artifacts within a single Skaffold configuration.