HTTP 서버를 Spark 사이드카로 실행하기
HTTP 사이드카는 각 Spark 실행기 옆에서 서버를 실행하고, 같은 실행기의 작업 함수가 로컬 엔드포인트를 호출하는 구성입니다. 서버가 모델이나 외부 언어의 계산 엔진을 감싸는 경우에도 요청과 응답을 주고받는 위치는 실행기입니다. 드라이버의 localhost는 실행기 옆 사이드카의 주소로 사용할 수 없습니다.
예제 서버는 /hello에서 Hello World를 반환합니다. 변환은 실제 HTTP 응답을 response_text라는 문자열 열에 저장합니다.
이미지 파일
다음 세 파일을 같은 로컬 빌드 폴더에 둡니다.
| 파일 | 내용 |
|---|---|
| app.py | Flask 애플리케이션과 /hello 경로를 정의합니다. |
| requirements.txt | Flask >=3.1,<4, Gunicorn >=23,<24를 설치합니다. |
| Dockerfile | Python 3.12 slim 이미지를 사용하고 UID 1234로 서버를 실행합니다. |
서버의 애플리케이션 객체 이름은 app입니다. Gunicorn은 app:app에서 앞의 app을 모듈 이름, 뒤의 app을 WSGI 애플리케이션 객체로 해석합니다. 실행 명령은 다음과 같습니다.
gunicorn --workers 1 --bind 0.0.0.0:1234 app:app
이 예제는 Gunicorn 워커 하나를 사용합니다. 0.0.0.0:1234는 컨테이너의 인터페이스에서 요청을 받는 서버 바인딩이며, 클라이언트는 127.0.0.1:1234를 호출합니다. 포트 1234는 숫자 비-root UID가 사용할 수 있는 범위에 있습니다. Dockerfile의 EXPOSE만으로 외부 사용자에게 서비스를 공개하는 것은 아닙니다.
이미지 등록과 저장소 설정
컨테이너 이미지 등록 절차에 따라 Docker Artifacts 저장소에 인증한 뒤 빌드하고 푸시합니다. FOUNDRY_CONTAINER_REGISTRY에는 그 저장소의 실제 이미지 경로를 설정합니다.
: "${FOUNDRY_CONTAINER_REGISTRY:?Artifacts 저장소에 표시된 이미지 경로를 설정하세요}"
IMAGE="${FOUNDRY_CONTAINER_REGISTRY}/simple-http:0.0.1"
docker build --platform linux/amd64 --tag "$IMAGE" .
docker push "$IMAGE"
Python 코드 저장소에서는 다음을 준비합니다.
Libraries에transforms-sidecar와requests를 추가하고 커밋합니다.Settings > Libraries에 해당 Docker Artifacts 저장소를 추가합니다.- transform.py를 변환 모듈로 넣고, 예제 출력 경로
/training/containers/http-response를 자신의 프로젝트에 쓸 수 있는 실제 경로로 바꿉니다.
이미지 이름 simple-http와 태그 0.0.1은 변환의 @sidecar(image="simple-http", tag="0.0.1")와 일치해야 합니다.
요청을 실행기에 배치하는 방법
변환은 parallelize([1], 1)로 파티션 하나인 RDD를 만든 뒤, map으로 HTTP 호출 함수를 적용합니다. 이 함수가 Spark 실행기에서 실행되므로 로컬 요청이 해당 실행기의 사이드카로 향합니다. 반환한 한 행에는 HTTP 응답 본문이 들어갑니다. 출력 스키마를 response_text: string으로 명시하므로 스키마 추론에 의존하지 않습니다.
서버 시작에는 시간이 걸릴 수 있어 작업 함수가 TCP 포트의 준비를 최대 60초 동안 기다립니다. 포트가 준비되면 HTTP 요청을 한 번 보내며, 연결 시간 제한은 5초, 응답 읽기 시간 제한은 30초입니다. raise_for_status()가 HTTP 오류 응답을 예외로 전달합니다. 서버 준비 실패나 요청 실패를 Hello World 문자열로 대체하지 않습니다.
60초, 5초와 30초는 이 예제 코드의 설정값입니다. 실제 서버의 초기화 시간과 요청 처리 시간에 맞춰 조정합니다. TCP 연결 성공은 포트가 열렸음을 뜻하며, 애플리케이션의 계산 성공은 이어지는 실제 HTTP 응답으로 판단합니다.
병렬화와 재실행
입력 파티션이 늘면 여러 실행기와 사이드카 쌍에서 요청을 처리할 수 있습니다. 한 실행기는 여러 작업을 순차 처리할 수 있으므로 서버는 요청 한 번 뒤 종료하지 않고 계속 요청을 받습니다. CPU, 메모리와 GPU가 더 필요하면 사이드카 리소스 프로필을 지정합니다.
Spark는 실패한 작업을 다시 실행할 수 있습니다. HTTP 요청으로 외부 상태를 변경하는 서버라면 요청 식별자나 서버의 멱등성 규약으로 중복 실행을 처리해야 합니다. 이 /hello 예제는 읽기 요청이며 외부 상태를 변경하지 않습니다. 프로그램이 HTTP 서버가 아니라 입력 파일을 받아 한 번 실행한 뒤 끝나는 명령이라면 CLI 사이드카의 파일 교환 절차를 사용합니다.