Skaffold

What is "Skaffold" and how does it make inner development loop faster when working with Kubernetes?

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: Architecture

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.

Happy Learning & Coding...