Tekton – Tekton https://tekton.dev/ Recent content on Tekton Hugo -- gohugo.io Blog: Tekton Pipelines v1.10.0: Observability, Evolved https://tekton.dev/blog/2026/02/27/tekton-pipelines-v1.10.0-observability-evolved/ Fri, 27 Feb 2026 00:00:00 +0000 https://tekton.dev/blog/2026/02/27/tekton-pipelines-v1.10.0-observability-evolved/ <p>We&rsquo;re excited to announce the release of <a href="https://github.com/tektoncd/pipeline/releases/tag/v1.10.0">Tekton Pipelines v1.10.0</a>! The headline for this release is a major infrastructure change: <strong>the migration from OpenCensus to OpenTelemetry</strong> for all metrics instrumentation.</p> <h2 id="opencensus-to-opentelemetry-migration">OpenCensus to OpenTelemetry Migration</h2> <p><a href="https://opentelemetry.io/blog/2023/sunsetting-opencensus/">OpenCensus has been deprecated</a> in favor of <a href="https://opentelemetry.io/">OpenTelemetry</a>, and Tekton Pipelines now follows suit. This release migrates all PipelineRun and TaskRun metrics to OpenTelemetry instruments — histograms, counters, and gauges — and updates the underlying Knative dependency to v1.19.</p> <h3 id="what-changed">What Changed</h3> <ul> <li><strong>Infrastructure metrics renamed</strong>: Go runtime, Workqueue, and K8s Client metrics move from the <code>tekton_pipelines_controller_</code> prefix to standard OpenTelemetry/Knative namespaces (e.g., <code>kn_workqueue_*</code>, <code>go_*</code>).</li> <li><strong>New <code>reason</code> label</strong>: Duration metrics for PipelineRuns and TaskRuns now include a <code>reason</code> label (e.g., <code>Completed</code>, <code>Succeeded</code>) for more granular breakdown.</li> <li><strong>Removed metrics</strong>: <code>tekton_pipelines_controller_reconcile_count</code> and <code>tekton_pipelines_controller_reconcile_latency</code> have been removed. Use <code>kn_workqueue_process_duration_seconds</code> and <code>kn_workqueue_adds_total</code> instead.</li> <li><strong>Preserved compatibility</strong>: Core metrics like <code>pipelinerun_total</code>, <code>taskrun_total</code>, and <code>taskruns_pod_latency_milliseconds</code> retain their original names and labels.</li> </ul> <h3 id="what-you-need-to-do">What You Need to Do</h3> <ol> <li><strong>Update your <code>config-observability</code> ConfigMap</strong> to use <code>metrics-protocol: prometheus</code> (or <code>grpc</code>/<code>http</code>) instead of the old <code>metrics.backend-destination</code>. If you were already using Prometheus, no changes are needed.</li> <li><strong>Update your dashboards</strong>: <ul> <li>Replace <code>tekton_pipelines_controller_workqueue_*</code> queries with <code>kn_workqueue_*</code></li> <li>Replace <code>tekton_pipelines_controller_go_*</code> queries with standard <code>go_*</code> metrics</li> <li>Account for the new <code>reason</code> label on duration metrics</li> </ul> </li> </ol> <p>See <a href="https://github.com/tektoncd/pipeline/pull/9043">PR #9043</a> for the full migration table and details.</p> <h2 id="other-highlights">Other Highlights</h2> <h3 id="new-features">New Features</h3> <ul> <li><strong>SHA-256 support for Git resolver</strong>: The Git resolver now validates SHA-256 commit hashes (64 characters), future-proofing for Git v3+ which will use SHA-256 instead of SHA-1. (<a href="https://github.com/tektoncd/pipeline/pull/9278">#9278</a>)</li> </ul> <h3 id="bug-fixes">Bug Fixes</h3> <ul> <li><strong>Pipeline results from failed tasks</strong>: Pipeline-level results now correctly include results from failed, cancelled, and timed-out tasks. Previously, results referencing non-successful task outputs were left as unresolved variable strings. (<a href="https://github.com/tektoncd/pipeline/pull/9367">#9367</a>)</li> <li><strong>Pipeline param defaults with context variables</strong>: Fixed a bug where PipelineRun validation failed when a pipeline parameter&rsquo;s default value referenced a non-parameter variable like <code>$(context.pipelineRun.name)</code>. (<a href="https://github.com/tektoncd/pipeline/pull/9386">#9386</a>)</li> <li><strong>ResolutionRequest CRD on Kubernetes 1.33+</strong>: Removed redundant <code>shortNames</code> from the ResolutionRequest CRD that caused <code>ShortNamesConflict</code> on Kubernetes 1.33+. (<a href="https://github.com/tektoncd/pipeline/pull/9398">#9398</a>)</li> </ul> <h2 id="get-started">Get Started</h2> <p>Install or upgrade to v1.10.0:</p> <div class="highlight"><pre tabindex="0" style="background-color:#f0f3f3;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span>kubectl apply -f https://infra.tekton.dev/tekton-releases/pipeline/previous/v1.10.0/release.yaml </span></span></code></pre></div><p>Check out the full <a href="https://github.com/tektoncd/pipeline/releases/tag/v1.10.0">release notes</a> and <a href="https://github.com/tektoncd/pipeline/tree/v1.10.0/docs">documentation</a> for more details.</p> <hr> <p><em>Have questions or feedback? Join us on <a href="https://github.com/tektoncd/community/blob/main/contact.md#slack">Tekton Slack</a> or open an issue on <a href="https://github.com/tektoncd/pipeline/issues">GitHub</a>.</em></p> Blog: Introducing Tekton Pruner https://tekton.dev/blog/2026/02/05/introducing-tekton-pruner/ Thu, 05 Feb 2026 00:00:00 +0000 https://tekton.dev/blog/2026/02/05/introducing-tekton-pruner/ <p><a href="https://tekton.dev/docs/pruner/">Tekton Pruner</a> automatically cleans up completed PipelineRuns and TaskRuns based on retention policies you define.</p> <h2 id="the-problem">The Problem</h2> <p>Tekton does not delete PipelineRuns and TaskRuns after completion. Over time, this increases etcd storage usage and degrades API performance.</p> <h2 id="before-job-based-pruner">Before: Job-Based Pruner</h2> <p>The Tekton Operator has a <a href="https://tekton.dev/docs/operator/tektonconfig/#pruner">job-based pruner</a> configured via <code>TektonConfig</code>:</p> <div class="highlight"><pre tabindex="0" style="background-color:#f0f3f3;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-yaml" data-lang="yaml"><span style="display:flex;"><span><span style="color:#309;font-weight:bold">pruner</span>:<span style="color:#bbb"> </span></span></span><span style="display:flex;"><span><span style="color:#bbb"> </span><span style="color:#309;font-weight:bold">disabled</span>:<span style="color:#bbb"> </span><span style="color:#069;font-weight:bold">false</span><span style="color:#bbb"> </span></span></span><span style="display:flex;"><span><span style="color:#bbb"> </span><span style="color:#309;font-weight:bold">schedule</span>:<span style="color:#bbb"> </span><span style="color:#c30">&#34;0 8 * * *&#34;</span><span style="color:#bbb"> </span></span></span><span style="display:flex;"><span><span style="color:#bbb"> </span><span style="color:#309;font-weight:bold">startingDeadlineSeconds</span>:<span style="color:#bbb"> </span><span style="color:#f60">100</span><span style="color:#bbb"> </span><span style="color:#09f;font-style:italic"># optional</span><span style="color:#bbb"> </span></span></span><span style="display:flex;"><span><span style="color:#bbb"> </span><span style="color:#309;font-weight:bold">resources</span>:<span style="color:#bbb"> </span></span></span><span style="display:flex;"><span><span style="color:#bbb"> </span>- taskrun<span style="color:#bbb"> </span></span></span><span style="display:flex;"><span><span style="color:#bbb"> </span>- pipelinerun<span style="color:#bbb"> </span></span></span><span style="display:flex;"><span><span style="color:#bbb"> </span><span style="color:#309;font-weight:bold">keep</span>:<span style="color:#bbb"> </span><span style="color:#f60">3</span><span style="color:#bbb"> </span></span></span><span style="display:flex;"><span><span style="color:#bbb"> </span><span style="color:#09f;font-style:italic"># keep-since: 1440</span><span style="color:#bbb"> </span></span></span><span style="display:flex;"><span><span style="color:#bbb"> </span><span style="color:#09f;font-style:italic"># NOTE: you can use either &#34;keep&#34; or &#34;keep-since&#34;, not both</span><span style="color:#bbb"> </span></span></span><span style="display:flex;"><span><span style="color:#bbb"> </span><span style="color:#309;font-weight:bold">prune-per-resource</span>:<span style="color:#bbb"> </span><span style="color:#069;font-weight:bold">true</span><span style="color:#bbb"> </span></span></span></code></pre></div><p>The operator creates a CronJob based on this config:</p> <ul> <li><code>schedule</code>: Cron expression for when cleanup runs. <code>0 8 * * *</code> means daily at 8 AM.</li> <li><code>resources</code>: Which resources to prune - <code>taskrun</code>, <code>pipelinerun</code>, or both.</li> <li><code>keep</code>: Retain the last N runs. With <code>keep: 3</code>, only the 3 most recent runs are kept.</li> <li><code>keep-since</code>: Alternative to <code>keep</code>. Retain runs from the last N minutes. <code>keep-since: 1440</code> keeps runs from the last 24 hours. You can use one or the other, not both.</li> <li><code>prune-per-resource</code>: When <code>true</code>, limits apply per pipeline/task name. When <code>false</code>, the limit is global across the namespace.</li> <li><code>startingDeadlineSeconds</code>: How long the CronJob can be delayed before it&rsquo;s considered missed.</li> </ul> <p>You can also override at the namespace level using annotations:</p> <div class="highlight"><pre tabindex="0" style="background-color:#f0f3f3;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-yaml" data-lang="yaml"><span style="display:flex;"><span><span style="color:#309;font-weight:bold">metadata</span>:<span style="color:#bbb"> </span></span></span><span style="display:flex;"><span><span style="color:#bbb"> </span><span style="color:#309;font-weight:bold">annotations</span>:<span style="color:#bbb"> </span></span></span><span style="display:flex;"><span><span style="color:#bbb"> </span><span style="color:#309;font-weight:bold">operator.tekton.dev/prune.resources</span>:<span style="color:#bbb"> </span><span style="color:#c30">&#34;taskrun,pipelinerun&#34;</span><span style="color:#bbb"> </span></span></span><span style="display:flex;"><span><span style="color:#bbb"> </span><span style="color:#309;font-weight:bold">operator.tekton.dev/prune.keep-since</span>:<span style="color:#bbb"> </span><span style="color:#c30">&#34;7200&#34;</span><span style="color:#bbb"> </span></span></span><span style="display:flex;"><span><span style="color:#bbb"> </span><span style="color:#309;font-weight:bold">operator.tekton.dev/prune.keep</span>:<span style="color:#bbb"> </span><span style="color:#c30">&#34;5&#34;</span><span style="color:#bbb"> </span></span></span></code></pre></div><p>This works, but there are gaps.</p> <p>First, if you installed Tekton Pipelines with <code>kubectl apply</code> instead of the Operator, you don&rsquo;t have this pruner.</p> <p>Second, the batch model creates pressure. Run multiple pipelines a day with a daily cleanup schedule, and you&rsquo;ve got 500 completed PipelineRuns in etcd by the time the CronJob fires. In high-throughput environments, that&rsquo;s real load on your API server.</p> <p>Third, one policy per namespace is limiting. Your nightly test runs don&rsquo;t need the same retention as production deployments. But with the Operator pruner, they get the same treatment unless you split them into separate namespaces.</p> <h2 id="tekton-pruner">Tekton Pruner</h2> <p>Tekton Pruner is event-driven. When a PipelineRun or TaskRun completes, the controller evaluates it against your policies right then. No accumulation between scheduled runs.</p> <p>It also works without the Operator - install it alongside any Tekton Pipelines deployment.</p> <p>The configuration model is hierarchical. Set cluster-wide defaults, override per namespace, and use label selectors to apply different policies to different pipelines within the same namespace. Your test pipelines can be cleaned up in minutes while production runs could stick around for a week.</p> <p>If you&rsquo;re using Tekton Chains or Tekton Results, don&rsquo;t worry both add finalizers to PipelineRuns and TaskRuns. Chains adds finalizers (<code>chains.tekton.dev/taskrun</code> for TaskRuns, <code>chains.tekton.dev/pipelinerun</code> for PipelineRuns) that block deletion until signing and attestation storage completes. Results does the same with its own finalizer, holding the resource until it&rsquo;s persisted. Pruner respects these finalizers, so a run won&rsquo;t actually be removed until Chains and Results are done with it.</p> <h2 id="installation">Installation</h2> <h3 id="via-tekton-operator">Via Tekton Operator</h3> <p>If you&rsquo;re using the Tekton Operator, enable Tekton Pruner through TektonConfig. You need to disable the old job-based pruner first:</p> <div class="highlight"><pre tabindex="0" style="background-color:#f0f3f3;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-yaml" data-lang="yaml"><span style="display:flex;"><span><span style="color:#309;font-weight:bold">apiVersion</span>:<span style="color:#bbb"> </span>operator.tekton.dev/v1alpha1<span style="color:#bbb"> </span></span></span><span style="display:flex;"><span><span style="color:#bbb"></span><span style="color:#309;font-weight:bold">kind</span>:<span style="color:#bbb"> </span>TektonConfig<span style="color:#bbb"> </span></span></span><span style="display:flex;"><span><span style="color:#bbb"></span><span style="color:#309;font-weight:bold">metadata</span>:<span style="color:#bbb"> </span></span></span><span style="display:flex;"><span><span style="color:#bbb"> </span><span style="color:#309;font-weight:bold">name</span>:<span style="color:#bbb"> </span>config<span style="color:#bbb"> </span></span></span><span style="display:flex;"><span><span style="color:#bbb"></span><span style="color:#309;font-weight:bold">spec</span>:<span style="color:#bbb"> </span></span></span><span style="display:flex;"><span><span style="color:#bbb"> </span><span style="color:#309;font-weight:bold">pruner</span>:<span style="color:#bbb"> </span></span></span><span style="display:flex;"><span><span style="color:#bbb"> </span><span style="color:#309;font-weight:bold">disabled</span>:<span style="color:#bbb"> </span><span style="color:#069;font-weight:bold">true</span><span style="color:#bbb"> </span><span style="color:#09f;font-style:italic"># disable the job-based pruner</span><span style="color:#bbb"> </span></span></span><span style="display:flex;"><span><span style="color:#bbb"> </span><span style="color:#309;font-weight:bold">tektonpruner</span>:<span style="color:#bbb"> </span></span></span><span style="display:flex;"><span><span style="color:#bbb"> </span><span style="color:#309;font-weight:bold">disabled</span>:<span style="color:#bbb"> </span><span style="color:#069;font-weight:bold">false</span><span style="color:#bbb"> </span></span></span><span style="display:flex;"><span><span style="color:#bbb"> </span><span style="color:#309;font-weight:bold">global-config</span>:<span style="color:#bbb"> </span></span></span><span style="display:flex;"><span><span style="color:#bbb"> </span><span style="color:#309;font-weight:bold">enforcedConfigLevel</span>:<span style="color:#bbb"> </span>global<span style="color:#bbb"> </span></span></span><span style="display:flex;"><span><span style="color:#bbb"> </span><span style="color:#309;font-weight:bold">ttlSecondsAfterFinished</span>:<span style="color:#bbb"> </span><span style="color:#f60">3600</span><span style="color:#bbb"> </span></span></span><span style="display:flex;"><span><span style="color:#bbb"> </span><span style="color:#309;font-weight:bold">successfulHistoryLimit</span>:<span style="color:#bbb"> </span><span style="color:#f60">5</span><span style="color:#bbb"> </span></span></span><span style="display:flex;"><span><span style="color:#bbb"> </span><span style="color:#309;font-weight:bold">failedHistoryLimit</span>:<span style="color:#bbb"> </span><span style="color:#f60">3</span><span style="color:#bbb"> </span></span></span></code></pre></div><h3 id="standalone-installation">Standalone Installation</h3> <p>If you installed Tekton Pipelines without the Operator:</p> <div class="highlight"><pre tabindex="0" style="background-color:#f0f3f3;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span><span style="color:#366">export</span> <span style="color:#033">VERSION</span><span style="color:#555">=</span>0.3.5 <span style="color:#09f;font-style:italic"># check https://github.com/tektoncd/pruner/releases for latest</span> </span></span><span style="display:flex;"><span>kubectl apply -f <span style="color:#c30">&#34;https://infra.tekton.dev/tekton-releases/pruner/previous/v</span><span style="color:#a00">${</span><span style="color:#033">VERSION</span><span style="color:#a00">}</span><span style="color:#c30">/release.yaml&#34;</span> </span></span></code></pre></div><h3 id="verify">Verify</h3> <div class="highlight"><pre tabindex="0" style="background-color:#f0f3f3;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>kubectl get pods -n tekton-pipelines -l <span style="color:#033">app</span><span style="color:#555">=</span>tekton-pruner-controller </span></span></code></pre></div><p>You should see the controller pod running. The controller handles pruning logic and serves the validating webhook that checks ConfigMaps before they&rsquo;re applied.</p> <h2 id="configuration">Configuration</h2> <p>ConfigMaps need these labels (since v0.3.0):</p> <div class="highlight"><pre tabindex="0" style="background-color:#f0f3f3;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-yaml" data-lang="yaml"><span style="display:flex;"><span><span style="color:#309;font-weight:bold">labels</span>:<span style="color:#bbb"> </span></span></span><span style="display:flex;"><span><span style="color:#bbb"> </span><span style="color:#309;font-weight:bold">app.kubernetes.io/part-of</span>:<span style="color:#bbb"> </span>tekton-pruner<span style="color:#bbb"> </span></span></span><span style="display:flex;"><span><span style="color:#bbb"> </span><span style="color:#309;font-weight:bold">pruner.tekton.dev/config-type</span>:<span style="color:#bbb"> </span>global <span style="color:#bbb"> </span><span style="color:#09f;font-style:italic"># or &#39;namespace&#39;</span><span style="color:#bbb"> </span></span></span></code></pre></div><h3 id="cluster-wide-defaults">Cluster-Wide Defaults</h3> <div class="highlight"><pre tabindex="0" style="background-color:#f0f3f3;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-yaml" data-lang="yaml"><span style="display:flex;"><span><span style="color:#309;font-weight:bold">apiVersion</span>:<span style="color:#bbb"> </span>v1<span style="color:#bbb"> </span></span></span><span style="display:flex;"><span><span style="color:#bbb"></span><span style="color:#309;font-weight:bold">kind</span>:<span style="color:#bbb"> </span>ConfigMap<span style="color:#bbb"> </span></span></span><span style="display:flex;"><span><span style="color:#bbb"></span><span style="color:#309;font-weight:bold">metadata</span>:<span style="color:#bbb"> </span></span></span><span style="display:flex;"><span><span style="color:#bbb"> </span><span style="color:#309;font-weight:bold">name</span>:<span style="color:#bbb"> </span>tekton-pruner-default-spec<span style="color:#bbb"> </span></span></span><span style="display:flex;"><span><span style="color:#bbb"> </span><span style="color:#309;font-weight:bold">namespace</span>:<span style="color:#bbb"> </span>tekton-pipelines<span style="color:#bbb"> </span></span></span><span style="display:flex;"><span><span style="color:#bbb"> </span><span style="color:#309;font-weight:bold">labels</span>:<span style="color:#bbb"> </span></span></span><span style="display:flex;"><span><span style="color:#bbb"> </span><span style="color:#309;font-weight:bold">app.kubernetes.io/part-of</span>:<span style="color:#bbb"> </span>tekton-pruner<span style="color:#bbb"> </span></span></span><span style="display:flex;"><span><span style="color:#bbb"> </span><span style="color:#309;font-weight:bold">pruner.tekton.dev/config-type</span>:<span style="color:#bbb"> </span>global<span style="color:#bbb"> </span></span></span><span style="display:flex;"><span><span style="color:#bbb"></span><span style="color:#309;font-weight:bold">data</span>:<span style="color:#bbb"> </span></span></span><span style="display:flex;"><span><span style="color:#bbb"> </span><span style="color:#309;font-weight:bold">global-config</span>:<span style="color:#bbb"> </span>|<span style="color:#c30;font-style:italic"> </span></span></span><span style="display:flex;"><span><span style="color:#c30;font-style:italic"> enforcedConfigLevel: global </span></span></span><span style="display:flex;"><span><span style="color:#c30;font-style:italic"> ttlSecondsAfterFinished: 3600 </span></span></span><span style="display:flex;"><span><span style="color:#c30;font-style:italic"> successfulHistoryLimit: 5 </span></span></span><span style="display:flex;"><span><span style="color:#c30;font-style:italic"> failedHistoryLimit: 3</span><span style="color:#bbb"> </span></span></span></code></pre></div><ul> <li><strong>TTL</strong>: Once the time passes after completion, the run is deleted. Doesn&rsquo;t matter if you&rsquo;re under the history limit.</li> <li><strong>History limit</strong>: Deletes oldest runs when count exceeds the limit. Only matters if TTL hasn&rsquo;t already deleted them.</li> </ul> <p><strong>Example</strong>: <code>ttlSecondsAfterFinished: 300</code> and <code>historyLimit: 3</code>. You run a pipeline 5 times.</p> <ol> <li>History limit kicks in → keeps 3, deletes 2 oldest</li> <li>5 minutes later, TTL expires → all 3 remaining runs deleted</li> </ol> <p>History limit kept 3, but TTL deleted them anyway once 5 minutes passed. If you want runs to persist, increase TTL or use only history limits.</p> <h3 id="per-namespace-config">Per-Namespace Config</h3> <p>Set <code>enforcedConfigLevel: namespace</code> to allow namespace-level overrides.</p> <p><strong>Inline approach</strong> - define everything in the global ConfigMap:</p> <div class="highlight"><pre tabindex="0" style="background-color:#f0f3f3;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-yaml" data-lang="yaml"><span style="display:flex;"><span><span style="color:#309;font-weight:bold">data</span>:<span style="color:#bbb"> </span></span></span><span style="display:flex;"><span><span style="color:#bbb"> </span><span style="color:#309;font-weight:bold">global-config</span>:<span style="color:#bbb"> </span>|<span style="color:#c30;font-style:italic"> </span></span></span><span style="display:flex;"><span><span style="color:#c30;font-style:italic"> enforcedConfigLevel: namespace </span></span></span><span style="display:flex;"><span><span style="color:#c30;font-style:italic"> ttlSecondsAfterFinished: 3600 </span></span></span><span style="display:flex;"><span><span style="color:#c30;font-style:italic"> namespaces: </span></span></span><span style="display:flex;"><span><span style="color:#c30;font-style:italic"> production: </span></span></span><span style="display:flex;"><span><span style="color:#c30;font-style:italic"> ttlSecondsAfterFinished: 604800 </span></span></span><span style="display:flex;"><span><span style="color:#c30;font-style:italic"> successfulHistoryLimit: 20 </span></span></span><span style="display:flex;"><span><span style="color:#c30;font-style:italic"> dev: </span></span></span><span style="display:flex;"><span><span style="color:#c30;font-style:italic"> ttlSecondsAfterFinished: 1800</span><span style="color:#bbb"> </span></span></span></code></pre></div><p><strong>Separate ConfigMaps</strong> - namespace owners manage their own:</p> <div class="highlight"><pre tabindex="0" style="background-color:#f0f3f3;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-yaml" data-lang="yaml"><span style="display:flex;"><span><span style="color:#309;font-weight:bold">apiVersion</span>:<span style="color:#bbb"> </span>v1<span style="color:#bbb"> </span></span></span><span style="display:flex;"><span><span style="color:#bbb"></span><span style="color:#309;font-weight:bold">kind</span>:<span style="color:#bbb"> </span>ConfigMap<span style="color:#bbb"> </span></span></span><span style="display:flex;"><span><span style="color:#bbb"></span><span style="color:#309;font-weight:bold">metadata</span>:<span style="color:#bbb"> </span></span></span><span style="display:flex;"><span><span style="color:#bbb"> </span><span style="color:#309;font-weight:bold">name</span>:<span style="color:#bbb"> </span>tekton-pruner-namespace-spec<span style="color:#bbb"> </span></span></span><span style="display:flex;"><span><span style="color:#bbb"> </span><span style="color:#309;font-weight:bold">namespace</span>:<span style="color:#bbb"> </span>my-team<span style="color:#bbb"> </span></span></span><span style="display:flex;"><span><span style="color:#bbb"> </span><span style="color:#309;font-weight:bold">labels</span>:<span style="color:#bbb"> </span></span></span><span style="display:flex;"><span><span style="color:#bbb"> </span><span style="color:#309;font-weight:bold">app.kubernetes.io/part-of</span>:<span style="color:#bbb"> </span>tekton-pruner<span style="color:#bbb"> </span></span></span><span style="display:flex;"><span><span style="color:#bbb"> </span><span style="color:#309;font-weight:bold">pruner.tekton.dev/config-type</span>:<span style="color:#bbb"> </span>namespace<span style="color:#bbb"> </span></span></span><span style="display:flex;"><span><span style="color:#bbb"></span><span style="color:#309;font-weight:bold">data</span>:<span style="color:#bbb"> </span></span></span><span style="display:flex;"><span><span style="color:#bbb"> </span><span style="color:#309;font-weight:bold">ns-config</span>:<span style="color:#bbb"> </span>|<span style="color:#c30;font-style:italic"> </span></span></span><span style="display:flex;"><span><span style="color:#c30;font-style:italic"> ttlSecondsAfterFinished: 7200 </span></span></span><span style="display:flex;"><span><span style="color:#c30;font-style:italic"> successfulHistoryLimit: 10</span><span style="color:#bbb"> </span></span></span></code></pre></div><h3 id="label-based-selectors">Label-Based Selectors</h3> <p>Different pipelines in the same namespace can have different policies:</p> <div class="highlight"><pre tabindex="0" style="background-color:#f0f3f3;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-yaml" data-lang="yaml"><span style="display:flex;"><span><span style="color:#309;font-weight:bold">data</span>:<span style="color:#bbb"> </span></span></span><span style="display:flex;"><span><span style="color:#bbb"> </span><span style="color:#309;font-weight:bold">ns-config</span>:<span style="color:#bbb"> </span>|<span style="color:#c30;font-style:italic"> </span></span></span><span style="display:flex;"><span><span style="color:#c30;font-style:italic"> pipelineRuns: </span></span></span><span style="display:flex;"><span><span style="color:#c30;font-style:italic"> - selector: </span></span></span><span style="display:flex;"><span><span style="color:#c30;font-style:italic"> - matchLabels: </span></span></span><span style="display:flex;"><span><span style="color:#c30;font-style:italic"> app: critical-service </span></span></span><span style="display:flex;"><span><span style="color:#c30;font-style:italic"> ttlSecondsAfterFinished: 604800 </span></span></span><span style="display:flex;"><span><span style="color:#c30;font-style:italic"> successfulHistoryLimit: 50 </span></span></span><span style="display:flex;"><span><span style="color:#c30;font-style:italic"> - selector: </span></span></span><span style="display:flex;"><span><span style="color:#c30;font-style:italic"> - matchLabels: </span></span></span><span style="display:flex;"><span><span style="color:#c30;font-style:italic"> app: test-jobs </span></span></span><span style="display:flex;"><span><span style="color:#c30;font-style:italic"> ttlSecondsAfterFinished: 300 </span></span></span><span style="display:flex;"><span><span style="color:#c30;font-style:italic"> successfulHistoryLimit: 3</span><span style="color:#bbb"> </span></span></span></code></pre></div><p>Selectors only work in namespace-level ConfigMaps.</p> <h2 id="what-to-watch-out-for">What to Watch Out For</h2> <p><strong>System namespaces are off-limits.</strong> Don&rsquo;t create namespace-level ConfigMaps in <code>kube-*</code>, <code>openshift-*</code>, <code>tekton-pipelines</code>, or other <code>tekton-*</code> namespaces.</p> <p><strong>Webhook validates your config.</strong> If your ConfigMap is rejected, check the labels and YAML syntax. The webhook will tell you what&rsquo;s wrong.</p> <h2 id="checking-logs">Checking Logs</h2> <div class="highlight"><pre tabindex="0" style="background-color:#f0f3f3;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>kubectl logs -n tekton-pipelines -l <span style="color:#033">app</span><span style="color:#555">=</span>tekton-pruner-controller -f </span></span></code></pre></div><p>You&rsquo;ll see entries when resources are pruned, along with which policy triggered the deletion.</p> <h2 id="config-reference">Config Reference</h2> <table> <thead> <tr> <th>Field</th> <th>What it does</th> </tr> </thead> <tbody> <tr> <td><code>enforcedConfigLevel</code></td> <td><code>global</code> applies cluster-wide, <code>namespace</code> allows per-ns overrides</td> </tr> <tr> <td><code>ttlSecondsAfterFinished</code></td> <td>Delete runs older than this many seconds after completion</td> </tr> <tr> <td><code>successfulHistoryLimit</code></td> <td>Keep this many successful runs per pipeline</td> </tr> <tr> <td><code>failedHistoryLimit</code></td> <td>Keep this many failed runs per pipeline</td> </tr> <tr> <td><code>historyLimit</code></td> <td>Used when success/failed limits aren&rsquo;t set</td> </tr> </tbody> </table> <h2 id="links">Links</h2> <ul> <li><a href="https://github.com/tektoncd/pruner">GitHub</a></li> <li><a href="https://github.com/tektoncd/pruner/blob/main/ARCHITECTURE.md">Architecture docs</a></li> <li><a href="https://github.com/tektoncd/pruner/blob/main/docs/tutorials/getting-started.md">Getting started tutorial</a></li> </ul> Blog: Securing HTTP Resolver with Digest Verification https://tekton.dev/blog/2026/02/04/securing-http-resolver-with-digest-verification/ Wed, 04 Feb 2026 00:00:00 +0000 https://tekton.dev/blog/2026/02/04/securing-http-resolver-with-digest-verification/ <h2 id="overview">Overview</h2> <p>When fetching remote resources like Tasks and Pipelines from HTTP URLs for your PipelineRun, there&rsquo;s always a risk that the content could be tampered with during transit or at the source. To address this security concern, the Tekton HTTP resolver now supports optional digest validation, allowing users to verify the integrity of fetched content against a known cryptographic hash.</p> <p>This feature enables users to specify an expected digest (SHA256 or SHA512) in their PipelineRun definitions. The resolver will then validate the fetched content against this digest before proceeding, ensuring that only verified, untampered resources are executed in your pipelines.</p> <h2 id="why-digest-verification-matters">Why Digest Verification Matters</h2> <p>When using the HTTP resolver to fetch remote Tasks or Pipelines for your PipelineRun, several attack vectors could compromise your build process:</p> <ol> <li><strong>Man-in-the-Middle Attacks</strong>: An attacker intercepting network traffic could modify the content of fetched resources.</li> <li><strong>Compromised Source Repositories</strong>: If the source repository is compromised, malicious code could be injected into your CI/CD pipeline.</li> <li><strong>DNS Hijacking</strong>: Attackers could redirect your requests to a malicious server serving altered content.</li> </ol> <p>By providing a digest at the time of PipelineRun creation, you establish a cryptographic guarantee that the executed Pipeline or Task matches exactly what you intended to run. This ensures your PipelineRun only executes verified, untampered resources.</p> <h2 id="how-it-works">How It Works</h2> <p>The HTTP resolver now accepts an optional <code>digest</code> parameter that specifies the expected hash of the fetched content. The digest must be provided in the format <code>&lt;algorithm&gt;:&lt;hash&gt;</code>, where the supported algorithms are:</p> <ul> <li><code>sha256</code> - 256-bit hash (64 hexadecimal characters)</li> <li><code>sha512</code> - 512-bit hash (128 hexadecimal characters)</li> </ul> <p>When a digest is provided, the resolver:</p> <ol> <li>Fetches the content from the specified URL</li> <li>Computes the hash of the fetched content using the specified algorithm</li> <li>Compares the computed hash against the provided digest</li> <li>Only returns the content if the hashes match; otherwise, the resolution fails with an error</li> </ol> <h2 id="enabling-the-http-resolver">Enabling the HTTP Resolver</h2> <p>To use the HTTP resolver, ensure that the feature flag is enabled in your Tekton Pipelines installation. The <code>enable-http-resolver</code> flag should be set to <code>true</code> in the resolver&rsquo;s feature flags ConfigMap:</p> <div class="highlight"><pre tabindex="0" style="background-color:#f0f3f3;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-yaml" data-lang="yaml"><span style="display:flex;"><span><span style="color:#309;font-weight:bold">apiVersion</span>:<span style="color:#bbb"> </span>v1<span style="color:#bbb"> </span></span></span><span style="display:flex;"><span><span style="color:#bbb"></span><span style="color:#309;font-weight:bold">kind</span>:<span style="color:#bbb"> </span>ConfigMap<span style="color:#bbb"> </span></span></span><span style="display:flex;"><span><span style="color:#bbb"></span><span style="color:#309;font-weight:bold">metadata</span>:<span style="color:#bbb"> </span></span></span><span style="display:flex;"><span><span style="color:#bbb"> </span><span style="color:#309;font-weight:bold">name</span>:<span style="color:#bbb"> </span>resolvers-feature-flags<span style="color:#bbb"> </span></span></span><span style="display:flex;"><span><span style="color:#bbb"> </span><span style="color:#309;font-weight:bold">namespace</span>:<span style="color:#bbb"> </span>tekton-pipelines-resolvers<span style="color:#bbb"> </span></span></span><span style="display:flex;"><span><span style="color:#bbb"></span><span style="color:#309;font-weight:bold">data</span>:<span style="color:#bbb"> </span></span></span><span style="display:flex;"><span><span style="color:#bbb"> </span><span style="color:#309;font-weight:bold">enable-http-resolver</span>:<span style="color:#bbb"> </span><span style="color:#c30">&#34;true&#34;</span><span style="color:#bbb"> </span></span></span></code></pre></div><h2 id="usage-examples">Usage Examples</h2> <h3 id="basic-pipeline-resolution-with-digest-verification">Basic Pipeline Resolution with Digest Verification</h3> <p>Here&rsquo;s an example of using the HTTP resolver with SHA256 digest verification to fetch a Pipeline from a remote repository:</p> <div class="highlight"><pre tabindex="0" style="background-color:#f0f3f3;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-yaml" data-lang="yaml"><span style="display:flex;"><span><span style="color:#309;font-weight:bold">apiVersion</span>:<span style="color:#bbb"> </span>tekton.dev/v1<span style="color:#bbb"> </span></span></span><span style="display:flex;"><span><span style="color:#bbb"></span><span style="color:#309;font-weight:bold">kind</span>:<span style="color:#bbb"> </span>PipelineRun<span style="color:#bbb"> </span></span></span><span style="display:flex;"><span><span style="color:#bbb"></span><span style="color:#309;font-weight:bold">metadata</span>:<span style="color:#bbb"> </span></span></span><span style="display:flex;"><span><span style="color:#bbb"> </span><span style="color:#309;font-weight:bold">name</span>:<span style="color:#bbb"> </span>secure-http-demo<span style="color:#bbb"> </span></span></span><span style="display:flex;"><span><span style="color:#bbb"></span><span style="color:#309;font-weight:bold">spec</span>:<span style="color:#bbb"> </span></span></span><span style="display:flex;"><span><span style="color:#bbb"> </span><span style="color:#309;font-weight:bold">pipelineRef</span>:<span style="color:#bbb"> </span></span></span><span style="display:flex;"><span><span style="color:#bbb"> </span><span style="color:#309;font-weight:bold">resolver</span>:<span style="color:#bbb"> </span>http<span style="color:#bbb"> </span></span></span><span style="display:flex;"><span><span style="color:#bbb"> </span><span style="color:#309;font-weight:bold">params</span>:<span style="color:#bbb"> </span></span></span><span style="display:flex;"><span><span style="color:#bbb"> </span>- <span style="color:#309;font-weight:bold">name</span>:<span style="color:#bbb"> </span>url<span style="color:#bbb"> </span></span></span><span style="display:flex;"><span><span style="color:#bbb"> </span><span style="color:#309;font-weight:bold">value</span>:<span style="color:#bbb"> </span>https://raw.githubusercontent.com/tektoncd/catalog/main/pipeline/build-push-gke-deploy/0.1/build-push-gke-deploy.yaml<span style="color:#bbb"> </span></span></span><span style="display:flex;"><span><span style="color:#bbb"> </span>- <span style="color:#309;font-weight:bold">name</span>:<span style="color:#bbb"> </span>digest<span style="color:#bbb"> </span></span></span><span style="display:flex;"><span><span style="color:#bbb"> </span><span style="color:#309;font-weight:bold">value</span>:<span style="color:#bbb"> </span>sha256:e1a86b942e85ce5558fc737a3b4a82d7425ca392741d20afa3b7fb426e96c66b<span style="color:#bbb"> </span></span></span></code></pre></div><h3 id="task-resolution-with-sha512-digest">Task Resolution with SHA512 Digest</h3> <p>For users requiring stronger hash guarantees, SHA512 is also supported:</p> <div class="highlight"><pre tabindex="0" style="background-color:#f0f3f3;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-yaml" data-lang="yaml"><span style="display:flex;"><span><span style="color:#309;font-weight:bold">apiVersion</span>:<span style="color:#bbb"> </span>tekton.dev/v1<span style="color:#bbb"> </span></span></span><span style="display:flex;"><span><span style="color:#bbb"></span><span style="color:#309;font-weight:bold">kind</span>:<span style="color:#bbb"> </span>TaskRun<span style="color:#bbb"> </span></span></span><span style="display:flex;"><span><span style="color:#bbb"></span><span style="color:#309;font-weight:bold">metadata</span>:<span style="color:#bbb"> </span></span></span><span style="display:flex;"><span><span style="color:#bbb"> </span><span style="color:#309;font-weight:bold">name</span>:<span style="color:#bbb"> </span>secure-task-run<span style="color:#bbb"> </span></span></span><span style="display:flex;"><span><span style="color:#bbb"></span><span style="color:#309;font-weight:bold">spec</span>:<span style="color:#bbb"> </span></span></span><span style="display:flex;"><span><span style="color:#bbb"> </span><span style="color:#309;font-weight:bold">taskRef</span>:<span style="color:#bbb"> </span></span></span><span style="display:flex;"><span><span style="color:#bbb"> </span><span style="color:#309;font-weight:bold">resolver</span>:<span style="color:#bbb"> </span>http<span style="color:#bbb"> </span></span></span><span style="display:flex;"><span><span style="color:#bbb"> </span><span style="color:#309;font-weight:bold">params</span>:<span style="color:#bbb"> </span></span></span><span style="display:flex;"><span><span style="color:#bbb"> </span>- <span style="color:#309;font-weight:bold">name</span>:<span style="color:#bbb"> </span>url<span style="color:#bbb"> </span></span></span><span style="display:flex;"><span><span style="color:#bbb"> </span><span style="color:#309;font-weight:bold">value</span>:<span style="color:#bbb"> </span>https://raw.githubusercontent.com/tektoncd-catalog/git-clone/main/task/git-clone/git-clone.yaml<span style="color:#bbb"> </span></span></span><span style="display:flex;"><span><span style="color:#bbb"> </span>- <span style="color:#309;font-weight:bold">name</span>:<span style="color:#bbb"> </span>digest<span style="color:#bbb"> </span></span></span><span style="display:flex;"><span><span style="color:#bbb"> </span><span style="color:#309;font-weight:bold">value</span>:<span style="color:#bbb"> </span>sha512:a1b2c3d4e5f6...your-128-character-sha512-hash...<span style="color:#bbb"> </span></span></span></code></pre></div><h3 id="using-with-authentication">Using with Authentication</h3> <p>The digest verification works seamlessly with the HTTP resolver&rsquo;s authentication features:</p> <div class="highlight"><pre tabindex="0" style="background-color:#f0f3f3;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-yaml" data-lang="yaml"><span style="display:flex;"><span><span style="color:#309;font-weight:bold">apiVersion</span>:<span style="color:#bbb"> </span>tekton.dev/v1<span style="color:#bbb"> </span></span></span><span style="display:flex;"><span><span style="color:#bbb"></span><span style="color:#309;font-weight:bold">kind</span>:<span style="color:#bbb"> </span>PipelineRun<span style="color:#bbb"> </span></span></span><span style="display:flex;"><span><span style="color:#bbb"></span><span style="color:#309;font-weight:bold">metadata</span>:<span style="color:#bbb"> </span></span></span><span style="display:flex;"><span><span style="color:#bbb"> </span><span style="color:#309;font-weight:bold">name</span>:<span style="color:#bbb"> </span>authenticated-secure-demo<span style="color:#bbb"> </span></span></span><span style="display:flex;"><span><span style="color:#bbb"></span><span style="color:#309;font-weight:bold">spec</span>:<span style="color:#bbb"> </span></span></span><span style="display:flex;"><span><span style="color:#bbb"> </span><span style="color:#309;font-weight:bold">pipelineRef</span>:<span style="color:#bbb"> </span></span></span><span style="display:flex;"><span><span style="color:#bbb"> </span><span style="color:#309;font-weight:bold">resolver</span>:<span style="color:#bbb"> </span>http<span style="color:#bbb"> </span></span></span><span style="display:flex;"><span><span style="color:#bbb"> </span><span style="color:#309;font-weight:bold">params</span>:<span style="color:#bbb"> </span></span></span><span style="display:flex;"><span><span style="color:#bbb"> </span>- <span style="color:#309;font-weight:bold">name</span>:<span style="color:#bbb"> </span>url<span style="color:#bbb"> </span></span></span><span style="display:flex;"><span><span style="color:#bbb"> </span><span style="color:#309;font-weight:bold">value</span>:<span style="color:#bbb"> </span>https://raw.githubusercontent.com/myorg/private-repo/main/pipeline.yaml<span style="color:#bbb"> </span></span></span><span style="display:flex;"><span><span style="color:#bbb"> </span>- <span style="color:#309;font-weight:bold">name</span>:<span style="color:#bbb"> </span>http-username<span style="color:#bbb"> </span></span></span><span style="display:flex;"><span><span style="color:#bbb"> </span><span style="color:#309;font-weight:bold">value</span>:<span style="color:#bbb"> </span>git<span style="color:#bbb"> </span></span></span><span style="display:flex;"><span><span style="color:#bbb"> </span>- <span style="color:#309;font-weight:bold">name</span>:<span style="color:#bbb"> </span>http-password-secret<span style="color:#bbb"> </span></span></span><span style="display:flex;"><span><span style="color:#bbb"> </span><span style="color:#309;font-weight:bold">value</span>:<span style="color:#bbb"> </span>github-token<span style="color:#bbb"> </span></span></span><span style="display:flex;"><span><span style="color:#bbb"> </span>- <span style="color:#309;font-weight:bold">name</span>:<span style="color:#bbb"> </span>http-password-secret-key<span style="color:#bbb"> </span></span></span><span style="display:flex;"><span><span style="color:#bbb"> </span><span style="color:#309;font-weight:bold">value</span>:<span style="color:#bbb"> </span>token<span style="color:#bbb"> </span></span></span><span style="display:flex;"><span><span style="color:#bbb"> </span>- <span style="color:#309;font-weight:bold">name</span>:<span style="color:#bbb"> </span>digest<span style="color:#bbb"> </span></span></span><span style="display:flex;"><span><span style="color:#bbb"> </span><span style="color:#309;font-weight:bold">value</span>:<span style="color:#bbb"> </span>sha256:f37cdd0e86d35ac97a65e11c8c2b9af12345678901234567890abcdef1234567<span style="color:#bbb"> </span></span></span></code></pre></div><h2 id="calculating-digests">Calculating Digests</h2> <p>Before using digest verification, you need to calculate the hash of your Tekton resource. You can use standard command-line tools available on all major operating systems:</p> <h3 id="sha256-digest">SHA256 Digest</h3> <div class="highlight"><pre tabindex="0" style="background-color:#f0f3f3;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span><span style="color:#09f;font-style:italic"># Calculate sha256 digest</span> </span></span><span style="display:flex;"><span>curl -sL https://raw.githubusercontent.com/owner/repo/main/task/task.yaml | sha256sum </span></span></code></pre></div><h3 id="sha512-digest">SHA512 Digest</h3> <div class="highlight"><pre tabindex="0" style="background-color:#f0f3f3;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span><span style="color:#09f;font-style:italic"># Calculate sha512 digest</span> </span></span><span style="display:flex;"><span>curl -sL https://raw.githubusercontent.com/owner/repo/main/task/task.yaml | sha512sum </span></span></code></pre></div><p>The output will be a hexadecimal string that you can use as the digest value. Remember to prefix it with the algorithm name (e.g., <code>sha256:</code> or <code>sha512:</code>).</p> <div class="alert alert-primary" role="alert"> <h4 class="alert-heading">Tip</h4> <code>sha256sum</code> and <code>sha512sum</code> commands are available on all major Linux distributions and macOS. On Windows, you can use PowerShell&rsquo;s <code>Get-FileHash</code> cmdlet or install tools like Git Bash. </div> <h2 id="error-handling">Error Handling</h2> <p>When digest validation fails, the HTTP resolver returns a clear error message to help diagnose the issue:</p> <table> <thead> <tr> <th>Error Scenario</th> <th>Example Error Message</th> </tr> </thead> <tbody> <tr> <td>Invalid format</td> <td><code>invalid digest format: sha256</code></td> </tr> <tr> <td>Unsupported algorithm</td> <td><code>invalid digest algorithm: sha1</code></td> </tr> <tr> <td>Invalid hash length</td> <td><code>invalid sha256 digest value, expected length: 64, got: 8</code></td> </tr> <tr> <td>Hash mismatch</td> <td><code>SHA mismatch, expected abc123..., got def456...</code></td> </tr> </tbody> </table> <p>These errors will appear in the PipelineRun or TaskRun status, allowing you to quickly identify and fix any configuration issues.</p> <h2 id="best-practices">Best Practices</h2> <h3 id="1-pin-your-remote-resources">1. Pin Your Remote Resources</h3> <p>When using the HTTP resolver with digest verification, consider pinning your remote resources to specific commits or tags rather than branches:</p> <div class="highlight"><pre tabindex="0" style="background-color:#f0f3f3;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-yaml" data-lang="yaml"><span style="display:flex;"><span><span style="color:#09f;font-style:italic"># Good: Pinned to a specific commit</span><span style="color:#bbb"> </span></span></span><span style="display:flex;"><span><span style="color:#bbb"></span>- <span style="color:#309;font-weight:bold">name</span>:<span style="color:#bbb"> </span>url<span style="color:#bbb"> </span></span></span><span style="display:flex;"><span><span style="color:#bbb"> </span><span style="color:#309;font-weight:bold">value</span>:<span style="color:#bbb"> </span>https://raw.githubusercontent.com/tektoncd/catalog/abc123def/pipeline/my-pipeline.yaml<span style="color:#bbb"> </span></span></span><span style="display:flex;"><span><span style="color:#bbb"></span>- <span style="color:#309;font-weight:bold">name</span>:<span style="color:#bbb"> </span>digest<span style="color:#bbb"> </span></span></span><span style="display:flex;"><span><span style="color:#bbb"> </span><span style="color:#309;font-weight:bold">value</span>:<span style="color:#bbb"> </span>sha256:e1a86b942e85ce5558fc737a3b4a82d7425ca392741d20afa3b7fb426e96c66b<span style="color:#bbb"> </span></span></span><span style="display:flex;"><span><span style="color:#bbb"> </span></span></span><span style="display:flex;"><span><span style="color:#bbb"></span><span style="color:#09f;font-style:italic"># Risky: Using a branch that can change</span><span style="color:#bbb"> </span></span></span><span style="display:flex;"><span><span style="color:#bbb"></span>- <span style="color:#309;font-weight:bold">name</span>:<span style="color:#bbb"> </span>url<span style="color:#bbb"> </span></span></span><span style="display:flex;"><span><span style="color:#bbb"> </span><span style="color:#309;font-weight:bold">value</span>:<span style="color:#bbb"> </span>https://raw.githubusercontent.com/tektoncd/catalog/main/pipeline/my-pipeline.yaml<span style="color:#bbb"> </span></span></span></code></pre></div><h3 id="2-automate-digest-updates">2. Automate Digest Updates</h3> <p>Consider automating the process of updating digests when your remote resources change. This can be integrated into your GitOps workflow or CI/CD process.</p> <h3 id="3-use-sha256-for-standard-use-cases">3. Use SHA256 for Standard Use Cases</h3> <p>SHA256 provides sufficient security for most use cases and produces shorter digest values. Use SHA512 only if your security requirements specifically mandate it.</p> <h3 id="4-document-your-digests">4. Document Your Digests</h3> <p>Maintain documentation of which digests correspond to which versions of your resources. This helps with auditing and troubleshooting.</p> <h2 id="integration-with-tekton-chains">Integration with Tekton Chains</h2> <p>This feature complements <a href="https://tekton.dev/docs/chains/">Tekton Chains</a> for comprehensive pipeline security. While Chains provides attestation and provenance for your build artifacts, digest verification ensures the integrity of the resources used to perform those builds.</p> <p>Together, they provide end-to-end security for your PipelineRuns:</p> <ul> <li><strong>Digest verification</strong> ensures the integrity of your build definitions (Tasks and Pipelines)</li> <li><strong>Tekton Chains</strong> provides signed attestations for your build outputs</li> </ul> <h2 id="backward-compatibility">Backward Compatibility</h2> <p>The <code>digest</code> parameter is optional, ensuring full backward compatibility with existing configurations. Existing PipelineRuns and TaskRuns that don&rsquo;t specify a digest will continue to work as before, fetching content without verification.</p> <h2 id="conclusion">Conclusion</h2> <p>Digest verification for the HTTP resolver is a significant step toward securing your PipelineRuns. By enabling users to cryptographically verify the integrity of remote resources before execution, this feature helps prevent tampering attacks and ensures that your pipelines execute exactly the code you intend.</p> <p>We encourage all users who fetch Tasks and Pipelines from HTTP URLs to adopt digest verification as part of their security best practices. The feature is designed to be easy to use while providing strong security guarantees through constant-time comparison and support for industry-standard hashing algorithms.</p> <p>For more information about the HTTP resolver and its configuration options, refer to the <a href="https://tekton.dev/docs/pipelines/resolution/http-resolver/">HTTP Resolver documentation</a>.</p> <hr> <p><em>Have questions or feedback about this feature? Join the conversation on the <a href="https://github.com/tektoncd/community/blob/main/contact.md#slack">Tekton Slack</a> or open an issue on <a href="https://github.com/tektoncd/pipeline/issues">GitHub</a>.</em></p> Blog: Tekton Pipelines v1.9.0 LTS: Continued Innovation and Stability https://tekton.dev/blog/2026/02/02/tekton-pipelines-v1.9.0-lts-continued-innovation-and-stability/ Mon, 02 Feb 2026 00:00:00 +0000 https://tekton.dev/blog/2026/02/02/tekton-pipelines-v1.9.0-lts-continued-innovation-and-stability/ <p>We&rsquo;re excited to announce the release of Tekton Pipelines v1.9.0, our latest Long-Term Support (LTS) release! Since the milestone <a href="https://github.com/tektoncd/pipeline/releases/tag/v1.0.0">v1.0.0 release</a> in May 2025, the project has continued to evolve with significant new features, performance improvements, and stability enhancements. This post summarizes the journey from v1.0.0 to v1.9.0, organized by LTS milestones.</p> <h2 id="installation">Installation</h2> <div class="highlight"><pre tabindex="0" style="background-color:#f0f3f3;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span>kubectl apply -f https://infra.tekton.dev/releases/pipeline/previous/v1.9.0/release.yaml </span></span></code></pre></div><h2 id="v100--v130-lts-may---august-2025">v1.0.0 → v1.3.0 LTS (May - August 2025)</h2> <p>The first LTS after v1.0.0 focused on <strong>controller resilience and performance</strong>.</p> <h3 id="features">Features</h3> <ul> <li> <p><strong>Exponential backoff retry</strong> - Improved handling of transient webhook issues during Pod, TaskRun, and CustomRun creation. Configurable via the <code>wait-exponential-backoff</code> ConfigMap. <a href="https://tekton.dev/docs/pipelines/additional-configs/#exponential-backoff-for-taskrun-and-customrun-creation">Documentation</a></p> </li> <li> <p><strong>Controller HA improvements</strong> - Anti-affinity rules ensure controller replicas are scheduled on different nodes for better availability</p> </li> <li> <p><strong>PodTemplate param substitution</strong> - Enables multi-arch builds with Matrix by allowing param substitution in TaskRunSpecs&rsquo; PodTemplate. This lets you target nodes with specific architectures. <a href="https://tekton.dev/docs/pipelines/matrix/">Documentation</a></p> <div class="highlight"><pre tabindex="0" style="background-color:#f0f3f3;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-yaml" data-lang="yaml"><span style="display:flex;"><span><span style="color:#309;font-weight:bold">apiVersion</span>:<span style="color:#bbb"> </span>tekton.dev/v1<span style="color:#bbb"> </span></span></span><span style="display:flex;"><span><span style="color:#bbb"></span><span style="color:#309;font-weight:bold">kind</span>:<span style="color:#bbb"> </span>PipelineRun<span style="color:#bbb"> </span></span></span><span style="display:flex;"><span><span style="color:#bbb"></span><span style="color:#309;font-weight:bold">metadata</span>:<span style="color:#bbb"> </span></span></span><span style="display:flex;"><span><span style="color:#bbb"> </span><span style="color:#309;font-weight:bold">name</span>:<span style="color:#bbb"> </span>multi-arch-build<span style="color:#bbb"> </span></span></span><span style="display:flex;"><span><span style="color:#bbb"></span><span style="color:#309;font-weight:bold">spec</span>:<span style="color:#bbb"> </span></span></span><span style="display:flex;"><span><span style="color:#bbb"> </span><span style="color:#309;font-weight:bold">pipelineSpec</span>:<span style="color:#bbb"> </span></span></span><span style="display:flex;"><span><span style="color:#bbb"> </span><span style="color:#309;font-weight:bold">tasks</span>:<span style="color:#bbb"> </span></span></span><span style="display:flex;"><span><span style="color:#bbb"> </span>- <span style="color:#309;font-weight:bold">name</span>:<span style="color:#bbb"> </span>build<span style="color:#bbb"> </span></span></span><span style="display:flex;"><span><span style="color:#bbb"> </span><span style="color:#309;font-weight:bold">matrix</span>:<span style="color:#bbb"> </span></span></span><span style="display:flex;"><span><span style="color:#bbb"> </span><span style="color:#309;font-weight:bold">params</span>:<span style="color:#bbb"> </span></span></span><span style="display:flex;"><span><span style="color:#bbb"> </span>- <span style="color:#309;font-weight:bold">name</span>:<span style="color:#bbb"> </span>arch<span style="color:#bbb"> </span></span></span><span style="display:flex;"><span><span style="color:#bbb"> </span><span style="color:#309;font-weight:bold">value</span>:<span style="color:#bbb"> </span>[<span style="color:#c30">&#34;amd64&#34;</span>,<span style="color:#bbb"> </span><span style="color:#c30">&#34;arm64&#34;</span>]<span style="color:#bbb"> </span></span></span><span style="display:flex;"><span><span style="color:#bbb"> </span><span style="color:#309;font-weight:bold">taskSpec</span>:<span style="color:#bbb"> </span></span></span><span style="display:flex;"><span><span style="color:#bbb"> </span><span style="color:#309;font-weight:bold">steps</span>:<span style="color:#bbb"> </span></span></span><span style="display:flex;"><span><span style="color:#bbb"> </span>- <span style="color:#309;font-weight:bold">name</span>:<span style="color:#bbb"> </span>build<span style="color:#bbb"> </span></span></span><span style="display:flex;"><span><span style="color:#bbb"> </span><span style="color:#309;font-weight:bold">image</span>:<span style="color:#bbb"> </span>golang:1.21<span style="color:#bbb"> </span></span></span><span style="display:flex;"><span><span style="color:#bbb"> </span><span style="color:#309;font-weight:bold">script</span>:<span style="color:#bbb"> </span>|<span style="color:#c30;font-style:italic"> </span></span></span><span style="display:flex;"><span><span style="color:#c30;font-style:italic"> echo &#34;Building for $(params.arch)&#34; </span></span></span><span style="display:flex;"><span><span style="color:#c30;font-style:italic"> GOARCH=$(params.arch) go build -o app-$(params.arch) .</span><span style="color:#bbb"> </span></span></span><span style="display:flex;"><span><span style="color:#bbb"> </span><span style="color:#09f;font-style:italic"># PodTemplate with param substitution to schedule on correct architecture</span><span style="color:#bbb"> </span></span></span><span style="display:flex;"><span><span style="color:#bbb"> </span><span style="color:#309;font-weight:bold">podTemplate</span>:<span style="color:#bbb"> </span></span></span><span style="display:flex;"><span><span style="color:#bbb"> </span><span style="color:#309;font-weight:bold">nodeSelector</span>:<span style="color:#bbb"> </span></span></span><span style="display:flex;"><span><span style="color:#bbb"> </span><span style="color:#309;font-weight:bold">kubernetes.io/arch</span>:<span style="color:#bbb"> </span>$(params.arch)<span style="color:#bbb"> </span></span></span></code></pre></div></li> <li> <p><strong>Configurable threading</strong> - <code>THREADS_PER_CONTROLLER</code> environment variable for tuning controller performance based on cluster size</p> </li> <li> <p><strong>OOM detection</strong> - TaskRuns that fail due to Out-Of-Memory (OOM) conditions now clearly show the termination reason in status</p> </li> </ul> <h3 id="fixes">Fixes</h3> <ul> <li>Retryable validation errors no longer fail PipelineRuns</li> <li>PVC cleanup improvements - already-deleted PVCs no longer cause errors</li> <li>Fixed <code>managed-by</code> annotation propagation to Pods</li> </ul> <h3 id="breaking-changes">Breaking Changes</h3> <ul> <li><strong>Deprecated metrics removed</strong> - Use <code>pipelinerun_total</code> instead of <code>pipelinerun_count</code>, <code>taskrun_total</code> instead of <code>taskrun_count</code>, etc.</li> <li><strong>linux/arm images dropped</strong> - armv5, armv6, armv7 are no longer supported</li> </ul> <h2 id="v130-lts--v160-lts-august---october-2025">v1.3.0 LTS → v1.6.0 LTS (August - October 2025)</h2> <p>The second LTS brought <strong>major new features</strong> for remote resolution and pipeline composition.</p> <h3 id="features-1">Features</h3> <ul> <li> <p><strong>Resolvers caching</strong> - Automatic caching for bundle, git, and cluster resolvers. Three modes available: <code>always</code>, <code>never</code>, and <code>auto</code> (default, caches only immutable references). Configurable cache size and TTL via ConfigMap.</p> <div class="highlight"><pre tabindex="0" style="background-color:#f0f3f3;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-yaml" data-lang="yaml"><span style="display:flex;"><span><span style="color:#309;font-weight:bold">apiVersion</span>:<span style="color:#bbb"> </span>v1<span style="color:#bbb"> </span></span></span><span style="display:flex;"><span><span style="color:#bbb"></span><span style="color:#309;font-weight:bold">kind</span>:<span style="color:#bbb"> </span>ConfigMap<span style="color:#bbb"> </span></span></span><span style="display:flex;"><span><span style="color:#bbb"></span><span style="color:#309;font-weight:bold">metadata</span>:<span style="color:#bbb"> </span></span></span><span style="display:flex;"><span><span style="color:#bbb"> </span><span style="color:#309;font-weight:bold">name</span>:<span style="color:#bbb"> </span>resolvers-feature-flags<span style="color:#bbb"> </span></span></span><span style="display:flex;"><span><span style="color:#bbb"> </span><span style="color:#309;font-weight:bold">namespace</span>:<span style="color:#bbb"> </span>tekton-pipelines-resolvers<span style="color:#bbb"> </span></span></span><span style="display:flex;"><span><span style="color:#bbb"></span><span style="color:#309;font-weight:bold">data</span>:<span style="color:#bbb"> </span></span></span><span style="display:flex;"><span><span style="color:#bbb"> </span><span style="color:#309;font-weight:bold">enable-bundles-resolver-caching</span>:<span style="color:#bbb"> </span><span style="color:#c30">&#34;true&#34;</span><span style="color:#bbb"> </span></span></span><span style="display:flex;"><span><span style="color:#bbb"> </span><span style="color:#309;font-weight:bold">bundles-resolver-cache-ttl</span>:<span style="color:#bbb"> </span><span style="color:#c30">&#34;1h&#34;</span><span style="color:#bbb"> </span></span></span><span style="display:flex;"><span><span style="color:#bbb"> </span><span style="color:#309;font-weight:bold">bundles-resolver-cache-size</span>:<span style="color:#bbb"> </span><span style="color:#c30">&#34;100&#34;</span><span style="color:#bbb"> </span></span></span></code></pre></div></li> <li> <p><strong>Pipelines-in-Pipelines (<a href="https://github.com/tektoncd/community/blob/main/teps/0056-pipelines-in-pipelines.md">TEP-0056</a>)</strong> - Reference existing Pipelines as tasks within another Pipeline, enabling powerful composition and reuse patterns. <a href="https://tekton.dev/docs/pipelines/pipelines-in-pipelines/">Documentation</a></p> <div class="highlight"><pre tabindex="0" style="background-color:#f0f3f3;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-yaml" data-lang="yaml"><span style="display:flex;"><span><span style="color:#309;font-weight:bold">apiVersion</span>:<span style="color:#bbb"> </span>tekton.dev/v1<span style="color:#bbb"> </span></span></span><span style="display:flex;"><span><span style="color:#bbb"></span><span style="color:#309;font-weight:bold">kind</span>:<span style="color:#bbb"> </span>Pipeline<span style="color:#bbb"> </span></span></span><span style="display:flex;"><span><span style="color:#bbb"></span><span style="color:#309;font-weight:bold">metadata</span>:<span style="color:#bbb"> </span></span></span><span style="display:flex;"><span><span style="color:#bbb"> </span><span style="color:#309;font-weight:bold">name</span>:<span style="color:#bbb"> </span>integration-pipeline<span style="color:#bbb"> </span></span></span><span style="display:flex;"><span><span style="color:#bbb"></span><span style="color:#309;font-weight:bold">spec</span>:<span style="color:#bbb"> </span></span></span><span style="display:flex;"><span><span style="color:#bbb"> </span><span style="color:#309;font-weight:bold">tasks</span>:<span style="color:#bbb"> </span></span></span><span style="display:flex;"><span><span style="color:#bbb"> </span>- <span style="color:#309;font-weight:bold">name</span>:<span style="color:#bbb"> </span>run-unit-tests<span style="color:#bbb"> </span></span></span><span style="display:flex;"><span><span style="color:#bbb"> </span><span style="color:#309;font-weight:bold">taskRef</span>:<span style="color:#bbb"> </span></span></span><span style="display:flex;"><span><span style="color:#bbb"> </span><span style="color:#309;font-weight:bold">name</span>:<span style="color:#bbb"> </span>unit-test-pipeline<span style="color:#bbb"> </span></span></span><span style="display:flex;"><span><span style="color:#bbb"> </span><span style="color:#309;font-weight:bold">kind</span>:<span style="color:#bbb"> </span>Pipeline<span style="color:#bbb"> </span></span></span><span style="display:flex;"><span><span style="color:#bbb"> </span>- <span style="color:#309;font-weight:bold">name</span>:<span style="color:#bbb"> </span>run-e2e-tests<span style="color:#bbb"> </span></span></span><span style="display:flex;"><span><span style="color:#bbb"> </span><span style="color:#309;font-weight:bold">taskRef</span>:<span style="color:#bbb"> </span></span></span><span style="display:flex;"><span><span style="color:#bbb"> </span><span style="color:#309;font-weight:bold">name</span>:<span style="color:#bbb"> </span>e2e-test-pipeline<span style="color:#bbb"> </span></span></span><span style="display:flex;"><span><span style="color:#bbb"> </span><span style="color:#309;font-weight:bold">kind</span>:<span style="color:#bbb"> </span>Pipeline<span style="color:#bbb"> </span></span></span><span style="display:flex;"><span><span style="color:#bbb"> </span><span style="color:#309;font-weight:bold">runAfter</span>:<span style="color:#bbb"> </span></span></span><span style="display:flex;"><span><span style="color:#bbb"> </span>- run-unit-tests<span style="color:#bbb"> </span></span></span></code></pre></div></li> <li> <p><strong><code>managedBy</code> field</strong> - Delegate PipelineRun/TaskRun lifecycle control to external controllers for custom orchestration scenarios. <a href="https://tekton.dev/docs/pipelines/pipelineruns/#delegating-reconciliation">Documentation</a></p> <div class="highlight"><pre tabindex="0" style="background-color:#f0f3f3;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-yaml" data-lang="yaml"><span style="display:flex;"><span><span style="color:#309;font-weight:bold">apiVersion</span>:<span style="color:#bbb"> </span>tekton.dev/v1<span style="color:#bbb"> </span></span></span><span style="display:flex;"><span><span style="color:#bbb"></span><span style="color:#309;font-weight:bold">kind</span>:<span style="color:#bbb"> </span>PipelineRun<span style="color:#bbb"> </span></span></span><span style="display:flex;"><span><span style="color:#bbb"></span><span style="color:#309;font-weight:bold">metadata</span>:<span style="color:#bbb"> </span></span></span><span style="display:flex;"><span><span style="color:#bbb"> </span><span style="color:#309;font-weight:bold">name</span>:<span style="color:#bbb"> </span>externally-managed<span style="color:#bbb"> </span></span></span><span style="display:flex;"><span><span style="color:#bbb"></span><span style="color:#309;font-weight:bold">spec</span>:<span style="color:#bbb"> </span></span></span><span style="display:flex;"><span><span style="color:#bbb"> </span><span style="color:#309;font-weight:bold">managedBy</span>:<span style="color:#bbb"> </span>custom-orchestrator<span style="color:#bbb"> </span></span></span><span style="display:flex;"><span><span style="color:#bbb"> </span><span style="color:#309;font-weight:bold">pipelineRef</span>:<span style="color:#bbb"> </span></span></span><span style="display:flex;"><span><span style="color:#bbb"> </span><span style="color:#309;font-weight:bold">name</span>:<span style="color:#bbb"> </span>my-pipeline<span style="color:#bbb"> </span></span></span></code></pre></div></li> <li> <p><strong>Concurrent StepActions resolution</strong> - Significantly faster TaskRun startup when using multiple remote StepActions</p> </li> <li> <p><strong>Task timeout overrides</strong> - Override individual task timeouts via <code>spec.taskRunSpecs[].timeout</code>. <a href="https://tekton.dev/docs/pipelines/pipelineruns/#specifying-taskrunspecs">Documentation</a></p> <div class="highlight"><pre tabindex="0" style="background-color:#f0f3f3;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-yaml" data-lang="yaml"><span style="display:flex;"><span><span style="color:#309;font-weight:bold">apiVersion</span>:<span style="color:#bbb"> </span>tekton.dev/v1<span style="color:#bbb"> </span></span></span><span style="display:flex;"><span><span style="color:#bbb"></span><span style="color:#309;font-weight:bold">kind</span>:<span style="color:#bbb"> </span>PipelineRun<span style="color:#bbb"> </span></span></span><span style="display:flex;"><span><span style="color:#bbb"></span><span style="color:#309;font-weight:bold">metadata</span>:<span style="color:#bbb"> </span></span></span><span style="display:flex;"><span><span style="color:#bbb"> </span><span style="color:#309;font-weight:bold">name</span>:<span style="color:#bbb"> </span>custom-timeouts<span style="color:#bbb"> </span></span></span><span style="display:flex;"><span><span style="color:#bbb"></span><span style="color:#309;font-weight:bold">spec</span>:<span style="color:#bbb"> </span></span></span><span style="display:flex;"><span><span style="color:#bbb"> </span><span style="color:#309;font-weight:bold">pipelineRef</span>:<span style="color:#bbb"> </span></span></span><span style="display:flex;"><span><span style="color:#bbb"> </span><span style="color:#309;font-weight:bold">name</span>:<span style="color:#bbb"> </span>my-pipeline<span style="color:#bbb"> </span></span></span><span style="display:flex;"><span><span style="color:#bbb"> </span><span style="color:#309;font-weight:bold">taskRunSpecs</span>:<span style="color:#bbb"> </span></span></span><span style="display:flex;"><span><span style="color:#bbb"> </span>- <span style="color:#309;font-weight:bold">pipelineTaskName</span>:<span style="color:#bbb"> </span>slow-task<span style="color:#bbb"> </span></span></span><span style="display:flex;"><span><span style="color:#bbb"> </span><span style="color:#309;font-weight:bold">timeout</span>:<span style="color:#bbb"> </span>2h<span style="color:#bbb"> </span></span></span></code></pre></div></li> <li> <p><strong>Quota-aware PVC handling</strong> - PipelineRuns wait for quota availability instead of failing immediately</p> </li> <li> <p><strong>Array values in When expressions</strong> - More flexible conditional execution. <a href="https://tekton.dev/docs/pipelines/pipelines/#guard-task-execution-using-when-expressions">Documentation</a></p> </li> <li> <p><strong>Step displayName</strong> - Human-readable names for steps for better observability</p> </li> <li> <p><strong>ARM64 tested releases</strong> - E2E tests now run on ARM64 architecture</p> </li> </ul> <h3 id="fixes-1">Fixes</h3> <ul> <li>Fixed signal handling in SidecarLog for Kubernetes-native sidecar functionality</li> <li>Pods for timed-out TaskRuns are now retained when <code>keep-pod-on-cancel</code> is enabled</li> <li>Correct step status ordering when using StepActions</li> </ul> <h2 id="v160-lts--v190-lts-october-2025---january-2026">v1.6.0 LTS → v1.9.0 LTS (October 2025 - January 2026)</h2> <p>The latest LTS focuses on <strong>stability, observability, and pod configuration</strong>.</p> <h3 id="features-2">Features</h3> <ul> <li> <p><strong><code>hostUsers</code> field in PodTemplate</strong> - Control user namespace isolation for Task pods. <a href="https://tekton.dev/docs/pipelines/podtemplates/">Documentation</a></p> <div class="highlight"><pre tabindex="0" style="background-color:#f0f3f3;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-yaml" data-lang="yaml"><span style="display:flex;"><span><span style="color:#309;font-weight:bold">apiVersion</span>:<span style="color:#bbb"> </span>tekton.dev/v1<span style="color:#bbb"> </span></span></span><span style="display:flex;"><span><span style="color:#bbb"></span><span style="color:#309;font-weight:bold">kind</span>:<span style="color:#bbb"> </span>TaskRun<span style="color:#bbb"> </span></span></span><span style="display:flex;"><span><span style="color:#bbb"></span><span style="color:#309;font-weight:bold">metadata</span>:<span style="color:#bbb"> </span></span></span><span style="display:flex;"><span><span style="color:#bbb"> </span><span style="color:#309;font-weight:bold">name</span>:<span style="color:#bbb"> </span>secure-task<span style="color:#bbb"> </span></span></span><span style="display:flex;"><span><span style="color:#bbb"></span><span style="color:#309;font-weight:bold">spec</span>:<span style="color:#bbb"> </span></span></span><span style="display:flex;"><span><span style="color:#bbb"> </span><span style="color:#309;font-weight:bold">podTemplate</span>:<span style="color:#bbb"> </span></span></span><span style="display:flex;"><span><span style="color:#bbb"> </span><span style="color:#309;font-weight:bold">hostUsers</span>:<span style="color:#bbb"> </span><span style="color:#069;font-weight:bold">false</span><span style="color:#bbb"> </span></span></span><span style="display:flex;"><span><span style="color:#bbb"> </span><span style="color:#309;font-weight:bold">taskSpec</span>:<span style="color:#bbb"> </span></span></span><span style="display:flex;"><span><span style="color:#bbb"> </span><span style="color:#309;font-weight:bold">steps</span>:<span style="color:#bbb"> </span></span></span><span style="display:flex;"><span><span style="color:#bbb"> </span>- <span style="color:#309;font-weight:bold">name</span>:<span style="color:#bbb"> </span>run<span style="color:#bbb"> </span></span></span><span style="display:flex;"><span><span style="color:#bbb"> </span><span style="color:#309;font-weight:bold">image</span>:<span style="color:#bbb"> </span>alpine<span style="color:#bbb"> </span></span></span><span style="display:flex;"><span><span style="color:#bbb"> </span><span style="color:#309;font-weight:bold">script</span>:<span style="color:#bbb"> </span>echo &#34;Running with user namespace isolation&#34;<span style="color:#bbb"> </span></span></span></code></pre></div></li> <li> <p><strong>Digest validation for HTTP resolver</strong> - Ensure integrity of remotely fetched resources by validating SHA256 digests</p> </li> <li> <p><strong>ServiceAccount inheritance for Affinity Assistants</strong> - Better workspace management with proper credentials</p> </li> <li> <p><strong>Improved error messages</strong> - Actual result size now included when exceeding <code>maxResultSize</code> for easier troubleshooting</p> </li> </ul> <h3 id="fixes-2">Fixes</h3> <ul> <li><strong>Major performance fix</strong> - Resolved issues causing massive invalid status updates that impacted API server load and stability</li> <li><strong>Parameter resolution</strong> - Fixed defaults with object references</li> <li><strong>Timeout handling</strong> - Prevented excessive reconciliation when timeout is disabled</li> <li><strong>Pod configuration errors</strong> - Early detection instead of waiting for timeout</li> <li><strong>Race conditions</strong> - Fixed TaskRun status issues during timeout handling</li> <li><strong>Sidecar stopping</strong> - Fixed 409 conflict errors by using Patch instead of Update</li> <li><strong>Matrix validation</strong> - Prevented panics from invalid result references (v1beta1)</li> </ul> <h2 id="lts-support-policy">LTS Support Policy</h2> <p>With v1.9.0 being an LTS release, it will receive security and critical bug fixes for an extended period. Users upgrading from previous LTS versions can expect a smooth transition:</p> <table> <thead> <tr> <th>From</th> <th>To</th> <th>Key Considerations</th> </tr> </thead> <tbody> <tr> <td>v1.0.0</td> <td>v1.3.0 LTS</td> <td>Update metric dashboards for renamed metrics</td> </tr> <tr> <td>v1.3.0 LTS</td> <td>v1.6.0 LTS</td> <td>Smooth upgrade, new features opt-in</td> </tr> <tr> <td>v1.6.0 LTS</td> <td>v1.9.0 LTS</td> <td>Smooth upgrade, stability improvements</td> </tr> </tbody> </table> <p>Read more about <a href="https://github.com/tektoncd/community/blob/main/releases.md#support-policy">LTS releases and our support policy</a>.</p> <h2 id="looking-ahead">Looking Ahead</h2> <p>The Tekton Pipelines project continues to focus on:</p> <ul> <li><strong>Performance</strong> - Reducing reconciliation overhead and improving startup times</li> <li><strong>User experience</strong> - Better error messages, observability, and debugging tools</li> <li><strong>Resolver improvements</strong> - Working towards v2 resolvers with enhanced caching and usability</li> <li><strong>Kueue integration (<a href="https://github.com/tektoncd/community/pull/1241">TEP-0164</a>)</strong> - Native support for <a href="https://kueue.sigs.k8s.io/">Kueue</a> job queueing to enable better resource management and fair-sharing in multi-tenant environments</li> </ul> <p>We&rsquo;re also making progress on our transition to the <a href="https://github.com/cncf/toc/issues/1310">Cloud Native Computing Foundation (CNCF)</a>, which will provide Tekton with a neutral home and access to a broader ecosystem.</p> <h2 id="get-involved">Get Involved</h2> <p>We invite you to try v1.9.0 LTS, provide feedback, and contribute to the project:</p> <ul> <li><a href="https://github.com/tektoncd/pipeline">GitHub Repository</a></li> <li><a href="https://tekton.dev/docs/">Documentation</a></li> <li><a href="https://tektoncd.slack.com">Community Slack</a> (#tekton)</li> <li><a href="https://github.com/tektoncd/pipeline/releases/tag/v1.9.0">Release Notes</a></li> </ul> <p>Thank you to all the contributors who made these releases possible!</p> Blog: Tekton Pipelines Reaches 1.0: Stability Today, Innovation Tomorrow https://tekton.dev/blog/2025/05/23/tekton-pipelines-reaches-1.0-stability-today-innovation-tomorrow/ Fri, 23 May 2025 00:00:00 +0000 https://tekton.dev/blog/2025/05/23/tekton-pipelines-reaches-1.0-stability-today-innovation-tomorrow/ <p>We&rsquo;re thrilled to announce the official 1.0 release of the Tekton Pipelines component (<a href="https://github.com/tektoncd/pipeline"><code>tektoncd/pipeline</code></a> repository) ! While this marks a significant milestone for the project, it&rsquo;s important to note that the stability you&rsquo;ve come to rely on with the v1 API has been a reality for over two years. This release solidifies that foundation while paving the way for even more exciting changes in the Tekton ecosystem.</p> <p>The version 1.0 brings several key updates, reinforcing the project&rsquo;s commitment to stability and a streamlined user experience. Notably, the <code>StepAction</code> feature has graduated to General Availability (GA), signifying its maturity and readiness for production use. Furthermore, this release includes significant enhancements and bug fixes for the Git resolver, improving its reliability and performance. We&rsquo;ve also seen the recent introduction and ongoing development of the HTTP resolver, offering greater flexibility in how your pipelines fetch tasks and other resources. You can learn more about resolvers and their capabilities in the <a href="https://tekton.dev/docs/pipelines/resolution/">Tekton documentation</a>. Finally, the deprecated <code>ClusterTask</code> resource has been removed, encouraging the adoption of the more flexible and namespaced <code>Task</code> resource or the use of the cluster resolver.</p> <p>The 1.0 release is not the finish line; it&rsquo;s a significant step forward on an exciting journey and one we could or should have done a while ago. Looking ahead, we&rsquo;ll be focused on stability, performance and user experience.</p> <ul> <li>Graduate <code>StepAction</code> to the v1 API, ensuring long-term stability and support for this powerful feature.</li> <li>Working towards a <code>v2</code> of the resolvers, with a strong focus on improving both usability and performance.</li> <li>Investing in better observability and metrics to provide users with clearer insights into their Pipeline executions.</li> </ul> <p>Our goal is to make Tekton Pipelines even more intuitive and efficient for developers and operators alike.</p> <p>Independently of the release, we are also making a significant step in the evolution of the Tekton project as we transition to the Cloud Native Computing Foundation (CNCF). You can follow the progress of this transition in the <a href="https://github.com/cncf/toc/issues/1310">CNCF TOC issue</a>. Joining the CNCF will provide Tekton with a neutral home and access to a vibrant and supportive ecosystem. This move will foster even greater collaboration, expand our community reach, and ensure the long-term sustainability and growth of Tekton Pipelines for the benefit of all cloud-native practitioners.</p> <p>We invite you to explore the 1.0 release, engage with our growing community, and contribute to the future of cloud-native CI/CD. The best is yet to come!</p> Blog: Protect Signing Secrets for Tekton Chains using Confidential Computing https://tekton.dev/blog/2025/04/23/protect-signing-secrets-for-tekton-chains-using-confidential-computing/ Wed, 23 Apr 2025 00:00:00 +0000 https://tekton.dev/blog/2025/04/23/protect-signing-secrets-for-tekton-chains-using-confidential-computing/ <h2 id="what-is-tekton-chains">What is Tekton Chains?</h2> <p><a href="https://github.com/tektoncd/chains/blob/main/README.md">Tekton Chains</a>, a part of the Tekton project, provides tools to generate, store, and sign provenance for artifacts built with Tekton Pipelines.</p> <p>Technically it&rsquo;s a Kubernetes Custom Resource Definition (CRD) controller that allows you to manage your supply chain security in Tekton. Chains observes Tekton Pipelines and generates provenance for the artifacts built the Pipelines.</p> <p>The following diagram from the Tekton Chains <a href="https://github.com/tektoncd/chains/blob/main/docs/tutorials/getting-started-tutorial.md">tutorial</a> shows the Tekton Chains workflow</p> <p><img src="./image1.png" alt="Tekton Chains workflow diagram showing the process from pipeline execution to provenance generation and signing" title="Tekton Chains workflow diagram"></p> <p>Src: <a href="https://tekton.dev/docs/chains/getting-started-tutorial/">https://tekton.dev/docs/chains/getting-started-tutorial/</a></p> <p>To summarise, here are the steps in Tekton Chains provenance signing</p> <ol> <li>Create signing secret (eg. cosign key-pair - cosign.pub, cosign.key, cosign.password)</li> <li>Save the signing secret as K8s secret - named signing-secrets in tekton-chains ns</li> <li>Create the pipelineRun object (execute your pipeline)</li> <li>Chains controller watches for pipelineRun completion and creates a snapshot</li> <li>Sign the snapshot using the private part of the signing secret (eg. cosign.key)</li> <li>As a consumer, verify the provenance by by checking the signature using the public part of the signing secret (eg. cosign.pub)</li> </ol> <h2 id="what-is-confidential-computing">What is Confidential Computing?</h2> <p>Confidential computing protects your workload and data from unauthorised entities — the host or hypervisor, system administrators, service providers, other virtual machines (VMs) and processes on the host.</p> <p>Confidential computing protects the data in use, completing the data security triad — securing data at rest, in-transit, and in-use. Only the data owner has access to the data.</p> <p><img src="./image2.png" alt="Diagram illustrating the three states of data protection - data at rest, data in transit, and data in use, with confidential computing protecting data in use"></p> <p>This key functionality gives you the additional confidence to run your sensitive workloads in untrusted infrastructure (e.g. third-party data-centers, public cloud) and reap the benefits of scale and cost-efficiency.</p> <div align="center"> <img src="./image3.png"> </div> <p>A Trusted Execution Environment (TEE) is at the heart of a confidential computing solution. TEEs are secure and isolated environments provided by confidential computing (CC) enabled hardware that prevents unauthorised access or modification of applications and data while in use. You’ll also hear the terms “enclaves” or “secure enclaves”. “TEEs” and “enclaves” are used interchangeably.</p> <p>So to reap the benefits of confidential computing, your application needs to run inside a TEE (secure enclave) for it to be protected.</p> <h2 id="how-can-you-leverage-confidential-computing-in-the-kubernetes-ecosystem">How can you leverage Confidential Computing in the Kubernetes ecosystem?</h2> <p>In the Kubernetes world, there are two broad ways for you to use confidential computing:</p> <p><strong>Confidential Cluster</strong>: The entire Kubernetes cluster is running inside a confidential environment. The cluster nodes are confidential VMs, and any workload deployed on these cluster nodes benefits from confidentiality.</p> <p><strong>Confidential Container</strong>: The Kubernetes pod is running inside a confidential environment. This approach is more granular, where confidentiality is available to the workload of your choice.</p> <p><img src="./image4.png" alt="Comparison diagram showing confidential cluster approach versus confidential container approach in Kubernetes environments"></p> <p>Both confidential Kubernetes clusters and containers aim to enhance data security and privacy of Kubernetes workloads by leveraging hardware-based encryption and attestations for trust.</p> <h2 id="tekton-chains-and-confidential-computing">Tekton Chains and Confidential Computing</h2> <p>In order to secure Tekton Chains code and the signing secrets from threats by privileged admins, you can leverage confidential computing.</p> <p>We have used the confidential container (CoCo) approach to secure Tekton chains.</p> <h2 id="confidential-containers-coco">Confidential Containers (CoCo)</h2> <p>Confidential Containers (CoCo) refers to a pod running inside the TEE.</p> <p>The CNCF Confidential Containers (CoCo) project is leading the effort to standardise confidential computing at the pod level and simplify its consumption in Kubernetes. This enables Kubernetes users to deploy confidential container workloads using familiar workflows and tools without extensive knowledge of the underlying confidential computing technologies.</p> <h2 id="confidential-containers-coco-building-blocks">Confidential Containers (CoCo) building blocks</h2> <p>Following is a high level architecture of a typical CoCo deployment in Kubernetes.</p> <p><img src="./image5.png" alt="High-level architecture diagram of Confidential Containers (CoCo) deployment in Kubernetes, showing TEE, CVM, enclave software stack, and attestation components"></p> <p>As shown in the diagram, CoCo uses Linux Confidential Virtual Machine (CVM) executing inside a TEE as the foundation. Using CVM as the foundation enables lift-and-shift of existing container workloads.</p> <p>The container images are downloaded and kept inside the enclave and can be either signed and/or encrypted.</p> <p>The components inside the CVM, namely image-rs, kata-agent, confidential data hub (CDH), attestation agent (AA) are collectively referred to as the enclave software stack. The enclave software stack is measured, which means that a trusted cryptographic algorithm is used to measure these entities running within the CVM. These measurements can be used for attestation purposes. Access to secrets—including encryption keys to decrypt the container image itself or to unlock a database used by the workload—can be controlled, released only when the enclave is attested to be valid.</p> <p>Attestation is the process of verifying that an enclave measurement meets some specified criteria set by the workload or data owner (mentioned as Relying party in the diagram). The attestation agent is responsible for initiating attestation and fetching of the secrets from the key broker service (KBS). For detailed information refer to the following documentation.</p> <p>The CNCF CoCo project provides the following components</p> <ul> <li>Enclave software stack - <a href="https://github.com/confidential-containers/guest-components">https://github.com/confidential-containers/guest-components</a></li> <li>Relying Party Services - <a href="https://github.com/confidential-containers/trustee">https://github.com/confidential-containers/trustee</a></li> <li>CoCo operator - <a href="https://github.com/confidential-containers/operator">https://github.com/confidential-containers/operator</a></li> <li>Trustee operator - <a href="https://github.com/confidential-containers/trustee-operator">https://github.com/confidential-containers/trustee-operator</a></li> <li>CoCo enablement for Kata containers local hypervisor - <a href="https://github.com/kata-containers/kata-containers">https://github.com/kata-containers/kata-containers</a></li> <li>CoCo enablement for Kata containers remote hypervisor - <a href="https://github.com/confidential-containers/cloud-api-adaptor">https://github.com/confidential-containers/cloud-api-adaptor</a></li> </ul> <h3 id="tekton-chains-and-confidential-containers-coco">Tekton Chains and Confidential Containers (CoCo)</h3> <p>Recall from Tekton Chains <a href="https://docs.google.com/document/d/1ivTjtZ1D_gjSBeaDqn4FGwIoBDid2xt3u4knVknDzzo/edit?tab=t.0#bookmark=id.7m33px6pnidl">signing workflow</a>, the signing secret is stored as Kubernetes secret accessible to any cluster admin. If you are using third party services, you would want to protect the signing secret even from the cluster admin. CoCo allows you to do that, by ensuring that the signing secret is only available inside the TEE with no access to the cluster admin.</p> <p>In the following sections we&rsquo;ll see how the signing secrets can be protected using CoCo.</p> <h3 id="setup">Setup</h3> <p>For the purpose of this blog, we&rsquo;ll be using CoCo in AWS leveraging the Kata containers remote hypervisor setup provided via the CoCo cloud-api-adaptor project.</p> <p>Instructions to set up CoCo on AWS - <a href="https://confidentialcontainers.org/docs/examples/aws-simple">https://confidentialcontainers.org/docs/examples/aws-simple</a>.</p> <p>KBS setup details are described in the following <a href="https://confidentialcontainers.org/blog/2024/06/10/deploy-trustee-in-kubernetes/">blog</a>.</p> <p>For other environments refer to the CoCo documentation - <a href="https://confidentialcontainers.org/docs/getting-started">https://confidentialcontainers.org/docs/getting-started</a></p> <h3 id="tekton-chains-setup">Tekton Chains Setup</h3> <p>Instructions to install Tekton Chains Installation - <a href="https://github.com/tektoncd/chains?tab=readme-ov-file#installation">https://github.com/tektoncd/chains?tab=readme-ov-file#installation</a></p> <h4 id="signing-secrets-for-tekton-chains">Signing Secrets for Tekton Chains</h4> <p>We&rsquo;ll be using the <code>sealed secrets</code> functionality of CoCo. A sealed secret is a way to encapsulate confidential data such that it can be accessed only inside a Trusted Execution Environment (TEE) after verification of the TEE environment. There are two types of sealed secrets in CoCo - envelope and vault.</p> <p>We&rsquo;ll be using the <code>vault</code> type. A vault secret is a pointer to a secret that is stored remotely in a KMS. In the CoCo environment this is managed by the Compute attestation operator as shown previously. When deploying a workload as CoCo, the CoCo runtime components inside the TEE will retrieve the actual secret from the remote provider and make it available to the workload. This happens transparently.</p> <p>Let&rsquo;s see an example of a vault type sealed secret. The first step is to create a json file containing the location of the secret in a specified format.</p> <p>An example json file <code>secret.json</code> is shown below. Note the <code>name</code> and the <code>provider</code>. This defines the location of the actual secret <code>secret</code>.</p> <div class="highlight"><pre tabindex="0" style="background-color:#f0f3f3;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>cat secret.json </span></span><span style="display:flex;"><span> </span></span><span style="display:flex;"><span><span style="color:#555">{</span> </span></span><span style="display:flex;"><span> <span style="color:#c30">&#34;version&#34;</span>: <span style="color:#c30">&#34;0.1.0&#34;</span>, </span></span><span style="display:flex;"><span> <span style="color:#c30">&#34;type&#34;</span>: <span style="color:#c30">&#34;vault&#34;</span>, </span></span><span style="display:flex;"><span> <span style="color:#c30">&#34;name&#34;</span>: <span style="color:#c30">&#34;kbs:///default/mysecret/secret&#34;</span>, </span></span><span style="display:flex;"><span> <span style="color:#c30">&#34;provider&#34;</span>: <span style="color:#c30">&#34;kbs&#34;</span>, </span></span><span style="display:flex;"><span> <span style="color:#c30">&#34;provider_settings&#34;</span>: <span style="color:#555">{}</span>, </span></span><span style="display:flex;"><span> <span style="color:#c30">&#34;annotations&#34;</span>: <span style="color:#555">{}</span> </span></span><span style="display:flex;"><span><span style="color:#555">}</span> </span></span></code></pre></div><p>The sealed secret is of the form - <code>sealed.JWS header.JWS body (secret content).signature</code></p> <p>For using sealed secrets in K8s, we use the following: <code>sealed.fakejwsheader.base64url(secret content).fakesignature</code></p> <p>Continuing with <code>secret.json</code> example, the sealed secret will be the following:</p> <div class="highlight"><pre tabindex="0" style="background-color:#f0f3f3;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>cat secret.json | basenc --base64url -w0 </span></span><span style="display:flex;"><span> </span></span><span style="display:flex;"><span><span style="color:#033">ewogICAgInZlcnNpb24iOiAiMC4xLjAiLAogICAgInR5cGUiOiAidmF1bHQiLAogICAgIm5hbWUiOiAia2JzOi8vL2RlZmF1bHQvbXlzZWNyZXQvc2VjcmV0IiwKICAgICJwcm92aWRlciI6ICJrYnMiLAogICAgInByb3ZpZGVyX3NldHRpbmdzIjoge30sCiAgICAiYW5ub3RhdGlvbnMiOiB7fQp9Cgo</span><span style="color:#555">=</span> </span></span><span style="display:flex;"><span> </span></span><span style="display:flex;"><span><span style="color:#033">sealed_secret</span><span style="color:#555">=</span>sealed.fakejwsheader.ewogICAgInZlcnNpb24iOiAiMC4xLjAiLAogICAgInR5cGUiOiAidmF1bHQiLAogICAgIm5hbWUiOiAia2JzOi8vL2RlZmF1bHQvbXlzZWNyZXQvc2VjcmV0IiwKICAgICJwcm92aWRlciI6ICJrYnMiLAogICAgInByb3ZpZGVyX3NldHRpbmdzIjoge30sCiAgICAiYW5ub3RhdGlvbnMiOiB7fQp9Cgo<span style="color:#555">=</span>.fakesignature </span></span></code></pre></div><p>Now let&rsquo;s see how we can use this approach to protect the signing secrets for Tekton Chains.</p> <p>As mentioned previously, a CoCo deployment uses a trusted environment to store the secrets and releases it to the workload. The actual secret will be in the trusted environment whereas the sealed secret will be used in the untrusted environment running Tekton Chains.</p> <p>Generate cosign key-pairs - cosign.pub, cosign.key, cosign.password</p> <div class="highlight"><pre tabindex="0" style="background-color:#f0f3f3;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>cosign generate-key-pair </span></span></code></pre></div><p>Store the keys in the KBS. In my setup the cosign are stored under <code>default/cosign-secrets/{cosign.key,cosign.pub,cosign.password}</code></p> <p>Create sealed secrets to be used by the Tekton chains controller</p> <h3 id="cosignkeyjson"><code>cosign.key.json</code></h3> <div class="highlight"><pre tabindex="0" style="background-color:#f0f3f3;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-json" data-lang="json"><span style="display:flex;"><span>{ </span></span><span style="display:flex;"><span> <span style="color:#309;font-weight:bold">&#34;version&#34;</span>: <span style="color:#c30">&#34;0.1.0&#34;</span>, </span></span><span style="display:flex;"><span> <span style="color:#309;font-weight:bold">&#34;type&#34;</span>: <span style="color:#c30">&#34;vault&#34;</span>, </span></span><span style="display:flex;"><span> <span style="color:#309;font-weight:bold">&#34;name&#34;</span>: <span style="color:#c30">&#34;kbs:///default/cosign-secrets/cosign.key&#34;</span>, </span></span><span style="display:flex;"><span> <span style="color:#309;font-weight:bold">&#34;provider&#34;</span>: <span style="color:#c30">&#34;kbs&#34;</span>, </span></span><span style="display:flex;"><span> <span style="color:#309;font-weight:bold">&#34;provider_settings&#34;</span>: {}, </span></span><span style="display:flex;"><span> <span style="color:#309;font-weight:bold">&#34;annotations&#34;</span>: {} </span></span><span style="display:flex;"><span>} </span></span></code></pre></div><p><strong>Sealed secret</strong><br> <code>sealed.fakejwsheader.ewogICAgInZlcnNpb24iOiAiMC4xLjAiLAogICAgInR5cGUiOiAidmF1bHQiLAogICAgIm5hbWUiOiAia2JzOi8vL2RlZmF1bHQvY29zaWduLXNlY3JldHMvY29zaWduLmtleSIsCiAgICAicHJvdmlkZXIiOiAia2JzIiwKICAgICJwcm92aWRlcl9zZXR0aW5ncyI6IHt9LAogICAgImFubm90YXRpb25zIjoge30KfQo=.fakesignature</code></p> <hr> <h3 id="cosignpubjson"><code>cosign.pub.json</code></h3> <div class="highlight"><pre tabindex="0" style="background-color:#f0f3f3;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-json" data-lang="json"><span style="display:flex;"><span>{ </span></span><span style="display:flex;"><span> <span style="color:#309;font-weight:bold">&#34;version&#34;</span>: <span style="color:#c30">&#34;0.1.0&#34;</span>, </span></span><span style="display:flex;"><span> <span style="color:#309;font-weight:bold">&#34;type&#34;</span>: <span style="color:#c30">&#34;vault&#34;</span>, </span></span><span style="display:flex;"><span> <span style="color:#309;font-weight:bold">&#34;name&#34;</span>: <span style="color:#c30">&#34;kbs:///default/cosign-secrets/cosign.pub&#34;</span>, </span></span><span style="display:flex;"><span> <span style="color:#309;font-weight:bold">&#34;provider&#34;</span>: <span style="color:#c30">&#34;kbs&#34;</span>, </span></span><span style="display:flex;"><span> <span style="color:#309;font-weight:bold">&#34;provider_settings&#34;</span>: {}, </span></span><span style="display:flex;"><span> <span style="color:#309;font-weight:bold">&#34;annotations&#34;</span>: {} </span></span><span style="display:flex;"><span>} </span></span></code></pre></div><p><strong>Sealed secret</strong><br> <code>sealed.fakejwsheader.ewogICAgInZlcnNpb24iOiAiMC4xLjAiLAogICAgInR5cGUiOiAidmF1bHQiLAogICAgIm5hbWUiOiAia2JzOi8vL2RlZmF1bHQvY29zaWduLXNlY3JldHMvY29zaWduLnB1YiIsCiAgICAicHJvdmlkZXIiOiAia2JzIiwKICAgICJwcm92aWRlcl9zZXR0aW5ncyI6IHt9LAogICAgImFubm90YXRpb25zIjoge30KfQo=.fakesignature</code></p> <hr> <h3 id="cosignpasswordjson"><code>cosign.password.json</code></h3> <div class="highlight"><pre tabindex="0" style="background-color:#f0f3f3;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-json" data-lang="json"><span style="display:flex;"><span>{ </span></span><span style="display:flex;"><span> <span style="color:#309;font-weight:bold">&#34;version&#34;</span>: <span style="color:#c30">&#34;0.1.0&#34;</span>, </span></span><span style="display:flex;"><span> <span style="color:#309;font-weight:bold">&#34;type&#34;</span>: <span style="color:#c30">&#34;vault&#34;</span>, </span></span><span style="display:flex;"><span> <span style="color:#309;font-weight:bold">&#34;name&#34;</span>: <span style="color:#c30">&#34;kbs:///default/cosign-secrets/cosign.password&#34;</span>, </span></span><span style="display:flex;"><span> <span style="color:#309;font-weight:bold">&#34;provider&#34;</span>: <span style="color:#c30">&#34;kbs&#34;</span>, </span></span><span style="display:flex;"><span> <span style="color:#309;font-weight:bold">&#34;provider_settings&#34;</span>: {}, </span></span><span style="display:flex;"><span> <span style="color:#309;font-weight:bold">&#34;annotations&#34;</span>: {} </span></span><span style="display:flex;"><span>} </span></span></code></pre></div><p><strong>Sealed secret</strong><br> <code>sealed.fakejwsheader.ewogICAgInZlcnNpb24iOiAiMC4xLjAiLAogICAgInR5cGUiOiAidmF1bHQiLAogICAgIm5hbWUiOiAia2JzOi8vL2RlZmF1bHQvY29zaWduLXNlY3JldHMvY29zaWduLnBhc3N3b3JkIiwKICAgICJwcm92aWRlciI6ICJrYnMiLAogICAgInByb3ZpZGVyX3NldHRpbmdzIjoge30sCiAgICAiYW5ub3RhdGlvbnMiOiB7fQp9Cg==.fakesignature</code></p> <hr> <h4 id="the-signing-secrets-looks-like-this">The <code>signing-secrets</code> looks like this</h4> <div class="highlight"><pre tabindex="0" style="background-color:#f0f3f3;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-yaml" data-lang="yaml"><span style="display:flex;"><span><span style="color:#309;font-weight:bold">apiVersion</span>:<span style="color:#bbb"> </span>v1<span style="color:#bbb"> </span></span></span><span style="display:flex;"><span><span style="color:#bbb"></span><span style="color:#309;font-weight:bold">data</span>:<span style="color:#bbb"> </span></span></span><span style="display:flex;"><span><span style="color:#bbb"> </span><span style="color:#309;font-weight:bold">cosign.key</span>:<span style="color:#bbb"> </span>c2VhbGVkLmZha2Vqd3NoZWFkZXIuZXdvZ0lDQWdJblpsY25OcGIyNGlPaUFpTUM0eExqQWlMQW9nSUNBZ0luUjVjR1VpT2lBaWRtRjFiSFFpTEFvZ0lDQWdJbTVoYldVaU9pQWlhMkp6T2k4dkwyUmxabUYxYkhRdlkyOXphV2R1TFhObFkzSmxkSE12WTI5emFXZHVMbXRsZVNJc0NpQWdJQ0FpY0hKdmRtbGtaWElpT2lBaWEySnpJaXdLSUNBZ0lDSndjbTkyYVdSbGNsOXpaWFIwYVc1bmN5STZJSHQ5TEFvZ0lDQWdJbUZ1Ym05MFlYUnBiMjV6SWpvZ2UzMEtmUW89LmZha2VzaWduYXR1cmUK<span style="color:#bbb"> </span></span></span><span style="display:flex;"><span><span style="color:#bbb"> </span><span style="color:#309;font-weight:bold">cosign.password</span>:<span style="color:#bbb"> </span>c2VhbGVkLmZha2Vqd3NoZWFkZXIuZXdvZ0lDQWdJblpsY25OcGIyNGlPaUFpTUM0eExqQWlMQW9nSUNBZ0luUjVjR1VpT2lBaWRtRjFiSFFpTEFvZ0lDQWdJbTVoYldVaU9pQWlhMkp6T2k4dkwyUmxabUYxYkhRdlkyOXphV2R1TFhObFkzSmxkSE12WTI5emFXZHVMbkJoYzNOM2IzSmtJaXdLSUNBZ0lDSndjbTkyYVdSbGNpSTZJQ0pyWW5NaUxBb2dJQ0FnSW5CeWIzWnBaR1Z5WDNObGRIUnBibWR6SWpvZ2UzMHNDaUFnSUNBaVlXNXViM1JoZEdsdmJuTWlPaUI3ZlFwOUNnPT0uZmFrZXNpZ25hdHVyZQo=<span style="color:#bbb"> </span></span></span><span style="display:flex;"><span><span style="color:#bbb"> </span><span style="color:#309;font-weight:bold">cosign.pub</span>:<span style="color:#bbb"> </span>c2VhbGVkLmZha2Vqd3NoZWFkZXIuZXdvZ0lDQWdJblpsY25OcGIyNGlPaUFpTUM0eExqQWlMQW9nSUNBZ0luUjVjR1VpT2lBaWRtRjFiSFFpTEFvZ0lDQWdJbTVoYldVaU9pQWlhMkp6T2k4dkwyUmxabUYxYkhRdlkyOXphV2R1TFhObFkzSmxkSE12WTI5emFXZHVMbkIxWWlJc0NpQWdJQ0FpY0hKdmRtbGtaWElpT2lBaWEySnpJaXdLSUNBZ0lDSndjbTkyYVdSbGNsOXpaWFIwYVc1bmN5STZJSHQ5TEFvZ0lDQWdJbUZ1Ym05MFlYUnBiMjV6SWpvZ2UzMEtmUW89LmZha2VzaWduYXR1cmUK<span style="color:#bbb"> </span></span></span><span style="display:flex;"><span><span style="color:#bbb"></span><span style="color:#309;font-weight:bold">immutable</span>:<span style="color:#bbb"> </span><span style="color:#069;font-weight:bold">true</span><span style="color:#bbb"> </span></span></span><span style="display:flex;"><span><span style="color:#bbb"></span><span style="color:#309;font-weight:bold">kind</span>:<span style="color:#bbb"> </span>Secret<span style="color:#bbb"> </span></span></span><span style="display:flex;"><span><span style="color:#bbb"></span><span style="color:#309;font-weight:bold">metadata</span>:<span style="color:#bbb"> </span></span></span><span style="display:flex;"><span><span style="color:#bbb"> </span><span style="color:#309;font-weight:bold">name</span>:<span style="color:#bbb"> </span>signing-secrets<span style="color:#bbb"> </span></span></span><span style="display:flex;"><span><span style="color:#bbb"> </span><span style="color:#309;font-weight:bold">namespace</span>:<span style="color:#bbb"> </span>tekton-chains<span style="color:#bbb"> </span></span></span><span style="display:flex;"><span><span style="color:#bbb"></span><span style="color:#309;font-weight:bold">type</span>:<span style="color:#bbb"> </span>Opaque<span style="color:#bbb"> </span></span></span></code></pre></div><hr> <h2 id="-custom-tekton-chains-deployment">⚙️ Custom Tekton Chains Deployment</h2> <p>Update the <code>TektonConfig</code> CR:</p> <p>📖 <a href="https://github.com/tektoncd/operator/blob/main/docs/TektonConfig.md#deployments">Tekton Operator Deployment Options</a></p> <div class="highlight"><pre tabindex="0" style="background-color:#f0f3f3;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-yaml" data-lang="yaml"><span style="display:flex;"><span><span style="color:#309;font-weight:bold">chain</span>:<span style="color:#bbb"> </span></span></span><span style="display:flex;"><span><span style="color:#bbb"> </span><span style="color:#309;font-weight:bold">options</span>:<span style="color:#bbb"> </span></span></span><span style="display:flex;"><span><span style="color:#bbb"> </span><span style="color:#309;font-weight:bold">deployments</span>:<span style="color:#bbb"> </span></span></span><span style="display:flex;"><span><span style="color:#bbb"> </span><span style="color:#309;font-weight:bold">tekton-chains-controller</span>:<span style="color:#bbb"> </span></span></span><span style="display:flex;"><span><span style="color:#bbb"> </span><span style="color:#309;font-weight:bold">spec</span>:<span style="color:#bbb"> </span></span></span><span style="display:flex;"><span><span style="color:#bbb"> </span><span style="color:#309;font-weight:bold">template</span>:<span style="color:#bbb"> </span></span></span><span style="display:flex;"><span><span style="color:#bbb"> </span><span style="color:#309;font-weight:bold">spec</span>:<span style="color:#bbb"> </span></span></span><span style="display:flex;"><span><span style="color:#bbb"> </span><span style="color:#309;font-weight:bold">containers</span>:<span style="color:#bbb"> </span></span></span><span style="display:flex;"><span><span style="color:#bbb"> </span>- <span style="color:#309;font-weight:bold">name</span>:<span style="color:#bbb"> </span>tekton-chains-controller<span style="color:#bbb"> </span></span></span><span style="display:flex;"><span><span style="color:#bbb"> </span><span style="color:#309;font-weight:bold">runtimeClassName</span>:<span style="color:#bbb"> </span>kata-remote<span style="color:#bbb"> </span></span></span></code></pre></div><hr> <h2 id="-run-the-pipeline">🚀 Run the Pipeline</h2> <p>Now you can run your pipeline and let Tekton chains sign the provenance using secrets that are only available inside the confidential environment.</p> <p>We&rsquo;ll use the following sample from the getting started guide - <a href="https://github.com/tektoncd/chains/blob/main/docs/tutorials/getting-started-tutorial.md">https://github.com/tektoncd/chains/blob/main/docs/tutorials/getting-started-tutorial.md</a></p> <div class="highlight"><pre tabindex="0" style="background-color:#f0f3f3;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>kubectl create -f pipelinerun.yaml </span></span><span style="display:flex;"><span> </span></span><span style="display:flex;"><span>tkn pr list </span></span><span style="display:flex;"><span> </span></span><span style="display:flex;"><span>tkn pr describe </span></span><span style="display:flex;"><span> </span></span><span style="display:flex;"><span><span style="color:#366">export</span> <span style="color:#033">PR_UID</span><span style="color:#555">=</span><span style="color:#069;font-weight:bold">$(</span>tkn pr describe --last -o <span style="color:#033">jsonpath</span><span style="color:#555">=</span><span style="color:#c30">&#39;{.metadata.uid}&#39;</span><span style="color:#069;font-weight:bold">)</span> </span></span><span style="display:flex;"><span> </span></span><span style="display:flex;"><span>tkn pr describe --last <span style="color:#c30;font-weight:bold">\ </span></span></span><span style="display:flex;"><span><span style="color:#c30;font-weight:bold"></span> -o <span style="color:#033">jsonpath</span><span style="color:#555">=</span><span style="color:#c30">&#34;{.metadata.annotations.chains\.tekton\.dev/signature-pipelinerun-</span><span style="color:#033">$PR_UID</span><span style="color:#c30">}&#34;</span> <span style="color:#c30;font-weight:bold">\ </span></span></span><span style="display:flex;"><span><span style="color:#c30;font-weight:bold"></span> | base64 -d &gt; metadata.json </span></span></code></pre></div><hr> <h2 id="-cosign-verification">✅ Cosign Verification</h2> <div class="highlight"><pre tabindex="0" style="background-color:#f0f3f3;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>cosign verify-blob-attestation --insecure-ignore-tlog <span style="color:#c30;font-weight:bold">\ </span></span></span><span style="display:flex;"><span><span style="color:#c30;font-weight:bold"></span> --key cosign.pub --signature metadata.json <span style="color:#c30;font-weight:bold">\ </span></span></span><span style="display:flex;"><span><span style="color:#c30;font-weight:bold"></span> --type slsaprovenance --check-claims<span style="color:#555">=</span><span style="color:#366">false</span> /dev/null </span></span></code></pre></div><pre tabindex="0"><code>WARNING: Skipping tlog verification is an insecure practice that lacks of transparency and auditability verification for the blob attestation. Verified OK </code></pre><hr> <h2 id="-confidentiality-verification">🔍 Confidentiality Verification</h2> <p>The following output is from the controller container.</p> <p>As you can see the actual secrets are available in the volume mount path. Also the secrets are in memory.</p> <div class="highlight"><pre tabindex="0" style="background-color:#f0f3f3;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>cat /sealed/signing-secrets/cosign.pub </span></span></code></pre></div><div class="highlight"><pre tabindex="0" style="background-color:#f0f3f3;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>-----BEGIN PUBLIC KEY----- </span></span><span style="display:flex;"><span>MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEnI15trNzbvWtdAfVyNKRnY7/vrAP </span></span><span style="display:flex;"><span>vNnJ/gkCnoBNaaBWL/JgbdfQxF8PXMGXuoDvUFuePHwR7OY5xAoEGaVePw<span style="color:#555">==</span> </span></span><span style="display:flex;"><span>-----END PUBLIC KEY----- </span></span><span style="display:flex;"><span>/ $ cat /sealed/signing-secrets/cosign.key </span></span><span style="display:flex;"><span>-----BEGIN ENCRYPTED SIGSTORE PRIVATE KEY----- </span></span><span style="display:flex;"><span>eyJrZGYiOnsibmFtZSI6InNjcnlwdCIsInBhcmFtcyI6eyJOIjo2NTUzNiwiciI6 </span></span><span style="display:flex;"><span>OCwicCI6MX0sInNhbHQiOiJYMVV6d0h3Uy9iUTJNa1FDV2NsUmFZRkdLTnpTTnJz </span></span><span style="display:flex;"><span>cy8yOFRyWEw2eEgwPSJ9LCJjaXBoZXIiOnsibmFtZSI6Im5hY2wvc2VjcmV0Ym94 </span></span><span style="display:flex;"><span>Iiwibm9uY2UiOiI2bjhtSDRna2ZzaGQ3L3pBbTdOVk93WnNycVZVL3FNdCJ9LCJj </span></span><span style="display:flex;"><span>aXBoZXJ0ZXh0IjoiZERuaXZWWDRSZnZ6b2tTS2RVaUNRZG5taksxckd6SmlmMmVM </span></span><span style="display:flex;"><span>dWxudmo3dzFnbnpMMFdGdnhpRW16MUthc1RscjlhVDg3bFhoVGtqZmpRYU1pL3hT </span></span><span style="display:flex;"><span>NHkrRi9RMm5yc0xvcUNLUnNsREdOL016UnlBZjdXQkp4dU9jMGZtdWFiL1ZuM1lJ </span></span><span style="display:flex;"><span>aWVDOTBzdjhzZC9TdzBmWi8rVjJrUkEvRStkQk1QZmdUSnFqTzdwSUFoTWNVR01s </span></span><span style="display:flex;"><span>YlEyaWxmS01WempUR1hYbk5iODVwUEk2OHc9PSJ9 </span></span><span style="display:flex;"><span>-----END ENCRYPTED SIGSTORE PRIVATE KEY----- </span></span><span style="display:flex;"><span>/ $ </span></span><span style="display:flex;"><span> </span></span><span style="display:flex;"><span>uname -a </span></span><span style="display:flex;"><span>Linux tekton-chains-controller-5c6c9684-cl4dn 6.11.5-100.fc39.x86_64 <span style="color:#09f;font-style:italic">#1 SMP PREEMPT_DYNAMIC Tue Oct 22 19:26:45 UTC 2024 x86_64 Linux</span> </span></span><span style="display:flex;"><span> </span></span><span style="display:flex;"><span> </span></span><span style="display:flex;"><span><span style="color:#09f;font-style:italic"># The unsealed secrets are in memory</span> </span></span><span style="display:flex;"><span> </span></span><span style="display:flex;"><span>/ $ df -h </span></span><span style="display:flex;"><span>Filesystem Size Used Available Use% Mounted on </span></span><span style="display:flex;"><span>overlay 5.9G 166.5M 5.7G 3% / </span></span><span style="display:flex;"><span>tmpfs 64.0M <span style="color:#f60">0</span> 64.0M 0% /dev </span></span><span style="display:flex;"><span>tmpfs 5.9G 166.5M 5.7G 3% /sealed/signing-secrets </span></span><span style="display:flex;"><span>tmpfs 5.9G 166.5M 5.7G 3% /etc/hosts </span></span><span style="display:flex;"><span>tmpfs 5.9G 166.5M 5.7G 3% /dev/termination-log </span></span><span style="display:flex;"><span>tmpfs 5.9G 166.5M 5.7G 3% /etc/hostname </span></span><span style="display:flex;"><span>tmpfs 5.9G 166.5M 5.7G 3% /etc/resolv.conf </span></span><span style="display:flex;"><span>shm 14.7G <span style="color:#f60">0</span> 14.7G 0% /dev/shm </span></span><span style="display:flex;"><span>tmpfs 5.9G 166.5M 5.7G 3% /var/run/sigstore/cosign </span></span><span style="display:flex;"><span>tmpfs 5.9G 166.5M 5.7G 3% /var/run/secrets/kubernetes.io/serviceaccount </span></span><span style="display:flex;"><span>tmpfs 64.0M <span style="color:#f60">0</span> 64.0M 0% /proc/kcore </span></span><span style="display:flex;"><span>tmpfs 64.0M <span style="color:#f60">0</span> 64.0M 0% /proc/keys </span></span><span style="display:flex;"><span>tmpfs 64.0M <span style="color:#f60">0</span> 64.0M 0% /proc/latency_stats </span></span><span style="display:flex;"><span>tmpfs 64.0M <span style="color:#f60">0</span> 64.0M 0% /proc/timer_list </span></span></code></pre></div><hr> <p>The following screenshot shows the CVM running the container workload - <code>podvm-tekton-chains-controller-....</code> using an <code>&quot;r6a&quot;</code> instance type which is an AMD SNP confidential compute instance.</p> <div align="center"> <img src="./image6.png"> </div> <div align="center"> <img src="./image7.png"> </div> <h3 id="references">References</h3> <p><a href="https://github.com/tektoncd/chains">https://github.com/tektoncd/chains</a></p> <p><a href="https://tekton.dev/docs/getting-started/supply-chain-security/">https://tekton.dev/docs/getting-started/supply-chain-security/</a></p> <p><a href="https://github.com/confidential-containers/guest-components/blob/main/confidential-data-hub/docs/SEALED_SECRET.md">https://github.com/confidential-containers/guest-components/blob/main/confidential-data-hub/docs/SEALED_SECRET.md</a></p> <p><a href="https://opensource.googleblog.com/2023/03/getting-to-slsa-level-2-with-tekton-and-tekton-chains.html">https://opensource.googleblog.com/2023/03/getting-to-slsa-level-2-with-tekton-and-tekton-chains.html</a></p> <p><a href="https://github.com/tektoncd/operator/pull/2441">https://github.com/tektoncd/operator/pull/2441</a></p> Blog: Migration to Github Container Registry https://tekton.dev/blog/2025/04/03/migration-to-github-container-registry/ Thu, 03 Apr 2025 00:00:00 +0000 https://tekton.dev/blog/2025/04/03/migration-to-github-container-registry/ <h2 id="why-and-how">Why and How</h2> <p>Dear Tekton users and contributors, to reduce costs, we&rsquo;ve migrated all our releases to the free tier on <a href="http://ghcr.io/tektoncd">ghcr.io/tektoncd</a>.</p> <p>All new Tekton releases are exclusively on <a href="http://ghcr.io/tektoncd">ghcr.io/tektoncd</a>. Old releases are also now available on <a href="http://ghcr.io/tektoncd">ghcr.io/tektoncd</a>.</p> <p>Please migrate your old releases to ghcr.io immediately since we have limited funding to allocate to gcr.io egress.</p> <p>To migrate you need to replace <code>gcr.io/tekton-releases</code> with <code>ghcr.io/tektoncd</code> in all your images including all image references in the manifests, not only those that specify the <code>image</code> of the deployment, e.g. in the Tekton pipelines controller deployment:</p> <div class="highlight"><pre tabindex="0" style="background-color:#f0f3f3;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-yaml" data-lang="yaml"><span style="display:flex;"><span><span style="color:#309;font-weight:bold">containers</span>:<span style="color:#bbb"> </span></span></span><span style="display:flex;"><span><span style="color:#bbb"></span>- <span style="color:#309;font-weight:bold">name</span>:<span style="color:#bbb"> </span>tekton-pipelines-controller<span style="color:#bbb"> </span></span></span><span style="display:flex;"><span><span style="color:#bbb"> </span><span style="color:#309;font-weight:bold">image</span>:<span style="color:#bbb"> </span>ghcr.io/tektoncd/pipeline/controller-... <span style="color:#bbb"> </span><span style="color:#09f;font-style:italic"># &lt;&lt;== HERE</span><span style="color:#bbb"> </span></span></span><span style="display:flex;"><span><span style="color:#bbb"> </span><span style="color:#309;font-weight:bold">args</span>:<span style="color:#bbb"> </span>[<span style="color:#bbb"> </span></span></span><span style="display:flex;"><span><span style="color:#bbb"> </span><span style="color:#c30">&#34;-entrypoint-image&#34;</span>,<span style="color:#bbb"> </span><span style="color:#c30">&#34;ghcr.io/tektoncd/pipeline/entrypoint-...&#34;</span>,<span style="color:#bbb"> </span><span style="color:#09f;font-style:italic"># &lt;&lt;== HERE</span><span style="color:#bbb"> </span></span></span><span style="display:flex;"><span><span style="color:#bbb"> </span><span style="color:#c30">&#34;-nop-image&#34;</span>,<span style="color:#bbb"> </span><span style="color:#c30">&#34;ghcr.io/tektoncd/pipeline/nop-...&#34;</span>,<span style="color:#bbb"> </span><span style="color:#09f;font-style:italic"># &lt;&lt;== HERE</span><span style="color:#bbb"> </span></span></span><span style="display:flex;"><span><span style="color:#bbb"> </span><span style="color:#c30">&#34;-sidecarlogresults-image&#34;</span>,<span style="color:#bbb"> </span><span style="color:#c30">&#34;ghcr.io/tektoncd/pipeline/side...&#34;</span>,<span style="color:#bbb"> </span><span style="color:#09f;font-style:italic"># &lt;&lt;== HERE</span><span style="color:#bbb"> </span></span></span><span style="display:flex;"><span><span style="color:#bbb"> </span><span style="color:#c30">&#34;-workingdirinit-image&#34;</span>,<span style="color:#bbb"> </span><span style="color:#c30">&#34;ghcr.io/tektoncd/pipeline/working...&#34;</span>,<span style="color:#bbb"> </span><span style="color:#09f;font-style:italic"># &lt;&lt;== HERE</span><span style="color:#bbb"> </span></span></span><span style="display:flex;"><span><span style="color:#bbb"> </span><span style="color:#09f;font-style:italic"># ...</span><span style="color:#bbb"> </span></span></span><span style="display:flex;"><span><span style="color:#bbb"></span>]<span style="color:#bbb"> </span></span></span></code></pre></div><p>Find all the gcr entries in other components and update them similar to the Tekton pipelines controller.</p> <p>In general the change should resemble this:</p> <div class="highlight"><pre tabindex="0" style="background-color:#f0f3f3;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-sh" data-lang="sh"><span style="display:flex;"><span><span style="color:#09f;font-style:italic"># old</span> </span></span><span style="display:flex;"><span>gcr.io/tekton-releases/github/tektoncd/pipeline/cmd/entrypoint:v0.9.2 </span></span><span style="display:flex;"><span> </span></span><span style="display:flex;"><span><span style="color:#09f;font-style:italic"># new</span> </span></span><span style="display:flex;"><span>ghcr.io/tektoncd/github.com/tektoncd/pipeline/cmd/entrypoint:v0.9.2 </span></span></code></pre></div><p>You could run:</p> <div class="highlight"><pre tabindex="0" style="background-color:#f0f3f3;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-sh" data-lang="sh"><span style="display:flex;"><span>sed -e <span style="color:#c30">&#39;s,gcr.io/tekton-releases,ghcr.io/tektoncd,g&#39;</span> </span></span></code></pre></div><h3 id="images-relocated">Images relocated</h3> <p>During the migration some images has been moved to a sub folder new location and must be also renamed during the override</p> <ul> <li>Operator job Pruner <code>/tektoncd/dogfooding/tkn</code> becomes <code>/tektoncd/plumbing/tkn</code></li> </ul> <p>Other images path remains the same.</p> <h2 id="end-of-life-releases">End of Life Releases</h2> <p>We started enforcing the download of Tekton images from <code>ghcr.io</code>.</p> <p>Here are the details of what changed:</p> <ul> <li>Tekton LTS releases originally released to <code>gcr.io</code> will remain available on <code>gcr.io</code> until the EOL date.</li> <li>The same images are available on <code>ghcr.io</code>, so we ask users to please update their manifests and download images from <code>ghcr.io</code> to save egress bandwidth costs.</li> <li>Any EOL Tekton release will only be available on <code>ghcr.io</code>.</li> <li>Images on <code>gcr.io</code> will be removed from public access over the next few days.</li> <li>New releases will only be made on <code>ghcr.io</code>, so no action is required.</li> </ul> <p>Please feel free to reach out to us via <a href="https://github.com/tektoncd/community/blob/main/contact.md#slack">Slack</a> or our <a href="https://github.com/tektoncd/community/blob/main/contact.md#mailing-list">mailing list</a> if you have any questions.</p> <p>The original info mails were sent on our mailing list and if you&rsquo;re in our google group you can read them <a href="https://groups.google.com/g/tekton-dev/c/RoEFXeNZjKE">here</a>.</p> Blog: Speeding Up Container Image Builds in Tekton Pipelines https://tekton.dev/blog/2023/11/02/speeding-up-container-image-builds-in-tekton-pipelines/ Thu, 02 Nov 2023 00:00:00 +0000 https://tekton.dev/blog/2023/11/02/speeding-up-container-image-builds-in-tekton-pipelines/ <h2 id="overview">Overview</h2> <p>When DevOps or developer teams evaluate the move from a persistent CI server (or a CI server using persistent workers) to a system using non-persistent workers backed by Kubernetes pods, such as Tekton Pipelines, they might also wonder how to speed up container image building using cached layers. While using cached layers is relatively easy when builds always run on the same server where layers can be stored locally, it is more challenging in an environment where the builds are run in non-persistent containers on Kubernetes. This article will show how to use Kaniko caching capabilities to speed up builds in your Tekton Pipeline.</p> <p><img src="image1.png" alt="alt_text" title="Speed Up Container Image Builds in Tekton Pipelines"></p> <h2 id="tekton-pipelines">Tekton Pipelines</h2> <p><a href="https://tekton.dev/">Tekton</a> is a powerful and flexible, open source, cloud-native framework for creating CI/CD systems, allowing developers to build, test, and deploy across cloud providers and on-premise systems.</p> <p>Tekton consists of multiple projects. Among them is <a href="https://tekton.dev/docs/pipelines/pipelines/">Tekton Pipelines</a>, which provides the basic building blocks, in the form of Kubernetes CRDs, for creating CI/CD pipelines, whose tasks run as pods managed and orchestrated by Kubernetes.</p> <p>The main building blocks are:</p> <ul> <li><strong>Step</strong>: smaller execution unit of a pipeline, is a Kubernetes container specification and includes the container image and all the info you need to run it, as the command or environment variables. It defines a step of your pipeline as “mvn package” or “docker build”. It is defined inside the Task Kubernetes custom resource.</li> <li><strong>Task</strong>: Kubernetes custom resource, defines a sequence of Steps running in sequential order on a single pod in the same Kubernetes node.</li> <li><strong>Pipeline</strong>: A group of tasks that you can configure to run in parallel or in sequence, it represents your CI/CD pipeline.</li> <li><strong>TaskRun</strong>: Specific instance of a Task, linking it to parameters related to a specific environment or application. (For example: git repository, target container image to build, or target environment to deploy to.)</li> <li><strong>PipelineRun</strong>: Specific instance of a Pipeline associating it to parameters.</li> </ul> <p>You will find more information and tutorials in the <a href="https://tekton.dev/docs/">Tekton Documentation</a></p> <h2 id="speeding-up-container-image-builds-on-tekton">Speeding up container image builds on Tekton</h2> <p>Running build steps as containers in Kubernetes has multiple advantages like portability, reusability, and the possibility to leverage all the capabilities of the underlying Kubernetes platform, but since these containers aren’t persistent by nature, optimizing the build execution through caching would need some additional actions compared to what you were used to do in a standalone CI server.</p> <p>In the following sections, you will see some examples of how to use caching to speed up image builds in Tekton pipelines using Kaniko. <a href="https://github.com/GoogleContainerTools/kaniko">Kaniko</a> is an open source tool that can be used to build container images from a Dockerfile. It doesn’t require a Docker daemon to run, which makes it ideal for building images in environments where Docker daemons aren’t available or can’t be run, such as Kubernetes clusters.</p> <p>To run through the examples you will need a Kubernetes cluster with <a href="https://tekton.dev/docs/installation/pipelines/">Tekton Pipelines installed</a>, a git-based Source Code Management (SCM), and a container registry with permissions to push artifacts. I used a GKE cluster on Google Cloud, a GitHub repository, and Artifact Registry, but steps are reproducible on any standard Kubernetes platform, git based SCM, and container registry with null or minimal modifications.</p> <p>Example code and assets are available in the: <a href="https://github.com/tektoncd/website/tree/main/content/en/blog/2023/speeding-up-container-image-builds-in-tekton-pipelines/tekton-speed-builds">tekton-speed-builds</a> folder of the <a href="https://github.com/tektoncd/website">Tekton CD Website repo</a></p> <p>To follow along you need to clone the <a href="https://github.com/tektoncd/website">Tekton CD Website repo</a> locally and then copy and activate the <a href="https://github.com/tektoncd/website/tree/main/content/en/blog/2023/speeding-up-container-image-builds-in-tekton-pipelines/tekton-speed-builds">tekton-speed-builds</a> folder as a new repo in your personal GitHub account or other git-based SCM if different.</p> <h3 id="experiment-the-default-behavior">Experiment the default behavior</h3> <p>After you have your copy of the example repository clone it locally and look at its content:</p> <ul> <li>The <a href="https://github.com/tektoncd/website/tree/main/content/en/blog/2023/speeding-up-container-image-builds-in-tekton-pipelines/tekton-speed-builds/sample-app">sample-app</a> folder contains source code, Maven project files, and a Dockerfile for an example Spring Boot Java app. Look at the <a href="https://github.com/tektoncd/website/tree/main/content/en/blog/2023/speeding-up-container-image-builds-in-tekton-pipelines/tekton-speed-builds/sample-app/Dockerfile">Dockerfile</a>: it’s multi-staged using the <code>maven</code> base image for packaging your code and the <code>eclipse-temurin:19-jdk-alpine</code> one to run your application:</li> </ul> <pre tabindex="0"><code>FROM maven as build COPY mvnw . COPY pom.xml . COPY src src RUN mvn package -Dmaven.test.skip=true FROM eclipse-temurin:19-jdk-alpine COPY --from=build /target/demo-0.0.1-SNAPSHOT.jar app.jar CMD [&#34;java&#34;, &#34;-jar&#34;, &#34;app.jar&#34;] </code></pre><ul> <li>The <a href="https://github.com/tektoncd/website/tree/main/content/en/blog/2023/speeding-up-container-image-builds-in-tekton-pipelines/tekton-speed-builds/tekton-assets">tekton-assets</a> folders contain resource manifests for the Tekton assets used in this article: <ul> <li><a href="https://github.com/tektoncd/website/tree/main/content/en/blog/2023/speeding-up-container-image-builds-in-tekton-pipelines/tekton-speed-builds/tekton-assets/pipeline.yaml">pipeline.yaml</a> defines a pipeline running 2 Tasks: <ul> <li><a href="https://github.com/tektoncd/website/tree/main/content/en/blog/2023/speeding-up-container-image-builds-in-tekton-pipelines/tekton-speed-builds/tekton-assets/git-clone.yaml">git-clone.yaml</a> clones the example repo to the source Tekton workspace</li> <li><a href="https://github.com/tektoncd/website/tree/main/content/en/blog/2023/speeding-up-container-image-builds-in-tekton-pipelines/tekton-speed-builds/tekton-assets/image-build.yaml">image-build.yaml</a> runs Kaniko to build a container image from the source code cloned in the workspace and push it to the target container registry</li> </ul> </li> <li><a href="https://github.com/tektoncd/website/tree/main/content/en/blog/2023/speeding-up-container-image-builds-in-tekton-pipelines/tekton-speed-builds/tekton-assets/source-pvc.yaml">source-pvc.yaml</a> is the manifest for the source-pvc persistent volume claim that will be used as persistent storage for the source Tekton workspace. The storage class is intentionally not defined to make it portable so it will use whatever is the default on your cluster, you can modify the manifest to use your preferred storage class.</li> </ul> </li> <li>The <a href="https://github.com/tektoncd/website/tree/main/content/en/blog/2023/speeding-up-container-image-builds-in-tekton-pipelines/tekton-speed-builds/kaniko-basecache">kaniko-basecache</a>, <a href="https://github.com/tektoncd/website/tree/main/content/en/blog/2023/speeding-up-container-image-builds-in-tekton-pipelines/tekton-speed-builds/kaniko-cache">kaniko-cache</a>, and <a href="https://github.com/tektoncd/website/tree/main/content/en/blog/2023/speeding-up-container-image-builds-in-tekton-pipelines/tekton-speed-builds/m2cache">m2cache</a> folders contain example resources useful to implement the various caching options.</li> </ul> <p>Let’s create the needed Tekton resources and run our pipeline. From your locally cloned repository, apply the resources in the tekton-assets folder to your cluster:</p> <pre tabindex="0"><code>kubectl apply -f tekton-assets </code></pre><p>This will create the pvc, tasks, and pipeline described above.</p> <p>Now let’s start our pipeline manually. Depending on your configuration you may need to specify, using the -s parameter, a Service Account to authenticate to the registry to push the image, check <a href="https://tekton.dev/docs/how-to-guides/kaniko-build-push/#container-registry-authentication">this section</a> of the Tekton docs for more info.</p> <p>Type the following command to start the pipeline</p> <pre tabindex="0"><code>tkn pipeline start pipeline-clone-and-build --workspace name=source,claimName=source-pvc --showlog </code></pre><p>When prompted for the value of the <code>git-url</code> parameter, type your git repository url.</p> <p>When prompted for the value of the <code>image-name</code> parameter, type your container image url including the repo and image name.</p> <p>Here’s an example configuration:</p> <pre tabindex="0"><code>➜ ~ tkn pipeline start pipeline-clone-and-build --workspace name=source,claimName=source-pvc --showlog ? Value for param `git-url` of type `string`? https://github.com/ggalloro/tekton-speed-builds ? Value for param `image-name` of type `string`? europe-west1-docker.pkg.dev/galloro-demos/tektoncd/javasample </code></pre><p>The pipeline will start and you will see the output of the steps executed.</p> <p>If your pipeline run is successful the last step of the image-build task will print your image url in the console and you will have your image pushed to your target registry:</p> <pre tabindex="0"><code>[image-build : write-url] europe-west1-docker.pkg.dev/galloro-demos/tektoncd/javasample:457848d </code></pre><p>The pipeline execution created 2 TaskRun resources to execute the 2 tasks, type the following command to see the TaskRun information:</p> <pre tabindex="0"><code>tkn tr ls </code></pre><p>You will get an output similar to the one below:</p> <pre tabindex="0"><code>NAME STARTED DURATION STATUS pipeline-clone-and-build-run-68hjg-image-build 4 minutes ago 50s Succeeded pipeline-clone-and-build-run-68hjg-git-clone 4 minutes ago 11s Succeeded </code></pre><p>Since your build will always run in a new container, if you change just a line in your source code your build will always need to download the base images and the Maven dependencies and can’t leverage any cache, let’s try that.</p> <p>Change the text in line 25 of the <a href="https://github.com/tektoncd/website/tree/main/content/en/blog/2023/speeding-up-container-image-builds-in-tekton-pipelines/tekton-speed-builds/sample-app/src/main/resources/templates/index.html">index.html</a> file in <a href="https://github.com/tektoncd/website/tree/main/content/en/blog/2023/speeding-up-container-image-builds-in-tekton-pipelines/tekton-speed-builds/sample-app/src/main/resources/templates">sample-app/src/main/resources/templates</a> to “Hello, Slow Builder!”</p> <p>Commit your change and push it to your remote repository:</p> <pre tabindex="0"><code>git add . git commit -m &#34;change to index.html&#34; git push </code></pre><p>Start your pipeline again following the same instructions given above.</p> <p>After the Pipeline run completes look at your TasRuns info again:</p> <pre tabindex="0"><code>NAME STARTED DURATION STATUS pipeline-clone-and-build-run-fnzxj-image-build 55 seconds ago 49s Succeeded pipeline-clone-and-build-run-fnzxj-git-clone 1 minute ago 12s Succeeded pipeline-clone-and-build-run-68hjg-image-build 4 minutes ago 50s Succeeded pipeline-clone-and-build-run-68hjg-git-clone 4 minutes ago 11s Succeeded </code></pre><p>As you can see, even if you change just one line of code, the build needs approximately the same time to execute. In the next sections, we will explore the options to optimize build speed through caching.</p> <h3 id="caching-layers-in-a-container-registry">Caching layers in a container registry</h3> <p>Kaniko can cache layers created by RUN and COPY commands in a remote repository. Before running a command, Kaniko checks the cache for the layer. If the layer exists in the cache, Kaniko will pull and extract it instead of running the command. If the layer doesn’t exist in the cache, Kaniko will run the command and then push the newly created layer to the cache.</p> <p>This can help speed up builds in Tekton.</p> <p>To use Kaniko cache you must add the <code>--cache=true</code> flag to Kaniko in our image-build Task so the build-and-push step reads as follows:</p> <pre tabindex="0"><code>- name: build-and-push workingDir: $(workspaces.source.path)/sample-app/ image: gcr.io/kaniko-project/executor:latest args: - --dockerfile=$(params.DOCKERFILE) - --context=$(params.CONTEXT) # The user does not need to care the workspace and the source. - --destination=$(params.IMAGE):$(params.commit) - --digest-file=$(results.IMAGE_DIGEST.path) - --cache=true securityContext: runAsUser: 0 </code></pre><p>To do that you can apply the modified <a href="https://github.com/tektoncd/website/tree/main/content/en/blog/2023/speeding-up-container-image-builds-in-tekton-pipelines/tekton-speed-builds/kaniko-cache/image-build-cache.yaml">image-build-cache.yaml</a> in the <a href="https://github.com/tektoncd/website/tree/main/content/en/blog/2023/speeding-up-container-image-builds-in-tekton-pipelines/tekton-speed-builds/kaniko-cache">kaniko-cache</a> folder to update the image-build Task:</p> <pre tabindex="0"><code>kubectl apply -f kaniko-cache/image-build-cache.yaml </code></pre><p>To leverage Kaniko layer caching capabilities you should also properly configure your Dockerfile to move the directives that are unlikely to change between builds to the top and the ones that are likely to change to the bottom.</p> <p>Let’s edit the Dockerfile in the sample-app directory to separate the Maven dependency download from the code build so the dependencies are cached in a separate layer from the software artifact and any change to the code won’t cause the dependencies to be downloaded again. Add the <code>RUN mvn dependency:go-offline</code> line to your Dockerfile so it reads as follows:</p> <pre tabindex="0"><code>FROM maven as build COPY mvnw . COPY pom.xml . RUN mvn dependency:go-offline COPY src src RUN mvn package -Dmaven.test.skip=true FROM eclipse-temurin:19-jdk-alpine COPY --from=build /target/demo-0.0.1-SNAPSHOT.jar app.jar CMD [&#34;java&#34;, &#34;-jar&#34;, &#34;app.jar&#34;] </code></pre><p>Once you changed your Dockerfile you need to commit and push your changes so your build will use it:</p> <pre tabindex="0"><code>git add . git commit -m &#34;update to Dockerfile&#34; git push </code></pre><p>Now run your pipeline again as you did before, the first execution output should be similar to the previous run, and all the dependencies will be downloaded.</p> <p>Let’s look at the TaskRun info. The build duration should be similar to the previous as well (although it might be a bit longer due to the upload of layers to the registry):</p> <pre tabindex="0"><code>NAME STARTED DURATION STATUS pipeline-clone-and-build-run-gsgwx-image-build 1 minute ago 58s Succeeded pipeline-clone-and-build-run-gsgwx-git-clone 1 minute ago 17s Succeeded pipeline-clone-and-build-run-fnzxj-image-build 55 seconds ago 49s Succeeded pipeline-clone-and-build-run-fnzxj-git-clone 1 minute ago 12s Succeeded pipeline-clone-and-build-run-68hjg-image-build 4 minutes ago 50s Succeeded pipeline-clone-and-build-run-68hjg-git-clone 4 minutes ago 11s Succeeded </code></pre><p>The image layers have been uploaded to your registry, as you can see in the picture below for Artifact Registry (javasample/cache folder):</p> <p><img src="image2.png" alt="alt_text" title="Cache foolder in registry"></p> <p>Now let’s update the code (use “Hello, Fast Builder!” this time), commit your changes, and run the pipeline again following the instructions from the previous section. From the output log, you should note that the bulk of dependencies will not be downloaded again and the cached layer should be used:</p> <p><img src="image3.png" alt="alt_text" title="Using cached layer"></p> <p>The image-build TaskRun execution should be faster compared to the previous execution (42 vs 58 sec in this example):</p> <pre tabindex="0"><code>NAME STARTED DURATION STATUS pipeline-clone-and-build-run-5s87p-image-build 1 minute ago 42s Succeeded pipeline-clone-and-build-run-5s87p-git-clone 1 minute ago 17s Succeeded pipeline-clone-and-build-run-gsgwx-image-build 7 minutes ago 58s Succeeded pipeline-clone-and-build-run-gsgwx-git-clone 7 minutes ago 17s Succeeded pipeline-clone-and-build-run-fnzxj-image-build 18 minutes ago 49s Succeeded pipeline-clone-and-build-run-fnzxj-git-clone 18 minutes ago 12s Succeeded pipeline-clone-and-build-run-68hjg-image-build 21 minutes ago 50s Succeeded pipeline-clone-and-build-run-68hjg-git-clone 22 minutes ago 11s Succeeded </code></pre><p>You have experienced how enabling caching layers to a container registry can improve your build speed on Tekton, the effective speed gain would depend on various factors such as project configuration and connection to your registry.</p> <h3 id="caching-base-images-on-a-persistent-disk">Caching base images on a persistent disk</h3> <p>In addition to cache layers on your container registry, Kaniko can use a persistent volume to store cached base images. By default, Kaniko will look for cached base images in the <code>/cache</code> folder but you can customize that with the <code>--cache-dir</code> flag.</p> <p>The persistent volume must be populated before usage, Kaniko provides an image for doing that: <code>gcr.io/kaniko-project/warmer</code></p> <p>Let’s add a volume mount mapping the <code>/cache</code> path to a PVC named <code>basechache-pvc</code> to our build-image Task:</p> <pre tabindex="0"><code>- name: build-and-push workingDir: $(workspaces.source.path)/sample-app/ image: gcr.io/kaniko-project/executor:latest args: - --dockerfile=$(params.DOCKERFILE) - --context=$(params.CONTEXT) # The user does not need to care the workspace and the source. - --destination=$(params.IMAGE):$(params.commit) - --digest-file=$(results.IMAGE_DIGEST.path) - --cache=true # kaniko assumes it is running as root, which means this example fails on platforms # that default to run containers as random uid (like OpenShift). Adding this securityContext # makes it explicit that it needs to run as root. securityContext: runAsUser: 0 volumeMounts: - name: basecache mountPath: /cache - name: write-url image: docker.io/library/bash:5.1.4@sha256:b208215a4655538be652b2769d82e576bc4d0a2bb132144c060efc5be8c3f5d6 script: | set -e image=&#34;$(params.IMAGE):$(params.commit)&#34; echo -n &#34;${image}&#34; | tee &#34;$(results.IMAGE_URL.path)&#34; volumes: - name: basecache persistentVolumeClaim: claimName: basecache-pvc </code></pre><p>To do that you can apply the modified <a href="https://github.com/tektoncd/website/tree/main/content/en/blog/2023/speeding-up-container-image-builds-in-tekton-pipelines/tekton-speed-builds/kaniko-basecache/image-build-basecache.yaml">image-build-basecache.yaml</a> in the <a href="https://github.com/tektoncd/website/tree/main/content/en/blog/2023/speeding-up-container-image-builds-in-tekton-pipelines/tekton-speed-builds/kaniko-basecachespeed-builds/tree/main/kaniko-cache">kaniko-basecache</a> folder to update the image-build Task:</p> <pre tabindex="0"><code>kubectl apply -f kaniko-basecache/image-build-basecache.yaml </code></pre><p>Now let’s create the basecache-pvc PVC:</p> <pre tabindex="0"><code>kubectl apply -f kaniko-basecache/pvc-basecache.yaml </code></pre><p>Then, run the <code>kaniko-warmer</code> pod to populate the disk:</p> <pre tabindex="0"><code>kubectl apply -f kaniko-basecache/kaniko-warmer.yaml </code></pre><p>Check the <code>kaniko-warmer</code> pod logs:</p> <pre tabindex="0"><code>kubectl logs -f kaniko-warmer </code></pre><p>Until you get the output confirming that the 2 base images have been downloaded</p> <pre tabindex="0"><code>INFO[0000] Retrieving image manifest maven INFO[0000] Retrieving image maven from registry index.docker.io INFO[0004] Retrieving image manifest eclipse-temurin:19-jdk-alpine INFO[0004] Retrieving image eclipse-temurin:19-jdk-alpine from registry index.docker.io </code></pre><p>When done you can make a change to your code again (“Hello, Base Builder!”) commit it and start your pipeline again as done in the previous tests.</p> <p>This execution will leverage cached layers as the previous one and, in addition to that, will use the base images from your <code>basecache-pvc</code> persistent volume, as you can see in the output:</p> <p><img src="image4.png" alt="alt_text" title="Using base image cache"></p> <p>Even in this case, the speed improvement will depend on various factors such as how big your base images are, storage performance, and your registry connection.</p> <h3 id="caching-dependencies-on-a-persistent-disk">Caching dependencies on a persistent disk</h3> <p>Another option to speed up builds is to cache dependencies locally. In our example Maven project we can leverage the fact that by default, maven caches the dependency modules into $HOME/.m2 directory. This possibility depends on the language and build tools you are using.</p> <p>In this example, we will add another persistent volume to the build-image task and map it to the /root/.m2 folder to persist the Maven cache between builds.</p> <p>Let’s apply the modified <a href="https://github.com/tektoncd/website/tree/main/content/en/blog/2023/speeding-up-container-image-builds-in-tekton-pipelines/tekton-speed-builds/m2cache/image-build-m2cache.yaml">image-build-m2cache.yaml</a> in the <a href="https://github.com/tektoncd/website/tree/main/content/en/blog/2023/speeding-up-container-image-builds-in-tekton-pipelines/tekton-speed-builds/m2cache">m2cache</a> folder to update the image-build Task:</p> <pre tabindex="0"><code>kubectl apply -f m2cache/image-build-m2cache.yaml </code></pre><p>Now let’s create the <code>m2cache-pvc</code> PVC:</p> <pre tabindex="0"><code>kubectl apply -f m2cache/pvc-m2cache.yaml </code></pre><p>Since we don’t need to cache Maven dependencies in an image layer anymore, let’s remove the <code>RUN mvn dependency:go-offline </code>line<code> </code>from our Dockerfile and revert to its original structure. Commit and push your changes after that.</p> <p>Now run your pipeline again as you did before, Maven will download your dependencies again when the <code>mvn package</code> is run since your previously cached layer is not referenced anymore in your Dockerfile. Duration should be similar to our initial test.</p> <p>Make a change to your code again (“Hello, Very Fast Builder”), commit it, and start your pipeline again as done in the previous tests.</p> <p>This execution will leverage cached layers as the previous one and, in addition to that, will use the base images from your basecache-pvc persistent volume and cached dependencies.</p> <p>Even in this case, if you look at your TaskRun list, you should see a speed improvement compared to the first run:</p> <pre tabindex="0"><code>NAME STARTED DURATION STATUS pipeline-clone-and-build-run-lk8x2-image-build 1 minute ago 46s Succeeded pipeline-clone-and-build-run-lk8x2-git-clone 1 minute ago 14s Succeeded pipeline-clone-and-build-run-w7sd5-image-build 3 minutes ago 59s Succeeded pipeline-clone-and-build-run-w7sd5-git-clone 3 minutes ago 12s Succeeded </code></pre><h1 id="summary">Summary</h1> <p>You saw multiple options to leverage different types of caching to speed up image builds in Tekton using Kaniko:</p> <ul> <li>How to cache layers in your container registry</li> <li>How to use cached base images in a persistent volume</li> <li>How to host your local dependencies cache on a persistent volume</li> </ul> <p>Now, you are ready to speed up your build in Tekton !</p> <h3 id="note">Note</h3> <p>This blog was originally posted in the <a href="https://cd.foundation/blog/2023/10/12/speed-up-container-image-builds-tekton-pipelines/">Continuous Delivery Foundation Blog</a></p> Blog: Distributed Traces for Testing with Tekton Pipelines and Tracetest https://tekton.dev/blog/2023/08/15/distributed-traces-for-testing-with-tekton-pipelines-and-tracetest/ Tue, 15 Aug 2023 00:00:00 +0000 https://tekton.dev/blog/2023/08/15/distributed-traces-for-testing-with-tekton-pipelines-and-tracetest/ <p><a href="https://tekton.dev/">Tekton</a> is an <a href="https://github.com/tektoncd/pipeline">open-source framework</a> for creating efficient CI/CD systems. This empowers developers to seamlessly construct, test, and deploy applications across various cloud environments and on-premise setups.</p> <p><a href="https://tracetest.io">Tracetest</a>, an <a href="https://github.com/kubeshop/tracetest">open-source testing tool</a> that uses <a href="https://opentelemetry.io/">OpenTelemetry</a> traces for testing, offers a sophisticated test harness for distributed cloud-native apps. It empowers users to test their apps by harnessing data from distributed traces produced by OpenTelemetry. This enables creating test specs and assertions that validate whether an application aligns with the intended behavior, as defined by pre-established test parameters.</p> <h2 id="why-use-distributed-traces-for-testing">Why use distributed traces for testing?</h2> <p>The rationale behind integrating Tracetest with Tekton is compelling. Tracetest <a href="https://tracetest.io/features">uses pre-existing OpenTelemetry instrumentation</a> to execute assertions against every part of an HTTP transaction.</p> <p><a href="https://docs.tracetest.io/ci-cd-automation/tekton-pipeline">Combining Tracetest and Tekton</a> enables adding trace-based testing into CI/CD pipelines within your Kubernetes cluster. This integration not only furnishes the capability to initiate planned test cycles and synthetic testing but also preserves the core tenets of trace-based testing. It empowers exhaustive and in-depth assertions with trace data.</p> <h2 id="infrastructure-overview">Infrastructure Overview</h2> <p>The following is a high level sequence diagram on how Tekton and Tracetest interact with the different pieces of the system.</p> <p><img src="./tracetest-tekton-architecture-1.png" alt="tekton and tracetest architecture"></p> <h2 id="1-install-tekton-pipelines-triggers-and-dashboard">1. Install Tekton Pipelines, Triggers, and Dashboard</h2> <div class="highlight"><pre tabindex="0" style="background-color:#f0f3f3;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>kubectl apply --filename <span style="color:#c30;font-weight:bold">\ </span></span></span><span style="display:flex;"><span><span style="color:#c30;font-weight:bold"></span>https://storage.googleapis.com/tekton-releases/pipeline/latest/release.yaml </span></span><span style="display:flex;"><span> </span></span><span style="display:flex;"><span>kubectl apply --filename <span style="color:#c30;font-weight:bold">\ </span></span></span><span style="display:flex;"><span><span style="color:#c30;font-weight:bold"></span>https://storage.googleapis.com/tekton-releases/triggers/latest/release.yaml </span></span><span style="display:flex;"><span> </span></span><span style="display:flex;"><span>kubectl apply --filename <span style="color:#c30;font-weight:bold">\ </span></span></span><span style="display:flex;"><span><span style="color:#c30;font-weight:bold"></span>https://storage.googleapis.com/tekton-releases/triggers/latest/interceptors.yaml </span></span><span style="display:flex;"><span> </span></span><span style="display:flex;"><span>kubectl apply --filename <span style="color:#c30;font-weight:bold">\ </span></span></span><span style="display:flex;"><span><span style="color:#c30;font-weight:bold"></span>https://storage.googleapis.com/tekton-releases/dashboard/latest/release.yaml </span></span></code></pre></div><h2 id="2-install-tracetest-cli">2. Install Tracetest CLI</h2> <p>Install Tracetest CLI by following <a href="https://docs.tracetest.io/getting-started/installation">these instructions</a> for your OS.</p> <ul class="nav nav-tabs" id="tabs-0" role="tablist"><li class="nav-item"> <a class="nav-link active persistLang-bash" id="tabs-0-0-tab" data-toggle="tab" href="#tabs-0-0" role="tab" onclick="persistLang(&#34;bash&#34;);" aria-controls="tabs-0-0" aria-selected="false">MacOS</a> </li> <li class="nav-item"> <a class="nav-link persistLang-bash" id="tabs-0-1-tab" data-toggle="tab" href="#tabs-0-1" role="tab" onclick="persistLang(&#34;bash&#34;);" aria-controls="tabs-0-1" aria-selected="false">Linux</a> </li> <li class="nav-item"> <a class="nav-link persistLang-bash" id="tabs-0-2-tab" data-toggle="tab" href="#tabs-0-2" role="tab" onclick="persistLang(&#34;bash&#34;);" aria-controls="tabs-0-2" aria-selected="false">Windows</a> </li> </ul> <div class="tab-content" id="tabs-0-content"><div class="tab-body tab-pane fade show active" id="tabs-0-0" role="tabpanel" aria-labelled-by="tabs-0-0-tab"> brew install kubeshop/tracetest/tracetest </div> <div class="tab-body tab-pane fade" id="tabs-0-1" role="tabpanel" aria-labelled-by="tabs-0-1-tab"> curl -L https://raw.githubusercontent.com/kubeshop/tracetest/main/install-cli.sh | bash </div> <div class="tab-body tab-pane fade" id="tabs-0-2" role="tabpanel" aria-labelled-by="tabs-0-2-tab"> choco source add --name=kubeshop_repo --source=https://chocolatey.kubeshop.io/chocolatey ; choco install tracetest </div> </div> <h2 id="3-install-tracetest-in-your-kubernetes-cluster">3. Install Tracetest in Your Kubernetes Cluster</h2> <div class="highlight"><pre tabindex="0" style="background-color:#f0f3f3;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>tracetest server install </span></span><span style="display:flex;"><span> </span></span><span style="display:flex;"><span><span style="color:#555">[</span>Output<span style="color:#555">]</span> </span></span><span style="display:flex;"><span>How <span style="color:#069;font-weight:bold">do</span> you want to run TraceTest? <span style="color:#555">[</span><span style="color:#366">type</span> to search<span style="color:#555">]</span>: </span></span><span style="display:flex;"><span> Using Docker Compose </span></span><span style="display:flex;"><span>&gt; Using Kubernetes </span></span></code></pre></div><p>Select <code>Using Kubernetes</code>.</p> <div class="highlight"><pre tabindex="0" style="background-color:#f0f3f3;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>[Output] </span></span><span style="display:flex;"><span>Do you have OpenTelemetry based tracing already set up, or would you like us to install a demo tracing environment and app? [type to search]: </span></span><span style="display:flex;"><span> I have a tracing environment already. Just install Tracetest </span></span><span style="display:flex;"><span>&gt; Just learning tracing! Install Tracetest, OpenTelemetry Collector and the sample app. </span></span></code></pre></div><p>Select <code>Just learning tracing! Install Tracetest, OpenTelemetry Collector and the sample app.</code>.</p> <p>Confirm that Tracetest is running:</p> <div class="highlight"><pre tabindex="0" style="background-color:#f0f3f3;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>kubectl get all -n tracetest </span></span><span style="display:flex;"><span> </span></span><span style="display:flex;"><span><span style="color:#555">[</span>Output<span style="color:#555">]</span> </span></span><span style="display:flex;"><span>NAME READY STATUS RESTARTS AGE </span></span><span style="display:flex;"><span>pod/otel-collector-7f4d87489f-vp6zn 1/1 Running <span style="color:#f60">0</span> 5m41s </span></span><span style="display:flex;"><span>pod/tracetest-78b9c84c57-t4prx 1/1 Running <span style="color:#f60">3</span> <span style="color:#555">(</span>4m15s ago<span style="color:#555">)</span> 5m29s </span></span><span style="display:flex;"><span>pod/tracetest-postgresql-0 1/1 Running <span style="color:#f60">0</span> 5m42s </span></span><span style="display:flex;"><span> </span></span><span style="display:flex;"><span>NAME TYPE CLUSTER-IP EXTERNAL-IP PORT<span style="color:#555">(</span>S<span style="color:#555">)</span> AGE </span></span><span style="display:flex;"><span>service/otel-collector ClusterIP 10.96.173.226 &lt;none&gt; 4317/TCP 5m46s </span></span><span style="display:flex;"><span>service/tracetest ClusterIP 10.96.248.146 &lt;none&gt; 11633/TCP,4317/TCP 5m42s </span></span><span style="display:flex;"><span>service/tracetest-postgresql ClusterIP 10.96.155.147 &lt;none&gt; 5432/TCP 5m42s </span></span><span style="display:flex;"><span>service/tracetest-postgresql-hl ClusterIP None &lt;none&gt; 5432/TCP 5m42s </span></span><span style="display:flex;"><span> </span></span><span style="display:flex;"><span>NAME READY UP-TO-DATE AVAILABLE AGE </span></span><span style="display:flex;"><span>deployment.apps/otel-collector 1/1 <span style="color:#f60">1</span> <span style="color:#f60">1</span> 5m46s </span></span><span style="display:flex;"><span>deployment.apps/tracetest 1/1 <span style="color:#f60">1</span> <span style="color:#f60">1</span> 5m42s </span></span><span style="display:flex;"><span> </span></span><span style="display:flex;"><span>NAME DESIRED CURRENT READY AGE </span></span><span style="display:flex;"><span>replicaset.apps/otel-collector-7f4d87489f <span style="color:#f60">1</span> <span style="color:#f60">1</span> <span style="color:#f60">1</span> 5m46s </span></span><span style="display:flex;"><span>replicaset.apps/tracetest-78b9c84c57 <span style="color:#f60">1</span> <span style="color:#f60">1</span> <span style="color:#f60">1</span> 5m42s </span></span><span style="display:flex;"><span> </span></span><span style="display:flex;"><span>NAME READY AGE </span></span><span style="display:flex;"><span>statefulset.apps/tracetest-postgresql 1/1 5m42s </span></span></code></pre></div><p>By default, Tracetest is installed in the <code>tracetest</code> namespace.</p> <p>To explore the Tracetest Web UI, run the command:</p> <div class="highlight"><pre tabindex="0" style="background-color:#f0f3f3;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>kubectl --kubeconfig &lt;path-to-your-home&gt;/.kube/config --context &lt;your-cluster-context&gt; --namespace tracetest port-forward svc/tracetest <span style="color:#f60">11633</span> </span></span></code></pre></div><p><img src="./tracetest-web-ui-1.png" alt="Tracetest Web UI"></p> <h2 id="4-create-a-test-in-tracetest">4. Create a Test in Tracetest</h2> <p>Start by clicking <code>Create</code> &gt; <code>Create New Test</code> &gt; <code>HTTP Request</code> &gt; <code>Next</code> &gt; <code>Choose Example</code> (dropdown) &gt; <code>Pokeshop - List</code> (generates a sample test from the Tracetest demo) &gt; <code>Next</code> &gt; <code>URL</code> is prefilled with <code>http://demo-pokemon-api.demo/pokemon?take=20&amp;skip=0</code> &gt; <code>Create &amp; Run</code>.</p> <p>This will trigger the test and display a distributed trace in the <code>Trace</code> tab to run assertions against.</p> <p><img src="./tracetest-trace-view-2.png" alt="Tracetest distributed trace test run view"></p> <p>Proceed to add a test spec to assert all database queries return within 500 ms. Click the <code>Test</code> tab and proceed to click the <code>Add Test Spec</code> button.</p> <p>In the span selector make sure to add this selector:</p> <div class="highlight"><pre tabindex="0" style="background-color:#f0f3f3;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-css" data-lang="css"><span style="display:flex;"><span><span style="color:#309;font-weight:bold">span</span><span style="color:#555">[</span><span style="color:#309;font-weight:bold">tracetest</span>.<span style="color:#0a8;font-weight:bold">span</span>.<span style="color:#0a8;font-weight:bold">type</span><span style="color:#555">=</span><span style="color:#c30">&#34;database&#34;</span><span style="color:#555">]</span> </span></span></code></pre></div><p>In the assertion field add:</p> <div class="highlight"><pre tabindex="0" style="background-color:#f0f3f3;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-css" data-lang="css"><span style="display:flex;"><span><span style="color:#309;font-weight:bold">attr</span>:<span style="color:#99f">tracetest</span>.<span style="color:#0a8;font-weight:bold">span</span>.<span style="color:#0a8;font-weight:bold">duration</span> <span style="color:#555">&lt;</span> <span style="color:#309;font-weight:bold">500ms</span> </span></span></code></pre></div><p>Save the test spec and publish the test.</p> <p><img src="./tracetest-assertions-3.png" alt="Assertion for database queries"></p> <p>The database spans that are returning in less than <code>500ms</code> are labeled in green.</p> <p><img src="./tracetest-assertions-4.png" alt="Assertions failing"></p> <p>This is an example of a trace-based test that asserts against every single part of an HTTP transaction, including all interactions with the database.</p> <p>Let&rsquo;s introduce how Tekton makes it possible to run this test as part of your CI/CD pipeline.</p> <h2 id="5-create-a-task-in-tekton">5. Create a Task in Tekton</h2> <p>Click the <code>Automate</code> tab.</p> <p><img src="./tracetest-automate-5.png" alt="test automate"></p> <p>This contains both a YAML definition for the test run and a guide how to run the test with the Tracetest CLI.</p> <p>Save this into a file called <code>test-api.yaml</code>:</p> <div class="highlight"><pre tabindex="0" style="background-color:#f0f3f3;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-yaml" data-lang="yaml"><span style="display:flex;"><span><span style="color:#09f;font-style:italic"># test-api.yaml</span><span style="color:#bbb"> </span></span></span><span style="display:flex;"><span><span style="color:#bbb"> </span></span></span><span style="display:flex;"><span><span style="color:#bbb"></span><span style="color:#309;font-weight:bold">type</span>:<span style="color:#bbb"> </span>Test<span style="color:#bbb"> </span></span></span><span style="display:flex;"><span><span style="color:#bbb"></span><span style="color:#309;font-weight:bold">spec</span>:<span style="color:#bbb"> </span></span></span><span style="display:flex;"><span><span style="color:#bbb"> </span><span style="color:#309;font-weight:bold">id</span>:<span style="color:#bbb"> </span>L7wr5xeVR<span style="color:#bbb"> </span></span></span><span style="display:flex;"><span><span style="color:#bbb"> </span><span style="color:#309;font-weight:bold">name</span>:<span style="color:#bbb"> </span>Pokeshop - List<span style="color:#bbb"> </span></span></span><span style="display:flex;"><span><span style="color:#bbb"> </span><span style="color:#309;font-weight:bold">description</span>:<span style="color:#bbb"> </span>Get a Pokemon<span style="color:#bbb"> </span></span></span><span style="display:flex;"><span><span style="color:#bbb"> </span><span style="color:#309;font-weight:bold">trigger</span>:<span style="color:#bbb"> </span></span></span><span style="display:flex;"><span><span style="color:#bbb"> </span><span style="color:#309;font-weight:bold">type</span>:<span style="color:#bbb"> </span>http<span style="color:#bbb"> </span></span></span><span style="display:flex;"><span><span style="color:#bbb"> </span><span style="color:#309;font-weight:bold">httpRequest</span>:<span style="color:#bbb"> </span></span></span><span style="display:flex;"><span><span style="color:#bbb"> </span><span style="color:#309;font-weight:bold">method</span>:<span style="color:#bbb"> </span>GET<span style="color:#bbb"> </span></span></span><span style="display:flex;"><span><span style="color:#bbb"> </span><span style="color:#309;font-weight:bold">url</span>:<span style="color:#bbb"> </span>http://demo-pokemon-api.demo/pokemon?take=20&amp;skip=0<span style="color:#bbb"> </span></span></span><span style="display:flex;"><span><span style="color:#bbb"> </span><span style="color:#309;font-weight:bold">headers</span>:<span style="color:#bbb"> </span></span></span><span style="display:flex;"><span><span style="color:#bbb"> </span>- <span style="color:#309;font-weight:bold">key</span>:<span style="color:#bbb"> </span>Content-Type<span style="color:#bbb"> </span></span></span><span style="display:flex;"><span><span style="color:#bbb"> </span><span style="color:#309;font-weight:bold">value</span>:<span style="color:#bbb"> </span>application/json<span style="color:#bbb"> </span></span></span><span style="display:flex;"><span><span style="color:#bbb"> </span><span style="color:#309;font-weight:bold">specs</span>:<span style="color:#bbb"> </span></span></span><span style="display:flex;"><span><span style="color:#bbb"> </span>- <span style="color:#309;font-weight:bold">selector</span>:<span style="color:#bbb"> </span>span[tracetest.span.type=&#34;database&#34;]<span style="color:#bbb"> </span></span></span><span style="display:flex;"><span><span style="color:#bbb"> </span><span style="color:#309;font-weight:bold">name</span>:<span style="color:#bbb"> </span>Database queries less than 500ms<span style="color:#bbb"> </span></span></span><span style="display:flex;"><span><span style="color:#bbb"> </span><span style="color:#309;font-weight:bold">assertions</span>:<span style="color:#bbb"> </span></span></span><span style="display:flex;"><span><span style="color:#bbb"> </span>- attr:tracetest.span.duration &lt; 500ms<span style="color:#bbb"> </span></span></span></code></pre></div><p>Note that you&rsquo;ll use this CLI command to run the test:</p> <div class="highlight"><pre tabindex="0" style="background-color:#f0f3f3;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>tracetest run <span style="color:#366">test</span> --file test-api.yaml --required-gates test-specs --output pretty </span></span></code></pre></div><p>It set&rsquo;s the required gates to pass the test by only validating the test specs.</p> <p>Create another YAML file, name it <code>install-and-run-tracetest.yaml</code>. This contains the Tekton <code>Task</code> definition.</p> <div class="highlight"><pre tabindex="0" style="background-color:#f0f3f3;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-yaml" data-lang="yaml"><span style="display:flex;"><span><span style="color:#09f;font-style:italic"># install-and-run-tracetest.yaml</span><span style="color:#bbb"> </span></span></span><span style="display:flex;"><span><span style="color:#bbb"> </span></span></span><span style="display:flex;"><span><span style="color:#bbb"></span><span style="color:#309;font-weight:bold">apiVersion</span>:<span style="color:#bbb"> </span>tekton.dev/v1beta1<span style="color:#bbb"> </span></span></span><span style="display:flex;"><span><span style="color:#bbb"></span><span style="color:#309;font-weight:bold">kind</span>:<span style="color:#bbb"> </span>Task<span style="color:#bbb"> </span></span></span><span style="display:flex;"><span><span style="color:#bbb"></span><span style="color:#309;font-weight:bold">metadata</span>:<span style="color:#bbb"> </span></span></span><span style="display:flex;"><span><span style="color:#bbb"> </span><span style="color:#309;font-weight:bold">name</span>:<span style="color:#bbb"> </span>install-and-run-tracetest<span style="color:#bbb"> </span></span></span><span style="display:flex;"><span><span style="color:#bbb"></span><span style="color:#309;font-weight:bold">spec</span>:<span style="color:#bbb"> </span></span></span><span style="display:flex;"><span><span style="color:#bbb"> </span><span style="color:#309;font-weight:bold">steps</span>:<span style="color:#bbb"> </span></span></span><span style="display:flex;"><span><span style="color:#bbb"> </span>- <span style="color:#309;font-weight:bold">name</span>:<span style="color:#bbb"> </span>create-test-files<span style="color:#bbb"> </span></span></span><span style="display:flex;"><span><span style="color:#bbb"> </span><span style="color:#309;font-weight:bold">image</span>:<span style="color:#bbb"> </span>ubuntu<span style="color:#bbb"> </span></span></span><span style="display:flex;"><span><span style="color:#bbb"> </span><span style="color:#309;font-weight:bold">script</span>:<span style="color:#bbb"> </span>|<span style="color:#c30;font-style:italic"> </span></span></span><span style="display:flex;"><span><span style="color:#c30;font-style:italic"> #!/usr/bin/env bash </span></span></span><span style="display:flex;"><span><span style="color:#c30;font-style:italic"> cat &lt;&lt;EOF &gt;/workspace/test-api.yaml </span></span></span><span style="display:flex;"><span><span style="color:#c30;font-style:italic"> type: Test </span></span></span><span style="display:flex;"><span><span style="color:#c30;font-style:italic"> spec: </span></span></span><span style="display:flex;"><span><span style="color:#c30;font-style:italic"> id: L7wr5xeVR </span></span></span><span style="display:flex;"><span><span style="color:#c30;font-style:italic"> name: Pokeshop - List </span></span></span><span style="display:flex;"><span><span style="color:#c30;font-style:italic"> description: Get a Pokemon </span></span></span><span style="display:flex;"><span><span style="color:#c30;font-style:italic"> trigger: </span></span></span><span style="display:flex;"><span><span style="color:#c30;font-style:italic"> type: http </span></span></span><span style="display:flex;"><span><span style="color:#c30;font-style:italic"> httpRequest: </span></span></span><span style="display:flex;"><span><span style="color:#c30;font-style:italic"> method: GET </span></span></span><span style="display:flex;"><span><span style="color:#c30;font-style:italic"> url: http://demo-pokemon-api.demo/pokemon?take=20&amp;skip=0 </span></span></span><span style="display:flex;"><span><span style="color:#c30;font-style:italic"> headers: </span></span></span><span style="display:flex;"><span><span style="color:#c30;font-style:italic"> - key: Content-Type </span></span></span><span style="display:flex;"><span><span style="color:#c30;font-style:italic"> value: application/json </span></span></span><span style="display:flex;"><span><span style="color:#c30;font-style:italic"> specs: </span></span></span><span style="display:flex;"><span><span style="color:#c30;font-style:italic"> - selector: span[tracetest.span.type=&#34;database&#34;] </span></span></span><span style="display:flex;"><span><span style="color:#c30;font-style:italic"> name: Database queries less than 500ms </span></span></span><span style="display:flex;"><span><span style="color:#c30;font-style:italic"> assertions: </span></span></span><span style="display:flex;"><span><span style="color:#c30;font-style:italic"> - attr:tracetest.span.duration &lt; 500ms </span></span></span><span style="display:flex;"><span><span style="color:#c30;font-style:italic"> EOF</span><span style="color:#bbb"> </span></span></span><span style="display:flex;"><span><span style="color:#bbb"> </span><span style="color:#309;font-weight:bold">volumeMounts</span>:<span style="color:#bbb"> </span></span></span><span style="display:flex;"><span><span style="color:#bbb"> </span>- <span style="color:#309;font-weight:bold">name</span>:<span style="color:#bbb"> </span>custom<span style="color:#bbb"> </span></span></span><span style="display:flex;"><span><span style="color:#bbb"> </span><span style="color:#309;font-weight:bold">mountPath</span>:<span style="color:#bbb"> </span>/workspace<span style="color:#bbb"> </span></span></span><span style="display:flex;"><span><span style="color:#bbb"> </span>- <span style="color:#309;font-weight:bold">name</span>:<span style="color:#bbb"> </span>install-and-run-tracetest<span style="color:#bbb"> </span></span></span><span style="display:flex;"><span><span style="color:#bbb"> </span><span style="color:#309;font-weight:bold">image</span>:<span style="color:#bbb"> </span>kubeshop/tracetest:v0.13.3<span style="color:#bbb"> </span></span></span><span style="display:flex;"><span><span style="color:#bbb"> </span><span style="color:#09f;font-style:italic"># The official Tracetest image comes with the Tracetest CLI installed</span><span style="color:#bbb"> </span></span></span><span style="display:flex;"><span><span style="color:#bbb"> </span><span style="color:#309;font-weight:bold">script</span>:<span style="color:#bbb"> </span>|<span style="color:#c30;font-style:italic"> </span></span></span><span style="display:flex;"><span><span style="color:#c30;font-style:italic"> # Configure and Run Tracetest CLI </span></span></span><span style="display:flex;"><span><span style="color:#c30;font-style:italic"> tracetest configure -g --endpoint http://tracetest.tracetest.svc.cluster.local:11633/ </span></span></span><span style="display:flex;"><span><span style="color:#c30;font-style:italic"> tracetest run test --file /workspace/test-api.yaml --required-gates test-specs --output pretty</span><span style="color:#bbb"> </span></span></span><span style="display:flex;"><span><span style="color:#bbb"> </span><span style="color:#309;font-weight:bold">volumeMounts</span>:<span style="color:#bbb"> </span></span></span><span style="display:flex;"><span><span style="color:#bbb"> </span>- <span style="color:#309;font-weight:bold">name</span>:<span style="color:#bbb"> </span>custom<span style="color:#bbb"> </span></span></span><span style="display:flex;"><span><span style="color:#bbb"> </span><span style="color:#309;font-weight:bold">mountPath</span>:<span style="color:#bbb"> </span>/workspace<span style="color:#bbb"> </span></span></span><span style="display:flex;"><span><span style="color:#bbb"> </span><span style="color:#309;font-weight:bold">volumes</span>:<span style="color:#bbb"> </span></span></span><span style="display:flex;"><span><span style="color:#bbb"> </span>- <span style="color:#309;font-weight:bold">name</span>:<span style="color:#bbb"> </span>custom<span style="color:#bbb"> </span></span></span><span style="display:flex;"><span><span style="color:#bbb"> </span><span style="color:#309;font-weight:bold">emptyDir</span>:<span style="color:#bbb"> </span>{}<span style="color:#bbb"> </span></span></span></code></pre></div><div class="highlight"><pre tabindex="0" style="background-color:#f0f3f3;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>kubectl apply -f ./install-and-run-tracetest.yaml </span></span></code></pre></div><p>Make sure to use the Tracetest service as the endpoint for your <a href="https://docs.tracetest.io/cli/reference/tracetest_configure/"><code>tracetest configure</code> command</a>. This may vary depending on your installation.</p> <div class="highlight"><pre tabindex="0" style="background-color:#f0f3f3;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>http://tracetest.tracetest.svc.cluster.local:11633/ </span></span></code></pre></div><h2 id="6-run-the-tracetest-trace-based-test-in-tekton-with-a-taskrun">6. Run the Tracetest Trace-based Test in Tekton with a TaskRun</h2> <p>Finally, to run the test, create a <code>TaskRun</code>.</p> <p>Create a file called <code>install-and-run-tracetest-run.yaml</code>.</p> <div class="highlight"><pre tabindex="0" style="background-color:#f0f3f3;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-yaml" data-lang="yaml"><span style="display:flex;"><span><span style="color:#09f;font-style:italic"># install-and-run-tracetest-run.yaml</span><span style="color:#bbb"> </span></span></span><span style="display:flex;"><span><span style="color:#bbb"> </span></span></span><span style="display:flex;"><span><span style="color:#bbb"></span><span style="color:#309;font-weight:bold">apiVersion</span>:<span style="color:#bbb"> </span>tekton.dev/v1beta1<span style="color:#bbb"> </span></span></span><span style="display:flex;"><span><span style="color:#bbb"></span><span style="color:#309;font-weight:bold">kind</span>:<span style="color:#bbb"> </span>TaskRun<span style="color:#bbb"> </span></span></span><span style="display:flex;"><span><span style="color:#bbb"></span><span style="color:#309;font-weight:bold">metadata</span>:<span style="color:#bbb"> </span></span></span><span style="display:flex;"><span><span style="color:#bbb"> </span><span style="color:#309;font-weight:bold">name</span>:<span style="color:#bbb"> </span>install-and-run-tracetest-run<span style="color:#bbb"> </span></span></span><span style="display:flex;"><span><span style="color:#bbb"></span><span style="color:#309;font-weight:bold">spec</span>:<span style="color:#bbb"> </span></span></span><span style="display:flex;"><span><span style="color:#bbb"> </span><span style="color:#309;font-weight:bold">taskRef</span>:<span style="color:#bbb"> </span></span></span><span style="display:flex;"><span><span style="color:#bbb"> </span><span style="color:#309;font-weight:bold">name</span>:<span style="color:#bbb"> </span>install-and-run-tracetest<span style="color:#bbb"> </span></span></span></code></pre></div><div class="highlight"><pre tabindex="0" style="background-color:#f0f3f3;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>kubectl apply -f ./install-and-run-tracetest-run.yaml </span></span></code></pre></div><p>Here&rsquo;s how to check the logs:</p> <div class="highlight"><pre tabindex="0" style="background-color:#f0f3f3;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>kubectl logs --selector<span style="color:#555">=</span>tekton.dev/taskRun<span style="color:#555">=</span>install-and-run-tracetest-run </span></span></code></pre></div><p>You can also trigger a Task with the <a href="https://tekton.dev/docs/cli/">Tekton CLI</a>.</p> <div class="highlight"><pre tabindex="0" style="background-color:#f0f3f3;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>tkn task start install-and-run-tracetest </span></span><span style="display:flex;"><span> </span></span><span style="display:flex;"><span><span style="color:#555">[</span>Output<span style="color:#555">]</span> </span></span><span style="display:flex;"><span>TaskRun started: install-and-run-tracetest-run-xmhfg </span></span></code></pre></div><p>In order to track the TaskRun progress run:</p> <div class="highlight"><pre tabindex="0" style="background-color:#f0f3f3;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>tkn taskrun logs install-and-run-tracetest-run-gccjk -f -n default </span></span><span style="display:flex;"><span> </span></span><span style="display:flex;"><span><span style="color:#555">[</span>Output<span style="color:#555">]</span> </span></span><span style="display:flex;"><span><span style="color:#555">[</span>install-and-run-tracetest<span style="color:#555">]</span> ✔ Pokeshop - List <span style="color:#555">(</span>http://tracetest.tracetest.svc.cluster.local:11633/test/RUkKQ_aVR/run/3/test<span style="color:#555">)</span> - trace id: 0549641531d3221ded696f2fd3b20ce6 </span></span><span style="display:flex;"><span><span style="color:#555">[</span>install-and-run-tracetest<span style="color:#555">]</span> ✔ Database queries less than <span style="color:#f60">500</span> ms </span></span><span style="display:flex;"><span><span style="color:#555">[</span>install-and-run-tracetest<span style="color:#555">]</span> </span></span></code></pre></div><p>To preview which tasks failed or succeeded, use this command:</p> <div class="highlight"><pre tabindex="0" style="background-color:#f0f3f3;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>tkn taskrun list </span></span><span style="display:flex;"><span> </span></span><span style="display:flex;"><span><span style="color:#555">[</span>Output<span style="color:#555">]</span> </span></span><span style="display:flex;"><span>NAME STARTED DURATION STATUS </span></span><span style="display:flex;"><span>install-and-run-tracetest-run <span style="color:#f60">3</span> minutes ago 23s Succeeded </span></span><span style="display:flex;"><span>install-and-run-tracetest-run-nmptn <span style="color:#f60">7</span> minutes ago 33s Failed </span></span><span style="display:flex;"><span>install-and-run-tracetest-run-bhf7v <span style="color:#f60">20</span> minutes ago 23s Succeeded </span></span><span style="display:flex;"><span>install-and-run-tracetest-run-wm8bj <span style="color:#f60">21</span> minutes ago 22s Succeeded </span></span><span style="display:flex;"><span>install-and-run-tracetest-run-dbrbt <span style="color:#f60">23</span> minutes ago 24s Failed </span></span></code></pre></div><h2 id="7-trigger-trace-based-tests-with-an-eventlistener">7. Trigger Trace-based Tests with an EventListener</h2> <p>By using Tektons&rsquo;s <a href="https://tekton.dev/docs/getting-started/triggers/">triggers</a>, you can trigger tests via an <a href="https://tekton.dev/docs/getting-started/triggers/#create-an-eventlistener">eventlistener</a>.</p> <h3 id="create-a-triggertemplate-and-triggerbinding">Create a TriggerTemplate and TriggerBinding</h3> <div class="highlight"><pre tabindex="0" style="background-color:#f0f3f3;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-yaml" data-lang="yaml"><span style="display:flex;"><span><span style="color:#09f;font-style:italic"># install-and-run-tracetest-trigger-binding.yaml</span><span style="color:#bbb"> </span></span></span><span style="display:flex;"><span><span style="color:#bbb"> </span></span></span><span style="display:flex;"><span><span style="color:#bbb"></span><span style="color:#309;font-weight:bold">apiVersion</span>:<span style="color:#bbb"> </span>triggers.tekton.dev/v1beta1<span style="color:#bbb"> </span></span></span><span style="display:flex;"><span><span style="color:#bbb"></span><span style="color:#309;font-weight:bold">kind</span>:<span style="color:#bbb"> </span>TriggerTemplate<span style="color:#bbb"> </span></span></span><span style="display:flex;"><span><span style="color:#bbb"></span><span style="color:#309;font-weight:bold">metadata</span>:<span style="color:#bbb"> </span></span></span><span style="display:flex;"><span><span style="color:#bbb"> </span><span style="color:#309;font-weight:bold">name</span>:<span style="color:#bbb"> </span>install-and-run-tracetest-template<span style="color:#bbb"> </span></span></span><span style="display:flex;"><span><span style="color:#bbb"></span><span style="color:#309;font-weight:bold">spec</span>:<span style="color:#bbb"> </span></span></span><span style="display:flex;"><span><span style="color:#bbb"> </span><span style="color:#309;font-weight:bold">resourcetemplates</span>:<span style="color:#bbb"> </span></span></span><span style="display:flex;"><span><span style="color:#bbb"> </span>- <span style="color:#309;font-weight:bold">apiVersion</span>:<span style="color:#bbb"> </span>tekton.dev/v1beta1<span style="color:#bbb"> </span></span></span><span style="display:flex;"><span><span style="color:#bbb"> </span><span style="color:#309;font-weight:bold">kind</span>:<span style="color:#bbb"> </span>TaskRun<span style="color:#bbb"> </span></span></span><span style="display:flex;"><span><span style="color:#bbb"> </span><span style="color:#309;font-weight:bold">metadata</span>:<span style="color:#bbb"> </span></span></span><span style="display:flex;"><span><span style="color:#bbb"> </span><span style="color:#309;font-weight:bold">generateName</span>:<span style="color:#bbb"> </span>install-and-run-tracetest-run-<span style="color:#bbb"> </span></span></span><span style="display:flex;"><span><span style="color:#bbb"> </span><span style="color:#309;font-weight:bold">spec</span>:<span style="color:#bbb"> </span></span></span><span style="display:flex;"><span><span style="color:#bbb"> </span><span style="color:#309;font-weight:bold">taskRef</span>:<span style="color:#bbb"> </span></span></span><span style="display:flex;"><span><span style="color:#bbb"> </span><span style="color:#309;font-weight:bold">name</span>:<span style="color:#bbb"> </span>install-and-run-tracetest<span style="color:#bbb"> </span></span></span></code></pre></div><div class="highlight"><pre tabindex="0" style="background-color:#f0f3f3;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-yaml" data-lang="yaml"><span style="display:flex;"><span><span style="color:#09f;font-style:italic"># install-and-run-tracetest-trigger-template.yaml</span><span style="color:#bbb"> </span></span></span><span style="display:flex;"><span><span style="color:#bbb"> </span></span></span><span style="display:flex;"><span><span style="color:#bbb"></span><span style="color:#309;font-weight:bold">apiVersion</span>:<span style="color:#bbb"> </span>triggers.tekton.dev/v1beta1<span style="color:#bbb"> </span></span></span><span style="display:flex;"><span><span style="color:#bbb"></span><span style="color:#309;font-weight:bold">kind</span>:<span style="color:#bbb"> </span>TriggerBinding<span style="color:#bbb"> </span></span></span><span style="display:flex;"><span><span style="color:#bbb"></span><span style="color:#309;font-weight:bold">metadata</span>:<span style="color:#bbb"> </span></span></span><span style="display:flex;"><span><span style="color:#bbb"> </span><span style="color:#309;font-weight:bold">name</span>:<span style="color:#bbb"> </span>install-and-run-tracetest-binding<span style="color:#bbb"> </span></span></span><span style="display:flex;"><span><span style="color:#bbb"></span><span style="color:#309;font-weight:bold">spec</span>:<span style="color:#bbb"> </span></span></span><span style="display:flex;"><span><span style="color:#bbb"> </span><span style="color:#309;font-weight:bold">params</span>:<span style="color:#bbb"> </span></span></span><span style="display:flex;"><span><span style="color:#bbb"> </span>- <span style="color:#309;font-weight:bold">name</span>:<span style="color:#bbb"> </span>run<span style="color:#bbb"> </span></span></span><span style="display:flex;"><span><span style="color:#bbb"> </span><span style="color:#309;font-weight:bold">value</span>:<span style="color:#bbb"> </span>$(body.run)<span style="color:#bbb"> </span></span></span></code></pre></div><div class="highlight"><pre tabindex="0" style="background-color:#f0f3f3;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>kubectl apply -f install-and-run-tracetest-trigger-binding.yaml </span></span><span style="display:flex;"><span>kubectl apply -f install-and-run-tracetest-trigger-template.yaml </span></span></code></pre></div><h3 id="create-an-eventlistener">Create an EventListener</h3> <div class="highlight"><pre tabindex="0" style="background-color:#f0f3f3;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-yaml" data-lang="yaml"><span style="display:flex;"><span><span style="color:#09f;font-style:italic"># install-and-run-tracetest-event-listener.yaml</span><span style="color:#bbb"> </span></span></span><span style="display:flex;"><span><span style="color:#bbb"> </span></span></span><span style="display:flex;"><span><span style="color:#bbb"></span><span style="color:#309;font-weight:bold">apiVersion</span>:<span style="color:#bbb"> </span>triggers.tekton.dev/v1beta1<span style="color:#bbb"> </span></span></span><span style="display:flex;"><span><span style="color:#bbb"></span><span style="color:#309;font-weight:bold">kind</span>:<span style="color:#bbb"> </span>EventListener<span style="color:#bbb"> </span></span></span><span style="display:flex;"><span><span style="color:#bbb"></span><span style="color:#309;font-weight:bold">metadata</span>:<span style="color:#bbb"> </span></span></span><span style="display:flex;"><span><span style="color:#bbb"> </span><span style="color:#309;font-weight:bold">name</span>:<span style="color:#bbb"> </span>install-and-run-tracetest-event-listener<span style="color:#bbb"> </span></span></span><span style="display:flex;"><span><span style="color:#bbb"></span><span style="color:#309;font-weight:bold">spec</span>:<span style="color:#bbb"> </span></span></span><span style="display:flex;"><span><span style="color:#bbb"> </span><span style="color:#309;font-weight:bold">serviceAccountName</span>:<span style="color:#bbb"> </span>tekton-robot<span style="color:#bbb"> </span></span></span><span style="display:flex;"><span><span style="color:#bbb"> </span><span style="color:#309;font-weight:bold">triggers</span>:<span style="color:#bbb"> </span></span></span><span style="display:flex;"><span><span style="color:#bbb"> </span>- <span style="color:#309;font-weight:bold">name</span>:<span style="color:#bbb"> </span>install-and-run-tracetest-trigger <span style="color:#bbb"> </span></span></span><span style="display:flex;"><span><span style="color:#bbb"> </span><span style="color:#309;font-weight:bold">bindings</span>:<span style="color:#bbb"> </span></span></span><span style="display:flex;"><span><span style="color:#bbb"> </span>- <span style="color:#309;font-weight:bold">ref</span>:<span style="color:#bbb"> </span>install-and-run-tracetest-binding<span style="color:#bbb"> </span></span></span><span style="display:flex;"><span><span style="color:#bbb"> </span><span style="color:#309;font-weight:bold">template</span>:<span style="color:#bbb"> </span></span></span><span style="display:flex;"><span><span style="color:#bbb"> </span><span style="color:#309;font-weight:bold">ref</span>:<span style="color:#bbb"> </span>install-and-run-tracetest-template<span style="color:#bbb"> </span></span></span></code></pre></div><p>The EventListener requires a service account to run. To create the service account for this example create a file named <code>tekton-robot-rbac.yaml</code> and add the following:</p> <div class="highlight"><pre tabindex="0" style="background-color:#f0f3f3;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-yaml" data-lang="yaml"><span style="display:flex;"><span><span style="color:#09f;font-style:italic"># tekton-robot-rbac.yaml</span><span style="color:#bbb"> </span></span></span><span style="display:flex;"><span><span style="color:#bbb"> </span></span></span><span style="display:flex;"><span><span style="color:#bbb"></span><span style="color:#309;font-weight:bold">apiVersion</span>:<span style="color:#bbb"> </span>v1<span style="color:#bbb"> </span></span></span><span style="display:flex;"><span><span style="color:#bbb"></span><span style="color:#309;font-weight:bold">kind</span>:<span style="color:#bbb"> </span>ServiceAccount<span style="color:#bbb"> </span></span></span><span style="display:flex;"><span><span style="color:#bbb"></span><span style="color:#309;font-weight:bold">metadata</span>:<span style="color:#bbb"> </span></span></span><span style="display:flex;"><span><span style="color:#bbb"> </span><span style="color:#309;font-weight:bold">name</span>:<span style="color:#bbb"> </span>tekton-robot<span style="color:#bbb"> </span></span></span><span style="display:flex;"><span><span style="color:#bbb"></span><span style="color:#0cf;font-weight:bold">---</span><span style="color:#bbb"> </span></span></span><span style="display:flex;"><span><span style="color:#bbb"></span><span style="color:#309;font-weight:bold">apiVersion</span>:<span style="color:#bbb"> </span>rbac.authorization.k8s.io/v1<span style="color:#bbb"> </span></span></span><span style="display:flex;"><span><span style="color:#bbb"></span><span style="color:#309;font-weight:bold">kind</span>:<span style="color:#bbb"> </span>RoleBinding<span style="color:#bbb"> </span></span></span><span style="display:flex;"><span><span style="color:#bbb"></span><span style="color:#309;font-weight:bold">metadata</span>:<span style="color:#bbb"> </span></span></span><span style="display:flex;"><span><span style="color:#bbb"> </span><span style="color:#309;font-weight:bold">name</span>:<span style="color:#bbb"> </span>triggers-example-eventlistener-binding<span style="color:#bbb"> </span></span></span><span style="display:flex;"><span><span style="color:#bbb"></span><span style="color:#309;font-weight:bold">subjects</span>:<span style="color:#bbb"> </span></span></span><span style="display:flex;"><span><span style="color:#bbb"></span>- <span style="color:#309;font-weight:bold">kind</span>:<span style="color:#bbb"> </span>ServiceAccount<span style="color:#bbb"> </span></span></span><span style="display:flex;"><span><span style="color:#bbb"> </span><span style="color:#309;font-weight:bold">name</span>:<span style="color:#bbb"> </span>tekton-robot<span style="color:#bbb"> </span></span></span><span style="display:flex;"><span><span style="color:#bbb"></span><span style="color:#309;font-weight:bold">roleRef</span>:<span style="color:#bbb"> </span></span></span><span style="display:flex;"><span><span style="color:#bbb"> </span><span style="color:#309;font-weight:bold">apiGroup</span>:<span style="color:#bbb"> </span>rbac.authorization.k8s.io<span style="color:#bbb"> </span></span></span><span style="display:flex;"><span><span style="color:#bbb"> </span><span style="color:#309;font-weight:bold">kind</span>:<span style="color:#bbb"> </span>ClusterRole<span style="color:#bbb"> </span></span></span><span style="display:flex;"><span><span style="color:#bbb"> </span><span style="color:#309;font-weight:bold">name</span>:<span style="color:#bbb"> </span>tekton-triggers-eventlistener-roles<span style="color:#bbb"> </span></span></span><span style="display:flex;"><span><span style="color:#bbb"></span><span style="color:#0cf;font-weight:bold">---</span><span style="color:#bbb"> </span></span></span><span style="display:flex;"><span><span style="color:#bbb"></span><span style="color:#309;font-weight:bold">apiVersion</span>:<span style="color:#bbb"> </span>rbac.authorization.k8s.io/v1<span style="color:#bbb"> </span></span></span><span style="display:flex;"><span><span style="color:#bbb"></span><span style="color:#309;font-weight:bold">kind</span>:<span style="color:#bbb"> </span>ClusterRoleBinding<span style="color:#bbb"> </span></span></span><span style="display:flex;"><span><span style="color:#bbb"></span><span style="color:#309;font-weight:bold">metadata</span>:<span style="color:#bbb"> </span></span></span><span style="display:flex;"><span><span style="color:#bbb"> </span><span style="color:#309;font-weight:bold">name</span>:<span style="color:#bbb"> </span>triggers-example-eventlistener-clusterbinding<span style="color:#bbb"> </span></span></span><span style="display:flex;"><span><span style="color:#bbb"></span><span style="color:#309;font-weight:bold">subjects</span>:<span style="color:#bbb"> </span></span></span><span style="display:flex;"><span><span style="color:#bbb"></span>- <span style="color:#309;font-weight:bold">kind</span>:<span style="color:#bbb"> </span>ServiceAccount<span style="color:#bbb"> </span></span></span><span style="display:flex;"><span><span style="color:#bbb"> </span><span style="color:#309;font-weight:bold">name</span>:<span style="color:#bbb"> </span>tekton-robot<span style="color:#bbb"> </span></span></span><span style="display:flex;"><span><span style="color:#bbb"> </span><span style="color:#309;font-weight:bold">namespace</span>:<span style="color:#bbb"> </span>default<span style="color:#bbb"> </span></span></span><span style="display:flex;"><span><span style="color:#bbb"></span><span style="color:#309;font-weight:bold">roleRef</span>:<span style="color:#bbb"> </span></span></span><span style="display:flex;"><span><span style="color:#bbb"> </span><span style="color:#309;font-weight:bold">apiGroup</span>:<span style="color:#bbb"> </span>rbac.authorization.k8s.io<span style="color:#bbb"> </span></span></span><span style="display:flex;"><span><span style="color:#bbb"> </span><span style="color:#309;font-weight:bold">kind</span>:<span style="color:#bbb"> </span>ClusterRole<span style="color:#bbb"> </span></span></span><span style="display:flex;"><span><span style="color:#bbb"> </span><span style="color:#309;font-weight:bold">name</span>:<span style="color:#bbb"> </span>tekton-triggers-eventlistener-clusterroles<span style="color:#bbb"> </span></span></span></code></pre></div><div class="highlight"><pre tabindex="0" style="background-color:#f0f3f3;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>kubectl apply -f tekton-robot-rbac.yaml </span></span><span style="display:flex;"><span>kubectl apply -f install-and-run-tracetest-event-listener.yaml </span></span></code></pre></div><p>Enable port forwarding.</p> <div class="highlight"><pre tabindex="0" style="background-color:#f0f3f3;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>kubectl port-forward service/el-install-and-run-tracetest-event-listener <span style="color:#f60">8080</span> </span></span></code></pre></div><p>Hitting the port forwarded endpoint will trigger the task.</p> <div class="highlight"><pre tabindex="0" style="background-color:#f0f3f3;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>curl -v \ </span></span><span style="display:flex;"><span> -H &#39;content-Type: application/json&#39; \ </span></span><span style="display:flex;"><span> -d &#39;{&#34;run&#34;:true}&#39; \ </span></span><span style="display:flex;"><span> http://localhost:8080 </span></span></code></pre></div><p>Checking the <code>taskruns</code> will confirm this.</p> <div class="highlight"><pre tabindex="0" style="background-color:#f0f3f3;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>tkn taskrun list </span></span><span style="display:flex;"><span> </span></span><span style="display:flex;"><span><span style="color:#555">[</span>Output<span style="color:#555">]</span> </span></span><span style="display:flex;"><span>NAME STARTED DURATION STATUS </span></span><span style="display:flex;"><span>install-and-run-tracetest-run-69zrz <span style="color:#f60">4</span> seconds ago --- Running<span style="color:#555">(</span>Pending<span style="color:#555">)</span> </span></span></code></pre></div><p>Finally, check the logs:</p> <div class="highlight"><pre tabindex="0" style="background-color:#f0f3f3;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>tkn taskrun logs -f install-and-run-tracetest-run-69zrz </span></span><span style="display:flex;"><span> </span></span><span style="display:flex;"><span><span style="color:#555">[</span>Output<span style="color:#555">]</span> </span></span><span style="display:flex;"><span><span style="color:#555">[</span>install-and-run-tracetest<span style="color:#555">]</span> ✔ Pokeshop - List <span style="color:#555">(</span>http://tracetest.tracetest.svc.cluster.local:11633/test/RUkKQ_aVR/run/5/test<span style="color:#555">)</span> </span></span><span style="display:flex;"><span><span style="color:#555">[</span>install-and-run-tracetest<span style="color:#555">]</span> ✔ Database queries less than <span style="color:#f60">500</span> ms </span></span></code></pre></div><h2 id="8-preview-trace-based-tests-with-tekton-dashboard">8. Preview Trace-based Tests with Tekton Dashboard</h2> <p>Start by port forwarding the Tekton Dashboard.</p> <div class="highlight"><pre tabindex="0" style="background-color:#f0f3f3;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>kubectl --namespace tekton-pipelines port-forward svc/tekton-dashboard 9097:9097 </span></span></code></pre></div><p>Open it up in your browser at <code>http://localhost:9097</code>. Navigate to the TaskRuns. Open the TaskRun you ran above.</p> <p><img src="./tekton-dashboard-6.png" alt="Tekton Dashboard TaskRuns"></p> <p>This lets you easily preview the Tracetest test runs by copying the link to the Tracetest instance. However, because you&rsquo;re using an internal service for Tracetest, make sure to use the port forwarded link to access the Tracetest Dashboard.</p> <p>Replace:</p> <div class="highlight"><pre tabindex="0" style="background-color:#f0f3f3;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>http://tracetest.tracetest.svc.cluster.local:11633/test/RUkKQ_aVR/run/4/test </span></span></code></pre></div><p>With:</p> <div class="highlight"><pre tabindex="0" style="background-color:#f0f3f3;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>http://localhost:11633/test/RUkKQ_aVR/run/4/test </span></span></code></pre></div><p><img src="./tracetest-dashboard-preview-7.png" alt="Tracetest Dashboard test run preview"></p> <p>Alternatively, you can use the Deep Link feature to trigger a new test run directly via the browser like this:</p> <div class="highlight"><pre tabindex="0" style="background-color:#f0f3f3;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>http://localhost:11633/test/RUkKQ_aVR/run? </span></span></code></pre></div><h2 id="conclusion">Conclusion</h2> <p>To sum up, the partnership between Tekton and Tracetest offers a powerful approach to testing Kubernetes with distributed tracing. Tekton provides a framework for building efficient CI/CD pipelines. Tracetest utilizes OpenTelemetry traces for testing, making it a valuable tool for testing cloud-native apps.</p> <p>By combining Tracetest and Tekton, developers gain the ability to integrate trace-based testing into Kubernetes clusters. This integration allows for scheduled test cycles, synthetic tests, and thorough assertions using trace data. This cohesive approach ensures that applications align with intended behavior, improving overall reliability and functionality. As cloud-native apps continue to evolve, this integration showcases how to enhance testing as well.</p> <h2 id="next-steps">Next Steps</h2> <p>To explore more options that Tracetest gives you, check out <a href="https://docs.tracetest.io/">the docs</a> to learn more!</p> <p>If you like what the <a href="https://github.com/tektoncd/pipeline">Tekton</a> and <a href="https://github.com/kubeshop/tracetest">Tracetest</a> communities are doing, please leave a ⭐️ in GitHub.</p> Blog: Getting To SLSA Level 2 with Tekton and Tekton Chains https://tekton.dev/blog/2023/04/19/getting-to-slsa-level-2-with-tekton-and-tekton-chains/ Wed, 19 Apr 2023 00:00:00 +0000 https://tekton.dev/blog/2023/04/19/getting-to-slsa-level-2-with-tekton-and-tekton-chains/ <h1 id="overview">Overview</h1> <p>As application developers, we achieve amazing results quickly by leveraging a rich ecosystem of freely available libraries, modules and frameworks that provide ready-to-use capabilities and abstract away from underlying complexity. This is so foundational to how we work that we&rsquo;ll nonchalantly build and publish an app that pulls in hundreds of dependencies without even thinking about it. And it&rsquo;s only fairly recently, in the wake of some very high profile and high impact compromises, that we&rsquo;ve started to reckon with the fact that this wonderful ecosystem is also a security quagmire. All of the dependencies that feed into your build make up your software supply chain, and supply chains need to be secured. In this post, we&rsquo;ll show how an increasingly popular open source CI/CD system, Tekton, implements the <a href="https://slsa.dev/">OpenSSF SLSA</a> framework to provide you with supply chain security guarantees.</p> <h1 id="software-supply-chain-security">Software Supply Chain Security</h1> <p>A software supply chain is anything that goes into or affects your code from development, through your CI/CD pipeline, until it gets deployed into production. Increasingly, the software supply chain has become a vector for attacks. The recent Log4j, SolarWinds, Kaseya, and Codecov hacks highlight vulnerable surface areas exposed by an insecure software supply chain.</p> <p>Between 2020 and 2021, there has been a <a href="https://www.sonatype.com/resources/state-of-the-software-supply-chain-2021">650% Surge</a> in OSS supply chain attacks, and <a href="https://www.gartner.com/en/documents/4003625">Gartner projects</a> that 45% of organizations worldwide will have experienced software supply chain attacks by 2025.</p> <h1 id="supply-chains-levels-for-software-artifacts-slsa">Supply Chains Levels for Software Artifacts (SLSA)</h1> <p>The Supply chain Levels for Software Artifacts (SLSA) framework is a check-list of controls to prevent tampering, improve integrity, and increase security in the packages and infrastructure used by projects, businesses or enterprises. SLSA formalizes criteria around software supply chain integrity to help the industry and open source ecosystem secure the software development life cycle at all stages.</p> <p>As part of the framework, SLSA has multiple levels of assurances. These levels contain industry-recognized best practices to create four levels of increasing assurance.</p> <img src="levels.png"> <p>SLSA provides a <a href="https://slsa.dev/spec/v0.1/requirements">set of requirements</a> that needs to be met for an artifact to be considered for a particular SLSA level.</p> <h1 id="tekton--tekton-chains">Tekton + Tekton Chains</h1> <p>Tekton is a powerful and flexible, open source, cloud-native framework for creating CI/CD systems, allowing developers to build, test, and deploy across cloud providers and on-premise systems. Tekton consists of several subprojects which are relevant to SLSA:</p> <ul> <li>Pipelines: A system that allows one to define a pipeline of CI/CD tasks and have it be orchestrated by the Tekton controller.</li> <li>Chains: A standalone system which observes Pipelines and generates provenance for the artifacts built by Pipelines. Tekton build processes are defined as tasks and pipelines. A Task is a collection of Steps that are defined and arranged in a specific order of execution as part of a continuous integration flow.</li> </ul> <p>A Pipeline is a collection of Tasks defined and arranged in a specific order of execution as part of a continuous integration flow.</p> <p>A TaskRun is an instantiation of a Task with specific inputs, outputs and execution parameters while a PipelineRun is an instantiation of a Pipeline.</p> <p>A Task/Pipeline can define a set of Results. TaskRuns and PipelineRuns create Results as defined in the Task/Pipeline. Results are used to communicate to Tekton Chains run specifics like the uri and the digest of the built artifact.</p> <p>Tasks, Pipelines, TaskRuns and PipelineRuns are defined through yaml files. The entire build is defined by the set of yaml files which define Tekton Tasks, Pipelines, TaskRuns and PipelineRuns. These yaml files can be checked in as code and run directly from the code repository.</p> <h1 id="getting-to-slsa-l1-automation--provenance">Getting to SLSA L1: Automation + Provenance</h1> <p>For an artifact to be <a href="https://slsa.dev/spec/v0.1/requirements">SLSA L1</a> compliant it should satisfy the following:</p> <ol> <li><a href="https://slsa.dev/spec/v0.1/requirements#scripted-build">Scripted build</a>: All build steps are fully defined in some sort of “build script”. The only manual command, if any, is to invoke the build script.</li> <li><a href="https://slsa.dev/spec/v0.1/requirements#available">Provenance</a>: The provenance is available to the consumer in a format that the consumer accepts. The format SHOULD be in-toto SLSA Provenance, but another format MAY be used if both producer and consumer agree and it meets all the other requirements.</li> </ol> <p>Tekton Tasks, TaskRuns, Pipelines and PipelineRuns are specified in yaml files. These yaml files can be considered as scripts and can even be checked in into a code repository. These could also be run from code repositories. Tekton Chains provides a way to generate provenance in in-toto SLSA format. As such, Tekton can easily make builds which satisfy the SLSA L1 requirements.</p> <div class="alert alert-primary" role="alert"> <h4 class="alert-heading">Note</h4> The linked example demonstrates SLSA level 2 on Google Cloud, but the same principles are applicable to any build environment. </div> <p>Let&rsquo;s follow through with <a href="https://github.com/tektoncd/chains/tree/main/docs/vendor/gcp/slsa-2">an example</a>, which has the following files:</p> <ul> <li><code>setup.sh</code>: Sets up Google cloud to run an instance of the build specified in <code>pipeline_run.yaml</code>. It also installs Tekton Pipeline and Tekton Chains. In the production environment, this would be run once to set up the environment and all builds would use the same environment.</li> <li><code>pipeline_run.yaml</code>: This file is the actual build file that is run by Tekton Pipelines. The build here first clones a Github repo, builds the container specified in the source and uploads it to a Docker repository.</li> </ul> <img src="example.png"> <p>The build script <code>pipeline.yaml</code> is the definition of the script while <code>pipeline_run.yaml</code> defines an instance of the build. It provides instance specific parameters for the build. Though both <code>pipeline_run.yaml</code> and <code>pipeline.yaml</code> are in source control for this example, the build definition is in <code>pipeline.yaml</code> and as such <code>pipeline.yaml</code> being in source control would satisfy the requirement of a source controlled build script.</p> <div class="highlight"><pre tabindex="0" style="background-color:#f0f3f3;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>kubectl create -f </span></span><span style="display:flex;"><span> https://raw.githubusercontent.com/tektoncd/chains/main/docs/vendor/gcp/slsa-2/pipeline_run.yaml </span></span></code></pre></div><h1 id="tekton-chains-for-provenance-generation">Tekton Chains for Provenance Generation</h1> <p>Provenance is metadata about how an artifact was built, including the build process, top-level source, and dependencies. Knowing the provenance allows software consumers to make risk-based security decisions.</p> <p>Tekton Chains observes TaskRuns and PipelineRuns in a Kubernetes cluster. Once the runs are done, Chains collects information (provenance) about the Run or the build process and the artifact created by the Run. It signs <a href="https://slsa.dev/provenance/v0.2">the provenance</a> and stores the signed provenance. The provenance generated for the example build complies to the SLSA provenance schema and is explained further below.</p> <p>Note that every step of the build has been recorded and can be reconstructed by following the steps in the provenance.</p> <h1 id="next-steps-cicd--slsa-l2">Next Steps: CI/CD @ SLSA L2</h1> <p><a href="https://slsa.dev/spec/v0.1/requirements">SLSA requires</a> that for a build to be SLSA L2 compliant it should satisfy the following</p> <ol> <li><a href="https://slsa.dev/spec/v0.1/requirements#version-controlled">Every change</a> to the source is tracked in a version control system</li> <li><a href="https://slsa.dev/spec/v0.1/requirements#scripted-build">All build steps</a> were fully defined in some sort of “build script”. The only manual command, if any, was to invoke the build script.</li> <li><a href="https://slsa.dev/spec/v0.1/requirements#build-service">All build steps</a> ran using some build service, not on a developer’s workstation.</li> <li><a href="https://slsa.dev/spec/v0.1/requirements#available">The provenance is available</a> to the consumer in a format that the consumer accepts. The format SHOULD be in-toto SLSA Provenance, but another format MAY be used if both producer and consumer agree and it meets all the other requirements.</li> <li><a href="https://slsa.dev/spec/v0.1/requirements#authenticated">The provenance’s authenticity</a> and integrity can be verified by the consumer. This SHOULD be through a digital signature from a private key accessible only to the service generating the provenance.</li> <li><a href="https://slsa.dev/spec/v0.1/requirements#service-generated">The data in the provenance</a> MUST be obtained from the build service (either because the generator is the build service or because the provenance generator reads the data directly from the build service). Regular users of the service MUST NOT be able to inject or alter the contents.</li> </ol> <h2 id="every-changeslsa-r1-to-the-source-is-tracked-in-a-version-control-system"><a href="https://slsa.dev/spec/v0.1/requirements#version-controlled">Every change</a> to the source is tracked in a version control system</h2> <p>Tekton does not explicitly enforce that the source is version controlled. Tekton users can enforce that the source is version controlled by writing an appropriate Task which will check for version control. The source should also be communicated by Tekton Pipelines to Tekton Chains through a <a href="https://github.com/tektoncd/chains/blob/82c213c172a99329d6571d76499ad816755a9069/docs/intoto.md#structured-result-type-hinting">result variable</a> that is suffixed with <code>-ARTIFACT_INPUTS</code>.</p> <h2 id="all-build-stepsslsa-r2-were-fully-defined-in-some-sort-of-build-script-the-only-manual-command-if-any-was-to-invoke-the-build-script"><a href="https://slsa.dev/spec/v0.1/requirements#scripted-build">All build steps</a> were fully defined in some sort of “build script”. The only manual command, if any, was to invoke the build script.</h2> <p>This is a requirement for SLSA L1 as well and as explained above, Tekton provides a way to script the build through yaml files. The build is defined as a Pipeline (or Task) which can be saved as a yaml file and submitted into source control. The build instance which is defined as a PipelineRun (or TaskRun) can resolve the Pipeline (or Task) yaml from source control and use it for the current instance of the build.</p> <h2 id="all-build-stepsslsa-r3-ran-using-some-build-service-not-on-a-developers-workstation"><a href="https://slsa.dev/spec/v0.1/requirements#build-service">All build steps</a> ran using some build service, not on a developer’s workstation.</h2> <p>Tekton can be hosted on a cloud provider or on a hosted Kubernetes cluster and run as a build service. The build scripts can be submitted into source control (like GitHub) and Tekton can read the scripts directly from source control.</p> <h2 id="provenance-should-be-availableslsa-r4">Provenance should be <a href="https://slsa.dev/spec/v0.1/requirements#available">available</a></h2> <p>This is a requirement for SLSA L1 and as explained above Tekton Chains provides build provenance.</p> <h2 id="provenance-should-be-signed-and-authenticatedslsa-r5">Provenance should be <a href="https://slsa.dev/spec/v0.1/requirements#authenticated">signed and Authenticated</a></h2> <p>As can be seen in the example, Tekton Chains creates and signs the build provenance. The signature can be verified anytime to ensure that the provenance has not been tampered after the build and the provenance is really created by the build process that claims to have built it. The signing is done according to the <a href="https://slsa.dev/attestation-model">SLSA specification</a> using the <a href="https://github.com/secure-systems-lab/dsse/blob/master/envelope.md">DSSE format</a>.</p> <p>Tekton Chains creates the provenance and signs it using a secure private key. Chains then uploads the signed provenance to a user-specified location, one of which is Google Cloud’s Container Analysis, which implements the open standard <a href="https://github.com/grafeas/grafeas">Grafeas API</a> for storing provenance.</p> <img src="provenance.png"> <h2 id="provenance-should-be-generated-by-a-serviceslsa-r6">Provenance should be <a href="https://slsa.dev/spec/v0.1/requirements#service-generated">generated by a Service</a></h2> <p>Note that the provenance in the example is generated by the Tekton Chains service and it cannot be modified after it has been generated, which is guaranteed by the signature.</p> <h1 id="slsa-requirementsprovenance-requirements-for-the-contents-of-the-provenance-for-the-build-to-be-considered-l2"><a href="https://slsa.dev/spec/v0.1/requirements#provenance-requirements">SLSA requirements</a> for the contents of the provenance, for the build to be considered L2.</h1> <p>All images below are extracted from the provenance of the example build. These can be verified by re-running the example.</p> <ol> <li>Identifies artifact: The provenance MUST identify the output artifact via at least one cryptographic hash. The subject field in the SLSA provenance captures the location of the built artifact and the cryptographic hash associated with it. To be able to capture the artifact, Tekton Pipelines should populate the result variable <code>-ARTIFACT_OUTPUTS</code> with the location and the digest of the artifact.</li> </ol> <img src="p1.png"> <ol start="2"> <li>Identifies builder: The provenance identifies the entity that performed the build and generated the provenance. The <code>builder.id</code> field captures the builder that built the artifact.</li> </ol> <img src="p2.png"> <ol start="3"> <li>Identifies build instructions: The provenance identifies the top-level instructions used to execute the build. In our example, the build script is in source control. Recording the repo, the path in the repo and the commit hash will uniquely identify the build instructions used to build the artifact.</li> </ol> <img src="p3.png"> <ol start="4"> <li>Identifies source code: The provenance identifies the repository origin(s) for the source code used in the build. The materials field records all the dependencies used to build the artifact, one of which is the source code. In the example the source used is in a GitHub repo, and as such the repo name and the commit hash will uniquely identify the source code.</li> </ol> <img src="p4.png"> <h1 id="conclusion">Conclusion</h1> <p>SLSA aims to secure the software supply chain by providing guidelines on how the software build should be done. Tekton pipelines and Tekton chains implement those guidelines and help in securing the software supply chain.</p> <div class="alert alert-primary" role="alert"> <h4 class="alert-heading">Note</h4> This blog post was first published on the <a href="https://opensource.googleblog.com/2023/03/getting-to-slsa-level-2-with-tekton-and-tekton-chains.html">Google Open Source Blog</a>. </div> Blog: Meet with Tekton Community at cdCon + GitOpsCon 2023 https://tekton.dev/blog/2023/04/14/meet-with-tekton-community-at-cdcon--gitopscon-2023/ Fri, 14 Apr 2023 00:00:00 +0000 https://tekton.dev/blog/2023/04/14/meet-with-tekton-community-at-cdcon--gitopscon-2023/ <figure class="card rounded p-2 td-post-card mb-4 mt-4" style="max-width: 710px"> <img class="card-img-top" src="https://tekton.dev/blog/2023/04/14/meet-with-tekton-community-at-cdcon--gitopscon-2023/banner_hu3edca6e79142eb081bb1a7aa7435c472_177554_700x500_fit_catmullrom_3.png" width="700" height="366"> </figure> <p>The <a href="https://cd.foundation">Continuous Delivery Foundation (CDF)</a> is happy to host its fourth flagship event, cdCon, taking place on May 8–9, 2023 in Vancouver, Canada as <a href="https://events.linuxfoundation.org/cdcon-gitopscon/">cdCon + GitOpsCon</a>, co-organized with the <a href="https://cncf.io/">Cloud Native Computing Foundation (CNCF)</a>, making it the must-attend event for anyone who is involved in CD, DevOps, and GitOps.</p> <p>By combining the two events, cdCon + GitOpsCon aims to bring their communities together to collaborate and build the future of GitOps and CD. The program committees reviewed more than 250 submissions and selected over 60 sessions that will span topics from technical challenges and deep dives, to end-user stories and introductory content.</p> <p>The <a href="https://events.linuxfoundation.org/cdcon-gitopscon/program/schedule/">cdCon + GitOpsCon program</a> contains sessions from the most widely used CI/CD and GitOps technologies. The Tekton Community will be there with project updates and various talks from our community members and users. Here are some of the sessions you don’t want to miss.</p> <ul> <li><a href="https://sched.co/1Jp8P">Operating Tekton with Secure Defaults</a> - Christie Wilson Warwick &amp; Wendy Dembowski, Google</li> <li><a href="https://sched.co/1KDgj">Tekton Project Update and Roadmap</a> - Andrea Frittoli, IBM</li> <li><a href="https://sched.co/1JpAX">Save Your Pipelines (and Clusters!) with Tekton Results</a> - Adam Kaplan, Red Hat &amp; Dibyo Mukherjee, Google</li> <li><a href="https://sched.co/1KDTf">Tekton Supply Chain Security</a> - Billy Lynch, Chainguard</li> </ul> <p>In addition to these sessions, Andrea Frittoli of IBM, a member of the Tekton Governance Committee and maintainer will take part in <a href="https://sched.co/1Js9F">the Graduated Projects Keynote Panel</a>, discussing Tekton Community’s experiences with graduation and sharing his thoughts on why graduation matters for the community and users of Tekton.</p> <p>We look forward to an awesome event and we hope to see you there!</p> Blog: Tekton Graduation https://tekton.dev/blog/2022/10/26/tekton-graduation/ Wed, 26 Oct 2022 00:00:00 +0000 https://tekton.dev/blog/2022/10/26/tekton-graduation/ <p>We&rsquo;re very happy to announce that Tekton has reached graduated status within the Continuous Delivery Foundation (CDF). The CDF Technical Oversight Committee (TOC) conducted public <a href="https://lists.cd.foundation/g/cdf-toc/topic/94265202#861">voting</a> to decide on the graduation status for Tekton, and the result was unanimously positive. The Tekton community is very proud of the results of the vote and will continue working to make Tekton better and safer for its users.</p> <p>In this blog post I will explore a bit of the history of Tekton, its &ldquo;road to graduation&rdquo; and what this milestone means for the project.</p> <h2 id="early-days">Early Days</h2> <p>The Tekton project has its roots in <a href="https://knative.dev">Knative</a>, where it was initially called &ldquo;Knative Build&rdquo; and later &ldquo;Knative Pipeline&rdquo;. The project was spun off in August 2018, when it got it&rsquo;s current name and a new home on GitHub as <a href="https://github.com/tektoncd/pipeline">&ldquo;tektoncd/pipeline&rdquo;</a>. Here&rsquo;s one of the project&rsquo;s very first commits:</p> <pre tabindex="0"><code class="language-git" data-lang="git">commit 49d2316d71e8c315e0a8fd76008bc2920f56b3c3 Author: Christie Wilson &lt;[email protected]&gt; Date: Fri Aug 31 17:15:35 2018 -0700 Add pipeline strawman example @dlorenc @ImJasonH @tejal29 @aaron-prindle and I have been working on a strawman proposal for adding a Pipeline CRD and also for possibly envolving the Build CRD into a slightly more generic Task CRD. This PR demonstrates some paper prototype examples of what it could look like to define pipelines using the CRDs described in the README. </code></pre><p>A few months later, in March 2019, <a href="https://cd.foundation/blog/2019/03/12/introducing-the-continuous-delivery-foundation-the-new-home-for-tekton-jenkins-jenkins-x-and-spinnaker/">Tekton was donated</a> to the newly formed <a href="https://cd.foundation">Continuos Delivery Foundation (CDF)</a>.</p> <h2 id="growing-the-community">Growing the community</h2> <p>Since then the project has thrived thanks to a rich community of contributors. One of earlier repositories to be created was the <a href="https://github.com/tektoncd/community">community</a> one, where the project documented its governance, code of conduct and contributing guidelines.</p> <p>At the end of 2019 Tekton the number of repositories had grown to eleven. A regular monthly release cadence was established - Pipeline had 9 releases and in March 2020 the beta version of the Tekton Pipeline API was <a href="https://github.com/tektoncd/pipeline/releases/tag/v0.11.0">released</a>. During this time, we also implemented the project&rsquo;s release automation using Tekton itself.</p> <p>The &ldquo;results&rdquo; and &ldquo;chains&rdquo; project were started in spring 2020, and in August the Tekton Hub was <a href="https://cd.foundation/blog/2020/08/10/introducing-tekton-hub/">officially launched</a>.</p> <p>The Tekton community kept growing thanks to Tekton adopters and end-users contributing features, ideas and issues.</p> <figure class="card rounded p-2 td-post-card mb-4 mt-4" style="max-width: 710px"> <img class="card-img-top" src="https://tekton.dev/blog/2022/10/26/tekton-graduation/contributions_hu04d52bdf5973ab2447b9c771b5a33128_410958_700x500_fit_catmullrom_3.png" width="700" height="316"> <figcaption class="card-body px-0 pt-2 pb-0"> <p class="card-text"> Contributions and contributors to Tekton Projects over time. Source <a href="https://tekton.devstats.cd.foundation/d/74/contributions-chart?orgId=1&from=1540938487786&to=1666996087786&var-period=m&var-metric=contributions&var-repogroup_name=All&var-country_name=All&var-company_name=All&var-company=all&viewPanel=5&theme=light&kiosk=">devstats</a>. </p> </figcaption> </figure> <h2 id="focus-on-security">Focus on security</h2> <p>One year later, it&rsquo;s now 2021, Tekton had matured considerably, while remaining true to its nature of having a small footprint and giving users full flexibility in how they setup their CI/CD system through Tekton.</p> <p>This very flexibility has enabled Tekton to become the base for the implementation of more opinionated services on top, ranging from open source projects, and cloud services as well as end-user platforms for DevOps services.</p> <p>It was then prime time to focus more thoroughly on security! In July 2021 the Tekton Vulnerability Team was formed. Tekton pipelines release v0.29 was the first one to be signed through Tekton chains, with the provenance Rekor UUID included in the release notes.</p> <p>End user adoption shows how Tekton, with the help of Tekton Chains, can help solve software supply chain security challenges.</p> <blockquote class="twitter-tweet"><p lang="en" dir="ltr">Very excited to see SolarWinds Trebuchet really exploring the full potential of Tekton!! 😻 <a href="https://twitter.com/hashtag/SupplyChainSecurityCon?src=hash&amp;ref_src=twsrc%5Etfw">#SupplyChainSecurityCon</a> <a href="https://twitter.com/hashtag/KubeCon?src=hash&amp;ref_src=twsrc%5Etfw">#KubeCon</a> <a href="https://t.co/IFJKvED1q7">https://t.co/IFJKvED1q7</a> <a href="https://t.co/bS1UuBGuxh">pic.twitter.com/bS1UuBGuxh</a></p>&mdash; tektoncd (@tektoncd) <a href="https://twitter.com/tektoncd/status/1447608787737538560?ref_src=twsrc%5Etfw">October 11, 2021</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script> <p>In March 2022, thanks to the the sponsorship of the CDF, Tekton completed an <a href="https://cd.foundation/blog/2022/08/26/tekton-security-review-completed/">independent security audit</a>.</p> <p>Later that year, Tekton achieved the <a href="https://bestpractices.coreinfrastructure.org/en">OpenSSF Best Practices badges</a> for its six core components.</p> <h2 id="long-term-support">Long Term Support</h2> <p>In October 2022 the Tekton community defined its <a href="https://github.com/tektoncd/community/blob/main/releases.md#support-policy">policy for long term support (LTS)</a>:</p> <blockquote> <p>The Tekton project maintains four release branches for each project, created one every three months, which results in a overall support window of approximately one year for each of these releases.</p> </blockquote> <p>These releases are called LTS, and throughout the support period, patch releases may be created to resolve:</p> <ul> <li>CVEs (under the advisement of the Tekton Vulnerability Team)</li> <li>dependency issues (including base image updates)</li> <li>critical core component issues</li> </ul> <p>The community-wide policy can be extended by each project. Pipeline continuous with its monthly cadence, and it selects four releases a year for LTS.</p> <figure class="card rounded p-2 td-post-card mb-4 mt-4" style="max-width: 710px"> <img class="card-img-top" src="https://tekton.dev/blog/2022/10/26/tekton-graduation/releases_hu2171de425f0c2dafe5526f10f8fa1975_233697_700x500_fit_catmullrom_3.png" width="700" height="425"> <figcaption class="card-body px-0 pt-2 pb-0"> <p class="card-text"> Tekton Pipeline Releases and their support window. </p> </figcaption> </figure> <h2 id="graduation">Graduation</h2> <p>The Graduated Stage for projects under the CD Foundation umbrella is when they have reached their growth goals and are now on a sustaining cycle of development, maintenance, and long-term support. Graduated Stage projects are used commonly in enterprise production environments and have large, well-established project communities.</p> <p>More specifically, the Technical Oversight Committee (TOC) <a href="https://github.com/cdfoundation/toc/blob/b4844654fe5d355496481bed1bff3166889584ed/PROJECT_LIFECYCLE.md#graduated-stage">defines graduation</a> as a set of requirements about project maturity, best practices, security stance and adoption.</p> <p>Tekton is the second project to graduate from the CD Foundation, after Jenkins. All the details about the twelve graduation criteria be found in the <a href="https://github.com/cdfoundation/toc/blob/main/proposals/tekton/graduation.md">graduation proposal</a>.</p> <figure class="card rounded p-2 td-post-card mb-4 mt-4" style="max-width: 710px"> <img class="card-img-top" src="https://tekton.dev/blog/2022/10/26/tekton-graduation/banner_hu17a6c1a56b71bfd2f1a4341d584defe4_2637834_700x500_fit_catmullrom_3.png" width="700" height="366"> </figure> <h2 id="whats-next">What&rsquo;s Next</h2> <p>Graduation is a great milestone for the project and a great responsibility too. The community will continue to work on improving Tekton, while keeping the project stable and secure.</p> <p>We are working on several security features like trusted resources and trusted workloads, as well as releasing the v1 version of the API.</p> <h2 id="acknowledgments">Acknowledgments</h2> <p>The graduation has been the result of the years long work of the Tekton community. Congratulations and thank you to all the Tekton contributors who made it possible!</p> <p>Thank you for the the CDF for hosting the project and supporting it, especially through the security audit. Thank you to the TOC and its chair Oleg for their support and sponsorship as well as to the CDF team, Fatih, Jesse and Roxanne for their great work with marketing and organizing the <a href="https://cd.foundation/announcement/2022/10/25/cd-foundation-welcomes-new-software-supply-chain-security-project-pyrsia-announces-tekton-graduation-and-cdevents-release/">press release</a>.</p>