데이터 격리와 샌드박싱
데이터 격리와 샌드박싱 (Data Isolation and Sandboxing)
데이터 워크플로의 일부를 AI 에이전트에게 맡기는 팀이 늘어나면서, 안전하게 데이터를 격리하는 일이 더욱 중요해졌어요. lakeFS는 에이전트에게 자기만의 zero-copy 브랜치를 주어 작업하게 할 수 있어요. 그러면 에이전트가 완전히 격리된 샌드박스에서 데이터를 변환, 생성, 정리해도 프로덕션이나 다른 에이전트에는 위험이 없어요. 브랜칭이 저렴하기 때문에 모든 에이전트가 필요할 때 자기 환경을 얻을 수 있고, 검토 전에는 아무 것도 프로덕션에 도달하지 않기 때문에 에이전트의 변경 사항이 머지되기 전 게이트를 두는 풀 리퀘스트로 human-in-the-loop를 유지할 수 있어요. 에이전트가 취한 모든 액션은 커밋 히스토리와 감사 로그에 기록되어, 각 에이전트가 무엇을 언제 했는지에 대한 완전하고 검토 가능한 기록을 얻게 돼요. 위험한 ETL 잡으로부터 프로덕션을 지키는 바로 그 격리가 신뢰할 수 없는 에이전트로부터도 프로덕션을 지켜주기 때문에, 신뢰성을 희생하지 않고도 에이전트가 데이터를 관리하게 할 수 있어요.
본문
격리된 환경이 왜 중요한가요?
데이터 레이크에 변경을 가할 때, 신뢰할 수 있는 결과를 보장하려면 실제 프로덕션 데이터로 그 변경을 테스트해야 해요. 이를 위해서는 프로덕션 데이터와 그것에 의존하는 소비자에게 영향을 주지 않으면서 프로덕션 데이터에 접근할 수 있는 격리된 환경이 필요해요.
적절한 테스트 없이 파이프라인, 변환 잡, 모델 업데이트를 바로 프로덕션에서 실행하는 것은 상당한 위험을 수반해요. 조만간 데이터 이슈가 대시보드, ML 모델, 다운스트림 시스템으로 퍼져나가 값비싼 오류와 신뢰 상실로 이어질 수 있어요.
프로덕션을 직접 바꾸는 것을 피하는 가장 흔한 방법은 별도의 개발과 테스트 환경을 만드는 거예요. 실제로는 보통 대량의 데이터를 실험과 검증을 위한 전용 개발 환경으로 복사하는 일을 의미해요.
하지만 lakeFS 없이는 이런 환경을 만들고 유지하는 것이 시간도 오래 걸리고 비용도 커요. 대용량 데이터셋을 복제해야 해서 스토리지 비용이 늘어나죠. 팀은 결국 제한된 개발 환경을 공유하게 되고, 그러면 조정 오버헤드가 생기고 개발이 느려져요. 그리고 이 환경들은 진정한 격리가 아니라 데이터 복사에 의존하기 때문에, 프로덕션과의 완전한 분리도 보장하지 못해요.
lakeFS는 어떻게 개발/테스트 환경을 도와주나요?
lakeFS는 ETL 잡, 변환, ML 워크플로를 위한 진정으로 격리된 개발·테스트 환경을 빠르고 비용 효율적으로 만들게 해줘요. 대량의 데이터를 복사하는 대신, lakeFS는 zero-copy branching으로 객체를 복제하지 않고 즉시 새 환경을 만들어요.
lakeFS 저장소에서는 모든 데이터가 브랜치 위에 살아요. 각 브랜치를 독립적인 환경이라고 생각하면 돼요. 브랜치는 완전히 격리돼요: 명시적으로 머지하지 않는 한, 한 브랜치에서 가한 변경은 다른 브랜치에 영향을 주지 않아요. 덕분에 팀은 프로덕션이나 다른 개발자에게 영향을 주지 않으면서 실험하고, 변경을 검증하고, 반복할 수 있어요.
lakeFS는 물리적 복사가 아니라 메타데이터 포인터로 브랜치를 만들기 때문에, 변경되지 않은 객체는 브랜치들 사이에서 공유돼요. 새 데이터나 수정된 데이터만 추가 스토리지를 소비해요. 이것은 여러 복사 환경을 유지하는 높은 비용과 운영 부담을 없애요.
변경이 검증되고 승격될 준비가 되면, 머지 연산으로 그것을 다른 브랜치에 적용할 수 있어요(예: 개발 브랜치에서 프로덕션으로). 이것은 승격 프로세스를 통제되고, 명시적이고, 버저닝된 것으로 만들어요.
브랜치를 개발·테스트 환경으로 사용하기
격리된 데이터 환경에 lakeFS를 사용할 때의 핵심 차이는, 변경을 테스트하기 직전에 환경을 즉시 만들 수 있다는 거예요. 그리고 새 데이터가 프로덕션에 머지되면 브랜치를 삭제하면 돼요 - 사실상 기존 환경을 삭제하는 거죠.
이것은 모든 업데이트를 테스트하는 스테이징 영역으로 쓰이는 장수하는(long-living) 테스트 환경을 만드는 것과는 다른 방식이에요. lakeFS에서는 프로덕션에 가하려는 변경마다 새 브랜치를 만들어요. 이것의 이점 하나는 여러 변경을 한 번에 테스트할 수 있다는 거예요.
직접 해보기: lakeFS로 개발/테스트 환경 만들기
lakeFS는 Git 스타일 연산을 실행하기 위해 UI, CLI(lakectl 명령줄 유틸리티), 그리고 API를 위한 여러 클라이언트를 지원해요. 아래에서 이 각 옵션으로 개발/테스트 환경을 만드는 방법을 살펴볼게요.
lakeFS를 체험하는 방법은 두 가지가 있어요:
-
lakeFS Cloud - 무료 체험이 있는 완전 관리형 lakeFS
-
로컬 Docker 기반 퀵스타트와 samples
-
Self-hosted lakeFS Enterprise 퀵스타트
예제: lakeFS Cloud 사용하기
이 튜토리얼에서는 lakeFS Cloud 환경을 사용해 ETL 테스팅을 위한 개발/테스트 데이터 환경을 만들 거예요. 이렇게 하면 클릭 한 번으로 lakeFS 인스턴스를 띄우고, 데이터 저장소에서 단순히 브랜치를 만들어 여러 데이터 환경을 생성하고, 이 격리된 브랜치에서 데이터 파이프라인을 개발·테스트할 수 있어요.
먼저 cloud 인스턴스를 띄우세요. 라이브 환경이 생기면 access key와 secret key로 인스턴스에 로그인하세요. 그러면 여러분을 위해 만들어진 샘플 데이터 저장소 my-repo로 작업할 수 있어요.
my-repo를 클릭해 보세요. 기본으로 저장소에 main 브랜치가 만들어져 있고 sample_data가 미리 로드되어 작업할 준비가 돼 있어요.
Branches 탭으로 가서 Create Branch를 클릭하면 새 브랜치(예: test-env)를 만들 수 있어요. 성공하면 저장소 아래에 두 브랜치가 보일 거예요: main과 test-env.
이제 main 브랜치의 데이터에 영향을 주지 않으면서 test-env 브랜치 아래에서 객체를 추가, 수정, 삭제할 수 있어요.
Docker와 Jupyter Notebook으로 lakeFS 체험하기
이 유스 케이스는 lakeFS 브랜치를 사용해 ETL 테스팅용 개발/테스트 데이터 환경을 만드는 방법을 보여줘요. 다음 튜토리얼은 lakeFS 환경, Jupyter 노트북, Python SDK API를 제공해 lakeFS와 Spark의 통합을 시연해요. 이 튜토리얼은 로컬 머신에서 실행할 수 있어요.
아래 튜토리얼 비디오를 따라 lakeFS Cloud와 Jupyter 노트북으로 시작하거나, 이 페이지의 지침을 따르세요.
사전 요구 사항
시작하기 전에 머신에 Docker가 설치되어 있어야 해요.
lakeFS와 Jupyter Notebook 실행하기
아래 단계를 따라 lakeFS로 개발/테스트 환경을 만들어요.
- lakeFS samples Git 저장소를 클론하는 것부터 시작해요:
git clone https://github.com/treeverse/lakeFS-samples.git
cd lakeFS-samples
- Python, Spark, Jupyter Notebook, JDK, Hadoop 바이너리, lakeFS Python SDK, Airflow를 포함하는 Docker 컨테이너를 내려받아 실행하려면 다음 명령을 실행해요(Docker 이미지 크기는 약 4.5GB예요):
git submodule init && git submodule update
docker compose up
- 로컬 Jupyter Notebook을 열고
spark-demo.ipynb노트북으로 가세요.
lakeFS Python 클라이언트 설정하기
실행 중인 lakeFS 인스턴스를 위한 lakeFS 접근 자격 증명을 설정해요. samples 저장소 Docker Compose가 사용하는 기본값은 다음과 같아요:
lakefs_access_key = '«redacted:AKIA…»'
lakefs_secret_key = 'wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY'
lakefs_endpoint = 'http://lakefs:8000'
다음으로, 스토리지 네임스페이스를 여러분이 설정한 버킷의 위치로 설정해요. 스토리지 네임스페이스는 이 저장소의 데이터가 저장될 기반 스토리지의 위치예요.
storageNamespace = 's3://example/'
lakeFS는 UI, API, lakectl 명령줄을 통해 사용할 수 있어요. 이 유스 케이스에서는 python lakefs로 lakeFS 핵심 연산을 실행해요.
import lakefs
from lakefs import Client
# lakeFS credentials and endpoint
client = Client(
host=lakefs_endpoint,
username=lakefs_access_key,
password=lakefs_secret_key
)
lakeFS는 두 가지 방식으로 Spark와 함께 동작하도록 설정할 수 있어요:
-
S3 호환 API로 lakeFS 접근하기
-
lakeFS 전용 Hadoop FileSystem으로 lakeFS 접근하기
샘플 데이터를 메인 브랜치에 업로드하기
my-repo로 객체를 업로드하려면 다음 명령을 사용해요.
import os
import lakefs
with open('/data/lakefs_test.csv', 'rb') as f:
lakefs.repository("my-repo", client=client).branch("main").object(filenName).upload(data=f.read())
업로드되면 main 브랜치에 변경을 커밋하고, 커밋에 메타데이터도 붙여요.
lakefs.repository("my-repo", client=client).branch("main").commit(message="Added my first object!", metadata={'using': 'python'})
이 예제에서는 lakeFS S3A 게이트웨이를 사용해 스토리지 버킷에서 데이터를 읽어요.
dataPath = f"s3a://my-repo/main/lakefs_test.csv"
df = spark.read.csv(dataPath)
df.show()
테스트 브랜치 만들기
my-repo 예제 저장소에서 새 브랜치 test-env를 만드는 것부터 시작할게요.
lakefs.repository("my-repo", client=client).branch("test-env").create(source_reference="main")
이제 Spark를 사용해 main 브랜치의 csv 파일을 Parquet 파일로 lakeFS 저장소의 test-env에 쓸 수 있어요. 실수로 데이터프레임을 test-env 브랜치에 다시 쓴다고 해 보죠. 이번에는 append 모드로요.
df.write.mode('overwrite').parquet('s3a://my-repo/test-env/')
df.write.mode('append').parquet('s3a://my-repo/test-env/')
두 브랜치에서 데이터를 다시 읽고 결과 DataFrame에 카운트를 수행하면 어떻게 될까요? test-env 브랜치에는 두 배의 row가 있을 거예요. 즉, 실수로 데이터를 복제해 버린 거예요! 아이고!
데이터 복제는 데이터 분석, BI, 머신러닝 작업에 오류를 유입시켜요. 그래서 우리는 데이터 복제를 피하고 싶죠.
반면 main 브랜치에는 아직 원본 데이터만 있어요. 우리의 Spark 코드에 전혀 손대지 않았죠. 이것이 lakeFS의 브랜치 기반 격리 환경의 유용성을 보여줘요.
lakeFS의 격리 능력 덕분에 무사한 main의 데이터로 안전하게 계속 작업할 수 있어요.
더 읽을거리
-
Case Study: How Enigma use lakeFS for isolated development and staging environments
-
Tutorial: ETL Testing Tutorial with lakeFS: Step-by-Step Guide
더 알아보기 (Learn more)
공식 문서의 원문은 https://docs.lakefs.io/use-cases/isolated-environments/ 에서 확인할 수 있어요.