AI & ML/MLOps Study

[머신러닝 플랫폼 스터디] 챕터 5 — Kubeflow Pipelines로 배치 추론하기

백곰곰 2026. 10. 31. 21:36
728x90
반응형

4장에서는 MLflow에 소득 분류 모델을 등록하고 Feast에서 피처를 조회했습니다. 이번 글에서는 준비한 모델과 피처를 Kubeflow Pipelines로 연결해 배치 추론을 실행합니다.

실습은 참고 자료에 링크한 블로그 글을 따라 진행했습니다. 앞선 글에서 구성한 로컬 kind 클러스터와 데이터를 사용합니다.

1. 배치 추론과 Kubeflow Pipelines

어떤 작업을 자동화할까?

배치 추론은 여러 입력을 모아 한 번에 모델 예측을 수행하는 방식입니다. 이번 실습에서는 사용자 목록을 읽고, 각 사용자에게 필요한 피처를 조회한 뒤 소득 분류 모델의 예측 결과를 파일로 저장합니다.

실시간 요청마다 한 명의 결과를 반환하는 방식과 달리, 여기서는 준비된 입력 데이터 전체를 한 번의 파이프라인 실행으로 처리합니다.

Kubeflow Pipelines란?

Kubeflow Pipelines(KFP)는 Kubernetes에서 머신러닝 작업을 파이프라인으로 구성하고 실행·관리하는 도구입니다. 전체 Kubeflow 플랫폼의 구성요소로 사용할 수도 있고, KFP만 별도로 설치할 수도 있습니다.

  • 컴포넌트(Component): 데이터를 읽거나 예측하는 것처럼 하나의 작업을 정의한 구성요소
  • 파이프라인(Pipeline): 컴포넌트의 실행 순서와 데이터 연결을 정의한 작업 흐름
  • Run: 파이프라인에 입력값을 넣어 실행한 한 번의 기록
  • 아티팩트(Artifact): 단계가 만들고 다음 단계에 전달하는 데이터 파일 등의 결과물

이번 환경에서는 각 컴포넌트가 Kubernetes의 별도 Pod에서 실행됩니다. 앞 단계의 출력은 파일 형태로 다음 단계에 전달되므로, Pod끼리 Python 메모리 객체를 직접 공유하지 않습니다.

2. 실습에서 구성하는 파이프라인

전체 흐름

Kubeflow Pipelines · 파이프라인 실행 및 관리

추론 대상 읽기
사용자 ID · 기준 시각
Feast 피처 조회
과거 시점 피처
MLflow 모델 추론
입력 변환 · 예측
결과 저장
Parquet · 객체 저장소
이번 실습의 작업 흐름을 단순화한 그림입니다.
순서 컴포넌트 입력과 수행 작업 결과
1 데이터 읽기 객체 저장소에서 사용자 ID와 기준 시각이 담긴 목록을 읽음 피처 조회에 사용할 입력 데이터
2 피처 조회 Feast에서 각 사용자와 기준 시각에 맞는 과거 피처를 조회 모델 입력에 사용할 피처 데이터
3 모델 추론 MLflow에 등록한 모델을 불러와 입력을 변환하고 예측 예측값이 추가된 데이터
4 결과 저장 예측 데이터를 객체 저장소에 기록 Parquet 결과 파일

이 파이프라인은 모델을 다시 훈련하는 과정이 아니라 4장에서 등록한 모델을 사용해 예측하는 과정입니다. 피처 조회에는 Feast의 과거 시점 조회를 사용하며, 4장에서 실습한 Redis 온라인 조회와는 경로가 다릅니다.

 

KFP에 등록한 네 컴포넌트와 출력 연결입니다.

무엇을 예측할까?

4장에서 준비한

로 분류하도록 훈련했습니다. 이번 추론 컴포넌트는 모델이 반환한 양성 클래스의 확률을 결과 열에 기록합니다.

입력으로 사용하는 피처는 Feast에서 조회합니다. 조회된 범주형 값을 훈련 당시와 같은 방식으로 변환하고, 4장 Run에 기록한 column_list.pkl을 이용해 모델 입력 열의 순서를 맞춥니다.

3. 실습 환경 준비

내 PC · 브라우저
포트 포워딩 · localhost:8080

Kubernetes 클러스터 · kind

Kubeflow Pipelines
작업별 Pod 실행

컴포넌트 Pod와 서비스 연결

