로컬 임시 스토리지

로컬 임시 스토리지 (Local ephemeral storage)

노드에는 로컬로 연결된 쓰기 가능한 장치, 때로는 RAM이 뒷받침하는 **로컬 임시 스토리지(local ephemeral storage)**가 있어요. "임시(ephemeral)"란 내구성에 대한 장기 보장이 없다는 뜻입니다.

Pod는 스크래치 공간, 캐싱, 로그에 임시 로컬 스토리지를 사용합니다. kubelet은 로컬 임시 스토리지를 사용해 emptyDir 볼륨을 컨테이너에 마운트하는 방식으로 Pod에 스크래치 공간을 제공할 수 있어요.

kubelet은 또한 이런 종류의 스토리지를 사용해 노드 수준 컨테이너 로그, 컨테이너 이미지, 실행 중인 컨테이너의 쓰기 가능 레이어를 저장합니다.

주의: 노드가 실패하면 임시 스토리지의 데이터가 손실될 수 있습니다. 애플리케이션은 로컬 임시 스토리지에서 어떤 성능 SLA(예: 디스크 IOPS)도 기대할 수 없습니다.

참고: ephemeral-storage에 리소스 쿼터가 작동하게 하려면 두 가지가 필요합니다: 관리자가 네임스페이스에 ephemeral-storage에 대한 리소스 쿼터를 설정한다. 사용자가 Pod 스펙에 ephemeral-storage 리소스에 대한 limits를 지정해야 한다. 사용자가 Pod 스펙에 ephemeral-storage 리소스 limit을 지정하지 않으면 리소스 쿼터가 ephemeral-storage에 적용되지 않습니다.

Kubernetes는 Pod가 소비할 수 있는 임시 로컬 스토리지의 양을 추적, 예약, 제한할 수 있게 해줍니다.

출처: 문서

로컬 임시 스토리지 구성 (Configurations for local ephemeral storage)

Kubernetes는 노드에서 로컬 임시 스토리지를 구성하는 다음 방식을 지원합니다: 단일 파일시스템(Single filesystem), 런타임 파일시스템(Runtime filesystem), 분리 이미지 파일시스템(Split image filesystem).

단일 파일시스템 구성에서는 모든 종류의 임시 로컬 데이터(emptyDir 볼륨, 쓰기 가능 레이어, 컨테이너 이미지, 로그)를 하나의 파일시스템에 둡니다. kubelet도 노드 수준 컨테이너 로그를 쓰며 이를 임시 로컬 스토리지와 유사하게 취급합니다. kubelet은 구성된 로그 디렉터리(기본값 /var/log) 안의 파일에 로그를 쓰고, 다른 로컬 저장 데이터를 위한 기본 디렉터리(기본값 /var/lib/kubelet)가 있습니다. 보통 /var/lib/kubelet/var/log 모두 시스템 루트 파일시스템에 있고, kubelet은 그 레이아웃을 염두에 두고 설계되었습니다. 필요에 따라 Kubernetes에 사용하지 않는 다른 파일시스템을 얼마든지 가질 수 있습니다.

런타임 파일시스템 구성에서는 실행 중인 Pod의 임시 데이터(로그, emptyDir 볼륨 등)에 노드의 한 파일시스템을 사용합니다. 이 파일시스템을 Kubernetes와 관련 없는 시스템 로그 같은 다른 데이터에도 사용할 수 있고, 루트 파일시스템일 수도 있습니다. kubelet도 노드 수준 컨테이너 로그를 첫 번째 파일시스템에 쓰며 이를 임시 로컬 스토리지와 유사하게 취급합니다. 또한 다른 논리적 저장 장치가 뒷받침하는 별도의 파일시스템도 사용합니다. 이 구성에서 컨테이너 런타임은 컨테이너 이미지 레이어와 쓰기 가능 레이어를 모두 이 두 번째 파일시스템에 저장합니다. 이 저장 위치는 kubelet이 아니라 컨테이너 런타임에서 구성하세요. 첫 번째 파일시스템은 어떤 이미지 레이어나 쓰기 가능 레이어도 보관하지 않습니다. 필요에 따라 Kubernetes에 사용하지 않는 다른 파일시스템을 얼마든지 가질 수 있습니다.

분리 이미지 파일시스템 구성에서는 컨테이너 이미지 레이어가 별도의 파일시스템에 있고, 컨테이너 쓰기 가능 레이어는 로그와 emptyDir 볼륨 같은 kubelet의 임시 데이터와 같은 파일시스템에 있습니다. 이 레이아웃은 containerfs 축출 신호에 대한 지원이 필요합니다. 이 레이아웃을 지원하는 기능 게이트와 컨테이너 런타임에 대한 자세한 내용은 노드 압력 축출 문서를 참고하세요.

노드 압력 축출 페이지는 관찰된 이 파일시스템들을 nodefs, imagefs, containerfs라고 부릅니다. 그 이름들이 항상 별도의 마운트 지점을 의미하는 것은 아닙니다.

로컬 임시 스토리지에 대해 지원되는 구성 중 하나로 노드를 설정하면 kubelet이 로컬 스토리지 사용량을 측정할 수 있어요.

