반응형

MLOps 라고 불리는 s/w 가 여러개 있는데 그 중에서 Kubeflow 는 Kubernetes 기반의 MLOps 를 쉽게 구축할 수 있는 오픈 소스이다. 초창기 개발은 Google 이 주축이 되어 Arrikto 가 같이 참여하여 개발하는 형식이었는데 이제는 많은 글로벌 회사에서 같이 참여하여 점차 확대되고 있는 추세이다.

Kubeflow 는 Kubernetes 위에서만 돌아가기 때문에 Kubernetes 를 알아야 한다는 단점이 있지만, 일단 Kubernets 를 알고 있다면 설치가 아주 쉽다. 물론 그 안에 들어가는 컴포넌트들이 많고, MLOps 의 특성상 자동화는 workflow 를 잘 작성해서 pipeline 을 어떻게 구성하느냐가 중요하기 때문에 어려운 사용법을 익혀야 한다.

KServe 는 Kubeflow 의 여러 기능 중에서 ML Model Serving 에 해당하는 컴포넌트이며, 얼마전 kubeflow 내의 KFServe 컴포넌트 이었다가 독립적인 Add-Ons 으로 빠져 나오면서 KServe 로 이름을 바꾸고 자체 github repository 를 만들었다.
 
 

KServe Architecture

KServe 아키텍처는 다음과 같다.

