🗂

TEKTONとArgoを比較してみた

2020/12/24に公開

はじめに

この記事は NTTコミュニケーションズ Advent Calendar 2020の24日目の記事です。

Kubernetesで、CI/CDツールを選定するときに選択肢が多すぎて、何を選定したらいいかわからない!!
多くの担当者が抱えているあるあるだと思います。
ある程度トレンドを抑え、導入する環境の要件に相応しいCI/CDを選定していきたいものです。

その中でも、TEKTONとArgoが有名なCI/CDツールである。ということは何となくわかっていますが、
よくよく違いについてあまり理解していなかったので、調査してきました。

実はプロジェクトのこと

TEKTONとArgoをCI/CDツールと思っている人は少なくないと思いますが、
実は、プロジェクトであるということです。
実際、我々がTEKTONとArgoと省略して呼んでいるのはどうやら、大抵は以下のことを指していることが多いです。

  • TEKTON = TEKTON Pipeline
  • Argo = Argo CD

TEKTONとは

TektonはGoogleのKnativeのプロジェクトにいたが、
現在、CD FOUNDATIONのプロジェクトとして位置しているということです。

代表されるプロジェクトとしては以下のグループがあります。

グループ 説明
Pipelines CI/CDのパイプラインを構成する。Tektonと言ったらこれを指すと言ってもよい、コアな機能といえる。
Triggers GithubやGitlabなどからリクエストを受け取って、Tektonパイプラインを動作させるためのWEBサービス
CLI TektonPipelines用のCLIを提供
Dashboard TektonPipelinesのWEB-UIを提供

これらのグループを一式提供するoperatorも開発が進められているようです!

Argoとは

Argoは Cloud Native Computing Foundationのプロジェクトとして位置しているということです。

代表されるプロジェクトとしては以下のグループがあります。

グループ 説明
Argo Workflow CI/CDのパイプラインを構成する。
Argo CD CD機能を提供する。Gitリポジトリの変更検知を行い、helm/kustomizeなどにも対応している。Argoといえばこの機能を指すといってもよい
Argo Rollouts Blue/Greenデプロイ カナリアリリースなどのデプロイを実現でき、デプロイ分析も行うことができる。
Argo Events 様々なイベント(webhookなど)を受け取り、トリガーするためのWEBサービス

Gitopsを考えると

さきほど説明したグループを使って、TEKTONとArgoのそれぞれでGitopsをすることを考えてみます。

Applicatonリポジトリへのソースをcommitし、Build/PushするCIと、
Applicatonリポジトリへの変更を契機に、kubernetesマニフェストをデプロイするCDを想定すると、
以下のような区分けができそうです。

TEKTONでCD機能を実装することはあまり有用ではないかもしれない

TEKTONはパイプラインとトリガーの機能しか備わっていないため、CDをしようとなるとTektonPipelinesのパイプライン内で実現しなくてはなりません。
またTEKTONは、ArgoCDのような差分検知は難しく、デプロイ手法や分析も乏しいです。
実際に、TEKTON pipelinesとArgoCDを併用することもできるため、CDの手段にはArgoCDを使うのが良さそうです。

TEKTONとArgoでは被っていそうなグループもある

図をみてみると、役割としては以下が役割として被っていそうです。

  • TEKTON pipelineとArgoWorkflow
  • TEKTON TriggerとArgoEvents

被ってそうなところを見てみる

TEKTON pipelineとArgoWorkflow

CIのパイプライン部分を司る役割ではどちらも同じ機能と言えそうです。
実際の概念をそれぞれ確認してみます。

TEKTON pipeline

主なコンポーネント

TEKTONのパイプラインにおける、主なコンポーネントは以下のような感じです。

用語 説明
Step 実行処理の最小単位。Task内に記載する。
Task Stepの集合体。CRDで定義されている。
Pipeline TASKの集合体。並列もしくは直列にTaskを設定できる。CRDで定義されている。
TaskRun Taskの実行インスタンス。CRDで定義されている。
PipelineRun Pipelineの実行インスタンス。CRDで定義されている。
PipelineResource Pipelineが参照するアーティファクトの定義。CRDで定義されている。

