CI-CD

Argo Workflows - (2) Core Concepts

Operation CWAL 2021. 7. 4. 22:03

Core Concepts

이번 시간엔 Argo Workflows의 기본 개념과 Workflow에 대해서 알아보자. 가장 먼저 Argo Workflows 공식 홈페이지에서 제공하는 간단한 'Hello world' 예제부터 시작한다.

'Hello world' Workflow

아래와 같이 'wf-hello-world.yaml'을 작성한다. 

apiVersion: argoproj.io/v1alpha1
kind: Workflow
metadata:
  generateName: hello-world-  # Name of this Workflow
spec:
  entrypoint: whalesay        # Defines "whalesay" as the "main" template
  templates:
  - name: whalesay            # Defining the "whalesay" template
    container:
      image: docker/whalesay
      command: [cowsay]
      args: ["hello world"]   # This template runs "cowsay" in the "whalesay" image with arguments "hello world"

 

'Workflow'는 Argo Workflows에서 사용하는 CRD(Custom Resource Definition)이며, 당장은 위 YAML이 뭘 의미하는지 이해가 잘 안가도 'whalesay' 컨테이너를 통해 'hello world'를 출력하지 않을까라는 느낌이 든다. 아래 명령어로 Workflow를 생성해보자.

kubectl -n argo create -f wf-hello-world.yaml

Argo Workflows 대시보드에서 'hello-world' workflow를 확인할 차례다.

SUMMARY 메뉴에서 MAIN LOGS 버튼을 선택하면 컨테이너 로그 조회가 가능하며, 'hello world' 메시지가 출력된 것을 확인할 수 있다.

 

'workflow' CRD의 Manifest는 YAML 또는 JSON 형식으로 작성하며, K8s의 기본 Workload(ex: Deployment, Pod)와 같이 크게 4개의 파트로 구성된다.

  • apiVersion: 해당 Manifest의 API Version을 의미하며, 'argoproj.io/v1alpha1'를 사용한다.
  • kind: K8s에 생성할 Resource 타입으로, 'Workflow'를 사용한다.
  • metadata: Workflow의 이름(name) 또는 접두어(generateName), 그리고 namespace를 설정한다.
  • spec
    • entrypoint: 맨처음 시작할 template을 선택한다.
    • templates: Workflow에 포함할 template들을 정의한다.

 

Template

Template은 Workflow 안에서 실제 작업을 수행하는 최소 단위로, 사용자에 의해 정의되고 재사용이 가능하다. 현재 Argo Workflows에선 총 4개의 Template 형식이 존재한다.

 

Container Template

Container Template은 Pod spec에서 container를 정의하는 것과 동일하다. container 생성시 사용할 image, 그리고 command 또는 args 필드를 설정한다. 다음은 container template을 사용한 workflow이며, 'hello-world' 예제와 구성이 크게 다르지 않다. 대부분의 경우, 많이 사용하는 방식이다.

apiVersion: argoproj.io/v1alpha1
kind: Workflow
metadata:
  generateName: wf-container-template-
spec:
  entrypoint: container-template
  templates:
  - name: container-template
    container:
      image: python:3.8-slim
      command: [echo, "The container template was executed successfully."]
kubectl -n argo create -f wf-container-template.yaml

Script Template

컨테이너에서 사용할 스크립트를 직접 Manifest 안에 정의한다는 점에서 Container Template과는 큰 차이가 있다. 다음은 간단한 script template 예제로, source 필드 안에 정의한 Python 스크립트를 컨테이너 안에서 실행한다. 따로 Image를 생성하지 않고도, 간단한 스크립트를 추가할 수 있다는 점에서 꽤 유용하다.

apiVersion: argoproj.io/v1alpha1
kind: Workflow
metadata:
  generateName: wf-script-template-
spec:
  entrypoint: script-template
  templates:
  - name: script-template
    script:
      image: python:3.8-slim
      command: [python]
      source: |
        print("The script template was executed successfully.")
kubectl -n argo create -f wf-script-template.yaml

Resource Template

Workflow 실행시 다른 K8s 리소스를 생성할 수 있는 Template으로, Manifest 내용을 확인하면 상당히 재밌는 개념이다. 

아래는 resource template 내부에서 'wf-test'라는 이름의 workflow 리소스를 생성하는 예제이다. workflow 안에 workflow를 정의한 것을 볼 수 있다.

apiVersion: argoproj.io/v1alpha1
kind: Workflow
metadata:
  generateName: wf-resource-template-
spec:
  entrypoint: resource-template
  templates:
  - name: resource-template
    resource:
      action: create
      manifest: |
        apiVersion: argoproj.io/v1alpha1
        kind: Workflow
        metadata:
          name: wf-test
        spec:
          entrypoint: test-template
          templates:
          - name: test-template
            script:
              image: python:3.8-slim
              command: [python]
              source: |
                print("Workflow wf-test created with resource template.")
kubectl -n argo create -f wf-resource-template.yaml

로그를 확인하면 해당 template으로부터 'wf-test' workflow가 생성되었다고 한다.

