Quick Start

Installation of Tekton Results

This document explains how to install Tekton Results using an existing database.

NOTE

Currently, the built-in PostgreSQL database is not supported, please use an external database.

About external database please refer to Using PostgreSQL from Data Services

TIP

Tekton Results supports storing logs in various storage backends. S3-compatible object storage (such as AWS S3, Ceph, MinIO) is now the recommended approach for scalable and durable log retention. For detailed S3 storage configuration, see the S3 Storage Configuration Guide. Local PVC storage is not recommended for production use.

Prerequisites

  1. Tekton Pipelines must be installed in the cluster.

    TIP

    The following instructions assume that you have installed Results into the tekton-pipelines namespace by default.

    If you have installed it into a different namespace, please replace tekton-pipelines with your namespace.

  2. Create a database root password.

    Users must generate a database root password and store it in a Kubernetes Secret before installation. By default, Tekton Results expects this Secret to have the following attributes:

    • Namespace: tekton-pipelines
    • Name: tekton-results-postgres
    • Including the following fields:
      • POSTGRES_USER=<your_username>
      • POSTGRES_PASSWORD=<your_password>

    You can quickly generate a Secret using the following command:

    kubectl create secret generic tekton-results-postgres --namespace="tekton-pipelines" --from-literal=POSTGRES_USER={POSTGRES} --from-literal=POSTGRES_PASSWORD={PASSWORD}
  3. Generate a certificate/key pair. Note: Any certificate management software can be used for this purpose!

    Tekton Results expects the certificate/key pair to be stored in a TLS Kubernetes Secret named tekton-results-tls.

    • Generate a new self-signed certificate

      openssl req -x509 \
        -newkey rsa:4096 \
        -keyout key.pem \
        -out cert.pem \
        -days 365 \
        -nodes \
        -subj "/CN=tekton-results-api-service.tekton-pipelines.svc.cluster.local" \
        -addext "subjectAltName = DNS:tekton-results-api-service.tekton-pipelines.svc.cluster.local"
      TIP

      If your openssl version is too low and does not support some parameters, please upgrade your openssl version from openssl binaries .

    • Create a new TLS Secret from the certificate.

      kubectl create secret tls -n tekton-pipelines tekton-results-tls \
        --cert=cert.pem \
        --key=key.pem
  4. (For quick start only) Create a PVC if you are using the legacy File storage type (not recommended for production).

    WARNING

    PVC-based local storage is not recommended for production use. S3-compatible object storage is the recommended approach for scalable and durable log retention. For S3 storage configuration, see the S3 Storage Configuration Guide.

    If you still need to use PVC for testing purposes:

    cat <<EOF | kubectl create -f -
    apiVersion: v1
    kind: PersistentVolumeClaim
    metadata:
      name: tekton-logs
      namespace: tekton-pipelines
    spec:
      accessModes:
        - ReadWriteOnce  # The access mode indicating it can be read and written by a single node
      resources:
        requests:
          storage: 100Gi  # The requested storage size
    EOF
    • Please adjust the PVC size as needed.
    • Note: This is only required if using the legacy File storage type.

Installing using operator CRD

$ cat <<EOF | kubectl create -f -
apiVersion: operator.tekton.dev/v1alpha1
kind: TektonConfig
metadata:
  name: config
spec:
  # Target namespace
  targetNamespace: tekton-pipelines
  result:
    # Update with database address
    db_host: <database_host>
    db_port: 5432
    db_name: <database_name>
    # Use external database
    is_external_db: true
    # secret containing database account information created earlier
    db_secret_name: tekton-results-postgres
    # Basic settings
    server_port: 8080
    # Disable authentication
    auth_disable: true
    db_enable_auto_migration: true
    log_level: debug
    # Use logs storage service
    logs_api: true
    log_type: File
    logging_pvc_name: tekton-logs
    # logs_type: S3  # Recommended: S3-compatible storage for scalable log retention
    # secret_name: tekton-results-s3-credentials  # Secret containing S3 credentials
    logs_path: /logs
    logs_buffer_size: 92160
    # S3 storage does not require PVC, unlike legacy File storage
EOF
DETAILS