1. 데이터 읽기 Pod
입력 읽기
SeaweedFS · S3 호환 저장소
2. 피처 조회 Pod · Feast SDK
피처 정의 · 과거 피처 조회
SeaweedFS · S3 호환 저장소
3. 모델 추론 Pod
등록 모델 조회
MLflow 서버
4. 결과 저장 Pod
예측 결과 저장
SeaweedFS · S3 호환 저장소
브라우저는 클러스터 밖에서 접속하고, KFP와 컴포넌트 Pod, MLflow, SeaweedFS는 클러스터 안에서 동작합니다. 모델 아티팩트는 설정에 따라 객체 저장소에 직접 접근하거나 MLflow 서버를 경유할 수 있습니다.

5장에서는 파이프라인의 컴포넌트가 클러스터 안에서 실행되며, MLflow의 모델과 Feast의 과거 피처를 사용합니다. 실습에서 사용하는 연결만 표시한 구성도입니다.

4장에서 이어서 사용하는 구성

준비물 이번 실습의 상태
클러스터 로컬 kind, Kubernetes v1.24.17
KFP 서버 2.4.1, Python SDK 2.9.0
모델 MLflow에 등록한 random-forest-classifier 버전 1
피처 Feast의 세 Feature View와 객체 저장소의 원천 데이터
객체 저장소 SeaweedFS가 제공하는 S3 호환 저장소

5장 코드는 Production stage의 모델을 조회하므로 4장에서 등록한 모델 버전에 해당 stage를 지정했습니다. MLflow의 model stage는 deprecated 상태이지만, 이번 실습에서는 코드가 이 방식에 의존합니다.

5장 코드 가져오기

4장 실습 환경 저장소의 루트에서 책의 5장 코드 저장소를 내려받고, 이번 실습에서 사용한 커밋을 선택합니다.

git clone https://github.com/practical-mlops/chapter-5.git upstream/chapter-5
git -C upstream/chapter-5 checkout 332915b2f617e7fed8646b7c096653c87eed9d30

실습 환경과 4장 코드의 준비 과정은 4장 실습 글에 정리했습니다. 코드를 내려받은 뒤에는 변경될 파일과 명령의 내용을 확인합니다.

KFP 화면 접속

브라우저에서 KFP UI에 접근하려면 로컬 포트를 클러스터 안의 KFP 서비스로 전달해야 합니다. 4장에서 사용한 포트 포워딩이 종료됐다면, 실습용 kubeconfig가 설정된 별도 터미널에서 환경 저장소의 명령을 다시 실행합니다.

python bookenv.py forward

이 명령은 KFP UI뿐 아니라 MLflow, 객체 저장소, Redis 등 실습 서비스의 포트도 함께 전달합니다. 터미널을 유지한 상태에서 브라우저로 http://localhost:8080을 열어 KFP 화면을 확인합니다.

KFP UI만 따로 전달하려면 실습 환경에서 다음 명령을 사용할 수 있습니다. 앞의 명령이 이미 8080번 포트를 사용하고 있다면 중복해서 실행하지 않습니다.

kubectl -n kubeflow port-forward svc/ml-pipeline-ui 8080:80

클러스터용 Feast 설정

4장 노트북은 Mac에서 포트 포워딩으로 저장소에 접속했습니다. 반면 5장의 컴포넌트는 클러스터 안의 Pod에서 실행됩니다. Pod 안에서 localhost는 Mac이 아니라 해당 Pod 자신을 가리키므로, 클러스터 내부 서비스 주소를 사용하는 설정이 필요합니다.

이번 실습에서는 클러스터용 설정을 준비하고 Feast Job에서 feast apply를 다시 실행해 별도의 레지스트리에 피처 정의를 등록했습니다. 5장의 피처 조회는 과거 시점 원천 데이터를 읽으므로, 이 Job에서 Redis에 다시 materialize하지는 않았습니다.

컴포넌트 이미지와 입력 데이터

이번 환경에서는 네 컴포넌트가 같은 book-ch5/components 이미지를 사용하고, 컴포넌트마다 다른 스크립트를 실행합니다. 해당 이미지를 빌드해 kind 노드에 적재하고, 추론 대상 목록과 클러스터용 Feast 설정을 객체 저장소에 준비했습니다.

실습에서는 파이프라인 컴포넌트용 이미지와 Feast 정의를 등록할 Job용 이미지를 각각 빌드했습니다. 명령은 4장 실습 환경 저장소의 루트에서 실행하며, Dockerfile과 빌드할 코드를 먼저 확인합니다.

docker build -t book-ch5/feast-job:0.1 \
  -f book/ch05/Dockerfile.feast-job upstream/chapter-5/scripts/feast

