Module 3.2: Tekton
Цей контент ще не доступний вашою мовою.
Toolkit Track | Complexity:
[COMPLEX]| Time: 45-50 min
The platform architect presented the migration proposal to the CTO with unexpected confidence. Their hosted CI service had been steadily increasing costs—$340,000 per year for a 90-person engineering team—and vendor lock-in was strangling their ability to customize pipelines. “We can run the same workloads on our own Kubernetes clusters for a third of the cost,” she explained, “and we’ll own our CI infrastructure like we own our application infrastructure.” Eighteen months later, with Tekton powering 2,400 pipeline runs per day across five clusters, they’d reduced CI costs to $95,000 per year while gaining the ability to run pipelines on-premise for their government clients—a capability that won them a $12 million contract.
Prerequisites
Section titled “Prerequisites”Before starting this module:
- DevSecOps Discipline — CI/CD concepts
- Kubernetes basics (Pods, Services, CRDs)
- Container fundamentals
- YAML proficiency
What You’ll Be Able to Do
Section titled “What You’ll Be Able to Do”After completing this module, you will be able to:
- Deploy Tekton on Kubernetes and configure Tasks, Pipelines, and PipelineRuns for CI/CD workflows
- Implement reusable Tekton task catalogs with parameterized inputs and workspace sharing
- Configure event-driven pipeline triggers using Tekton Triggers and interceptors
- Evaluate Tekton’s Kubernetes-native approach against hosted CI services for cost and control trade-offs
Why This Module Matters
Section titled “Why This Module Matters”Tekton is a Kubernetes-native CI/CD framework. Unlike hosted CI services, Tekton runs in your cluster—giving you full control, no vendor lock-in, and the ability to scale pipelines like any other Kubernetes workload.
Born from Google’s Knative Build project and now a CNCF project, Tekton powers enterprise CI/CD at companies like IBM, Red Hat, and Google.
Did You Know?
Section titled “Did You Know?”- Tekton is named after the Greek word for “builder”—appropriate for a build system
- Tekton powers Google Cloud Build and OpenShift Pipelines—it’s the foundation of major enterprise CI/CD offerings
- Tekton Pipelines runs as pods in your cluster—each task step is a container, scaling naturally with Kubernetes
- The Tekton Catalog has 100+ reusable tasks—from Git clone to Kubernetes deploy, pre-built and maintained
Tekton Architecture
Section titled “Tekton Architecture”┌─────────────────────────────────────────────────────────────────┐│ TEKTON ARCHITECTURE │├─────────────────────────────────────────────────────────────────┤│ ││ CUSTOM RESOURCES ││ ┌──────────────────────────────────────────────────────────┐ ││ │ │ ││ │ Task TaskRun Pipeline PipelineRun│ ││ │ (template) (instance) (template) (instance) │ ││ │ ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐│ ││ │ │ Steps: │──▶│ Pod │ │ Tasks: │───▶│ TaskRuns││ ││ │ │ - clone │ │ running │ │ - build │ │ running ││ ││ │ │ - build │ │ │ │ - test │ │ ││ ││ │ │ - push │ │ │ │ - deploy│ │ ││ ││ │ └─────────┘ └─────────┘ └─────────┘ └─────────┘│ ││ │ │ ││ └──────────────────────────────────────────────────────────┘ ││ │ ││ ▼ ││ ┌──────────────────────────────────────────────────────────┐ ││ │ TEKTON CONTROLLERS │ ││ │ │ ││ │ ┌─────────────────┐ ┌─────────────────┐ │ ││ │ │ Pipeline │ │ Triggers │ │ ││ │ │ Controller │ │ Controller │ │ ││ │ │ │ │ │ │ ││ │ │ Watches CRs │ │ Webhooks │ │ ││ │ │ Creates Pods │ │ Creates Runs │ │ ││ │ └─────────────────┘ └─────────────────┘ │ ││ │ │ ││ └──────────────────────────────────────────────────────────┘ ││ │ ││ ▼ ││ ┌──────────────────────────────────────────────────────────┐ ││ │ KUBERNETES CLUSTER │ ││ │ │ ││ │ ┌─────────────────────────────────────────────────────┐ │ ││ │ │ POD (TaskRun) │ │ ││ │ │ ┌─────────┐ ┌─────────┐ ┌─────────┐ │ │ ││ │ │ │ Step 1 │ │ Step 2 │ │ Step 3 │ │ │ ││ │ │ │ (init) │─▶│ (main) │─▶│ (post) │ │ │ ││ │ │ └─────────┘ └─────────┘ └─────────┘ │ │ ││ │ │ │ │ ││ │ │ Shared workspace volume │ │ ││ │ └─────────────────────────────────────────────────────┘ │ ││ │ │ ││ └──────────────────────────────────────────────────────────┘ ││ │└─────────────────────────────────────────────────────────────────┘Core Concepts
Section titled “Core Concepts”| Concept | Description |
|---|---|
| Task | A template defining a sequence of steps (containers) |
| TaskRun | An instance of a Task execution |
| Pipeline | A template defining a sequence of Tasks |
| PipelineRun | An instance of a Pipeline execution |
| Workspace | Shared storage between steps and tasks |
| Trigger | Webhook listener that creates PipelineRuns |
Installing Tekton
Section titled “Installing Tekton”# Install Tekton Pipelineskubectl apply -f https://storage.googleapis.com/tekton-releases/pipeline/latest/release.yaml
# Install Tekton Triggers (for webhooks)kubectl apply -f https://storage.googleapis.com/tekton-releases/triggers/latest/release.yamlkubectl apply -f https://storage.googleapis.com/tekton-releases/triggers/latest/interceptors.yaml
# Install Tekton Dashboard (optional)kubectl apply -f https://storage.googleapis.com/tekton-releases/dashboard/latest/release.yaml
# Wait for componentskubectl -n tekton-pipelines wait --for=condition=ready pod -l app=tekton-pipelines-controller --timeout=120s
# Install tkn CLIbrew install tektoncd-cli # macOSBasic Task
Section titled “Basic Task”apiVersion: tekton.dev/v1kind: Taskmetadata: name: hellospec: steps: - name: hello image: alpine script: | echo "Hello from Tekton!"Task with Parameters
Section titled “Task with Parameters”apiVersion: tekton.dev/v1kind: Taskmetadata: name: greetspec: params: - name: name type: string description: Name to greet default: World
steps: - name: greet image: alpine script: | echo "Hello, $(params.name)!"Task with Workspaces
Section titled “Task with Workspaces”apiVersion: tekton.dev/v1kind: Taskmetadata: name: git-clonespec: params: - name: url type: string
workspaces: - name: output description: The git repo will be cloned here
steps: - name: clone image: alpine/git workingDir: $(workspaces.output.path) script: | git clone $(params.url) . ls -laTask with Results
Section titled “Task with Results”apiVersion: tekton.dev/v1kind: Taskmetadata: name: get-versionspec: workspaces: - name: source
results: - name: version description: The version from package.json
steps: - name: get-version image: node:20-alpine workingDir: $(workspaces.source.path) script: | VERSION=$(node -p "require('./package.json').version") echo -n $VERSION | tee $(results.version.path)Build and Push Task
Section titled “Build and Push Task”apiVersion: tekton.dev/v1kind: Taskmetadata: name: build-pushspec: params: - name: image type: string - name: dockerfile default: Dockerfile
workspaces: - name: source - name: dockerconfig description: Docker config for registry auth
results: - name: digest description: Image digest
steps: - name: build-push image: gcr.io/kaniko-project/executor:latest workingDir: $(workspaces.source.path) env: - name: DOCKER_CONFIG value: $(workspaces.dockerconfig.path) args: - --dockerfile=$(params.dockerfile) - --destination=$(params.image) - --context=. - --digest-file=$(results.digest.path)TaskRuns
Section titled “TaskRuns”Running a Task
Section titled “Running a Task”apiVersion: tekton.dev/v1kind: TaskRunmetadata: generateName: greet-run-spec: taskRef: name: greet params: - name: name value: "Tekton"# Create TaskRunkubectl create -f taskrun.yaml
# List TaskRunstkn taskrun list
# View logstkn taskrun logs -f greet-run-xyz
# Describetkn taskrun describe greet-run-xyzTaskRun with Workspace
Section titled “TaskRun with Workspace”apiVersion: tekton.dev/v1kind: TaskRunmetadata: generateName: clone-run-spec: taskRef: name: git-clone params: - name: url value: https://github.com/tektoncd/pipeline.git workspaces: - name: output emptyDir: {} # Or use PVC for persistencePipelines
Section titled “Pipelines”Basic Pipeline
Section titled “Basic Pipeline”apiVersion: tekton.dev/v1kind: Pipelinemetadata: name: build-test-deployspec: params: - name: repo-url type: string - name: image type: string
workspaces: - name: shared-workspace - name: docker-credentials
tasks: - name: fetch-source taskRef: name: git-clone workspaces: - name: output workspace: shared-workspace params: - name: url value: $(params.repo-url)
- name: run-tests runAfter: - fetch-source taskRef: name: npm-test workspaces: - name: source workspace: shared-workspace
- name: build-push runAfter: - run-tests taskRef: name: build-push workspaces: - name: source workspace: shared-workspace - name: dockerconfig workspace: docker-credentials params: - name: image value: $(params.image)Pipeline with Parallel Tasks
Section titled “Pipeline with Parallel Tasks”apiVersion: tekton.dev/v1kind: Pipelinemetadata: name: parallel-cispec: workspaces: - name: shared-workspace
tasks: - name: fetch-source taskRef: name: git-clone workspaces: - name: output workspace: shared-workspace
# These run in parallel after fetch-source - name: lint runAfter: [fetch-source] taskRef: name: lint workspaces: - name: source workspace: shared-workspace
- name: test runAfter: [fetch-source] taskRef: name: test workspaces: - name: source workspace: shared-workspace
- name: security-scan runAfter: [fetch-source] taskRef: name: trivy-scan workspaces: - name: source workspace: shared-workspace
# This runs after all parallel tasks complete - name: build runAfter: [lint, test, security-scan] taskRef: name: build-push workspaces: - name: source workspace: shared-workspacePipeline with Conditional Tasks
Section titled “Pipeline with Conditional Tasks”apiVersion: tekton.dev/v1kind: Pipelinemetadata: name: conditional-deployspec: params: - name: deploy-to-prod type: string default: "false"
tasks: - name: build taskRef: name: build-push
- name: deploy-staging runAfter: [build] taskRef: name: kubectl-deploy params: - name: namespace value: staging
- name: deploy-production runAfter: [deploy-staging] when: - input: $(params.deploy-to-prod) operator: in values: ["true"] taskRef: name: kubectl-deploy params: - name: namespace value: productionUsing Results Between Tasks
Section titled “Using Results Between Tasks”apiVersion: tekton.dev/v1kind: Pipelinemetadata: name: version-pipelinespec: tasks: - name: get-version taskRef: name: get-version workspaces: - name: source workspace: shared-workspace
- name: build-image runAfter: [get-version] taskRef: name: build-push params: - name: image # Use result from previous task value: "myregistry/myapp:$(tasks.get-version.results.version)"PipelineRuns
Section titled “PipelineRuns”Running a Pipeline
Section titled “Running a Pipeline”apiVersion: tekton.dev/v1kind: PipelineRunmetadata: generateName: build-test-deploy-run-spec: pipelineRef: name: build-test-deploy params: - name: repo-url value: https://github.com/org/app.git - name: image value: ghcr.io/org/app:latest workspaces: - name: shared-workspace volumeClaimTemplate: spec: accessModes: - ReadWriteOnce resources: requests: storage: 1Gi - name: docker-credentials secret: secretName: docker-credentials# Create PipelineRunkubectl create -f pipelinerun.yaml
# List PipelineRunstkn pipelinerun list
# View logstkn pipelinerun logs -f build-test-deploy-run-xyz
# Cancel a running pipelinetkn pipelinerun cancel build-test-deploy-run-xyzTriggers
Section titled “Triggers”Webhook Trigger
Section titled “Webhook Trigger”# EventListener - receives webhooksapiVersion: triggers.tekton.dev/v1beta1kind: EventListenermetadata: name: github-listenerspec: serviceAccountName: tekton-triggers-sa triggers: - name: github-push bindings: - ref: github-push-binding template: ref: github-push-template
---# TriggerBinding - extracts data from webhookapiVersion: triggers.tekton.dev/v1beta1kind: TriggerBindingmetadata: name: github-push-bindingspec: params: - name: repo-url value: $(body.repository.clone_url) - name: revision value: $(body.head_commit.id) - name: branch value: $(body.ref)
---# TriggerTemplate - creates PipelineRunapiVersion: triggers.tekton.dev/v1beta1kind: TriggerTemplatemetadata: name: github-push-templatespec: params: - name: repo-url - name: revision - name: branch
resourcetemplates: - apiVersion: tekton.dev/v1 kind: PipelineRun metadata: generateName: github-triggered- spec: pipelineRef: name: build-test-deploy params: - name: repo-url value: $(tt.params.repo-url) - name: revision value: $(tt.params.revision) workspaces: - name: shared-workspace volumeClaimTemplate: spec: accessModes: [ReadWriteOnce] resources: requests: storage: 1GiExposing the Webhook
Section titled “Exposing the Webhook”# Ingress for webhookapiVersion: networking.k8s.io/v1kind: Ingressmetadata: name: github-webhook annotations: nginx.ingress.kubernetes.io/ssl-redirect: "false"spec: rules: - host: tekton.example.com http: paths: - path: /hooks pathType: Prefix backend: service: name: el-github-listener port: number: 8080Tekton Catalog
Section titled “Tekton Catalog”# Install a task from catalogkubectl apply -f https://raw.githubusercontent.com/tektoncd/catalog/main/task/git-clone/0.9/git-clone.yamlkubectl apply -f https://raw.githubusercontent.com/tektoncd/catalog/main/task/kaniko/0.6/kaniko.yamlkubectl apply -f https://raw.githubusercontent.com/tektoncd/catalog/main/task/kubernetes-actions/0.2/kubernetes-actions.yaml
# Or use tkn hubtkn hub install task git-clonetkn hub install task kanikoUsing Catalog Tasks
Section titled “Using Catalog Tasks”apiVersion: tekton.dev/v1kind: Pipelinemetadata: name: catalog-pipelinespec: params: - name: repo-url - name: image
workspaces: - name: shared-data - name: docker-credentials
tasks: - name: fetch-repo taskRef: name: git-clone # From catalog workspaces: - name: output workspace: shared-data params: - name: url value: $(params.repo-url)
- name: build-push runAfter: [fetch-repo] taskRef: name: kaniko # From catalog workspaces: - name: source workspace: shared-data - name: dockerconfig workspace: docker-credentials params: - name: IMAGE value: $(params.image)Common Mistakes
Section titled “Common Mistakes”| Mistake | Why It’s Bad | Better Approach |
|---|---|---|
| No workspaces | Data lost between steps | Use PVC workspaces for shared data |
| Large PVC for each run | Expensive, slow | Use volumeClaimTemplate with cleanup |
| No resource limits | Pods can starve cluster | Set CPU/memory limits on steps |
| Hardcoded secrets | Insecure | Use Secrets and Workspaces |
| No timeouts | Stuck pipelines waste resources | Set timeout on Tasks and Pipelines |
| Ignoring results | Can’t pass data between tasks | Use results for task outputs |
War Story: The $890,000 Workspace Disaster
Section titled “War Story: The $890,000 Workspace Disaster”An e-commerce company migrated from CircleCI to Tekton to reduce costs and gain multi-cloud capability. The migration seemed successful—pipelines ran faster, costs dropped initially, and teams loved the Kubernetes-native approach. Then Black Friday hit.
THE WORKSPACE DISASTER TIMELINE─────────────────────────────────────────────────────────────────NOVEMBER 25 (BLACK FRIDAY EVE)9:00 AM Feature freeze lifted, 47 PRs merge in first hour9:30 AM PipelineRuns start queuing (normal)10:15 AM Storage alerts: EBS provisioning hitting rate limits10:45 AM 47 pipelines stuck in "Pending" - no PVCs available11:00 AM Storage costs spiking: 10GB PVC per run, not cleaning up11:30 AM Kubernetes cluster storage at 94% capacity12:00 PM Critical hotfix needed for checkout bug12:15 PM Hotfix pipeline can't start - no storage available12:45 PM Manual PVC cleanup begins (47 orphaned PVCs)1:30 PM Hotfix finally deploys - 90 minutes late2:00 PM Checkout page slow - cache invalidated during chaos5:00 PM Black Friday traffic starts ramping
POST-INCIDENT DISCOVERY─────────────────────────────────────────────────────────────────Orphaned PVCs found: 847 (from 3 months of runs)Storage wasted: 8,470 GBStorage cost (accumulated): $42,350 over 3 monthsLost revenue (hotfix delay): ~$340,000 (90 min during peak prep)Engineering time for cleanup: 120 hours @ $100/hr = $12,000Incident response costs: $15,000Customer trust impact: $500,000+ (estimated)
TOTAL COST OF WORKSPACE MISMANAGEMENT: ~$890,000The root cause analysis revealed multiple failures:
# MISTAKE 1: Static PVC (never cleaned up)workspaces: - name: shared persistentVolumeClaim: claimName: pipeline-pvc # Reused but eventually abandoned
# MISTAKE 2: Oversized storage requestsresources: requests: storage: 10Gi # Actual usage: 200-500 MB
# MISTAKE 3: No resource quotas on tekton-pipelines namespace# Any pipeline could request unlimited storage
# MISTAKE 4: No monitoring on PVC lifecycle# 847 PVCs accumulated without anyone noticingThe Fix—Comprehensive Workspace Strategy:
# FIX 1: volumeClaimTemplate for automatic cleanupapiVersion: tekton.dev/v1kind: PipelineRunmetadata: generateName: build-spec: pipelineRef: name: build-pipeline workspaces: - name: shared volumeClaimTemplate: spec: accessModes: [ReadWriteOnce] storageClassName: fast-ssd # Explicit storage class resources: requests: storage: 500Mi # Right-sized for actual needs # PVC automatically deleted when PipelineRun completes
# FIX 2: Resource quotas for tekton namespace---apiVersion: v1kind: ResourceQuotametadata: name: tekton-storage-quota namespace: tekton-pipelinesspec: hard: persistentvolumeclaims: "100" requests.storage: "100Gi"
# FIX 3: LimitRange for default sizes---apiVersion: v1kind: LimitRangemetadata: name: tekton-storage-limits namespace: tekton-pipelinesspec: limits: - type: PersistentVolumeClaim max: storage: 2Gi default: storage: 500Mi
# FIX 4: PVC cleanup CronJob for any stragglers---apiVersion: batch/v1kind: CronJobmetadata: name: cleanup-orphaned-pvcsspec: schedule: "0 */6 * * *" # Every 6 hours jobTemplate: spec: template: spec: serviceAccountName: pvc-cleaner containers: - name: cleaner image: bitnami/kubectl command: - /bin/sh - -c - | # Delete PVCs older than 2 hours with no owner kubectl get pvc -n tekton-pipelines \ --field-selector status.phase=Bound \ -o json | jq -r '.items[] | select(.metadata.ownerReferences == null) | select(now - (.metadata.creationTimestamp | fromdateiso8601) > 7200) | .metadata.name' | xargs -r kubectl delete pvc -n tekton-pipelines restartPolicy: OnFailureResults After Fix:
BEFORE VS AFTER───────────────────────────────────────────────────────────────── Before AfterOrphaned PVCs/month: 280 0Storage costs/month: $14,000 $2,100Pipeline queue time: 5-15 min < 30 secStorage provisioning: Rate limited Never limitedBlack Friday readiness: FAILED PASSEDKey Takeaway: Tekton is Kubernetes-native—which means Kubernetes storage problems become Tekton problems. Plan your workspace strategy before your first pipeline, not after your first incident.
Question 1
Section titled “Question 1”What’s the difference between a Task and a Pipeline in Tekton?
Show Answer
Task: A single unit of work containing one or more sequential steps. Each step runs as a container in the same pod. Steps share the pod’s workspace and environment.
Pipeline: A collection of Tasks that can run sequentially or in parallel. Each Task runs as a separate pod. Pipelines use workspaces to share data between Tasks.
Think of it as:
- Task = one pod with multiple containers (steps)
- Pipeline = multiple pods (tasks) orchestrated together
Question 2
Section titled “Question 2”How do you pass data between Tasks in a Pipeline?
Show Answer
Two mechanisms:
- Workspaces: Shared storage (PVC) mounted in multiple Tasks. Good for files (source code, artifacts).
workspaces: - name: shared-data- Results: Small string values (< 4KB) written by one Task and read by another. Good for versions, digests, URLs.
# Task A writesecho -n "v1.2.3" > $(results.version.path)
# Pipeline uses in Task Bvalue: $(tasks.taskA.results.version)Use workspaces for file data, results for small values.
Question 3
Section titled “Question 3”Your pipeline has lint, test, and security-scan tasks that should run in parallel after git-clone. Write the YAML.
Show Answer
apiVersion: tekton.dev/v1kind: Pipelinemetadata: name: parallel-checksspec: tasks: - name: git-clone taskRef: name: git-clone
# All three run in parallel (same runAfter) - name: lint runAfter: [git-clone] taskRef: name: lint
- name: test runAfter: [git-clone] taskRef: name: test
- name: security-scan runAfter: [git-clone] taskRef: name: security-scan
# Build waits for all parallel tasks - name: build runAfter: [lint, test, security-scan] taskRef: name: buildTasks with the same runAfter dependency run in parallel. A task with multiple runAfter entries waits for all of them.
Question 4
Section titled “Question 4”How would you trigger a Tekton pipeline from a GitHub push webhook?
Show Answer
You need three components:
- EventListener: Receives the webhook
- TriggerBinding: Extracts data from the webhook payload
- TriggerTemplate: Creates the PipelineRun
apiVersion: triggers.tekton.dev/v1beta1kind: EventListenermetadata: name: githubspec: triggers: - bindings: [github-binding] template: ref: github-template---apiVersion: triggers.tekton.dev/v1beta1kind: TriggerBindingmetadata: name: github-bindingspec: params: - name: repo value: $(body.repository.clone_url)---apiVersion: triggers.tekton.dev/v1beta1kind: TriggerTemplatemetadata: name: github-templatespec: params: [repo] resourcetemplates: - apiVersion: tekton.dev/v1 kind: PipelineRun spec: pipelineRef: {name: my-pipeline} params: - name: repo-url value: $(tt.params.repo)Then expose the EventListener service via Ingress and configure GitHub webhook to POST to it.
Question 5
Section titled “Question 5”A company runs 500 Tekton pipeline runs per day. Each run uses a 2GB workspace PVC. Without volumeClaimTemplate (manual cleanup), they clean up PVCs weekly. With volumeClaimTemplate, PVCs are deleted immediately. Storage costs $0.10/GB/month. Calculate monthly storage cost savings.
Show Answer
Without volumeClaimTemplate (weekly cleanup):
Daily PVCs created: 500PVCs accumulated before cleanup: 500 × 7 days = 3,500 PVCsAverage PVCs existing: ~1,750 (middle of week)Storage: 1,750 × 2GB = 3,500 GBMonthly cost: 3,500 × $0.10 = $350/monthWith volumeClaimTemplate (immediate cleanup):
Concurrent pipelines: ~20 at any time (estimate)Storage: 20 × 2GB = 40 GBMonthly cost: 40 × $0.10 = $4/monthMonthly Savings: $350 - $4 = $346/month ($4,152/year)
But this calculation is conservative! The real cost includes:
- EBS provisioning API rate limits
- Time waiting for storage provisioning
- Risk of running out of storage quota
- Engineering time for cleanup scripts
The actual value of proper workspace management is often 10-100x the raw storage savings.
Question 6
Section titled “Question 6”Your Tekton pipeline has these tasks: git-clone (30s), lint (2m), unit-test (3m), integration-test (5m), build (2m), push (1m). Currently all tasks run sequentially. Lint, unit-test, and integration-test can run in parallel after git-clone. Build requires all three to pass. What’s the time savings from parallelization?
Show Answer
Sequential execution (current):
git-clone → lint → unit-test → integration-test → build → push 30s 2m 3m 5m 2m 1m
Total: 30s + 2m + 3m + 5m + 2m + 1m = 13 minutes 30 secondsParallel execution (optimized):
git-clone → [lint (2m), unit-test (3m), integration-test (5m)] → build → push 30s parallel: max(2m, 3m, 5m) = 5m 2m 1m
Total: 30s + 5m + 2m + 1m = 8 minutes 30 secondsTime savings: 13m30s - 8m30s = 5 minutes per run (37% faster)
At 500 runs/day:
- Time saved: 500 × 5 min = 2,500 min = 41.7 hours/day
- If developers wait for pipelines: 41.7 hrs × $75/hr = $3,125/day
Pipeline YAML for parallel:
tasks: - name: lint runAfter: [git-clone] # Same runAfter = parallel - name: unit-test runAfter: [git-clone] - name: integration-test runAfter: [git-clone] - name: build runAfter: [lint, unit-test, integration-test] # Waits for allQuestion 7
Section titled “Question 7”You’re designing a Tekton setup for a company with 15 teams, each with their own pipelines but sharing common tasks (git-clone, build-push, deploy). How would you structure the Tekton resources? Consider maintenance, security, and team autonomy.
Show Answer
Recommended Structure:
NAMESPACE STRATEGY─────────────────────────────────────────────────────────────────tekton-system/ # Tekton controllers (installed once)tekton-catalog/ # Shared Tasks (ClusterTasks deprecated)team-alpha-pipelines/ # Team Alpha's pipelines and runsteam-beta-pipelines/ # Team Beta's pipelines and runs...Implementation:
# 1. Shared Tasks in central namespace (or use Tekton Hub)apiVersion: tekton.dev/v1kind: Taskmetadata: name: git-clone namespace: tekton-catalog labels: app.kubernetes.io/version: "1.0"# ...
# 2. Team namespaces with RBAC---apiVersion: v1kind: Namespacemetadata: name: team-alpha-pipelines labels: team: alpha---apiVersion: rbac.authorization.k8s.io/v1kind: RoleBindingmetadata: name: team-alpha-tekton namespace: team-alpha-pipelinesroleRef: apiGroup: rbac.authorization.k8s.io kind: ClusterRole name: tekton-pipelines-adminsubjects: - kind: Group name: team-alpha apiGroup: rbac.authorization.k8s.io
# 3. Teams reference shared tasks---apiVersion: tekton.dev/v1kind: Pipelinemetadata: name: team-alpha-build namespace: team-alpha-pipelinesspec: tasks: - name: clone taskRef: resolver: cluster params: - name: kind value: task - name: name value: git-clone - name: namespace value: tekton-catalogKey Decisions:
| Aspect | Recommendation |
|---|---|
| Controllers | Single installation, cluster-wide |
| Common Tasks | Central namespace with versioning |
| Team Pipelines | Per-team namespace with RBAC |
| Secrets | Per-team, never shared |
| Storage | Per-namespace ResourceQuotas |
| Triggers | Per-team EventListeners |
This gives teams autonomy while maintaining governance over shared components.
Question 8
Section titled “Question 8”Your Tekton TaskRun shows status “Pending” with message “pod has unbound immediate PersistentVolumeClaims”. List all possible causes and how you’d diagnose each.
Show Answer
Diagnostic Checklist:
# 1. Check PVC statuskubectl get pvc -n <namespace>kubectl describe pvc <pvc-name>
# 2. Check StorageClasskubectl get storageclasskubectl describe storageclass <class-name>
# 3. Check available storage capacitykubectl get pvkubectl describe nodes | grep -A 5 "Allocatable"
# 4. Check resource quotaskubectl get resourcequota -n <namespace>kubectl describe resourcequota -n <namespace>
# 5. Check eventskubectl get events -n <namespace> --sort-by=.lastTimestampPossible Causes and Solutions:
| Cause | Diagnosis | Solution |
|---|---|---|
| No StorageClass default | kubectl get sc shows no (default) | Add annotation storageclass.kubernetes.io/is-default-class: "true" |
| StorageClass doesn’t exist | PVC shows “storageclass not found” | Create StorageClass or use existing one |
| Insufficient storage quota | ResourceQuota shows exceeded | Increase quota or clean up old PVCs |
| CSI driver not ready | CSI pods not running | Check kubectl get pods -n kube-system | grep csi |
| Cloud provider limits | Events show “rate limit” or “quota” | Check cloud provider quotas, request increase |
| Wrong access mode | PV exists but mode mismatch | Match PVC accessModes to available PVs |
| Node affinity mismatch | PV bound to unavailable node | Check PV nodeAffinity, ensure nodes available |
| Storage class provisioner failing | Provisioner pod logs show errors | kubectl logs -n kube-system <provisioner-pod> |
Quick Fix Workflow:
# Fast diagnosiskubectl get events -n tekton-pipelines | grep -i pvckubectl describe pvc -n tekton-pipelines | grep -A 10 "Events"
# If quota issuekubectl delete pvc -n tekton-pipelines -l tekton.dev/pipelineRun # Clean completed runs
# If StorageClass issuekubectl get pvc <name> -o yaml | grep storageClassNamekubectl get sc # Verify class existsHands-On Exercise
Section titled “Hands-On Exercise”Scenario: Build a Tekton Pipeline
Section titled “Scenario: Build a Tekton Pipeline”Create a Tekton pipeline that clones a repo, runs tests, and builds a container.
# Create kind clusterkind create cluster --name tekton-lab
# Install Tektonkubectl apply -f https://storage.googleapis.com/tekton-releases/pipeline/latest/release.yaml
# Wait for controllerkubectl -n tekton-pipelines wait --for=condition=ready pod -l app=tekton-pipelines-controller --timeout=120s
# Install tkn CLI if not installedbrew install tektoncd-cliCreate Tasks
Section titled “Create Tasks”apiVersion: tekton.dev/v1kind: Taskmetadata: name: git-clone-simplespec: params: - name: url workspaces: - name: output steps: - name: clone image: alpine/git script: | cd $(workspaces.output.path) git clone $(params.url) . ls -la---apiVersion: tekton.dev/v1kind: Taskmetadata: name: npm-testspec: workspaces: - name: source steps: - name: test image: node:20-alpine workingDir: $(workspaces.source.path) script: | if [ -f package.json ]; then npm install npm test || echo "No tests defined" else echo "No package.json found" fi---apiVersion: tekton.dev/v1kind: Taskmetadata: name: echo-donespec: steps: - name: done image: alpine script: | echo "Pipeline completed successfully!"kubectl apply -f tasks.yamlCreate Pipeline
Section titled “Create Pipeline”apiVersion: tekton.dev/v1kind: Pipelinemetadata: name: build-pipelinespec: params: - name: repo-url type: string default: https://github.com/tektoncd/pipeline.git
workspaces: - name: shared-workspace
tasks: - name: fetch-source taskRef: name: git-clone-simple params: - name: url value: $(params.repo-url) workspaces: - name: output workspace: shared-workspace
- name: run-tests runAfter: [fetch-source] taskRef: name: npm-test workspaces: - name: source workspace: shared-workspace
- name: finish runAfter: [run-tests] taskRef: name: echo-donekubectl apply -f pipeline.yamlRun Pipeline
Section titled “Run Pipeline”apiVersion: tekton.dev/v1kind: PipelineRunmetadata: generateName: build-pipeline-run-spec: pipelineRef: name: build-pipeline params: - name: repo-url value: https://github.com/kubernetes/examples.git workspaces: - name: shared-workspace volumeClaimTemplate: spec: accessModes: - ReadWriteOnce resources: requests: storage: 500Mi# Create and watchkubectl create -f pipelinerun.yaml
# Watch logstkn pipelinerun logs -f $(tkn pipelinerun list -o name | head -1 | cut -d'/' -f2)
# List runstkn pipelinerun listSuccess Criteria
Section titled “Success Criteria”- Tekton is running in the cluster
- Tasks are created
- Pipeline combines tasks
- PipelineRun executes successfully
- Can view logs with tkn CLI
Cleanup
Section titled “Cleanup”kind delete cluster --name tekton-labKey Takeaways
Section titled “Key Takeaways”Before moving on, ensure you can:
- Explain the difference between Task, TaskRun, Pipeline, and PipelineRun
- Write a multi-step Task with parameters, workspaces, and results
- Design pipelines with parallel tasks using
runAfterpatterns - Configure workspace strategies (volumeClaimTemplate vs static PVC)
- Set up Tekton Triggers for webhook-driven pipeline execution
- Calculate storage costs and implement cleanup strategies
- Use the Tekton Catalog for common tasks (git-clone, kaniko)
- Debug “Pending” TaskRuns using kubectl and tkn CLI
- Design multi-team Tekton setups with proper namespace isolation
- Compare Tekton’s Kubernetes-native approach with hosted CI services
Next Module
Section titled “Next Module”Continue to Module 3.3: Argo Workflows where we’ll explore DAG-based workflow orchestration.
“Kubernetes-native means your pipelines scale like pods, fail like pods, and are debugged like pods. Tekton makes CI/CD a first-class Kubernetes citizen.”