Tekton’s finally tasks are designed to execute regardless of whether the preceding tasks in a pipeline succeed or fail, making them perfect for cleanup operations.
Let’s see it in action. Imagine a pipeline that builds a Docker image, pushes it to a registry, and then deploys it. We want to ensure that any temporary files or Docker images created during the build process are removed, even if the push or deployment fails.
apiVersion: tekton.dev/v1beta1
kind: Pipeline
metadata:
name: build-and-deploy-with-cleanup
spec:
params:
- name: image-url
description: The URL for the Docker image
type: string
tasks:
- name: build-image
taskSpec:
params:
- name: image-url
type: string
steps:
- name: build
image: docker:stable
script: |
#!/bin/bash
echo "Building Docker image..."
echo "Simulating build for $(params.image-url)"
# In a real scenario, this would be docker build ...
sleep 5
echo "Build complete."
- name: push
image: docker:stable
script: |
#!/bin/bash
echo "Pushing Docker image..."
echo "Simulating push for $(params.image-url)"
# In a real scenario, this would be docker push ...
# Simulate a failure for demonstration
exit 1
- name: deploy
taskSpec:
params:
- name: image-url
type: string
steps:
- name: deploy
image: alpine:latest
script: |
#!/bin/bash
echo "Deploying image $(params.image-url)..."
sleep 3
echo "Deployment complete."
runIf: ["$(tasks.build-image.results.image-digest) != ''] # Only run if build succeeded
finally:
- name: cleanup
taskSpec:
steps:
- name: cleanup-docker-image
image: docker:stable
script: |
#!/bin/bash
echo "Cleaning up Docker resources..."
echo "Simulating removal of temporary build artifacts."
# In a real scenario, this might involve docker rmi or deleting local files
sleep 2
echo "Cleanup complete."
In this pipeline, the build-image task simulates building and pushing a Docker image. The deploy task is conditional, only running if the build-image task produces a result (we’re not actually using a digest here, but it’s a common pattern). The crucial part is the finally block, containing a cleanup task. This task will always run, whether build-image succeeds or fails, and whether deploy runs or not.
The problem this solves is ensuring resource hygiene. Without finally, if a task fails mid-way, any resources it created (like temporary files, intermediate Docker layers, or even cloud resources) might be left behind, leading to clutter, increased costs, or potential security issues. The finally block acts as a safety net, guaranteeing that your defined cleanup logic is executed.
Internally, Tekton tracks the status of each task within a pipeline. When the pipeline reaches its end, it checks the status of the primary tasks. If any of them failed, or if the pipeline was explicitly cancelled, the finally tasks are still scheduled and executed. This is managed by the Tekton controller, which orchestrates the execution of tasks and pipelines. The finally tasks are essentially a separate execution stage that is always appended to the execution graph, regardless of prior outcomes.
The runIf condition on the deploy task is important. It shows how primary tasks can have dependencies, but the finally tasks are independent of these specific success/failure paths of the main pipeline tasks. The finally tasks are only dependent on the overall pipeline run being initiated.
A common misunderstanding is that finally tasks only run if the entire pipeline fails. This is incorrect. They run always, regardless of success or failure of any preceding task, including if all tasks succeed. They are the last stage of execution for the pipeline run itself.
The next concept you’ll encounter is handling sensitive information within finally tasks, such as credentials for cleaning up cloud resources, and how to securely manage those using Secrets and ServiceAccounts.