7.6.1 잡: 일회성 작업 실행
지금까지 우리가 다루었던 디플로이먼트, 스테이트풀셋, 데몬셋과 같은 쿠버네티스 컨트롤러들은 주로 웹 서버나 데이터베이스처럼 지속적으로 실행되어야 하는 서비스를 관리하는 데 사용되었습니다. 이들 컨트롤러는 파드가 예기치 않게 종료되면 즉시 다시 시작시켜 서비스의 가용성을 유지하는 데 초점을 맞추고 있습니다. 하지만 모든 작업이 이렇게 영원히 실행되어야 하는 것은 아닙니다. 때로는 특정 계산을 수행하거나, 데이터를 처리하거나, 보고서를 생성하는 등 한 번 실행되고 성공적으로 완료되면 스스로 종료되어야 하는 일회성 작업들이 필요합니다.
예를 들어, 대규모 데이터셋에 대한 배치 처리, 이미지 또는 비디오 인코딩, 과학적 시뮬레이션 실행, 데이터베이스 마이그레이션 스크립트 실행 등이 이러한 일회성 작업에 해당합니다. 이러한 작업들은 완료되는 데 몇 분, 몇 시간, 또는 며칠이 걸릴 수도 있으며, 중간에 실패하더라도 결국에는 성공적으로 완료되는 것이 중요합니다.
쿠버네티스는 이러한 일회성 배치(batch) 작업을 효과적으로 관리하기 위해 잡(Job)이라는 특별한 워크로드 API 오브젝트를 제공합니다. 잡은 하나 이상의 파드를 생성하여 지정된 작업을 수행하고, 해당 작업이 성공적으로 완료될 때까지 파드의 실행을 책임집니다. 잡이 생성한 파드가 어떤 이유로 실패하면, 잡 컨트롤러는 이를 감지하고 자동으로 새로운 파드를 생성하여 작업을 재시도합니다. 작업이 성공적으로 완료되면, 잡은 더 이상 새로운 파드를 만들지 않고 자신의 임무를 마칩니다.
마치 한 번의 임무를 완수하기 위해 파견되는 특수 요원팀과 같습니다. 이 팀은 임무가 성공할 때까지 여러 번 시도할 수 있으며, 일단 임무가 완료되면 해산합니다. 이제 잡이 어떻게 일회성 작업을 안정적으로 실행하고 관리하는지 그 핵심 기능들을 자세히 살펴보겠습니다.
7.6.1.1 완료될 때까지 파드 실행 보장
잡(Job)의 가장 기본적인 역할이자 핵심적인 기능은 지정된 작업이 성공적으로 완료될 때까지 파드의 실행을 보장하는 것입니다. 여기서 ‘성공적으로 완료’된다는 것은 잡이 생성한 파드 중 하나 이상이 종료 코드 0 (성공적인 종료를 의미)으로 종료되는 것을 의미합니다.
일반적인 디플로이먼트의 경우, 파드가 성공적으로 종료되면 디플로이먼트는 이를 ‘비정상 종료’로 간주하고 즉시 새로운 파드를 생성하여 replicas 수를 유지하려고 합니다. 하지만 잡은 다릅니다. 잡은 파드가 성공적으로 종료되는 것을 ‘작업 완료’의 신호로 받아들입니다.
만약 잡이 생성한 파드가 어떤 이유로 실패하여 비정상적으로 종료된다면 (예: 0이 아닌 종료 코드로 종료되거나, 노드 장애로 인해 파드가 사라지는 경우), 잡 컨트롤러는 이를 감지하고 새로운 파드를 생성하여 작업을 자동으로 재시도합니다. 이러한 재시도는 작업이 결국 성공적으로 완료될 때까지 계속될 수 있습니다.
이러한 재시도 메커니즘은 일회성 작업의 신뢰성을 크게 높여줍니다. 간헐적인 네트워크 문제나 일시적인 리소스 부족으로 인해 파드가 실패하더라도, 잡은 끈기 있게 재시도하여 최종적으로 작업을 완료시킬 수 있도록 돕습니다.
잡 명세(spec)에는 이러한 재시도 동작을 제어하는 몇 가지 중요한 필드가 있습니다.
- backoffLimit 필드 (선택 사항):작업이 계속해서 실패할 경우, 무한정 재시도하는 것을 방지하기 위해 최대 재시도 횟수를 지정할 수 있습니다. 이 필드에 설정된 횟수만큼 재시도했음에도 작업이 성공하지 못하면, 잡은 해당 작업을 ‘실패(Failed)’ 상태로 간주하고 더 이상 재시도하지 않습니다. 기본값은 6이며, 이는 대략 5분 정도의 지연 시간(기본 backoff 지연 시간은 10초부터 시작하여 최대 6분까지 지수적으로 증가) 후에 재시도 횟수 제한에 도달할 수 있음을 의미합니다. 이 값을 0으로 설정하면 재시도하지 않습니다. 만약 backoffLimit에 도달하여 잡이 실패하면, 해당 잡과 관련된 파드들은 삭제되지 않고 남아있어 실패 원인을 분석하는 데 도움을 줄 수 있습니다.
- restartPolicy 필드 (파드 템플릿 내):잡의 파드 템플릿(spec.template.spec) 내에 정의되는 restartPolicy는 잡의 동작 방식에 따라 특별한 제약을 받습니다. 잡에 의해 생성된 파드의 restartPolicy는 Never 또는 OnFailure만 허용됩니다.
- Never: 파드 내의 컨테이너가 실패하면, 파드 자체는 실패 상태가 되고 새로운 파드가 생성되어 작업을 재시도합니다. 컨테이너가 재시작되지 않습니다.
- OnFailure: 파드 내의 컨테이너가 실패하면, 쿠버네티스는 동일 파드 내에서 해당 컨테이너를 재시작하려고 시도합니다. 만약 컨테이너 재시작으로도 문제가 해결되지 않거나 파드 자체가 어떤 이유로 실패하면 (예: 노드 장애), 잡은 새로운 파드를 생성하여 작업을 재시도합니다.
일반적으로 OnFailure가 더 선호될 수 있는데, 이는 간단한 오류는 파드 내 컨테이너 재시작으로 빠르게 해결하고, 심각한 문제 발생 시에만 새 파드를 생성하도록 하기 때문입니다. 만약 restartPolicy를 Always (디플로이먼트의 기본값)로 설정하려고 하면 잡 생성 시 오류가 발생합니다. 왜냐하면 잡은 ‘작업 완료’라는 명확한 종료 상태를 목표로 하기 때문입니다.
이처럼 잡은 작업이 성공적으로 완료될 때까지 파드의 실행을 끈기 있게 관리하며, 필요한 경우 자동으로 재시도함으로써 일회성 작업의 안정적인 수행을 보장합니다. 이는 개발자와 운영자가 배치 작업의 실행 결과에 대해 더 큰 확신을 가질 수 있도록 해줍니다.
7.6.1.2 병렬 실행 (completions, parallelism) 설정
어떤 일회성 작업들은 하나의 파드에서 순차적으로 처리하기에는 너무 오래 걸리거나, 본질적으로 여러 조각으로 나누어 동시에 처리할 수 있는 경우가 있습니다. 예를 들어, 100개의 파일을 각각 변환하는 작업이나, 큰 데이터셋을 여러 부분으로 나누어 병렬로 분석하는 작업 등이 그렇습니다. 이러한 경우, 여러 개의 파드를 동시에 실행하여 작업을 병렬로 처리하면 전체 작업 완료 시간을 크게 단축시킬 수 있습니다.
잡(Job)은 이러한 병렬 실행(parallel execution) 요구사항을 지원하기 위해 spec 필드 내에 completions와 parallelism이라는 두 가지 중요한 설정을 제공합니다.
- completions 필드 (선택 사항):이 필드는 해당 잡이 성공적으로 완료되어야 하는 총 파드의 수를 지정합니다. 즉, 잡의 목표 달성 기준이 됩니다.
- 만약 completions 필드가 설정되지 않거나 1로 설정되면 (기본값), 단 하나의 파드만 성공적으로 완료되면 잡은 성공한 것으로 간주됩니다. 이는 간단한 단일 작업에 적합합니다.
- 만약 completions: 5로 설정되면, 총 5개의 파드가 성공적으로 종료되어야 해당 잡이 완료된 것으로 처리됩니다.
completions는 주로 작업 큐(work queue) 패턴과 함께 사용될 때 유용합니다. 예를 들어, 100개의 독립적인 작업 항목이 있고, 각 파드가 이 큐에서 하나의 작업 항목을 가져와 처리한다고 가정해 봅시다. 이때 completions: 100으로 설정하면, 총 100개의 작업 항목이 모두 성공적으로 처리될 때까지 잡이 실행됩니다.
- parallelism 필드 (선택 사항):이 필드는 동시에 실행될 수 있는 파드의 최대 개수를 지정합니다. 즉, 한 번에 몇 개의 파드를 병렬로 띄울 것인지를 제어합니다.
- 만약 parallelism 필드가 설정되지 않거나 1로 설정되면 (기본값), 한 번에 하나의 파드만 실행됩니다. 즉, 순차적으로 작업이 진행됩니다. (단, completions가 1보다 크면, 하나의 파드가 완료된 후에 다음 파드가 실행됩니다.)
- 만약 parallelism: 3으로 설정되면, 최대 3개의 파드가 동시에 실행되어 작업을 병렬로 처리할 수 있습니다. 클러스터의 리소스가 허용하는 한, 잡은 parallelism 수만큼 파드를 띄우려고 시도합니다.
parallelism 값은 0보다 커야 하며, 일반적으로 completions 값보다 크거나 같게 설정하는 것은 의미가 없습니다 (단, 작업 큐 패턴처럼 각 파드가 여러 작업을 처리할 수 있는 경우는 예외일 수 있습니다).
completions와 parallelism의 조합에 따른 동작 방식:
이 두 필드를 어떻게 조합하느냐에 따라 잡의 실행 방식이 달라집니다.
- 단일 완료, 단일 병렬 (Non-parallel Job):
- completions 미설정 (또는 1), parallelism 미설정 (또는 1)
- 하나의 파드가 생성되고, 이 파드가 성공적으로 완료되면 잡이 종료됩니다. 가장 기본적인 형태의 잡입니다.
- 고정된 수의 완료, 병렬 실행 (Parallel Job with a Fixed Completion Count):
- completions: N (N > 1), parallelism: M (M >= 1)
- 잡은 총 N개의 파드가 성공적으로 완료될 때까지 실행됩니다. 한 번에 최대 M개의 파드가 병렬로 실행됩니다.
- 예를 들어, completions: 10, parallelism: 2로 설정하면, 먼저 2개의 파드가 실행되고, 그중 하나가 완료되면 새로운 파드가 추가되어 항상 2개의 파드가 병렬로 실행되도록 유지하면서 총 10개의 파드가 성공적으로 완료될 때까지 진행됩니다.
- 작업 큐 방식의 병렬 실행 (Parallel Job with a Work Queue):
- completions는 설정하지 않고 (또는 1로 설정), parallelism: M (M > 1)으로 설정하는 경우도 있습니다. 이 경우, 잡은 M개의 파드를 병렬로 실행시키고, 그중 하나라도 성공적으로 완료되면 잡은 성공한 것으로 간주하고 나머지 실행 중인 파드들을 종료시키려고 시도합니다. (이 동작은 파드들이 서로 협력하여 하나의 결과를 도출하는 경우보다는, 외부 작업 큐 시스템과 연동하여 각 파드가 독립적인 작업을 처리하고, 큐가 비거나 특정 조건이 만족되면 리더 파드가 잡을 종료시키는 시나리오 등에서 활용될 수 있습니다. 하지만 일반적인 작업 큐 패턴에서는 completions를 전체 작업 항목 수로 설정하는 것이 더 일반적입니다.)
- 더 일반적인 작업 큐 패턴: completions: N (전체 작업 항목 수), parallelism: M (동시 작업자 수). 각 파드는 외부 큐(예: RabbitMQ, Redis 등)에서 작업 항목을 가져와 처리하고 성공적으로 종료합니다. 잡은 총 N개의 작업 항목이 모두 처리(즉, N개의 파드가 성공적으로 완료)될 때까지 M개의 파드를 병렬로 유지합니다.
이처럼 completions와 parallelism 설정을 통해, 우리는 일회성 작업을 필요에 따라 순차적으로 실행하거나, 여러 파드를 병렬로 실행하여 작업 효율성을 크게 높일 수 있습니다. 이는 특히 시간이 오래 걸리는 대규모 배치 처리 작업에서 매우 유용하게 활용될 수 있는 기능입니다. 잡은 이러한 병렬 처리 과정을 조율하고, 각 파드의 성공 여부를 추적하여 최종적으로 원하는 수의 작업이 모두 완료되었음을 보장해줍니다.