TektonPipelinesをコンテナ内から実行

Tekton Pipelinesはkubernetesクラスタ上で動作するCI/CDツールです。
ダッシュボードやCLIを用いて操作する方法が一般的ですが、TektonのCRDの1つPipelineRunリソースをkubernetesのAPIサーバーに直接送信するプリミティブな方法でもタスクを実行できます。

ミニマムな構成では、次のような方法になります。

FRAGMENT=$(cat /dev/urandom | base64 | tr -dC '[:alnum:]' | tr '[A-Z]' '[a-z]' | fold -w 5 | head -n 1)

cat << EOF | kubectl apply -f -
apiVersion: tekton.dev/v1
kind: PipelineRun
metadata:
  name: <some-pipelinerun-name>-$FRAGMENT
spec:
  pipelineRef:
  name: <some-pipeline-name>
EOF

ヒアドキュメントには PipelineRunのマニフェストを記述します。
実際には、metadata.namespacespec.paramsspec.workspacesも指定することになるでしょう。

$FRAGMENTは繰り返し実行の際に、重複を避けるための識別子生成の例です。

またkubectl実行時にTekton Pipelinesのリソース作成権限などを前提としています。

なおこの方式は、 Tekton Triggersが適切に動作しているのであれば採用する意味はあまりありません。
Triggersのセットアップもそれなりに複雑であるため、Pipelinesのみで完結したい場合の選択肢と言えます。

コンテナ内で実行する

Pipelineをコンテナ内から起動する典型的な用途は CronJobでしょう。
コンテナイメージにkubectlがインストールしてあり、ServiceAccount経由で必要な権限を供給できれば、ホスト上の操作と同様に動作します。

次のような記述例になります。

apiVersion: batch/v1
kind: CronJob
metadata:
  name: <some-job-name>
spec:
  jobTemplate:
    spec:
      template:
        spec:
          serviceAccountName: <some-serviceaccount>
          containers:
          - name: create-pipeline
            image: <some-image-name-having-kubectl>
            env:
            - name: PODNAME
              valueFrom:
                fieldRef:
                  fieldPath: metadata.name
            command: ["bash"]
            args:
            - "-c"
            - |
              cat <<EOF | kubectl apply -f -
              apiVersion: tekton.dev/v1
              kind: PipelineRun
              metadata:
                name: $PODNAME
              spec:
                pipelineRef:
                  name: <some-pipeline-name>
              EOF

この例の特徴は2点あります。

  • spec.jobTemplate.spec.template.spec.serviceAccontNameにサービスアカウントを指定している
  • DownwardAPIを用いてjobの名前を流用することで、$FRAGMENT生成を省略している。必須の方法ではないが各jobとの対応は分かりやすくなる

サービスアカウント

コンテナには、あらかじめServiceAccountRoleRoleBindingのセットを登録しておくことで権限を供給します。

apiVersion: v1
kind: ServiceAccount
metadata:
  name: <some-serviceaccount>
---
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  name: tekton-pipelines-operator
rules:
- apiGroups: ["tekton.dev"]
  resources: ["pipelineruns", "taskruns"]
  verbs: ["get", "list", "create"]
- apiGroups: ["tekton.dev"]
  resources: ["pipeline"]
  verbs: ["get", "list"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: pipeline-operator-binding
subjects:
- kind: ServiceAccount
  name: <some-serviceaccount>
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: Role
  name: tekton-pipelines-operator

おそらくspec.pipelineRefの影響でPipelineのread権限も要求されます。

コンテナ内の非rootユーザーで実行する

CronJobはコンテナプロセスのユーザーで実行するため、ServiceAccountを指定するだけで、kubectlがアクセスに必要なリソースを取得できます。

非rootで実行するような特殊なケースでは、次のような追加の工夫が必要になります。

export KUBERNETES_SERVICE_HOST=<some-host-address>
export KUBERNETES_SERVICE_PORT=<some-host-port>

FRAGMENT=$(cat /dev/urandom | base64 | tr -dC '[:alnum:]' | tr '[A-Z]' '[a-z]' | fold -w 5 | head -n 1)

cat << EOF | sudo -E kubectl apply -f -
apiVersion: tekton.dev/v1
kind: PipelineRun
metadata:
  name: <some-pipelinerun-name>-$FRAGMENT
spec:
  pipelineRef:
  name: <some-pipeline-name>
EOF

root実行と異なる点は次のとおりです。

  • トークン類はroot向けに供給されるので、コンテナイメージにsudoをインストールし、実行ユーザー向けにセットアップしておく
  • kubectlが参照するAPIサーバーアドレスがrootの環境変数に登録されるので、該当ユーザーの環境変数に設定しておく

sudoを用いず、トークンを該当ユーザー向けにセットアップする方法も考えられますが、必要な手間は似たようなものでしょう。

⁋ 2025/09/09↻ 2025/09/10
中馬崇尋
Chuma Takahiro