[출처: https://www.kubeflow.org/docs/external-add-ons/kserve/kserve/]
 
 
그림과 같이 런타임으로 TensorFlow, PYTORCH, SKLearn, XGBoost, ONNX 등 다양한 모델 프레임워크를 지원하며 필요하면 커스텀 런타임을 만들어서 지원할 수 도 있다.

KServe 하단에는 Knative 와 Istio (Serverless Layer) 를 갖을 수 있는데 하단에는 다음과 같이 구성할 수 있다.

  1. KServe + Knative + Istio
  2. KServe + Istio

Knative 는 옵션이기는 하나 Knative 를 설치하면서 로깅 (fluentbit + ElasticSearch + Kibana), 모니터링 (Prometheus, Exporter), 트레이싱(Jaeger + ElasticSearch) 을 쉽게 연결할 수 있다는 장점이 있다. 또한 Istio 가 제공하는 Network 핸들링 기능을 쉽게 사용할 수 있다.

KServe 설치는 Istio 설치 → Knative 설치 → KServe 설치 순으로 진행하며, 이에 맞는 버전은 다음과 같다.
 
 

Recommended Version Matrix

Kubernetes Version Istio Version Knative Version
1.20 1.9, 1.10, 1.11 0.25, 0.26, 1.0
1.21 1.10, 1.11 0.25, 0.26, 1.0
1.22 1.11, 1.12 0.25, 0.26, 1.0

여기서는 Kubernetes 1.22 에 맞춰서 설치한다.
 
 

Istio 설치

Istio 는 Service Mesh 를 쉽게 구성가능하도록 지원하는 플랫폼으로 proxy 가 sidecar 형태로 추가되어 네트워크를 조절할 수 있다. 네트워크를 조절기능의 대표적인 것은 네트워크 쉬프팅이 있다. Canary Release 나 A/B Test 에서는 서로 다른 버전의 서비스로 호출되는 네트워크의 흐름 비중을 조절가능해야 한다.

이런 이유로 요즘 Service Mesh 는 Sidecar 활용 패턴을 사용하는데 Istio 에서는 서비스 배포 시에 Sidecar 를 자동으로 Injection 해주는 기능을 지원하고 있으며, 많은 곳에서 대부분 auto injeciton 을 사용하고 있다.

하지만 Knative 에서는 auto injection 을 사용하지 않는다. auto injection 은 kubernetes namespace 에 label 을 추가하여 (istio-injeciton=enabled) 자동으로 해당 namespace 에 배포되는 pod 에는 sidecar proxy 가 자동으로 설치되는 기능이라, Service Mesh 를 사용하고 싶지 않은 서비스들에게도 영향을 줄 수 있기 때문에 auto injection 을 disable 할 것을 권장하고 있다.

Istio 설치는 helm chart 로 쉽게 설치할 수 있다.

helm repo 를 추가하고 value 값을 오버라이드할 파일을 만든다.

$ helm repo add istio https://istio-release.storage.googleapis.com/charts
$ helm repo update

$ vi istiod_1.12.8_default_values.yaml
global:
  proxy:
        autoInject: disabled   # 원래 값은 enabled 임

 
 
Istio-system 네임스페이스를 생성한 후 helm chart 를 설치한다.

base 는 crd 를 설치하며, istiod 가 실제 데몬 서비스다.

$ kubectl create namespace istio-system
$ helm upgrade -i istio-base istio/base --version 1.12.8 -n istio-system -f istiod_1.12.8_default_values.yaml
$ helm upgrade -i istiod istio/istiod --version 1.12.8 -n istio-system -f istiod_1.12.8_default_values.yaml --wait

 
 
외부에서 서비스로 접근하기 위한 North - South 통신은 Istio Ingress Gateway 를 통해서 가능하다. 그러므로 Istio Gateway 를 추가로 설치해 준다.

먼저, value 값을 오버라이드할 파일을 만든다.

$ vi gateway_1.12.8_default_values.yaml
podAnnotations:
  prometheus.io/port: "15020"
  prometheus.io/scrape: "true"
  prometheus.io/path: "/stats/prometheus"
  inject.istio.io/templates: "gateway"
  sidecar.istio.io/inject: "true" 

 
 
istio-ingress 네임스페이스를 생성하고 istio ingress gateway 를 helm chart로 설치한다.

$ kubectl create ns istio-ingress
$ helm upgrade -i istio-ingress istio/gateway --version 1.12.8 -n istio-ingress -f gateway_1.12.8_default_values.yaml

 
 
아래와 같이 잘 설치되어 있음을 확인할 수 있다.

$ kubectl get pods -n istio-system
NAME                      READY   STATUS    RESTARTS   AGE
istiod-68d7bfb6d8-nt82m   1/1     Running   0          20d

$ kubectl get pods -n istio-ingress
NAME                             READY   STATUS    RESTARTS   AGE
istio-ingress-69495c6667-7njv8   1/1     Running   0          20d

 
 

Knative 설치

Knative 는 Serverless 플랫폼이라 생각하면 된다. 서비스를 Istio 를 활용하여 배포하면 Gateway, VirtualServie 를 만들어서 연결해야 하는데 Knative 를 이를 자동으로 생성해주기 때문에 편리하다. 또한 앞에서도 설명한 모니터링, 로깅, 트레이싱이 잘 연결되기 때문에 일단 설치를 한다면 사용하기 편리하다.

Knative 는 설치 모듈이 Serving 과 Eventing 2개로 나눠져 있다. 일단 API 서비스가 가능한 Serving 모듈만 설치하고 테스트를 한다. 또한 모니터링, 로깅, 트레이싱도 다음에 설명하고 지금은 Knative Serving 기능에 집중한다.

Knative 는 Yaml 과 Operator 로 설치할 수 있는데 공식 문서에서 Operator 는 개발/테스트 환경에서만 사용하라고 권고하기 때문에 yaml 로 설치한다.

먼저, crd 를 설치하고, Serving 모듈을 설치한다.

$ kubectl apply -f https://github.com/knative/serving/releases/download/knative-v1.5.0/serving-crds.yaml
--- output ---
customresourcedefinition.apiextensions.k8s.io/certificates.networking.internal.knative.dev created
customresourcedefinition.apiextensions.k8s.io/configurations.serving.knative.dev created
customresourcedefinition.apiextensions.k8s.io/clusterdomainclaims.networking.internal.knative.dev created
customresourcedefinition.apiextensions.k8s.io/domainmappings.serving.knative.dev created
customresourcedefinition.apiextensions.k8s.io/ingresses.networking.internal.knative.dev created
customresourcedefinition.apiextensions.k8s.io/metrics.autoscaling.internal.knative.dev created
customresourcedefinition.apiextensions.k8s.io/podautoscalers.autoscaling.internal.knative.dev created
customresourcedefinition.apiextensions.k8s.io/revisions.serving.knative.dev created
customresourcedefinition.apiextensions.k8s.io/routes.serving.knative.dev created
customresourcedefinition.apiextensions.k8s.io/serverlessservices.networking.internal.knative.dev created
customresourcedefinition.apiextensions.k8s.io/services.serving.knative.dev created
customresourcedefinition.apiextensions.k8s.io/images.caching.internal.knative.dev created

$ kubectl apply -f https://github.com/knative/serving/releases/download/knative-v1.5.0/serving-core.yaml
--- output ---
namespace/knative-serving created
clusterrole.rbac.authorization.k8s.io/knative-serving-aggregated-addressable-resolver created
clusterrole.rbac.authorization.k8s.io/knative-serving-addressable-resolver created
clusterrole.rbac.authorization.k8s.io/knative-serving-namespaced-admin created
clusterrole.rbac.authorization.k8s.io/knative-serving-namespaced-edit created
clusterrole.rbac.authorization.k8s.io/knative-serving-namespaced-view created
clusterrole.rbac.authorization.k8s.io/knative-serving-core created
clusterrole.rbac.authorization.k8s.io/knative-serving-podspecable-binding created
serviceaccount/controller created
clusterrole.rbac.authorization.k8s.io/knative-serving-admin created
clusterrolebinding.rbac.authorization.k8s.io/knative-serving-controller-admin created
clusterrolebinding.rbac.authorization.k8s.io/knative-serving-controller-addressable-resolver created
customresourcedefinition.apiextensions.k8s.io/images.caching.internal.knative.dev unchanged
customresourcedefinition.apiextensions.k8s.io/certificates.networking.internal.knative.dev unchanged
customresourcedefinition.apiextensions.k8s.io/configurations.serving.knative.dev unchanged
customresourcedefinition.apiextensions.k8s.io/clusterdomainclaims.networking.internal.knative.dev unchanged
customresourcedefinition.apiextensions.k8s.io/domainmappings.serving.knative.dev unchanged
customresourcedefinition.apiextensions.k8s.io/ingresses.networking.internal.knative.dev unchanged
customresourcedefinition.apiextensions.k8s.io/metrics.autoscaling.internal.knative.dev unchanged
customresourcedefinition.apiextensions.k8s.io/podautoscalers.autoscaling.internal.knative.dev unchanged
customresourcedefinition.apiextensions.k8s.io/revisions.serving.knative.dev unchanged
customresourcedefinition.apiextensions.k8s.io/routes.serving.knative.dev unchanged
customresourcedefinition.apiextensions.k8s.io/serverlessservices.networking.internal.knative.dev unchanged
customresourcedefinition.apiextensions.k8s.io/services.serving.knative.dev unchanged
image.caching.internal.knative.dev/queue-proxy created
configmap/config-autoscaler created
configmap/config-defaults created
configmap/config-deployment created
configmap/config-domain created
configmap/config-features created
configmap/config-gc created
configmap/config-leader-election created
configmap/config-logging created
configmap/config-network created
configmap/config-observability created
configmap/config-tracing created
horizontalpodautoscaler.autoscaling/activator created
poddisruptionbudget.policy/activator-pdb created
deployment.apps/activator created
service/activator-service created
deployment.apps/autoscaler created
service/autoscaler created
deployment.apps/controller created
service/controller created
deployment.apps/domain-mapping created
deployment.apps/domainmapping-webhook created
service/domainmapping-webhook created
horizontalpodautoscaler.autoscaling/webhook created
poddisruptionbudget.policy/webhook-pdb created
deployment.apps/webhook created
service/webhook created
validatingwebhookconfiguration.admissionregistration.k8s.io/config.webhook.serving.knative.dev created
mutatingwebhookconfiguration.admissionregistration.k8s.io/webhook.serving.knative.dev created
mutatingwebhookconfiguration.admissionregistration.k8s.io/webhook.domainmapping.serving.knative.dev created
secret/domainmapping-webhook-certs created
validatingwebhookconfiguration.admissionregistration.k8s.io/validation.webhook.domainmapping.serving.knative.dev created
validatingwebhookconfiguration.admissionregistration.k8s.io/validation.webhook.serving.knative.dev created
secret/webhook-certs created

 
 
다음은 Isito 와 연동하기 위한 network 들을 설치한다.

$ kubectl apply -f https://github.com/knative/net-istio/releases/download/knative-v1.5.0/net-istio.yaml

 
 
그대로 설치하면 Isito gateway 와 연동되지 않는다. 그렇기 때문에 아래와 같이 selector 를 수정해 줘야 한다.

$ kubectl edit gateway -n knative-serving knative-ingress-gateway
...
spec:
  selector:
    istio: ingressgateway
    istio: ingress          # 추가

$ kubectl edit gateway -n knative-serving knative-local-gateway
...
spec:
  selector:
    istio: ingressgateway
    istio: ingress          # 추가

 
 

Istio 의 Ingress gateway 앞단에는 LoadBalancer 가 연결되어 있다. LoadBalancer 가 External IP 로 연결되어 있으면 IP 를 dns 로 연결해 주는 magic dns (sslip.io) 를 사용할 수 있고, LoadBalancer 가 domain name 으로 연결되어 있으면 실제 DNS 에 CNAME 을 등록하여 연결하면 된다.

$ kubectl get svc -n istio-ingress
NAME            TYPE           CLUSTER-IP       EXTERNAL-IP 
istio-ingress   LoadBalancer   10.107.111.229   xxxxx.ap-northeast-2.elb.amazonaws.com

 
 

여기서는 aws 를 사용하고 있기 때문에 Route53 에 CNAME 을 등록하였다.

서비스 도메인: helloworld-go-default.taco-cat.xyz
target: xxxxx.ap-northeast-2.elb.amazonaws.com
type: CNAME

 
 

Knative ConfigMap 설정

마지막으로 Knative ConfigMap 에 기본 도메인과 full 도메인 설정을 세팅한다.

이 설정은 앞서 Route53 에 등록한 서비스 도메인과 같은 형식으로 설정되게 구성해야 한다.

## Domain: taco-cat.xyz
$ kubectl edit cm config-domain -n knative-serving
apiVersion: v1
data:
  taco-cat.xyz: ""
kind: ConfigMap
[...]

## Name: helloworld-go
## Namesapce: default
## Domain: taco-cat.xyz
$ kubectl edit cm config-network -n knative-serving
apiVersion: v1
data:
  domain-template: "{{.Name}}-{{.Namespace}}.{{.Domain}}"

 
 

Knative sample 배포 테스트

Knative 에서 제공하는 helloworld-go 샘플 프로그램을 배포해 보자.

서비스 이름이 helloworld-go, Namespace 가 default 로 앞서 Route53 및 ConfigMap 에 설정한 도메인 형식과 동일함을 할 수 있다.

$ git clone https://github.com/knative/docs knative-docs
$ cd knative-docs/code-samples/serving/hello-world/helloworld-go

$ vi service.yaml
apiVersion: serving.knative.dev/v1
kind: Service
metadata:
  name: helloworld-go
  namespace: default
spec:
  template:
    spec:
      containers:
      - image: gcr.io/knative-samples/helloworld-go
        env:
        - name: TARGET
          value: "Go Sample v1"

$ kubectl apply -f service.yaml

 
 

배포가 제대로 되었는지 확인해 보자.

$ kubectl get route
NAME            URL                                         READY   REASON
helloworld-go   http://helloworld-go-default.taco-cat.xyz   True

 
 

Knative 는 zero replicas 를 사용한다

Serverless 를 어떻게 구현했을까? 사실 Knative 는 Kubernetes 의 zero replicas 를 사용했다.

배포 후에 deployment 를 조회하면 아래과 같이 Ready 와 Available 이 0 상태임을 알 수 있다.

$ kubectl get deploy
NAME                                       READY   UP-TO-DATE   AVAILABLE   AGE
helloworld-go-00001-deployment             0/0     0            0           10d

 
 

배포도 잘되고 Route53 에 dns 도 어느 정도 시간이 지났다면 브라우저 혹은 curl 로 확인할 수 있다.

$ curl http://helloworld-go-default.taco-cat.xyz
--- output ---
Hello Go Sample v1!

 
 

이렇게 요청이 들어오면 실제로 pod 가 실행되고 있음을 알 수 있다. 1분 동안 아무런 요청이 없으면 pod 는 다시 사라지고 대기 상태가 된다. (요청이 없더라도 중간에 다시 pod 가 생겨서 실제로는 일정 시간 동안 새로운 pod 로 교체된다)

$ kubectl get deploy
NAME                                       READY   UP-TO-DATE   AVAILABLE   AGE
helloworld-go-00001-deployment             1/1     1            1           10d

 
 

TLS 인증서 적용

인증서를 가지고 있다면 gateway 에 tls 를 적용하여 tls termination 을 할 수 있다.

아래는 istio-ingress 네임스페이스에 secret 으로 taco-cat-tls 인증서를 설치한 후 gateway 에서 해당 인증서를 읽을 수 있도록 tls 를 추가한 부분이다.

$ kubectl edit gateway knative-ingress-gateway -n knative-serving
...
spec:
  selector:
    istio: ingress
  servers:
  - hosts:
    - '*'
    port:
      name: http
      number: 80
      protocol: HTTP
  - hosts:
    - '*.taco-cat.xyz'
    port:
      name: https
      number: 443
      protocol: HTTPS
    ## tls 추가
    tls:
      mode: SIMPLE
      credentialName: taco-cat-tls

 
 

HPA 설치

서비스에 요청이 신규로 들어오거나, 많아지면 replicas 수를 조절하여 pod 를 실행해주는 activator 가 있다. 이 activator 를 auto scaling 하는 hpa 를 설치한다.

$ kubectl apply -f https://github.com/knative/serving/releases/download/knative-v1.5.0/serving-hpa.yaml

 
 

hpa 를 조회해서 확인할 수 있다.

$ kubectl get hpa -n knative-serving
NAME        REFERENCE              TARGETS   MINPODS   MAXPODS   REPLICAS   AGE
activator   Deployment/activator   0%/100%   1         20        1          13d
webhook     Deployment/webhook     3%/100%   1         5         1          13d

 
 

KServe 설치

KServe 는 이제 막 Helm chart 가 만들어지고 있다. 그렇기 때문에 일단은 yaml 로 설치를 진행한다.

먼저 KServe 컴포넌트를 설치하고 이어서 각종 ML Framework 를 나타내는 Runtime을 설치한다.

$ kubectl apply -f https://github.com/kserve/kserve/releases/download/v0.8.0/kserve.yaml
--- output ---
namespace/kserve created
customresourcedefinition.apiextensions.k8s.io/clusterservingruntimes.serving.kserve.io created
customresourcedefinition.apiextensions.k8s.io/inferenceservices.serving.kserve.io created
customresourcedefinition.apiextensions.k8s.io/servingruntimes.serving.kserve.io created
customresourcedefinition.apiextensions.k8s.io/trainedmodels.serving.kserve.io created
serviceaccount/kserve-controller-manager created
role.rbac.authorization.k8s.io/leader-election-role created
clusterrole.rbac.authorization.k8s.io/kserve-manager-role created
clusterrole.rbac.authorization.k8s.io/kserve-proxy-role created
rolebinding.rbac.authorization.k8s.io/leader-election-rolebinding created
clusterrolebinding.rbac.authorization.k8s.io/kserve-manager-rolebinding created
clusterrolebinding.rbac.authorization.k8s.io/kserve-proxy-rolebinding created
configmap/inferenceservice-config created
configmap/kserve-config created
secret/kserve-webhook-server-secret created
service/kserve-controller-manager-metrics-service created
service/kserve-controller-manager-service created
service/kserve-webhook-server-service created
statefulset.apps/kserve-controller-manager created
certificate.cert-manager.io/serving-cert created
issuer.cert-manager.io/selfsigned-issuer created
mutatingwebhookconfiguration.admissionregistration.k8s.io/inferenceservice.serving.kserve.io created
validatingwebhookconfiguration.admissionregistration.k8s.io/inferenceservice.serving.kserve.io created
validatingwebhookconfiguration.admissionregistration.k8s.io/trainedmodel.serving.kserve.io created

$ kubectl apply -f https://github.com/kserve/kserve/releases/download/v0.8.0/kserve-runtimes.yaml
--- output---
clusterservingruntime.serving.kserve.io/kserve-lgbserver created
clusterservingruntime.serving.kserve.io/kserve-mlserver created
clusterservingruntime.serving.kserve.io/kserve-paddleserver created
clusterservingruntime.serving.kserve.io/kserve-pmmlserver created
clusterservingruntime.serving.kserve.io/kserve-sklearnserver created
clusterservingruntime.serving.kserve.io/kserve-tensorflow-serving created
clusterservingruntime.serving.kserve.io/kserve-torchserve created
clusterservingruntime.serving.kserve.io/kserve-tritonserver created
clusterservingruntime.serving.kserve.io/kserve-xgbserver created

 
 

KServe 설치를 확인한다.

$ kubectl get pod -n kserve
NAME                          READY   STATUS    RESTARTS   AGE
kserve-controller-manager-0   2/2     Running   0          7d10h

 
 

Rumtime 도 설치되었는지 확인한다.

$ kubectl get clusterservingruntimes
NAME                        DISABLED   MODELTYPE    CONTAINERS         AGE
kserve-lgbserver                       lightgbm     kserve-container   7d10h
kserve-mlserver                        sklearn      kserve-container   7d10h
kserve-paddleserver                    paddle       kserve-container   7d10h
kserve-pmmlserver                      pmml         kserve-container   7d10h
kserve-sklearnserver                   sklearn      kserve-container   7d10h
kserve-tensorflow-serving              tensorflow   kserve-container   7d10h
kserve-torchserve                      pytorch      kserve-container   7d10h
kserve-tritonserver                    tensorrt     kserve-container   7d10h
kserve-xgbserver                       xgboost      kserve-container   7d10h

 
 

Sample model 을 KServe 를 활용하여 배포

tensorflow 로 개발된 mnist 샘플 모델을 KServe 로 배포해 보자.

KServe 는 model in load 패턴을 적용하여 인퍼런스 서비스를 수행한다. 아래에서는 모델이 gs 에 저장되어 있으면 이를 가져와서 서빙하는 구조이다.

runtime 은 앞서 설치한 clusterservingruntime 중에 하나인 kserve-tensorflow-serving 이고 버전이 2 임을 알 수 있다.

$ vi mnist_tensorflow.yaml
---
apiVersion: "serving.kserve.io/v1beta1"
kind: "InferenceService"
metadata:
  name: "mnist"
spec:
  predictor:
    model:
      modelFormat:
        name: tensorflow
        version: "2"
      storageUri: "gs://kserve/models/mnist"
      runtime: kserve-tensorflow-serving
    logger:
      mode: all

$ kubectl apply -f mnist_tensorflow.yaml

 
 

서빙 배포 확인은 다음과 같다.

KServe 에서 도메인을 만들 때 namespace 를 추가로 붙히기 때문에 도메인이 아래와

$ kubectl get isvc
NAME    URL     READY   PREV   LATEST   PREVROLLEDOUTREVISION  LATESTREADYREVISION
mnist   http://mnist-default.taco-cat.xyz   True           100 mnist-predictor-default-00001

$ kubectl get route
NAME                      URL                                                   READY   REASON
mnist-predictor-default   http://mnist-predictor-default-default.taco-cat.xyz   True

 
 

Route53 에 도메인을 추가한다.

서비스 도메인: mnist-predictor-default-default.taco-cat.xyz
target: xxxxx.ap-northeast-2.elb.amazonaws.com
type: CNAME

 
 

아래와 같이 요청하여 결과값이 제대로 나오는지 확인한다.

$ curl https://mnist-predictor-default-default.taco-cat.xyz/v1/models/mnist:predict \
   -H 'Content-Type: application/json' \
   -d @mnist.json
--- output ---
{
    "predictions": [[3.2338352e-09, 1.66207215e-09, 1.17224181e-06, 0.000114716699, 4.34008705e-13, 4.64885304e-08, 3.96761454e-13, 0.999883413, 1.21785089e-08, 6.44099089e-07]
    ]
}

 
 

반응형
Posted by seungkyua@gmail.com
,
반응형

2018년에 Kubernetes 상에서 돌아가는 ML Platform 인 Kubeflow 를 처음 알게된 후로 관심을 갖고 재미삼아 하다가 2022년에는 업무와 연관되어 일을 해야하기 때문에 중점으로 살펴보고자 한다. (최근에는 ML Platform 보다는 AI Platform 이라고 말하는 사람들이 많은 듯)

 

Kubeflow 를 KubeCon 에서 만나다

Kubeflow 개발자들을 처음 만난 것은 2019년 KubeCon in Europe (Barcelona) 이다. 초기 Kubeflow 는 Goolge 과 Arrito 가 주축이 되어 개발하고 있었는데 마침 초기 버전이 나오면서 Kubeflow 홍보를 시작하던 때 였었다.

Kubeflow 의 주 개발자는 화면에 보이는 구글의 Senior S/W Engineer 인 Jeremy Lewi 다. 당시 저 발표는 간단한 설명후에 데모 형태로 발표가 되었는데 Kubernetes 위에 Kubeflow 를 설치한 상태에서 Jupyter Notebook 을 띄어 Model 을 개발하고, Fairing 으로 Model Training 후 Model Serving 하는 것을 시연으로 보여주었다.

 

영상은 아래를 클릭하면 볼 수 있다.

https://www.youtube.com/watch?v=-GYiatVNemY 

 

저녁에 Arrito 가 주최하는 Kubeflow 개발자 / 사용자와의 저녁 만남이 있었는데 거기서 Jeremy 와 이야기를 해봤을 때는 전형적인 내성적이고 약간은 고지식한 개발자라는 느낌을 받았던 기억이(물론 이건 주관적인 생각). 시간이 좀 지나니 혼자 따로 앉아 있던데. 

 

 

Kubeflow 를 왜 써야 하나?

AI Platform Developer 라면 아래의 그림은 많이 봐왔을 것이다. 정 가운데에 있는 ML Code 는 데이터 사이언티스트들이 모델을 개발하는 코드인데, 이런 개발을 도와주거나 실제 서비스로 구축하기 위해서는 코드 이외에도 많은 Tool / System 들이 필요하다는 의미를 보여준다.  

https://papers.nips.cc/paper/5656-hidden-technical-debt-in-machine-learning-systems.pdf

 

또한 위의 동영상에서도 아래와 같이 설명하고 있다.

 

 

간단하게 살펴보는 Kubeflow Architecture

아키텍처에 대한 설명은 Kubeflow document 사이트를 참고하여 간단히 설명하고자 한다.

https://www.kubeflow.org/docs/started/architecture/

 

 

 

ML 개발 프로세스는 Experimental Phase (실험 단계) 와 Production Phase (운영 단계) 로 나눌 수 있으며 전체 워크플로우는 아래와 같다.

실험 단계

1. 문제를 인식하고 데이터를 수집/분석

2. ML 알고리즘을 선택하여 모델을 코딩

3. 데이터를 가지고 모델 트레이닝

4. 하이퍼 파라미터 튜닝

 

운영 단계

1. 데이터 변환

2. 모델 트레이닝

3. 온라인/배치 예측을 위한 모델 서빙

4. 모델 성능 측정 (결과를 가지고 다시 트레이닝하거나 튜닝)

 

 

단계에 적용되는 Kubeflow 컴포넌트는 아래와 같다. 

 

  • Fairing: 위성발사를 생각해보면 로켓 맨 상단에 중요 내용물인 위성을 보호하기 위해서 Fairing 으로 감싸고 있다. 모델을 안전하게 다른 시스템으로 전달하는 기능으로 python library 를 제공한다.
  • Pipelines: Argo workflow 기반으로 python library 를 제공하여 pipeline 을 구축할 수 있다. 예를 들면 데이터 전처리 등 반복되는 작업을 자동으로 수행할 수 있다. 
  • Katib: 하이퍼 파라미터 튜닝을 자동으로 해주는 기능이다. 아래 그림과 같이 하이퍼 파라미터를 바꾸면서 결과를 그래프와 표로 보여준다.
  • KFServing:  Kubeflow 에서 제공해주는 Model Serving 기능이다.

 

마치며

현재 Kubeflow 의 최신 버전은 v1.4 이다. 2019년 Arrito 개발자들과 만나서 논의했을 때 (당시에 v0.3 인걸로 기억한다) v1.0 으로 올리는 것이 의미있냐고 질문을 받은 적이 있다. 고객이 오픈소스의 안정성을 의심하기 때문에 기능이 조금 미흡하더라도 v1.0 으로 올리는 것이 좋겠다는 의견을 준적이 있었는데 어느덧 버전이 v1.4 까지 나왔다.(물론 그 때 이후 한참 지나서야 v1.0 이 나왔지만)

많은 기업에서 자체 AI Platform 을 만들어서 사용하는 것으로 알고 있는데, 제 개인적인 생각으로는 지금이라도 Kubeflow 로 바꾸는 것이 좋다는 생각이다. 그 이유는 이미 모두 알고 있을 것이다.

반응형
Posted by seungkyua@gmail.com
,