Tektonは、kubernetesクラスタ上で動作するCI/CDツールです。
コンテナにスクリプトやパラメータを注入し、ワークフローを制御することでテストやビルドを実装します。
ビルドのパイプラインはすべてk8sのYAML manifestとして定義していくことになります。
Tektonのインストール
Tektonは、kubernetesのリソースとして実装されており、kubectl apply
でインストールできます。
基礎的な機能はPipelinesというモジュールが提供しており、以下のコマンドでセットアップできます。
$ kubectl apply --filename https://storage.googleapis.com/tekton-releases/pipeline/latest/release.yaml
CLIインストール
クライアント向けのCLIは GitHub Releasesから各プラットフォーム用のパッケージをダウンロードしてインストールします。
パイプラインやタスクを制御するtkn
コマンドを利用可能になります。
複数のクラスタがある場合、kubernetesのカレントコンテキストを参照してリクエストを発行します。
Webhook
Webhookの機能はアドオンです。Pipeliesの動作を前提としているため、まずはPipelinesの完備が先決と言えます。
詳細は、
Tekton Triggersを参照してください。
Tekton Pipelinesの概要
Tektonは 公式ドキュメントが充実しているため、個別機能についてはリファレンスを通じて比較的理解しやすいと言えます。
むしろコンテナネイティブの新規性のため、アーキテクチャを把握することの方が手間どりやすいでしょう。
- 処理手順を
Task
とPipeline
というリソースに実装する。 image
やvolumeMounts
など、kubernetes由来の機能をそのまま利用でき、プライベートリソースへのアクセスをセットアップできる。- 実際のジョブ実行リソースは、
TaskRun
とPipelineRun
。主に各ビルドのパラメータを注入する役割を持つ。これらをcreateするとPodが順次作成されビルドが走る。 - コンテナ間のデータ共有は、 Workspacesを利用する。Pod内のVolume共有と同様の実装になる
TaskRunはコンテキスト情報のセットであり、CLIからタスクを起動する際には以下のようにオプション指定します。
TaskRunを省略した場合には、必要なパラメータをコンソールから対話的に指定するモードになります。
$ tkn task start <task_name> --use-taskrun <taskrun_name>
Pipelinesの構成リソースのうち、現状整備が進んでいないのは、input
とoutput
の機能です。
アーティファクトはコンテナ間をinput
とoutput
で接続する想定でスタートしていますが、beta段階でやや非推奨状態になっています。
ドキュメントの書き方が一貫していないため、注意が必要です。
k8sバージョン互換性
Tekton Pipelinesは活発なリリースを維持しており、機能や品質、Deprecationの点で新バージョンを積極的に採り入れる運用がベターと言えます。
一方、TektonはKubernetesのサポートバージョンを適宜切り捨てている点には注意が必要です。非サポートのk8sクラスタ上でTektonをアップグレードすると、tekton-pipelines
ネームスペース内の新バージョンpodが起動しない挙動になります。
この場合、k8sのバージョンはノードではなくk8sマスターのバージョンを指しています。 component skewの解説のとおり、ノードはマスターより2マイナーバージョンまで古い構成を想定しているため、マスターのみ更新する手段は妥当でしょう。
ノードにはクラウドのストレージドライバなど稼働品質に直結するコンポーネントが含まれるため、検証のうえバージョンアップすべきです。
マネージドサービスではノードがマスターバージョンを自動追従する場合があるため、意図的にバージョン混在させる際には設定に注意が必要です。
Sidecar
taskの各処理はsteps
に記載しますが、sidecars
にもコンテナを追加できます。Sidecarは、steps実行前に起動され、前提サービスとして利用できます。
複数のコンテナを起動できるため、プロキシ構成も可能です。Sidecarのネットワークサービスには、stepのコンテナからlocalhostでアクセスできます。
SidecarはStepより前に準備される都合上、gitリポジトリなどを利用する場合、stepとは別にセットアップする必要があります。
PipelineとTask
Taskはsteps
の集合であり、PipelineはTaskの集合です。
また、Pipelineにはメインフローのspec.tasks
のほか、spec.finally
を定義できます。finally
は、try-catch-finallyのfinallyにあたる処理で、tasks
の処理状況によらず最終的に実行されます。
tasks.status
変数に処理結果が入るため、where
によるガード判定を追加することで、catch相当の処理を書くことも可能です。
Taskの組み合わせ方については、 Tekton Pipelinesの制御フローで解説しています。
環境変数
各ステップにはPod定義と同様の設定を記述でき、env
で環境変数も指定できます。
kubernetesのSecretでクレデンシャル管理で解説しているenvFrom
を利用するとSecretに定義したクレデンシャルを環境変数としてインポートできます。
imagePullPolicy
Taskで利用するコンテナイメージは、デフォルトではキャッシュされます。
imagePullPolicy: Always
を指定することで、各実行時にイメージを更新する挙動になります。
この点はドキュメントの言及がなく、修正してもイメージが差し替わらない挙動になると分かりづらいため、注意が必要です。
timeout
各ステップにはtimeout: 30s
のようにタイムアウトを指定できます。
ステップの処理が滞留した場合に時間切れでフェイルする挙動になります。
プライベートレジストリの認証
コンテナイメージの認証は、k8s標準の
プライベートレジストリへのアクセス権を設定の手順で設定できます。
ただし、ServiceAccountはネームスペースごとに作成されるオブジェクトであることに注意が必要です。taskのネームスペースのデフォルトServiceAccountにsecretをアタッチする必要があります。
podTemplate
TaskRunのspec.podTemplate
にはpod標準のspecを書けます。これをPipelineRunに記述する場合はspec.taskRunTemplate.podTemplate
に記述します。
たとえば
affinityを定義すると、タスクの実行ノードを指定できます。
タスクのリソース制約
tektonはタスクごとのPod内に、step単位でコンテナを作成します。コンテナのCPU、RAMなどのリソースはkubernetes標準の LimitRange設定を参照します。
Tekton Pipelinesのメリット
コンテナネイティブのメリットは、ビルディングブロックの再現性があります。
コンテナイメージに必要なツールをインストールしておくことで、均質なビルド環境を得られます。
実行環境もkubernetesのリソースプールの一角を利用できるため、ハード資源管理をアンバンドルできます。
Tekton Pipelinesは、ワークフロー管理がスムーズである点で良くできています。
JenkinsなどのCIツールで実装しようとすると、Job
の完了waitの機能不足などで細々とした使いにくさに直面します。
また、Pipelinesのマニフェスト規約も妥当な文法になっていると言えます。
従来のCIツールでは、メインのジョブ記述言語でラップされてしまうだめ、パラメータの参照やコンテナ上のスクリプトが素直に書けないという問題がありました。
CI/CDは複雑なシステムですが、Tektonを使うとすべてのプロセスを宣言的なコードとして管理できるようになります。
実行済タスクのクリーンアップ
tektonの実行済タスクを削除する機能は未実装です。
クリーンアップの方法は、
Using CronJobs to automatically clean up completed Runs #479のリンク先に掲載されている方法を利用できます。
ワンライナーのコマンドによりtaskrunの一括削除も可能です。
$ kubectl get taskrun --sort-by=.metadata.creationTimestamp -o name | (while read -r NAME; do kubectl delete "$NAME"; done)
ただし、taskrunにはテンプレートとインスタンスの違いがなく、一括削除するとtaskrunの再作成が必要になります。
| grep -v 'task$' |
などのシェルパイプを用いて、名称の末尾マッチで除外するとインスタンスのみ削除しやすくなるでしょう。
k8s標準のJobと同様、一時的なコンテナがたくさん生成されるため、あらかじめ独立のネームスペースを確保した方が使いやすいかもしれません。
TaskやPipelineなどあらゆるリソースにnamespace
指定するとコンテナ操作を切り分けられます。
Chuma Takahiro