docker build -t book-ch5/components:0.1 \
  -f book/ch05/Dockerfile.components upstream/chapter-5

로컬에서 빌드한 이미지를 kind 노드에 적재해 클러스터 안의 Pod가 사용할 수 있도록 했습니다.

python bookenv.py load book-ch5/feast-job:0.1
python bookenv.py load book-ch5/components:0.1

feast-job 이미지는 클러스터용 피처 정의 등록에 사용하고, components 이미지는 데이터 읽기·피처 조회·모델 추론·결과 저장의 네 작업이 공유합니다. 이미지를 공유하더라도 작업은 각각 별도의 Pod에서 실행됩니다.

컴포넌트 정의의 image 항목도 빌드한 이미지 이름과 일치해야 합니다. 이번 실습에서는 환경 저장소의 준비 과정으로 네 컴포넌트가 book-ch5/components:0.1을 참조하도록 맞췄습니다.

결과를 저장할 inference-datasets 버킷도 미리 만듭니다. 저장소 접속 정보는 파이프라인이 접근할 수 있도록 준비해야 합니다. 이 글에는 비밀값 주입 방법을 검증한 절차가 포함되어 있지 않으므로, 환경에 맞는 안전한 설정이 별도로 필요합니다. 접속 키나 사용자 ID는 본문과 화면 캡처에 넣지 않았습니다.

4. 컴포넌트와 파이프라인 정의

component.yaml이 하는 일

각 컴포넌트의 component.yaml은 작업의 입출력과 실행 방법을 정의합니다. 쿠버네티스의 Deployment를 정의하는 파일이 아니라 KFP가 컴포넌트를 실행할 때 읽는 명세입니다.

항목 의미
inputs 작업이 받는 값의 이름과 타입
outputs 작업이 내보내는 결과의 이름과 타입
implementation.container 작업에 사용할 컨테이너 이미지와 실행 명령
inputValue, outputPath 입력값과 출력 파일 경로를 명령의 인자에 전달하는 표현

예를 들어 데이터 읽기 컴포넌트는 저장소에서 입력 파일을 읽고, KFP가 지정한 출력 경로에 결과를 씁니다. 다음 단계는 이 출력을 입력으로 받아 피처를 조회합니다.

컴파일과 등록

inference_pipeline.py에서 네 컴포넌트를 연결하고 컴파일하면 파이프라인 명세 YAML이 만들어집니다. 이 파일을 KFP에 등록한 뒤 실행에 필요한 파라미터를 지정합니다.

파이프라인 코드에서 각 component.yaml을 읽고, 앞 컴포넌트의 출력을 다음 컴포넌트의 입력으로 연결합니다. 이번 실습에서는 앞의 세 컴포넌트가 data_output을 다음 단계에 전달하고, 마지막 컴포넌트가 예측 파일을 객체 저장소에 저장합니다.

컴포넌트 주요 입력과 설정 수행 작업 출력
데이터 읽기 입력 버킷과 entity_df.parquet 사용자 ID와 기준 시각이 담긴 입력 파일을 읽음 다음 단계에 전달할 data_output
피처 조회 앞 단계의 데이터, Feast 설정과 조회할 피처 목록 사용자와 기준 시각에 맞춰 과거 피처를 조회 피처가 결합된 data_output
모델 추론 앞 단계의 피처, MLflow 주소, 모델 이름과 stage 모델을 불러오고 입력을 변환해 예측 예측값이 추가된 data_output
결과 저장 앞 단계의 예측 데이터, 결과 버킷과 파일 이름 예측 결과를 객체 저장소에 기록 저장소의 income_predictions.parquet

네 컴포넌트는 book-ch5/components:0.1 이미지를 함께 사용하지만, 각 component.yaml의 실행 명령은 서로 다른 스크립트를 가리킵니다. 같은 이미지를 사용하더라도 입력과 출력, 수행하는 작업은 각각 다릅니다.

데이터 읽기 컴포넌트의 설정을 예로 들면 다음과 같습니다. 이해에 필요한 항목만 발췌해 일부 입력과 인자는 생략했습니다.

name: Read Data From Minio
inputs:
  - name: minio_host
    type: String
  - name: bucket_name
    type: String
outputs:
  - name: data_output
    type: Dataset
implementation:
  container:
    image: book-ch5/components:0.1
    command:
      - python3
      - /app/src/read_data/read_data.py
      - --minio_host
      - {inputValue: minio_host}
      - --bucket_name
      - {inputValue: bucket_name}
      - --data_output_path
      - {outputPath: data_output}