All Tekton Results configuration fields are nested under spec.result in the TektonConfig resource.

  • db_host: The host of the database.
  • db_port: The port of the database.
  • db_name: The name of the database.
  • is_external_db: Whether to use an external database.
    • true: Use an external database.
  • db_secret_name: The name of the secret containing the database account information.
    • This is the secret created in the previous step.
  • server_port: The port of the server.
  • targetNamespace: The namespace where the Results is deployed.
  • auth_disable: Whether to disable authentication.
  • db_enable_auto_migration: Whether to enable automatic database migration.
  • log_level: The level of the log.
  • logs_api: Whether to enable the logs API.
    • true: Enable the logs API.
  • logs_type: The type of the logs.
    • File: Store logs in a file (not recommended for production use).
    • S3: Store logs in S3-compatible object storage (e.g., AWS S3, Ceph, MinIO). This is the recommended approach for scalable and durable log retention. For detailed configuration, see the S3 Storage Configuration Guide.
  • secret_name: The name of the secret containing the S3 account information. For detailed configuration, see the S3 Storage Configuration Guide.
  • logs_path: The path of the logs.
  • logs_buffer_size: The buffer size of the logs.
  • logging_pvc_name: The name of the PVC to store the logs (only required when using legacy File storage type).
    • This is the PVC created in the previous step (not needed for S3 storage).
TIP

About more database configuration, please refer to PostgreSQL Configuration

After deployment, you can see that the status of results-api / results-retention-policy-agent / results-watcher is Running

$ kubectl get pods -n tekton-pipelines

NAME                                                    READY   STATUS    RESTARTS   AGE
tekton-results-api-68bb657996-bb487                     1/1     Running   0          14s
tekton-results-retention-policy-agent-c6ff5575b-prczg   1/1     Running   0          14s
tekton-results-watcher-6d7c68f576-p2gbl                 1/1     Running   0          14s

Verify Functionality

Functionality can be verified through a simple taskrun.

1. Create a TaskRun resource

$ cat <<'EOF' | kubectl create -f -
apiVersion: tekton.dev/v1
kind: TaskRun
metadata:
  name: hello
spec:
  taskSpec:
    steps:
      - name: hello
        image: alpine
        command: ["echo", "hello"]
EOF
NOTE

For air-gapped environments change the alpine image address to another present in the network

2. Wait for the task execution to complete

$ kubectl get taskruns.tekton.dev -n default -w

hello                                        Unknown     Pending     3s
hello                                        True        Succeeded   11s         0s

3. Use tkn-results CLI to query results

Preparing the CLI

tkn is a command-line tool for interacting with Tekton. You can download it from the official page.

You need to build tkn-results using golang.

# 1. Clone the repository
git clone https://github.com/tektoncd/results.git

# 2. Change to the project directory
cd results

# 3. Build the binary
go build -o tkn-results ./cmd/tkn-results/main.go

# 4. Copy the binary to a directory in your PATH
Querying the execution record list
$ tkn results --insecure records list default/results/-

default/results/209dcb81-e3c0-47cd-b082-d910e15702ae/records/209dcb81-e3c0-47cd-b082-d910e15702ae  tekton.dev/v1.TaskRun                   2025-02-19 16:17:11 +0800 CST           2025-02-19 16:17:21 +0800 CST
default/results/209dcb81-e3c0-47cd-b082-d910e15702ae/records/a750035d-0479-34a1-9db2-9a256b53243f  results.tekton.dev/v1alpha3.Log         2025-02-19 16:17:21 +0800 CST           2025-02-19 16:17:21 +0800 CST
Querying a single execution record
$ tkn results --insecure records get -o textproto default/results/209dcb81-e3c0-47cd-b082-d910e15702ae/records/209dcb81-e3c0-47cd-b082-d910e15702ae

