快速开始

Tekton Results 安装

本文档说明如何使用现有数据库安装 Tekton Results。

NOTE

目前不支持内置 PostgreSQL 数据库,请使用外部数据库。

关于外部数据库,请参阅 Using PostgreSQL from Data Services

TIP

Tekton Results 支持将日志存储到多种存储后端。S3 兼容对象存储(例如 AWS S3、Ceph、MinIO)现在是推荐方案,适用于可扩展且持久的日志保留。有关详细的 S3 存储配置,请参阅 S3 Storage Configuration Guide。不建议在生产环境中使用本地 PVC 存储。

前提条件

  1. 集群中必须已安装 Tekton Pipelines。

    TIP

    以下说明默认假设你已将 Results 安装到 tekton-pipelines 命名空间中。

    如果你安装到了其他命名空间,请将 tekton-pipelines 替换为你的命名空间。

  2. 创建数据库 root 密码。

    用户必须先生成数据库 root 密码,并在安装前将其存储到 Kubernetes Secret 中。默认情况下,Tekton Results 期望该 Secret 具有以下属性:

    • Namespace: tekton-pipelines
    • Name: tekton-results-postgres
    • 包含以下字段:
      • POSTGRES_USER=<your_username>
      • POSTGRES_PASSWORD=<your_password>

    你可以使用以下命令快速创建一个 Secret

    kubectl create secret generic tekton-results-postgres --namespace="tekton-pipelines" --from-literal=POSTGRES_USER={POSTGRES} --from-literal=POSTGRES_PASSWORD={PASSWORD}
  3. 生成证书/密钥对。注意:可使用任何证书管理软件完成此目的!

    Tekton Results 期望证书/密钥对存储在名为 tekton-results-tlsTLS Kubernetes Secret 中。

    • 生成新的自签名证书

      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

      如果你的 openssl 版本过低而不支持某些参数,请从 openssl binaries 升级你的 openssl 版本。

    • 根据证书创建新的 TLS Secret。

      kubectl create secret tls -n tekton-pipelines tekton-results-tls \
        --cert=cert.pem \
        --key=key.pem
  4. (仅适用于快速开始)如果你使用的是旧版 File 存储类型,请创建一个 PVC(不建议用于生产环境)。

    WARNING

    不建议在生产环境中使用基于 PVC 的本地存储。S3 兼容对象存储是用于可扩展且持久日志保留的推荐方案。有关 S3 存储配置,请参阅 S3 Storage Configuration Guide

    如果你仍然需要使用 PVC 进行测试:

    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
    • 请根据需要调整 PVC 大小。
    • 注意:仅在使用旧版 File 存储类型时才需要此步骤。

使用 operator CRD 安装

$ cat <<EOF | kubectl create -f -
apiVersion: operator.tekton.dev/v1alpha1
kind: TektonConfig
metadata:
  name: config
spec:
  # 目标命名空间
  targetNamespace: tekton-pipelines
  result:
    # 使用数据库地址更新
    db_host: <database_host>
    db_port: 5432
    db_name: <database_name>
    # 使用外部数据库
    is_external_db: true
    # 包含之前创建的数据库账户信息的 secret
    db_secret_name: tekton-results-postgres
    # 基本设置
    server_port: 8080
    # 禁用认证
    auth_disable: true
    db_enable_auto_migration: true
    log_level: debug
    # 使用日志存储服务
    logs_api: true
    log_type: File
    logging_pvc_name: tekton-logs
    # logs_type: S3  # 推荐:使用 S3 兼容存储实现可扩展的日志保留
    # secret_name: tekton-results-s3-credentials  # 包含 S3 凭证的 Secret
    logs_path: /logs
    logs_buffer_size: 92160
    # 与旧版 File 存储不同,S3 存储不需要 PVC
EOF
DETAILS