それぞれの実行単位がこんな感じで定義できるのがわかると思います。
Pipeline > Task > Step
また、それらを実行するためのインスタンス定義としてこうある感じでしょうか。
PipelineRun > TaskRun

Kubernetesの概念と非常に近しいから、コンセプトが非常にわかりやすい!!
Task ≒ Pods
Step ≒ Container
という概念であり、Step/TASKを組み立ててパイプラインを立てていくというイメージが湧きやすいです。

Pipeline/Taskの作成したyamlサンプルとしてはこんな感じで、以下を確認することができると思います。

  • pipelineにTaskが書かれていること
  • PipelineRunから呼び出すためのパラメータ類が定義されていること
  • TaskにStepが書かれており、複数のステップを記載できること。(sampleでは1つしか記載していない)
apiVersion: tekton.dev/v1beta1
kind: Pipeline
metadata:
  name: build-and-deploy-pipeline
spec:
  workspaces:
    - name: git-source
      description: The git repo
  # パラメータセクション  実行時に PipelineRun から変数を与える。
  params:
    - name: gitUrl
      description: Git repository url
    - name: gitRevision
      description: Git revision to check out
      default: master
    - name: pathToContext
      description: The path to the build context, used by Kaniko - within the workspace
      default: src
    - name: imageUrl
      description: Image name including repository
    - name: imageTag
      description: Image tag
      default: "latest"
    - name: GIT_USER_NAME
      type: string
      description: |
        Git user name for performing git operation.
      default: ""
    - name: GIT_USER_EMAIL
      type: string
      description: |
        Git user email for performing git operation.
      default: ""
    - name: GIT_SCRIPT
      description: The git script to run.
      type: string
      default: |
        git help
  tasks:
    # タスク #1
    # GitHubからソースコードをワークスペースにクローン(取得)する
    - name: clone-repo
      taskRef:
        name: git-clone
      workspaces:
        - name: output
          workspace: git-source
      params:
        - name: url
          value: "$(params.gitUrl)"
        - name: revision
          value: "$(params.gitRevision)"
        - name: subdirectory
          value: "."
        - name: deleteExisting
          value: "true"

    # タスク #2 
    # コンテナのビルドとレジストリへ登録  Kanikoタスクにパラメータを渡してビルド実行、イメージをレジストリへ登録
    - name: source-to-image
      taskRef:
        name: kaniko
      runAfter:
        - clone-repo
      workspaces:
        - name: source
          workspace: git-source
      params:
        - name: CONTEXT
          value: $(params.pathToContext)
        - name: IMAGE
          value: $(params.imageUrl):$(params.imageTag)
    # タスク #3 
    # Gitのクローンし、Imageタグを置換、新しいブランチを作成し、GithubへPushする。
    - name: git-etc
      taskRef:
        name: git-cli
      runAfter:
        - source-to-image
      workspaces:
        - name: source
          workspace: git-source
        - name: input
          workspace: git-source
      params:
        - name: GIT_USER_NAME
          value: $(params.GIT_USER_NAME)
        - name: GIT_USER_EMAIL
          value: $(params.GIT_USER_EMAIL)
        - name: GIT_SCRIPT
          value: $(params.GIT_SCRIPT)

