본문 바로가기

공부기록/MLOps | Infra

[kubeflow] kfp.dsl을 사용한 pod scheduling

반응형

node에 기존에 있는 pod 옮기기

kubectl drain <node-name>
  • worker-1에 실행되고 있던 기존 잡들을 다른 노드로 옮기기위해 drain 명령을 실행합니다. drain 이 실행되면 cordon의 과정이 포함되므로 어떤 파드도 스케줄링되지 않습니다.
  • 다른 node에 pod가 이동하는 것으로 보이지만 실제로는 기존 노드에서 실행되고 있던 파드들을 삭제한 후 다른 노드에서 재생성하는 과정이 진행됩니다. 이때, replica set에 있는 pod들은 다른 노드에서 살아나지만, 그렇지 않은 pod들은 복원되지 못한다는 것에 주의해야합니다.
  • -ignore-daemonsets=true option을 설정하면 데몬세트로 실행한 파드들을 무시하고 드레인 설정을 적용할 수 있습니다.

 

kubectl uncordon <node-name>
  • 원하는 작업을 수행한 후 cordon된 node를 해제하기 위해 uncordon 명령을 실행합니다.

 

 

kubeflow dsl을 사용한 pod scheduling

taint & toleration

먼저, 해당 노드에 taint를 추가합니다.

kubectl taint nodes <node-name> <key>=<value>:<effect>

 

만약, taint를 삭제하고 싶을 경우 아래와 같은 명령어를 사용합니다.

kubectl taint nodes <node-name> <key>=<value>:<effect>-

 

taint가 제대로 설정되어있는지 describe명령어로 확인합니다.

kubectl describe node <node-name>

 

이제 kubeflow dsl 에서 원하는 Pod에 특정 taint에 대한 toleration을 주도록 하겠습니다.

기존 파이썬으로 만든 컴포넌트에 add_toleration을 통해 toleration를 추가할 수 있습니다. 이때 Toleartion은 kubernetes client 객체를 사용하여 아래와 같이 입력해야합니다.

 

...
from kubernetes.client.models.v1_toleration import V1Toleration


def my_job():
  print("Hi")


my_component = components.create_component_from_func(func=my_job, base_image='my_image')

@dsl.pipeline(
    name="my_pl",
    description = "example pipelime"
)
def my_pipeline():
  ...
  toleration = kubernetes.client.models.v1_toleration.V1Toleration(
                                                                  key='key',
                                                                  value='experiment',
                                                                  operator='Equal',
                                                                  effect='NoSchedule'
                                                                  )
  my_task = my_component().add_toleration(toleration)

taint&toleration 설정 후 kubectl get pods -n kubeflow -o wide 명령어로 해당 파이프라인이 해당 node에 할당되었는지 확인합니다.

 

NodeAffinity

node affinity를 통해 파드의 생명주기에 따라 특정노드에 파드가 스케줄링 될 수 있도록 설정할 수 있습니다.

먼저, nodeselector로 사용할 label을 추가합니다.

 

kubectl label nodes <node-name> <key>=<value>

 

이제 kubeflow dsl에서 affinity를 설정하도록 하겠습니다.

toleraion과 마찬가지로 kubernetes client 객체를 사용해야합니다. affinity는 toleration보다는 조금 복잡합니다.

Nodeselector에 들어갈 expression을 V1NodeSelectorRequirement를 사용하여 생성하고, 이것을V1NodeSelectorTerm으로 받아서 V1NodeSelector 에 넣어준 후 원하는 상태를 선언하고 V1NodeAffinity 에 넣어서 V1Affinity 클래스로 만들어 dsl 매개변수로 넣어주면 됩니다.

예제 코드는 다음과 같습니다.

...
from kubernetes.client.models.v1_node_selector import V1NodeSelector
from kubernetes.client.models.v1_node_selector_term import V1NodeSelectorTerm
from kubernetes.client.models.v1_affinity import V1Affinity
from kubernetes.client.models.v1_node_affinity import V1NodeAffinity
from kubernetes.client.models.v1_node_selector_requirement import V1NodeSelectorRequirement


def my_job():
  print("Hi")


my_component = components.create_component_from_func(func=my_job, base_image='my_image')

@dsl.pipeline(
    name="my_pl",
    description = "example pipelime"
)
def my_pipeline():
  ...
  affinity = V1Affinity(
    node_affinity=V1NodeAffinity(
        required_during_scheduling_ignored_during_execution=V1NodeSelector(
            node_selector_terms=[V1NodeSelectorTerm(
                match_expressions=[V1NodeSelectorRequirement(
                    key='key',
                    operator='In',
                    values=['experiment'])])])))
                    
                    
  my_task = my_component().add_affinity(affinity)

 

 

<참>

operator 필드를 사용하여 쿠버네티스가 규칙을 해석할 때 사용할 논리 연산자를 지정할 수 있습니다. In, NotIn, Exists, DoesNotExist, GtLt 연산자를 사용할 수 있습니다.

 

Reference

반응형