In my earlier post Inner Dev Loop for Kubernetes, I demonstrated the use of Tilt. Tilt is a toolkit for fixing the pains of microservice development. In this post, I will explore Skaffold.
What is Skaffold?
Skaffold is a command line tool that facilitates continuous development for container based & Kubernetes applications. Skaffold handles the workflow for building, pushing, and deploying your application, and provides building blocks for creating CI/CD pipelines. This enables you to focus on iterating on your application locally while Skaffold continuously deploys to your local or remote Kubernetes cluster, local Docker environment or Cloud Run project.
Skaffold Workflow
Skaffold simplifies your development workflow by organizing common development stages into one simple command. Every time you run skaffold dev, the system
- Collects and watches your source code for changes
- Syncs files directly to pods if user marks them as syncable
- Builds artifacts from the source code
- Tests the built artifacts using container-structure-tests or custom scripts
- Tags the artifacts
- Pushes the artifacts
- Deploys the artifacts
- Monitors the deployed artifacts
- Cleans up deployed artifacts on exit (Ctrl+C)
NOTE: Any of these stages can be skipped.
Skaffold supports the following tools:
Enough talk, show me how to do it?
During Tilt exploration, I utilized ASP.NET Core Web App (Razor Pages) to develop a DEMO application. I intend to leverage this same DEMO application for Skaffold in order to gain a comprehensive understanding of their functionalities, as both platforms address analogous problem domains.
Installation of Skaffold
# Run this command to install Skaffold
brew install skaffold
# Run this command to check the Skaffold installation and available options
skaffold help
A tool that facilitates continuous development for Kubernetes applications.
Find more information at: https://skaffold.dev/docs/getting-started/
End-to-end Pipelines:
run Run a pipeline
dev Run a pipeline in development mode
debug Run a pipeline in debug mode
Pipeline Building Blocks:
build Build the artifacts
test Run tests against your built application images
deploy Deploy pre-built artifacts
delete Delete any resources deployed by Skaffold
render Generate rendered Kubernetes manifests
apply Apply hydrated manifests to a cluster
verify Run verification tests against skaffold deployments
Getting Started With a New Project:
init Generate configuration for deploying an application
Other Commands:
completion Output shell completion for the given shell (bash, fish or zsh)
config Interact with the global Skaffold config file (defaults to `$HOME/.skaffold/config`)
diagnose Run a diagnostic on Skaffold
exec Execute a custom action
fix Update old configuration to a newer schema version
schema List JSON schemas used to validate skaffold.yaml configuration
survey Opens a web browser to fill out the Skaffold survey
version Print the version information
Usage:
skaffold [flags] [options]
Creation of DEMO App
# To create a DEMO app, execute below command from terminal
dotnet new razor --no-https -n skaffolddemo
After successful creation of project, you can create docker file using Command Palette. (Refer below image).
The following code snippets outline the content of docker file.
# Dockerfile
FROM mcr.microsoft.com/dotnet/aspnet:8.0 AS base
WORKDIR /app
EXPOSE 5008
ENV ASPNETCORE_URLS=http://+:5008
USER app
FROM --platform=$BUILDPLATFORM mcr.microsoft.com/dotnet/sdk:8.0 AS build
ARG configuration=Release
WORKDIR /src
COPY ["skaffolddemo.csproj", "./"]
RUN dotnet restore "skaffolddemo.csproj"
COPY . .
WORKDIR "/src/."
RUN dotnet build "skaffolddemo.csproj" -c $configuration -o /app/build
FROM build AS publish
ARG configuration=Release
RUN dotnet publish "skaffolddemo.csproj" -c $configuration -o /app/publish /p:UseAppHost=false
FROM base AS final
WORKDIR /app
COPY --from=publish /app/publish .
ENTRYPOINT ["dotnet", "skaffolddemo.dll"]
The following code snippets outline the content of kubernetes file. Draft tool is used to create Kubernetes manifest files, such as deployment and service files. For simplicity, I merged them into one file.
# k8-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: skaffolddemo
labels:
app: skaffolddemo
kubernetes.azure.com/generator: draft
namespace: default
spec:
replicas: 1
selector:
matchLabels:
app: skaffolddemo
template:
metadata:
labels:
app: skaffolddemo
spec:
containers:
- name: skaffolddemo
image: skaffolddemo:latest
imagePullPolicy: Never
ports:
- containerPort: 5008
---
apiVersion: v1
kind: Service
metadata:
name: skaffolddemo
namespace: default
labels:
kubernetes.azure.com/generator: draft
spec:
type: LoadBalancer
selector:
app: skaffolddemo
ports:
- protocol: TCP
port: 5008
targetPort: 5008
Now, we are ready with the DEMO app, Dockerfile, Kubernetes manifest file and Skaffold installation. Next step: setting up a Kubernetes Cluster for deploying the app. I'm using Docker Desktop for this. Here is the configuration's details:
Initialization of Skaffold
In application directly, we run below command to bootstrap skaffold configuration.
skaffold init
skaffold init command prompts to
? Choose the builder to build image skaffolddemo [Use arrows to move, type to filter]
Buildpacks (skaffolddemo.csproj)
> Docker (Dockerfile)
None (image not built from these sources)
? Which builders would you like to create kubernetes resources for? [Use arrows to move, space to select, <right> to all, <left> to none, type to filter]
> [x] Buildpacks (skaffolddemo.csproj)
apiVersion: skaffold/v4beta10
kind: Config
metadata:
name: skaffolddemo
build:
artifacts:
- image: skaffolddemo
docker:
dockerfile: Dockerfile
manifests:
rawYaml:
- k8-deployment.yaml
? Do you want to write this configuration to skaffold.yaml? Yes
Configuration skaffold.yaml was written
You can now run [skaffold build] to build the artifacts
or [skaffold run] to build and deploy
or [skaffold dev] to enter development mode, with auto-redeploy
# skaffold.yaml
apiVersion: skaffold/v4beta10
kind: Config
metadata:
name: skaffolddemo
build:
artifacts:
- image: skaffolddemo
docker:
dockerfile: Dockerfile
manifests:
rawYaml:
- k8-deployment.yaml
As the skaffold.yaml file is ready, we can proceed to
Run skaffold
skaffold dev
Generating tags...
- skaffolddemo -> skaffolddemo:latest
Some taggers failed. Rerun with -vdebug for errors.
Checking cache...
- skaffolddemo: Not found. Building
Starting build...
Found [docker-desktop] context, using local docker daemon.
Building [skaffolddemo]...
Target platforms: [linux/amd64]
#0 building with "desktop-linux" instance using docker driver
#1 [internal] load build definition from Dockerfile
#1 DONE 0.0s
#1 [internal] load build definition from Dockerfile
#1 transferring dockerfile:
#1 transferring dockerfile: 768B 0.1s done
#1 DONE 0.2s
#2 [internal] load metadata for mcr.microsoft.com/dotnet/aspnet:8.0
#2 DONE 0.7s
#3 [internal] load metadata for mcr.microsoft.com/dotnet/sdk:8.0
#3 DONE 0.7s
#4 [internal] load .dockerignore
#4 transferring context: 383B 0.0s done
#4 DONE 0.1s
#5 [build 1/7] FROM mcr.microsoft.com/dotnet/sdk:8.0@sha256:3189e564f19e016a43838a46609fc81349f07322fdf6bc3299bd13f0dca9e647
#5 DONE 0.0s
#6 [base 1/2] FROM mcr.microsoft.com/dotnet/aspnet:8.0@sha256:7882d3eee2527584cc9db7b2f26540c27dba4462ec565b8cb160a44874a65b97
#6 DONE 0.0s
#7 [internal] load build context
#7 transferring context: 12.09kB 0.2s done
#7 DONE 0.2s
#8 [build 2/7] WORKDIR /src
#8 CACHED
#9 [build 3/7] COPY [skaffolddemo.csproj, ./]
#9 CACHED
#10 [build 4/7] RUN dotnet restore "skaffolddemo.csproj"
#10 CACHED
#11 [build 5/7] COPY . .
#11 DONE 1.9s
#12 [build 6/7] WORKDIR /src/.
#12 DONE 0.1s
#13 [build 7/7] RUN dotnet build "skaffolddemo.csproj" -c Release -o /app/build
#13 15.01 Determining projects to restore...
#13 18.73 All projects are up-to-date for restore.
#13 47.55 skaffolddemo -> /app/build/skaffolddemo.dll
#13 48.32
#13 48.33 Build succeeded.
#13 48.33 0 Warning(s)
#13 48.33 0 Error(s)
#13 48.33
#13 48.33 Time Elapsed 00:00:39.32
#13 DONE 48.7s
#14 [publish 1/1] RUN dotnet publish "skaffolddemo.csproj" -c Release -o /app/publish /p:UseAppHost=false
#14 2.448 Determining projects to restore...
#14 3.482 All projects are up-to-date for restore.
#14 4.872 skaffolddemo -> /src/bin/Release/net8.0/skaffolddemo.dll
#14 5.119 skaffolddemo -> /app/publish/
#14 DONE 5.3s
#15 [base 2/2] WORKDIR /app
#15 CACHED
#16 [final 1/2] WORKDIR /app
#16 CACHED
#17 [final 2/2] COPY --from=publish /app/publish .
#17 CACHED
#18 exporting to image
#18 exporting layers done
#18 writing image sha256:95365a97444db5fc7fd17f1ef3bd65e5dc9313e599f09082efd2d6d33dd32d1c done
#18 naming to docker.io/library/skaffolddemo:latest 0.0s done
#18 DONE 0.1s
What's next:
View a summary of image vulnerabilities and recommendations → docker scout quickview
Build [skaffolddemo] succeeded
Tags used in deployment:
- skaffolddemo -> skaffolddemo:95365a97444db5fc7fd17f1ef3bd65e5dc9313e599f09082efd2d6d33dd32d1c
Starting deploy...
- deployment.apps/skaffolddemo created
- service/skaffolddemo created
Waiting for deployments to stabilize...
- deployment/skaffolddemo is ready.
Deployments stabilized in 4.938 seconds
Listing files to watch...
- skaffolddemo
Press Ctrl+C to exit
Watching for changes...
[skaffolddemo] warn: Microsoft.AspNetCore.DataProtection.Repositories.FileSystemXmlRepository[60]
[skaffolddemo] Storing keys in a directory '/home/app/.aspnet/DataProtection-Keys' that may not be persisted outside of the container. Protected data will be unavailable when container is destroyed. For more information go to https://aka.ms/aspnet/dataprotectionwarning
[skaffolddemo] warn: Microsoft.AspNetCore.DataProtection.KeyManagement.XmlKeyManager[35]
[skaffolddemo] No XML encryptor configured. Key {3b5bf898-8154-415a-996a-2fdf94ef0e9a} may be persisted to storage in unencrypted form.
[skaffolddemo] warn: Microsoft.AspNetCore.Hosting.Diagnostics[15]
[skaffolddemo] Overriding HTTP_PORTS '8080' and HTTPS_PORTS ''. Binding to values defined by URLS instead 'http://+:5008'.
[skaffolddemo] info: Microsoft.Hosting.Lifetime[14]
[skaffolddemo] Now listening on: http://[::]:5008
[skaffolddemo] info: Microsoft.Hosting.Lifetime[0]
[skaffolddemo] Application started. Press Ctrl+C to shut down.
[skaffolddemo] info: Microsoft.Hosting.Lifetime[0]
[skaffolddemo] Hosting environment: Production
[skaffolddemo] info: Microsoft.Hosting.Lifetime[0]
[skaffolddemo] Content root path: /app
kubectl get pods
NAME READY STATUS RESTARTS AGE
skaffolddemo-7b8df7b5f4-lhdsw 1/1 Running 0 6m53s
kubectl get svc
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 26h
skaffolddemo LoadBalancer 10.103.123.185 localhost 5008:31934/TCP 6m59s
By using http://localhost:5008/ URL, you can access the DEMO application. While Skaffold is running, you can make code changes and observe that Skaffold automatically building and deploying the application.
Skaffold Pipelines & Building Blocks
Skaffold supports three type of end-to-end pipelines
# Run a pipeline
skaffold run
# Run a pipeline in development mode
skaffold dev
# Run a pipeline in debug mode
skaffold debug
and following Building Blocks
# Build the artifacts
skaffold build
# Run tests against your built application images
skaffold test
# Deploy pre-built artifacts
skaffold deploy
# Delete any resources deployed by Skaffold
skaffold delete
# Generate rendered Kubernetes manifests
skaffold render
# Apply hydrated manifests to a cluster
skaffold apply
# Run verification tests against skaffold deployments
skaffold verify
Conclusion
- Skaffold is a mature tool for continuous development, continuous integration and continuous delivery. It simplifies development workflow by organizing common development stages into one simple command.
- The pluggable architecture is central to Skaffold’s design, allowing you to use your preferred tool or technology in each stage.