Skaffold can build container images directly within your Kubernetes cluster, bypassing the need for a local Docker daemon and simplifying your CI/CD workflow.
Let’s see Skaffold build an image using Kaniko, without any local Docker installation.
First, ensure you have a Kubernetes cluster running and kubectl configured to access it. You’ll also need Skaffold installed.
Here’s a minimal skaffold.yaml configuration for this setup:
apiVersion: skaffold/v4beta10
kind: Config
build:
local:
useKaniko: true
artifacts:
- image: my-kaniko-app
context: .
docker:
dockerfile: Dockerfile
deploy:
kubectl:
manifests:
- k8s/*
In this skaffold.yaml:
build.local.useKaniko: truetells Skaffold to use Kaniko for building.artifactsdefines the image to build (my-kaniko-app), the build context (.), and the Dockerfile location.deploy.kubectlspecifies Kubernetes manifests to apply after the build.
Now, create a simple Dockerfile in the root of your project:
FROM alpine:latest
RUN echo "Hello from Kaniko!" > /app/message.txt
CMD ["cat", "/app/message.txt"]
And a basic Kubernetes deployment manifest in k8s/deployment.yaml:
apiVersion: apps/v1
kind: Deployment
metadata:
name: kaniko-demo
spec:
replicas: 1
selector:
matchLabels:
app: kaniko-demo
template:
metadata:
labels:
app: kaniko-demo
spec:
containers:
- name: kaniko-demo
image: my-kaniko-app # This will be replaced by Skaffold with the built image tag
ports:
- containerPort: 80
When you run skaffold dev, Skaffold will:
- Detect
useKaniko: true. - Create a temporary Kubernetes
Podthat runs the Kaniko executor image. - Mount your application code (the build context) into the Kaniko Pod.
- Instruct Kaniko to build the image based on your
Dockerfile. - Push the built image to your configured container registry (Docker Hub, GCR, ECR, etc. – ensure your Kubernetes cluster has credentials for this).
- Update your Kubernetes deployment manifest with the newly built image tag.
- Apply the updated manifest to your cluster.
The key benefit here is that the image build happens inside the cluster. Kaniko itself runs as a container, and it uses the cluster’s networking to pull base images and push the final image. It doesn’t require a Docker daemon running on your local machine or a dedicated builder agent.
To make this work, Kaniko needs to be able to push to a container registry. Skaffold automatically configures Kaniko to use the credentials available to the Kubernetes nodes or through service accounts. For example, if you’re using GCR, your Kubernetes nodes typically have service accounts with GCR push permissions. If you’re using Docker Hub, you might need to configure Kubernetes secrets for registry authentication.
Let’s say you want to push to Docker Hub. You’d typically create a Kubernetes secret:
kubectl create secret docker-registry regcred \
--docker-server=https://index.docker.io/v1/ \
--docker-username=<your-dockerhub-username> \
--docker-password=<your-dockerhub-password> \
--docker-email=<your-email>
And then configure Skaffold to use this secret:
apiVersion: skaffold/v4beta10
kind: Config
build:
local:
useKaniko: true
# Specify the Kubernetes secret for registry authentication
kanikoSecret: regcred
artifacts:
- image: your-dockerhub-username/my-kaniko-app # Use your Docker Hub username here
context: .
docker:
dockerfile: Dockerfile
deploy:
kubectl:
manifests:
- k8s/*
With this, Skaffold will pass the regcred secret to the Kaniko executor pod, allowing it to authenticate with Docker Hub.
The kanikoSecret directive is crucial. Without it, Kaniko won’t be able to push the image to a private registry. If you’re using a public registry like docker.io/library/alpine, you usually don’t need explicit credentials.
When you run skaffold dev, you’ll see output indicating that Skaffold is building the image using Kaniko, and then deploying. The output will look something like this:
...
[my-kaniko-app] Successfully built and tagged the-registry/my-kaniko-app:a1b2c3d4-dirty
[kubectl] deployment.apps/kaniko-demo created
...
The "magic" happens because Kaniko, running as a container within your cluster, has access to the cluster’s networking and storage. It doesn’t need a daemon to manage image layers or interact with the host kernel’s Docker API. Instead, it directly manipulates filesystem snapshots and uses the registry API to push the final layers. This isolation is what makes it suitable for running in unprivileged environments like Kubernetes, where you might not want or be able to run a full Docker daemon.
One detail often missed is how Kaniko handles the build context. When useKaniko: true, Skaffold will typically create a PersistentVolumeClaim (PVC) in your cluster, copy your build context into it, and then mount that PVC into the Kaniko executor pod. This ensures that Kaniko has access to your Dockerfile and any other files needed for the build. The size of this PVC is usually small, just enough for your project’s source files.
The next challenge you’ll likely encounter is optimizing build times by leveraging Kaniko’s cache, especially when dealing with multi-stage builds or frequent code changes.