Tekton Results 的所有配置字段都嵌套在 TektonConfig 资源的 spec.result 下。

  • db_host:数据库主机。
  • db_port:数据库端口。
  • db_name:数据库名称。
  • is_external_db:是否使用外部数据库。
    • true:使用外部数据库。
  • db_secret_name:包含数据库账户信息的 secret 名称。
    • 这是上一步创建的 secret。
  • server_port:服务器端口。
  • targetNamespace:部署 Results 的命名空间。
  • auth_disable:是否禁用认证。
  • db_enable_auto_migration:是否启用数据库自动迁移。
  • log_level:日志级别。
  • logs_api:是否启用日志 API。
    • true:启用日志 API。
  • logs_type:日志类型。
    • File:将日志存储为文件(不建议用于生产环境)。
    • S3:将日志存储到 S3 兼容对象存储(例如 AWS S3、Ceph、MinIO)。这是用于可扩展且持久日志保留的推荐方案。有关详细配置,请参阅 S3 Storage Configuration Guide
  • secret_name:包含 S3 账户信息的 secret 名称。有关详细配置,请参阅 S3 Storage Configuration Guide
  • logs_path:日志路径。
  • logs_buffer_size:日志缓冲区大小。
  • logging_pvc_name:用于存储日志的 PVC 名称(仅在使用旧版 File 存储类型时需要)。
    • 这是上一步创建的 PVC(S3 存储不需要)。
TIP

有关更多数据库配置,请参阅 PostgreSQL Configuration

部署后,你可以看到 results-api / results-retention-policy-agent / results-watcher 的状态为 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

验证功能

可以通过一个简单的 taskrun 来验证功能。

1. 创建一个 TaskRun 资源

$ 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

对于 air-gapped 环境,请将 alpine 镜像地址更换为网络中可用的其他镜像

2. 等待 task 执行完成

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

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

3. 使用 tkn-results CLI 查询结果

准备 CLI

tkn 是用于与 Tekton 交互的命令行工具。你可以从 official page 下载它。

你需要使用 golang 构建 tkn-results

不要始终从 main 构建。请使用与你环境中已部署的 Tekton Results 版本相匹配的 release 分支。 你可以在 Release NotesResults 列)中找到 Results 组件版本,然后检出对应的分支 release-v<version>.x

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

# 2. Change to the project directory
cd results

# 3. Checkout the matching release branch (example: Results 0.15.x -> release-v0.15.x)
git checkout release-v<version>.x

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

# 5. Copy the binary to a directory in your PATH
连接行为

当未设置 --addr 时,tkn-results 会尝试自动 port-forward 到 Results API service。

在许多版本中(包括 release-v0.15.x),自动目标是 tekton-pipelines/tekton-results-api-service。 如果你的 Results 部署使用了不同的命名空间或 service 名称,自动模式可能会失败。

当设置了 --addr 时,tkn-results 会直接连接到该地址。 在这种情况下,你通常需要自行运行 kubectl port-forward

查询执行记录列表
$ 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
auto port-forward 失败时的回退方案
$ kubectl port-forward -n <results-namespace> service/tekton-results-api-service 8080

$ tkn results --insecure --addr localhost:8080 records list default/results/-
$ tkn results --insecure --addr localhost:8080 records get -o textproto default/results/<result-uid>/records/<record-uid>
$ tkn results --insecure --addr localhost:8080 logs list default/results/-
$ tkn results --insecure --addr localhost:8080 logs get -o textproto default/results/<result-uid>/logs/<log-uid>
# If logs get returns "unknown service tekton.results.v1alpha3.Logs", retry with:
$ tkn results --insecure --addr localhost:8080 --v1alpha2 logs get -o textproto default/results/<result-uid>/logs/<log-uid>
查询单个执行记录
$ 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
}
查询日志列表
$ 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
查询单个日志

Logs API 版本可能因部署而异。 如果遇到 unknown service tekton.results.v1alpha3.Logs,请使用 --v1alpha2 标志重试该命令。

$ 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"

参考资料