다른 구성을 사용하면 kubelet은 임시 로컬 스토리지에 리소스 한도를 적용하지 않습니다.

참고: kubelet은 tmpfs emptyDir 볼륨을 로컬 임시 스토리지가 아니라 컨테이너 메모리 사용으로 추적합니다.

참고: kubelet은 지원되는 레이아웃을 통해 관찰하는 파일시스템에서만 임시 스토리지를 추적할 수 있습니다. /var/lib/kubelet, /var/log, 또는 컨테이너 런타임 스토리지 디렉터리 같은 경로 아래에 그 레이아웃 밖의 추가 파일시스템을 마운트하면 kubelet이 임시 스토리지를 올바르게 보고하지 못할 수 있어요.

로컬 임시 스토리지에 대한 requests와 limits 설정 (Setting requests and limits for local ephemeral storage)

ephemeral-storage를 지정해 로컬 임시 스토리지를 관리할 수 있어요. Pod의 각 컨테이너는 다음 중 하나 또는 둘 다를 지정할 수 있습니다.

  • spec.containers[].resources.limits.ephemeral-storage
  • spec.containers[].resources.requests.ephemeral-storage

ephemeral-storage의 limits와 requests는 바이트 단위로 측정됩니다. 스토리지를 일반 정수나 고정 소수점 숫자로 표현할 수 있으며, 다음 접미사 중 하나를 사용할 수 있어요: E, P, T, G, M, k. 또한 2의 거듭제곱 등가물인 Ei, Pi, Ti, Gi, Mi, Ki도 사용할 수 있습니다. 예를 들어 다음 양은 모두 대략 같은 값을 나타냅니다.

  • 128974848
  • 129e6
  • 129M
  • 123Mi

접미사의 대소문자에 주의하세요. ephemeral-storage로 400m을 요청하면 이는 0.4바이트의 요청입니다. 이렇게 입력한 사람은 아마 400 메비바이트(400Mi) 또는 400 메가바이트(400M)를 요청하려 했을 거예요.

다음 예시에서 Pod에는 두 개의 컨테이너가 있습니다. 각 컨테이너는 로컬 임시 스토리지 2GiB의 request가 있습니다. 각 컨테이너는 로컬 임시 스토리지 4GiB의 limit이 있습니다. 따라서 Pod는 로컬 임시 스토리지 4GiB의 request와 8GiB의 limit을 가져요. 그 limit의 500Mi는 emptyDir 볼륨이 소비할 수 있습니다.

apiVersion: v1
kind: Pod
metadata:
  name: frontend
spec:
  containers:
  - name: app
    image: images.my-company.example/app:v4
    resources:
      requests:
        ephemeral-storage: "2Gi"
      limits:
        ephemeral-storage: "4Gi"
    volumeMounts:
    - name: ephemeral
      mountPath: "/tmp"
  - name: log-aggregator
    image: images.my-company.example/log-aggregator:v6
    resources:
      requests:
        ephemeral-storage: "2Gi"
      limits:
        ephemeral-storage: "4Gi"
    volumeMounts:
    - name: ephemeral
      mountPath: "/tmp"
  volumes:
    - name: ephemeral
      emptyDir:
        sizeLimit: 500Mi

ephemeral-storage requests가 있는 Pod가 스케줄되는 방법 (How Pods with ephemeral-storage requests are scheduled)

Pod를 만들면 Kubernetes 스케줄러가 Pod가 실행될 노드를 선택합니다. 각 노드는 Pod에 제공할 수 있는 로컬 임시 스토리지의 최대량이 있습니다. 자세한 내용은 Node Allocatable을 참고하세요.

스케줄러는 스케줄된 컨테이너의 리소스 requests 합계가 노드의 용량보다 작도록 보장합니다.

임시 스토리지 소비 관리 (Ephemeral storage consumption management)

kubelet이 로컬 임시 스토리지를 리소스로 관리한다면, kubelet은 다음의 스토리지 사용을 측정합니다.

  • emptyDir 볼륨 (tmpfs emptyDir 볼륨 제외)
  • 노드 수준 로그를 보관하는 디렉터리
  • 컨테이너 쓰기 가능 레이어

Pod가 허용한 것보다 더 많은 임시 스토리지를 사용하면, kubelet은 Pod 축출을 촉발하는 축출 신호를 설정합니다.

컨테이너 수준 격리의 경우, 컨테이너의 쓰기 가능 레이어와 로그 사용이 스토리지 limit을 초과하면 kubelet은 Pod를 축출 대상으로 표시합니다.

Pod 수준 격리의 경우 kubelet은 그 Pod의 컨테이너 limit을 합산해 전체 Pod 스토리지 limit을 계산합니다. 이 경우 모든 컨테이너의 로컬 임시 스토리지 사용 합계와 Pod의 emptyDir 볼륨이 전체 Pod 스토리지 limit을 초과하면 kubelet은 Pod를 축출 대상으로 표시합니다.

