Skaffold’s deploy hooks let you run arbitrary scripts during the deploy phase of your workflow, giving you fine-grained control over pre- and post-deployment actions.
Let’s see it in action. Imagine you’re deploying a Kubernetes application and you need to perform a few setup steps before the actual kubectl apply happens, and then clean up some temporary resources afterward.
Here’s a skaffold.yaml snippet demonstrating this:
apiVersion: skaffold/v4beta10
kind: Config
metadata:
name: my-app
build:
artifacts:
- image: my-app
docker:
dockerfile: Dockerfile
deploy:
kubectl:
manifests:
- k8s/*.yaml
hooks:
- name: pre-deploy-setup
container:
image: ubuntu:latest
command: ["bash", "-c"]
args: ["echo 'Starting pre-deploy setup...' && sleep 5 && echo 'Pre-deploy setup complete.'"]
- name: post-deploy-cleanup
container:
image: ubuntu:latest
command: ["bash", "-c"]
args: ["echo 'Starting post-deploy cleanup...' && sleep 3 && echo 'Post-deploy cleanup complete.'"]
When you run skaffold dev or skaffold deploy with this configuration, Skaffold will execute the pre-deploy-setup hook before applying any Kubernetes manifests, and then the post-deploy-cleanup hook after the manifests have been applied. The output in your terminal will show the echo statements from the hooks, demonstrating their execution.
The core problem Skaffold deploy hooks solve is the automation of tasks that are tightly coupled with your application’s deployment lifecycle but don’t fit neatly into the build or Kubernetes manifest definition itself. This could include:
- Pre-deployment tasks: Seeding databases with initial data, setting up external services, performing readiness checks on dependencies, or injecting secrets that aren’t managed by Kubernetes.
- Post-deployment tasks: Running integration tests against the newly deployed application, performing smoke tests, cleaning up temporary resources created during deployment, or updating external service configurations to point to the new deployment.
Internally, Skaffold executes these hooks by spinning up a temporary Kubernetes pod running the specified container.image. It then executes the container.command and container.args within that pod. The hook is considered successful if the command exits with a status code of 0. If the command fails (non-zero exit code), Skaffold will halt the deploy process, preventing the rest of the deployment from proceeding. This is crucial for ensuring a stable deployment.
You control the behavior of these hooks primarily through the container field within the hook definition. You specify the image to use for the hook’s execution environment. This image should contain the necessary tools or binaries to run your script. For simple shell commands, a minimal image like ubuntu:latest or alpine:latest is often sufficient. For more complex tasks requiring specific SDKs or CLIs, you might use an image that already has those installed.
The command and args fields are where you define the actual script to be executed. You can use ["bash", "-c"] to run multi-line shell scripts or complex commands. The name field is for human-readable identification of the hook in Skaffold logs.
One critical aspect that often trips people up is the execution context of these hooks. They run within a Kubernetes pod managed by Skaffold. This means that if your hook needs to interact with your Kubernetes cluster (e.g., to check the status of deployed resources), it needs the appropriate Kubernetes RBAC permissions. By default, the temporary hook pod might not have these permissions. You’ll need to ensure the ServiceAccount used by Skaffold (or a dedicated one for hooks) has the necessary roles and rolebindings. For instance, if a post-deploy hook needs to get deployments, its ServiceAccount needs a RoleBinding with get permission on deployments.
The next step in managing your deployments is often integrating these hooks with more sophisticated GitOps workflows, where Skaffold might trigger external CI/CD pipelines based on hook success or failure.