name: "default/results/209dcb81-e3c0-47cd-b082-d910e15702ae/records/209dcb81-e3c0-47cd-b082-d910e15702ae"
id: "0805bbd0-e390-40dc-a1ea-f65ae9401930"
uid: "0805bbd0-e390-40dc-a1ea-f65ae9401930"
data: {
  type: "tekton.dev/v1.TaskRun"
  value: "{\"kind\": \"TaskRun\", \"spec\": {\"timeout\": \"1h0m0s\", \"taskSpec\": {\"steps\": [{\"name\": \"hello\", \"image\": \"152-231-registry.alauda.cn:60070/ops/ubuntu:latest\", \"command\": [\"echo\", \"hello\"], \"computeResources\": {}}]}, \"serviceAccountName\": \"default\"}, \"status\": {\"steps\": [{\"name\": \"hello\", \"imageID\": \"alpine\", \"container\": \"step-hello\", \"terminated\": {\"reason\": \"Completed\", \"exitCode\": 0, \"startedAt\": \"2025-02-19T08:17:20Z\", \"finishedAt\": \"2025-02-19T08:17:20Z\", \"containerID\": \"containerd://5e2cb72ca758fc976744b06b5ee97564bcc0958ca9cee2a54fdaab64323a1bf9\"}, \"terminationReason\": \"Completed\"}], \"podName\": \"hello-pod\", \"taskSpec\": {\"steps\": [{\"name\": \"hello\", \"image\": \"152-231-registry.alauda.cn:60070/ops/ubuntu:latest\", \"command\": [\"echo\", \"hello\"], \"computeResources\": {}}]}, \"startTime\": \"2025-02-19T08:17:10Z\", \"conditions\": [{\"type\": \"Succeeded\", \"reason\": \"Succeeded\", \"status\": \"True\", \"message\": \"All Steps have completed executing\", \"lastTransitionTime\": \"2025-02-19T08:17:21Z\"}], \"provenance\": {\"featureFlags\": {\"Coschedule\": \"workspaces\", \"MaxResultSize\": 4096, \"EnableAPIFields\": \"beta\", \"EnableArtifacts\": false, \"EnableParamEnum\": false, \"DisableCredsInit\": false, \"EnableStepActions\": true, \"SetSecurityContext\": false, \"AwaitSidecarReadiness\": true, \"EnableKeepPodOnCancel\": false, \"EnableTektonOCIBundles\": false, \"ResultExtractionMethod\": \"termination-message\", \"SendCloudEventsForRuns\": false, \"DisableAffinityAssistant\": false, \"EnableProvenanceInStatus\": true, \"EnforceNonfalsifiability\": \"none\", \"EnableCELInWhenExpression\": false, \"VerificationNoMatchPolicy\": \"ignore\", \"ScopeWhenExpressionsToTask\": false, \"RequireGitSSHSecretKnownHosts\": false, \"RunningInEnvWithInjectedSidecars\": true}}, \"completionTime\": \"2025-02-19T08:17:21Z\"}, \"metadata\": {\"uid\": \"209dcb81-e3c0-47cd-b082-d910e15702ae\", \"name\": \"hello\", \"labels\": {\"app.kubernetes.io/managed-by\": \"tekton-pipelines\"}, \"namespace\": \"default\", \"finalizers\": [\"results.tekton.dev/taskrun\", \"chains.tekton.dev\"], \"generation\": 1, \"annotations\": {\"results.tekton.dev/log\": \"default/results/209dcb81-e3c0-47cd-b082-d910e15702ae/logs/a750035d-0479-34a1-9db2-9a256b53243f\", \"chains.tekton.dev/signed\": \"true\", \"results.tekton.dev/record\": \"default/results/209dcb81-e3c0-47cd-b082-d910e15702ae/records/209dcb81-e3c0-47cd-b082-d910e15702ae\", \"results.tekton.dev/result\": \"default/results/209dcb81-e3c0-47cd-b082-d910e15702ae\", \"pipeline.tekton.dev/release\": \"8bfd3273cbe7776847884d7fa5004481e6be8f4a\"}, \"managedFields\": [{\"time\": \"2025-02-19T08:17:10Z\", \"manager\": \"kubectl-create\", \"fieldsV1\": {\"f:spec\": {\".\": {}, \"f:taskSpec\": {\".\": {}, \"f:steps\": {}}}}, \"operation\": \"Update\", \"apiVersion\": \"tekton.dev/v1\", \"fieldsType\": \"FieldsV1\"}, {\"time\": \"2025-02-19T08:17:21Z\", \"manager\": \"controller\", \"fieldsV1\": {\"f:metadata\": {\"f:finalizers\": {\"v:\\\"chains.tekton.dev\\\"\": {}}, \"f:annotations\": {\"f:chains.tekton.dev/signed\": {}, \"f:pipeline.tekton.dev/release\": {}}}}, \"operation\": \"Update\", \"apiVersion\": \"tekton.dev/v1\", \"fieldsType\": \"FieldsV1\"}, {\"time\": \"2025-02-19T08:17:21Z\", \"manager\": \"controller\", \"fieldsV1\": {\"f:status\": {\".\": {}, \"f:steps\": {}, \"f:podName\": {}, \"f:taskSpec\": {\".\": {}, \"f:steps\": {}}, \"f:artifacts\": {}, \"f:startTime\": {}, \"f:conditions\": {}, \"f:provenance\": {\".\": {}, \"f:featureFlags\": {\".\": {}, \"f:Coschedule\": {}, \"f:MaxResultSize\": {}, \"f:EnableAPIFields\": {}, \"f:EnableArtifacts\": {}, \"f:EnableParamEnum\": {}, \"f:DisableCredsInit\": {}, \"f:DisableInlineSpec\": {}, \"f:EnableStepActions\": {}, \"f:SetSecurityContext\": {}, \"f:AwaitSidecarReadiness\": {}, \"f:EnableKeepPodOnCancel\": {}, \"f:ResultExtractionMethod\": {}, \"f:SendCloudEventsForRuns\": {}, \"f:EnableKubernetesSidecar\": {}, \"f:DisableAffinityAssistant\": {}, \"f:EnableProvenanceInStatus\": {}, \"f:EnforceNonfalsifiability\": {}, \"f:EnableCELInWhenExpression\": {}, \"f:VerificationNoMatchPolicy\": {}, \"f:EnableConciseResolverSyntax\": {}, \"f:RequireGitSSHSecretKnownHosts\": {}, \"f:RunningInEnvWithInjectedSidecars\": {}}}, \"f:completionTime\": {}}}, \"operation\": \"Update\", \"apiVersion\": \"tekton.dev/v1\", \"fieldsType\": \"FieldsV1\", \"subresource\": \"status\"}, {\"time\": \"2025-02-19T08:17:21Z\", \"manager\": \"watcher\", \"fieldsV1\": {\"f:metadata\": {\"f:finalizers\": {\".\": {}, \"v:\\\"results.tekton.dev/taskrun\\\"\": {}}, \"f:annotations\": {\".\": {}, \"f:results.tekton.dev/log\": {}, \"f:results.tekton.dev/record\": {}, \"f:results.tekton.dev/result\": {}}}}, \"operation\": \"Update\", \"apiVersion\": \"tekton.dev/v1\", \"fieldsType\": \"FieldsV1\"}], \"resourceVersion\": \"1592422\", \"creationTimestamp\": \"2025-02-19T08:17:10Z\"}, \"apiVersion\": \"tekton.dev/v1\"}"
}
etag: "0805bbd0-e390-40dc-a1ea-f65ae9401930-1739953041309658421"
created_time: {
  seconds: 1739953031
  nanos: 16922000
}
create_time: {
  seconds: 1739953031
  nanos: 16922000
}
updated_time: {
  seconds: 1739953041
  nanos: 309658000
}
update_time: {
  seconds: 1739953041
  nanos: 309658000
}
Querying the log list
$ tkn results --insecure logs list default/results/-

default/results/209dcb81-e3c0-47cd-b082-d910e15702ae/logs/a750035d-0479-34a1-9db2-9a256b53243f  results.tekton.dev/v1alpha3.Log         2025-02-19 16:17:21 +0800 CST           2025-02-19 16:17:21 +0800 CST
Querying a single log
$ tkn results --insecure logs get -o textproto default/results/209dcb81-e3c0-47cd-b082-d910e15702ae/logs/a750035d-0479-34a1-9db2-9a256b53243f

content_type: "text/plain"
data: "[prepare] 2025/02/19 08:17:12 Entrypoint initialization\n\n[hello] hello\n\n"

References