Taskのyaml(タスク #3)としてはこんな感じ
※TEKTONでは、Tekton catalogからTaskのyamlを収集できるのが良い!!

apiVersion: tekton.dev/v1beta1
kind: Task
metadata:
  name: git-cli
  labels:
    app.kubernetes.io/version: "0.1"
  annotations:
    tekton.dev/pipelines.minVersion: "0.12.1"
    tekton.dev/tags: git
    tekton.dev/displayName: "git cli"
spec:
  description: >-
    This task can be used to perform git operations.

    Git command that needs to be run can be passed as a script to
    the task.This task needs authentication to git in order to push
    after the git operation.

  workspaces:
    - name: source
      description: A workspace that contains the fetched git repository.
    - name: input
      description: A workspace that contains file that needs to be added to git.
  params:
    - name: BASE_IMAGE
      description: |
        The base image for the task.
      type: string
      default: alpine/git:latest

    - name: GIT_USER_NAME
      type: string
      description: |
        Git user name for performing git operation.
      default: ""

    - name: GIT_USER_EMAIL
      type: string
      description: |
        Git user email for performing git operation.
      default: ""

    - name: GIT_SCRIPT
      description: The git script to run.
      type: string
      default: |
        git help

  results:
    - name: commit
      description: The precise commit SHA after the git operation.

  steps:
    - name: git
      image: $(params.BASE_IMAGE)
      workingDir: $(workspaces.source.path)
      script: |

        # Setting up the config for the git.
        git config --global user.email "$(params.GIT_USER_EMAIL)"
        git config --global user.name "$(params.GIT_USER_NAME)"

        $(params.GIT_SCRIPT)

        RESULT_SHA="$(git rev-parse HEAD | tr -d '\n')"
        EXIT_CODE="$?"
        if [ "$EXIT_CODE" != 0 ]
        then
          exit $EXIT_CODE
        fi
        # Make sure we don't add a trailing newline to the result!
        echo -n "$RESULT_SHA" > $(results.commit.path)

図にするとこんな感じ
PipelineRunの実行時に異なる実行パラメータを与えることで、PipelineがTemplateとして機能することがわかります。

ArgoWorkflow

主なコンポーネント

ArgoWorkflowは主なコンポーネントはこんな感じ。

用語 説明
workflow 1つ以上のテンプレートの実行を定義する。CRDで定義される
workflow template workflowを再利用するための定義。CRDで定義される。
Steps/Step workflowでの実行最小単位 およびそれを束ねたList
DAG(Directed Acyclic Graph) Stepと同レベルの実行単位。Stepと違い、依存関係を定義し、複雑なワークフローを実施できる

TEKTONと違い、workflowリソースのみを定義していくいこととなります。
それぞれの実行単位がこんな感じで定義できます。
workflow > Step or DAG

作成したサンプルのWorkflowのyaml例としてはこんな感じで、以下を確認することができると思います。

  • workflowのyaml内にStepが全て定義されていること

template配下の部分は、CRDで定義されている workflow templateで外出しし、
再利用することもできるようです。

apiVersion: argoproj.io/v1alpha1
kind: Workflow
metadata:
  name: sample-workflow
  namespace: sample-workflow
  generateName: sample-workflow-
spec:
  # select main path
  entrypoint: main
  # work-dir temp PVC
  volumeClaimTemplates:                 # define volume, same syntax as k8s Pod spec
  - metadata:
      name: workdir                     # name of volume claim
    spec:
      accessModes: [ "ReadWriteOnce" ]
      resources:
        requests:
          storage: 1Gi                  # Gi => 1024 * 1024 * 1024
  # select mount secrets or exsistence volume
  volumes:
    - name: git-aaa-secrets
      secret:
        secretName: git-aaa-secrets
        defaultMode: 256
    - name: git-bbb-secrets
      secret:
        secretName: git-bbb-secrets
        defaultMode: 256

 # main process
  templates:
  - name: main
    steps:
    # clone aaa-argo-source
    - - name: git-clone-aaa
        template: git-clone
        arguments:
          parameters: [{name: git-name, value: aaa}]
    # clone bbb-argo-manifests
    - - name: git-clone-bbb
        template: git-clone
        arguments:
          parameters: [{name: git-name, value: bbb}]
	  
  # git-clone template
  - name: git-clone
    inputs:
      parameters:
      - name: git-name
    container:
      image: alpine/git
      command: ["/bin/sh","-c"]
      args: 
        - >
          git clone git@github.com:sample-git/argo-{{inputs.parameters.git-name}}.git /tmp/{{inputs.parameters.git-name}}
      volumeMounts:                     
      - name: workdir
        mountPath: /tmp/

図にするとこんな感じ
(公式サイト引用:https://argoproj.github.io/argo/architecture/)

作り方に違いがありそう

インテグレーション方法として、イメージするなら、Tektonは実行タスクごとに部品を作っていき中からPipelineを組み立てるような作り方で、Argoはworkflow単位で外側から組み立てていくような作り方です。
ただ実際、どちらもTemplate化することはできるので、作りやすさに違いはないだろうと言えます。

そのほかの比較

そのほか、主要な機能について比較して纏めてみましたが、大きな違いはなさそうです。

機能 説明 Tekton pipelines Argo workflow
Template機能 再利用可能な部品 ○(Task/pipelines) ○(workflow template)
Cron機能 定期実行可能なワークフロー
リトライ指定 ワークフローに対するリトライ
DAG 有向非巡回グラフ的順序の設定
Prometheus Prometheusでメトリックスが取得できるか △(実験的)
kubernetesCluster-Version 求められるK8sクラスタのバージョン ver1.15~ 指定無し

TEKTONTriggerとArgoEvents

どちらも役割としては同じ、Gitなどをcommit/pushしたあとのWebhookを受け取る、トリガーとなる役割を司るようです。

TEKTON Trigger


TEKTON TRIGGERの基本的なコンポーネントは以下となるようです。

コンポーネント 説明
EventListener 外部からのイベントを定義するコンポーネント
TriggerBinding イベント/トリガーに対してバインドするコンポーネント
TriggerTemplate 実際にトリガーするTriggerのコンポーネント(TektonPipelinesのPipelineなどをトリガーする)

ArgoEvents

ArgoEventsの基本的なコンポーネントは以下となるようです。

コンポーネント 説明
Event Source 外部からのイベントを定義するコンポーネント
Sensor イベント入力とトリガー出力の依存関係を定義
Trigger センサーによって実行されるリソース/ワークロード

機能比較

これらの機能は、入力と出力の指定種類が機能の違いだと思うので、羅列して整理してみます。

入力

TEKTON

TEKTONではインセプターを利用して指定ができるようです。

  • Webhookインターセプター
  • GitHubインターセプター
  • GitLabインターセプター
  • Bitbucketインターセプター
  • CELインターセプター

Argo

  • AMQP
  • AWS SNS
  • AWS SQS
  • Cron Schedules
  • GCP PubSub
  • GitHub
  • GitLab
  • HDFS
  • File Based Events
  • Kafka
  • Minio
  • NATS
  • MQTT
  • K8s Resources
  • Slack
  • NetApp StorageGrid
  • Webhooks
  • Stripe
  • NSQ
  • Emitter
  • Redis
  • Azure Events Hub

出力

TEKTON

  • TEKTON pipelines

Argo

  • Argo Workflows
  • Standard K8s Objects
  • HTTP Requests / Serverless Workloads (OpenFaas, Kubeless, KNative etc.)
  • AWS Lambda
  • NATS Messages
  • Kafka Messages
  • Slack Notifications
  • Argo Rollouts
  • Custom Trigger / Build Your Own Trigger
  • Apache OpenWhisk

上記から、ArgoEventsは豊富なOutを用意しているのに対し、
TEKTON triggerはTEKTON pipelinesだけで使用する設計となっているようです。

まとめ

Pipelines機能に大きな違いはないものの、Trigger機能を実装する場合は、
以下のような掛け合わせはできないとわかります。

  • TEKTON Trigger --- Argoworkflow
  • ArgoEvents --- TEKTON pipelines

大きな違いは、やはりCD機能(ArgoCD,ArgoRollout)の有無であると言えます。
TEKTON pipelinesで実装するには限界があるので、高度なCDを実現する場合は、ArgoCD、ArgoRolloutを併用して使ってみるのが良いと思います。

最後に

疑問、質問、ご指摘などがあればコメントなどでぜひお願いいたします。

それでは、NTTコミュニケーションズ Advent Calendar 2020の24日目の記事はここまでとさせていただきます。

Discussion