실제로 'wf-test' workflow가 존재하며, 로그로부터 Manifest 작성시 정의한 메시지가 출력된 것을 알 수 있다.

 

Suspend Template

실행시 정해진 시간 동안 일시정지(suspend) 상태로 존재하는 template으로, 작업 간의 동기화 또는 대기 시간이 필요한 경우에 사용할 수 있다. 사용 방법은 Template Invocator를 먼저 소개한 후 알아보자.

 

Template Invocator

Template Invocator는 위에서 설명한 template(ex: container template, script template)을 호출할 수 있는 template으로, 여러 template들의 순차 또는 병렬 실행을 가능케 한다. 단일 template으로 구성된 workflow가 아니라면 반드시 필요한 template이다. 사용자가 직접 순서를 정의하는 Steps Template과 의존성을 통해 순서가 결정되는 DAG Template으로 구분된다.

Step Template - Serial

steps 필드 내 정의 순서에 따라 어떤 step이 먼저 실행될지 결정되며, 아래 Manifest의 경우 step1 -> step2 -> step3 순으로 실행된다. 후순위의 step은 앞서 실행중인 step이 성공하기 전엔 실행되지 않는다. 실제 작업을 수행할 template인 'task-template은 script template으로 정의하였으며, 각 step에 의해 호출되는 것을 알 수 있다.

apiVersion: argoproj.io/v1alpha1
kind: Workflow
metadata:
  name: wf-steps-templates-serial
spec:
  entrypoint: steps-template-serial
  templates:
  - name: steps-template-serial
    steps:
    - - name: step1
        template: task-template
    - - name: step2
        template: task-template
    - - name: step3
        template: task-template
  - name: task-template
    script:
      image: python:3.8-slim
      command: [python]
      source: |
        print("Task executed.")
kubectl -n argo create -f wf-step-template-serial.yaml

Step Template - Parallel

steps 필드 안에서 동일 레벨에 '-'가 존재할 경우, 병렬 실행된다. 아래 workflow를 생성할 경우, step2와 step3가 동시에 실행되는 것을 확인할 수 있다.

apiVersion: argoproj.io/v1alpha1
kind: Workflow
metadata:
  name: wf-steps-templates-parallel
spec:
  entrypoint: steps-template-parallel
  templates:
  - name: steps-template-parallel
    steps:
    - - name: step1
        template: task-template
    - - name: step2
        template: task-template
      - name: step3
        template: task-template
    - - name: step4
        template: task-template
  - name: task-template
    script:
      image: python:3.8-slim
      command: [python]
      source: |
        print("Task executed.")
kubectl -n argo create -f wf-step-template-parallel.yaml

DAG

steps template과는 달리, 명시적으로 순서를 정의하지 않는 대신 template 호출 단위인 'task' 간의 의존성(dependencies)을 기술함으로써, 자동으로 실행 순서가 결정된다. 의존성이 존재하지 않는 task의 경우, 대기없이 바로 실행된다. 다음은 DAG를 사용한 간단한 Workflow 예시이다. task1은 아무런 의존성이 없으므로 바로 실행되며, task2, task3는 모두 task1에 의존성이 있으므로 task1 완료 이후 실행되며, task4는 task2와 task3가 모두 끝난 뒤에 실행된다.

apiVersion: argoproj.io/v1alpha1
kind: Workflow
metadata:
  name: wf-dag-templates
spec:
  entrypoint: dag-template
  templates:
  - name: dag-template
    dag:
      tasks:
      - name: task1
        template: task-template
      - name: task2
        template: task-template
        dependencies: [task1]
      - name: task3
        template: task-template
        dependencies: [task1]
      - name: task4
        template: task-template
        dependencies: [task2, task3]

  - name: task-template
    script:
      image: python:3.8-slim
      command: [python]
      source: |
        print("Task executed.")
kubectl -n argo create -f wf-dag-template.yaml

 

위에서 언급했던 Suspend Template을 Parallel Steps template에 적용해보자. 다음은 template 호출시 10초간 일시정지가 발생하도록 구성한 Workflow이다.

apiVersion: argoproj.io/v1alpha1
kind: Workflow
metadata:
  name: wf-suspend-template
spec:
  entrypoint: steps-template-parallel
  templates:
  - name: steps-template-parallel
    steps:
    - - name: step1
        template: task-template
    - - name: step2
        template: task-template
      - name: step3
        template: task-template
    - - name: delay
        template: delay-template
    - - name: step4
        template: task-template
  - name: task-template
    script:
      image: python:3.8-slim
      command: [python]
      source: |
        print("Task executed.")
  - name: delay-template
    suspend:
      duration: "10s"
kubectl -n argo create -f wf-suspend-template.yaml

'delay' step의 SUMMARY 메뉴를 확인하면 duration이 10s인 것을 알 수 있다.

 

What comes next?

다음 시간엔 보다 정교한 Workflow 및 Template 정의에 필요한 기능인 Input/Output Parameter, Artifact, Loop, Condition 등에 대해서 공부해보자.