inputValue는 전달받은 설정값을 명령 인자에 넣고, outputPath는 KFP가 준비한 결과 파일 경로를 스크립트에 전달합니다. 스크립트가 이 경로에 결과를 쓰면 다음 컴포넌트가 해당 출력을 입력으로 받을 수 있습니다.

이번 Run에서 사용한 주요 설정은 다음과 같습니다.

설정 이번 실습 값
입력 데이터 feature-data-sets 버킷의 entity_df.parquet
Feast 설정 feature-registry 버킷의 feature_store_k8s.yaml
모델 random-forest-classifier, 모델 유형 sklearn, stage Production
결과 위치 inference-datasets 버킷의 income_predictions.parquet

컴포넌트 정의를 변경했다면 파이프라인을 다시 컴파일해야 변경 사항이 명세에 반영됩니다. 실습에서는 5장 코드 디렉터리에서 다음 명령을 실행했습니다.

python inference_pipeline.py

생성된 income_classifier_pipeline.yaml을 KFP에 등록하고 Run을 생성합니다. 접속 정보는 예시 설정에서 제외했습니다.

컴포넌트 정의
입력 · 출력 · 실행 명령
파이프라인 코드
작업 순서 · 연결
컴파일
YAML 명세
KFP 등록 · 실행
파라미터 · Run
컴포넌트와 파이프라인 정의를 실행 가능한 명세로 만듭니다.

실습에서는 컴파일한 파이프라인을 income-classifier-pipeline으로 등록했습니다. 등록 화면의 그래프에서 네 작업과 작업 사이의 data_output 연결을 확인할 수 있습니다.

컴포넌트 설계 시 유의할 점

  • 단일 책임과 모듈성: 컴포넌트마다 하나의 역할을 맡기면 수정과 재사용이 쉽습니다.
  • 입출력 명시: 값의 이름, 타입, 의미를 구체적으로 정해 컴포넌트 간 전달을 분명히 합니다.
  • 파라미터화: 실행마다 달라지는 값을 파라미터로 받으면 코드를 바꾸지 않고 동작을 조정할 수 있습니다.

 

5. 파이프라인 실행과 결과 확인

실행 결과

파이프라인을 실행한 결과 네 단계가 모두 SUCCEEDED로 표시됐고, 결과 버킷에 income_predictions.parquet 파일이 생성됐습니다.

파이프라인 Run에서 네 컴포넌트가 모두 성공한 화면입니다.

확인 항목 이번 실행 결과
결과 행 수 30,162행, 입력 행 수와 같음
결과 열
수
91개: 변환된 입력 열 90개와 예측 열 1개
결측값 0개
예측 열 Predicted_Income_Class: 양성 클래스의 예측 확률
예측 확률 분포 평균 약 0.25, 중앙값 약 0.12, 0.5 이상 약 21.9%

예측 확률이 0.5 이상이라는 것은 해당 기준으로 분류할 수 있는 행의 비율입니다. 이 숫자만으로 정확도나 실제 성능을 판단할 수는 없습니다. 이 결과 파일에는 정답 열이 없고, 입력은 모델 학습에 사용한 데이터와 같은 출처입니다.

개별 예측 결과 살펴보기

결과 파일에서 예측 확률이 높은 행, 낮은 행과 0.5에 가까운 행을 몇 개 살펴봤습니다. 아래 확률은 모델이 소득 기준을 초과할 것으로 예측한 값입니다.

구분 학력 혼인 상태 직업 예측 확률
높음 석사 기혼 전문직 1.0
높음 전문직 학위 기혼 전문직 1.0
낮음 고졸 미혼 기계 조작·검사 0.0
낮음 고졸 미혼 건설·수공업 0.0
경계 일부 대학 교육 기혼 전문직 0.538
경계 고졸 기혼 전문직 0.464

분류 기준을 0.5로 정한다면 0.538과 0.464는 기준 양쪽에 있는 예시입니다. 표의 범주는 원-핫 인코딩된 결과 열을 읽기 쉽게 복원한 것이며, 일부 생략된 기준 범주는 추정한 값입니다.

6. 정리

  • KFP는 데이터 읽기, 피처 조회, 추론, 결과 저장을 순서가 있는 파이프라인으로 연결합니다.
  • 각 컴포넌트는 별도 Pod에서 실행되며, 출력 파일이 다음 작업의 입력으로 전달됩니다.
  • 이번 실습에서는 MLflow 모델과 Feast의 과거 피처를 사용해 배치 추론 결과를 객체 저장소에 저장했습니다.

참고 자료

728x90