주의: kubelet이 로컬 임시 스토리지를 측정하지 않으면, 로컬 스토리지 limit을 초과하는 Pod는 로컬 스토리지 리소스 limit 위반으로 축출되지 않습니다. 그러나 컨테이너 쓰기 가능 레이어, 노드 수준 로그, emptyDir 볼륨의 파일시스템 공간이 부족해지면 노드는 로컬 스토리지가 부족하다고 스스로 테인트를 표시하고, 이 테인트를 특별히 허용(tolerate)하지 않는 모든 Pod에 대해 축출을 촉발합니다. 임시 로컬 스토리지의 지원 구성을 참고하세요.

kubelet은 Pod 스토리지 사용을 측정하는 여러 방법을 지원합니다.

  • 주기적 스캔 (Periodic scanning)
  • 파일시스템 프로젝트 쿼터 (Filesystem project quota)

kubelet은 정기적이고 예정된 검사를 수행해 각 emptyDir 볼륨, 컨테이너 로그 디렉터리, 컨테이너 쓰기 가능 레이어를 스캔합니다.

스캔은 얼마나 많은 공간이 사용되는지 측정합니다.

참고: 이 모드에서 kubelet은 삭제된 파일에 대한 열린 파일 디스크립터를 추적하지 않습니다. emptyDir 볼륨 안에서 파일을 만들고(또는 컨테이너가), 누군가 그 파일을 연 다음, 파일이 여전히 열려 있는 동안 그 파일을 삭제하면, 삭제된 파일의 inode는 그 파일을 닫을 때까지 남지만 kubelet은 그 공간을 사용 중으로 분류하지 않습니다.

참고: 기능 상태: Kubernetes v1.31부터 Beta, 기본 비활성화 (기능 게이트: LocalStorageCapacityIsolationFSQuotaMonitoring). 자세한 내용은 기능 게이트 활성화/비활성화를 참고하세요.

**프로젝트 쿼터(project quota)**는 파일시스템의 스토리지 사용을 관리하기 위한 운영 체제 수준 기능입니다. Kubernetes로 스토리지 사용 모니터링을 위한 프로젝트 쿼터를 활성화할 수 있어요. 노드에서 emptyDir 볼륨을 뒷받침하는 파일시스템이 프로젝트 쿼터 지원을 제공하는지 확인하세요. 예를 들어 XFS와 ext4fs는 프로젝트 쿼터를 제공합니다.

참고: 프로젝트 쿼터는 스토리지 사용을 모니터링하게 해줍니다. 한도를 강제하지는 않아요.

Kubernetes는 1048576부터 시작하는 프로젝트 ID를 사용합니다. 사용 중인 ID는 /etc/projects/etc/projid에 등록됩니다. 이 범위의 프로젝트 ID가 시스템에서 다른 목적으로 사용된다면, Kubernetes가 사용하지 않도록 그 프로젝트 ID를 /etc/projects/etc/projid에 등록해야 합니다.

쿼터는 디렉터리 스캔보다 빠르고 정확합니다. 디렉터리가 프로젝트에 할당되면 디렉터리 아래 생성되는 모든 파일이 그 프로젝트에서 생성되고, 커널은 그 프로젝트의 파일이 사용하는 블록 수만 추적하면 됩니다. 파일이 생성되고 삭제됐지만 열린 파일 디스크립터가 있으면 계속 공간을 소비합니다. 쿼터 추적은 그 공간을 정확히 기록하지만, 디렉터리 스캔은 삭제된 파일이 사용하는 스토리지를 놓칩니다.

쿼터를 사용해 Pod의 리소스 사용을 추적하려면 Pod가 user namespace에 있어야 합니다. user namespace 안에서 커널은 파일시스템의 projectID 변경을 제한하므로, 쿼터로 계산된 스토리지 메트릭의 신뢰성을 보장합니다.

프로젝트 쿼터를 사용하려면 다음을 해야 합니다.

  • kubelet 구성featureGates 필드를 사용해 LocalStorageCapacityIsolationFSQuotaMonitoring=true 기능 게이트를 활성화한다.
  • UserNamespacesSupport 기능 게이트가 활성화되어 있고, 커널, CRI 구현, OCI 런타임이 user namespaces를 지원하는지 확인한다.
  • 루트 파일시스템(또는 선택적 런타임 파일시스템)에 프로젝트 쿼터가 활성화되어 있는지 확인한다. 모든 XFS 파일시스템은 프로젝트 쿼터를 지원합니다. ext4 파일시스템의 경우 파일시스템이 마운트되지 않은 동안 프로젝트 쿼터 추적 기능을 활성화해야 합니다. ext4의 경우, /dev/block-device가 마운트되지 않은 상태에서 sudo tune2fs -O project -Q prjquota /dev/block-device
  • 루트 파일시스템(또는 선택적 런타임 파일시스템)이 프로젝트 쿼터를 활성화한 채 마운트되어 있는지 확인한다. XFS와 ext4fs 모두 마운트 옵션 이름은 prjquota입니다.

프로젝트 쿼터를 사용하지 않으려면 다음을 해야 합니다.

  • kubelet 구성featureGates 필드를 사용해 LocalStorageCapacityIsolationFSQuotaMonitoring 기능 게이트를 비활성화한다.

다음 단계 (What's next)

더 알아보기 (Learn more)