- 들어가며 — 이미지 풀이 느린 이유는 두 개다
- containerd 2.3에서 실제로 머지된 것
- differ 코드가 말해 주는 것 — 언팩이 사라지는 지점
- 레지스트리에서 직접 확인해 보기
- os.features — 하나의 태그로 두 세계를 서빙하기
- +zstd — 압축은 되찾았지만 언팩 회피는 절반
- 지연 로딩은 아직 없습니다
- dm-verity — 조용히 더 흥미로운 쪽
- 값을 치러야 하는 것들
- 표준은 어디에 있나
- 그래서, 지금 켜야 하나
- 마치며
- 참고 자료
들어가며 — 이미지 풀이 느린 이유는 두 개다
컨테이너 이미지 풀이 느리다고 할 때, 사실 두 개의 다른 문제가 한 단어에 뭉쳐 있습니다.
하나는 내려받는 시간입니다. 레지스트리에서 수 GB를 끌어오는 네트워크 비용이죠. 다른 하나는 푸는 시간입니다. tar+gzip을 스트리밍으로 해제하면서 수만 개 파일을 호스트 파일시스템에 하나씩 만들어 내는 비용입니다. 후자는 네트워크가 아니라 CPU와 파일시스템 메타데이터 저널의 문제라, 100Gbps 링크를 깔아도 그대로 남습니다.
지난 몇 년간 이 바닥의 화제는 대부분 첫 번째 문제였습니다. eStargz, SOCI, Nydus 같은 지연 로딩(lazy pull) 계열이 "전부 받지 말고 필요한 조각만 받자"고 했고, AWS의 SOCI는 아예 방향을 틀어 "그냥 병렬로 빨리 받자"는 모드를 붙였습니다. 이 계보는 컨테이너 런타임 비교 편에서 다룬 적이 있습니다.
2026년 4월 30일에 나온 containerd 2.3은 두 번째 문제를 정면으로 칩니다. 아이디어는 단순합니다 — tar를 풀어서 파일시스템을 만드는 대신, 애초에 파일시스템을 레이어로 배포하자. 이 글은 그게 실제로 어디까지 왔는지, 코드와 레지스트리 매니페스트로 확인해 본 기록입니다.
containerd 2.3에서 실제로 머지된 것
먼저 날짜와 PR을 못 박아 두겠습니다. EROFS 자체는 2.3에서 처음 나온 게 아닙니다.
| 시점 | 무엇 |
|---|---|
| containerd 2.1.0 (2025-05-07) | EROFS snapshotter와 differ 최초 탑재 (#10705, 2025-02-05 머지) |
| containerd 2.2.0 (2025-11-06) | mount manager 기반 개선, tar index 모드, 병렬 언팩 |
| containerd 2.3.0 (2026-04-30) | 네이티브 EROFS 레이어 — 레지스트리에서 EROFS blob을 그대로 수신 |
2.3에 들어간 조각들은 이렇습니다.
- #12567 (2026-01-06 머지) — media type
application/vnd.erofs.layer.v1추가. PR 설명 그대로 "containerd가 EROFS 네이티브 컨테이너 이미지를 직접 가져올 수 있도록" 하는 것. - #13091 (2026-04-01 머지) —
os.features에erofs가 있으면 transfer service가 EROFS snapshotter/differ를 고르도록. - #12502 (2026-04-01 머지) — EROFS snapshotter에 dm-verity 지원.
- #13185 (2026-04-12 머지) —
application/vnd.erofs.layer.v1+zstd, zstd로 감싼 EROFS 레이어.
참고로 2.3.0은 containerd 릴리스 정책이 바뀐 첫 릴리스이기도 합니다. 릴리스 노트의 표현으로는 쿠버네티스 일정에 맞춘 약 4개월 주기로 옮겼고, 2.3은 그 체계의 첫 연간 LTS입니다. endoflife.date가 독립적으로 같은 값을 보여 줍니다 — 2.3 릴리스 2026-04-30, EOL 2028-04-30, LTS 표시. 덧붙이면 같은 표에서 containerd 2.1은 이미 2026-07-03에 EOL이 지났습니다.
differ 코드가 말해 주는 것 — 언팩이 사라지는 지점
EROFS의 이득은 벤치마크 그래프가 아니라 differ 코드 몇 줄에서 가장 선명하게 보입니다. containerd 2.3.0의 plugins/diff/erofs/differ.go에는 세 갈래가 있습니다.
1. 일반 OCI tar 레이어를 받았을 때 — mkfs.erofs를 띄워 tar를 EROFS로 실시간 변환합니다. internal/erofsutils/mount.go의 ConvertTarErofs가 하는 일이 이겁니다.
args := append([]string{"--tar=f", "--aufs", "--quiet", "-Enoinline_data"}, mkfsExtraOpts...)
cmd := exec.CommandContext(ctx, "mkfs.erofs", args...)
cmd.Stdin = r
즉 tar 스트림을 mkfs.erofs의 표준입력으로 밀어 넣습니다. 파일을 하나씩 호스트 FS에 만드는 게 아니라 EROFS blob 하나로 찍어 내는 것이라, overlayfs snapshotter의 파일별 추출보다 메타데이터 저널 트래픽이 적고 GC 때 수만 개 파일을 지울 일도 없습니다. 이건 2.1부터 있던 이야기입니다.
2. 압축 없는 네이티브 EROFS 레이어를 받았을 때 — 2.3의 새 경로이고, 코드가 이렇게 끝납니다.
layerBlobPath := path.Join(layer, "layer.erofs")
// Allow copy file range when there is an uncompressed native EROFS layer
if fastcopy {
f, err := os.Create(layerBlobPath)
...
_, err = io.Copy(f, content.NewReader(ra))
f.Close()
...
return desc, nil
}
여기가 핵심입니다. mkfs.erofs도, tar 파서도, 파일별 생성도 없습니다. content store의 blob을 layer.erofs로 복사하고 끝냅니다. 언팩 단계 자체가 없어진 게 아니라, blob 복사 한 번으로 축약된 것입니다. 그다음 snapshotter가 layer.erofs를 fs/에 마운트하고 부모 레이어들과 함께 overlayfs 마운트를 돌려줍니다.
3. +zstd 레이어를 받았을 때 — 뒤에서 따로 보겠습니다.
레지스트리에서 직접 확인해 보기
문서만 읽고 넘어가면 재미가 없으니 실제 레지스트리를 찔러 봤습니다. EROFS 메인테이너가 테스트용으로 올려 둔 docker.io/hsiangkao/ubuntu 저장소에 관련 태그들이 있습니다. 아래는 2026-07-16에 registry-1.docker.io에서 직접 받아 본 결과입니다.
22.04-platforms 태그의 OCI index를 열면, amd64 매니페스트가 두 개 들어 있습니다.
{
"mediaType": "application/vnd.oci.image.index.v1+json",
"manifests": [
{ "digest": "sha256:1c4cc37c...",
"platform": { "architecture": "amd64", "os": "linux" } },
{ "digest": "sha256:06ae2788...",
"platform": { "architecture": "amd64", "os": "linux",
"os.features": ["erofs"] } }
]
}
같은 아키텍처, 같은 OS인데 os.features만 다릅니다. 각 매니페스트의 레이어를 열어 보면 media type이 갈립니다.
| 형식 | media type | 레이어 크기 |
|---|---|---|
| 표준 tar+gzip | application/vnd.oci.image.layer.v1.tar+gzip | 29,536,798 B (28.17 MiB) |
| EROFS 네이티브 (무압축) | application/vnd.erofs.layer.v1 | 45,289,472 B (43.19 MiB) |
| EROFS + zstd | application/vnd.erofs.layer.v1+zstd | 27,214,834 B (25.95 MiB) |
트레이드오프가 이 세 줄에 다 들어 있습니다. 무압축 EROFS는 tar+gzip 대비 와이어 바이트가 약 1.53배입니다 — 언팩을 없애는 값으로 네트워크를 53퍼센트 더 쓰는 셈입니다. zstd로 감싸면 오히려 tar+gzip보다 8퍼센트쯤 작아집니다.
정직하게 붙여 둘 단서가 있습니다. 이건 벤치마크가 아니라 매니페스트 한 개를 열어 본 것입니다. 이미지 하나(ubuntu 22.04 베이스, 단일 레이어), 그것도 EROFS 프로젝트 본인이 올린 테스트 아티팩트이고, EROFS blob의 내용이 tar 레이어와 바이트 단위로 동일한 rootfs인지는 제가 확인하지 않았습니다. 압축률은 이미지 내용에 따라 크게 흔들립니다. 여기서 읽어야 할 것은 정확한 비율이 아니라 부호 — 무압축 네이티브는 커지고, zstd를 씌우면 다시 작아진다는 방향입니다.
os.features — 하나의 태그로 두 세계를 서빙하기
위 index가 왜 우아한지 보겠습니다. 클라이언트가 EROFS를 못 쓰면 평범한 tar+gzip 매니페스트를 고르고, 쓸 수 있으면 EROFS 매니페스트를 고릅니다. 같은 태그, 같은 pull 명령입니다. ctr i pull --platform="linux(+erofs)" docker.io/hsiangkao/ubuntu:22.04-platforms 같은 문법이 PR 설명에 나옵니다.
그런데 os.features가 원래 이 용도였을까요? OCI image-spec의 image-index 문서를 읽어 보면 이렇게 정의돼 있습니다 — 이 OPTIONAL 속성은 필수 OS 기능의 문자열 배열이고, os가 windows일 때 구현체는 win32k 값을 이해해야 한다. 그리고 결정적인 한 줄이 이어집니다.
os가windows가 아닐 때, 값은 구현체 정의(implementation-defined)이며 표준화를 위해 이 명세에 제출되어야 한다(SHOULD).
즉 리눅스에서의 os.features는 스펙이 "각자 알아서 쓰되 표준화하러 오라"고 열어 둔 문이고, containerd는 그 문으로 들어간 겁니다. 아직 제출은 되지 않았습니다.
한 가지 오해하기 쉬운 부분 — os.features 지원은 자동 스위치가 아닙니다. PR #13091의 설명이 스스로 못 박습니다.
사용자는 EROFS 네이티브 이미지를 실행하려면 여전히 EROFS snapshotter를 명시적으로 지정해야 하며, 이는 설계상 그렇다. 이건 언팩 과정의 사용자 경험을 개선할 뿐이다.
기본 snapshotter로 돌리다가 EROFS 이미지를 만나면 overlayfs가 뱉는 알 수 없는 추출 에러 대신 명확한 에러를 보게 되는 것 — 개선의 실체는 딱 그만큼입니다.
+zstd — 압축은 되찾았지만 언팩 회피는 절반
무압축 네이티브 레이어의 53퍼센트 페널티는 아프고, 그래서 나온 게 +zstd입니다. 발상은 #12506 RFC에 잘 정리돼 있습니다 — 파일시스템 자체는 무압축으로 두고(런타임 읽기가 빠르도록), 전송할 때만 zstd로 감싸자(풀이 빠르도록).
그런데 2.3.0에 실제로 들어간 코드를 보면, +zstd 경로는 fastcopy 분기를 타지 않습니다. 표준 zstd 프로세서 체인을 통과한 뒤 layer.erofs로 복사됩니다.
processor := diff.NewProcessorChain(diffLayerType, content.NewReader(ra))
...
if native {
f, err := os.Create(layerBlobPath)
_, err = io.Copy(f, rc)
...
}
정리하면 이렇습니다.
- 여전히
mkfs.erofs는 안 돕니다 — tar 파싱과 파일별 생성은 없습니다. - 하지만 전체 스트림 압축 해제 패스가 돌아왔습니다. 27MB를 받아 43MB로 풀어서 디스크에 씁니다.
즉 +zstd는 무압축 네이티브와 tar+gzip 사이 어딘가입니다. 참고로 differ는 +zstd만 받고 다른 접미사는 거부합니다(unsupported erofs layer suffix). +gzip은 아예 고려 대상이 아닌데, PR #13185의 설명에 따르면 zstd에 skippable frame이 있기 때문입니다. 이 대목이 다음 절로 이어집니다.
지연 로딩은 아직 없습니다
여기가 이 글에서 가장 중요한 부분입니다.
#12703은 EROFS 레이어 포맷을 문서화하려는 제안서입니다. 첫 절의 동기 목록 맨 위에 이렇게 적혀 있습니다 — "런타임 랜덤 액세스(지연 로딩): 컨테이너는 이미지 전체가 내려오거나 풀리길 기다리지 않고 즉시 시작할 수 있고, 데이터는 온디맨드로 가져온다."
설계도 구체적입니다. zstd skippable frame(매직 0x184D2A5E) 안에 Chunk Mapping Table을 넣어, 표준 zstd 디코더는 그냥 건너뛰고 아는 리더만 비압축 오프셋을 압축 범위로 매핑해 특정 청크를 집어 오는 구조입니다. 헤더에 매직/버전/전체 크기/청크 크기(예: 4MiB)/해시 알고리즘이 들어가고, 청크마다 blob 내 절대 오프셋과 선택적 체크섬이 붙습니다. 필요한 메타데이터는 OCI 매니페스트 애노테이션으로 전달합니다 — dev.containerd.erofs.zstd.chunk_table_offset, dev.containerd.erofs.zstd.chunk_digest, dev.containerd.erofs.dmverity.root_digest 등.
문제는, 이 제안서가 2025-12-18에 열린 뒤 아직 머지되지 않았다는 것입니다. 본인 설명 첫 줄이 "This is a draft proposal, I'm opening as PR rather than issue to make it easier to comment"입니다.
구현 쪽은 더 결정적입니다. #12764 "Seekable-erofs"가 2026-01-09에 열려 2026-04-13에 마지막으로 갱신됐고, 지금도 머지되지 않았습니다. PR 본문에 구현 목록과 미구현 목록이 나란히 있는데, 미구현 쪽이 이렇습니다.
Does NOT implement:
- lazy-loading: the chunk table is written but not consumed
- dm-verity usage: the dm-verity data is decoded but yet not used in the differ / at mount time
청크 테이블을 쓰기는 하지만 읽지는 않습니다. 즉 2026년 7월 현재 containerd의 EROFS 경로에 지연 로딩은 없습니다. 제안서의 헤드라인 문구와 실제로 배에 실린 것 사이의 거리가 이만큼입니다.
그러니 containerd 2.3의 EROFS 네이티브 레이어를 한 줄로 요약하면 이렇습니다 — "게으르게 받기"가 아니라 "풀지 않기"입니다. 이미지 전체를 미리 받는다는 사실은 그대로고, 사라진 건 언팩입니다. 나쁜 게 아닙니다. 다만 다른 문제를 푸는 것이고, "이미지 풀이 빨라진다"는 기대를 갖고 켜면 어긋납니다.
dm-verity — 조용히 더 흥미로운 쪽
지연 로딩 이야기에 묻히지만, 2.3에서 실제로 완성돼 들어간 건 무결성 쪽입니다.
EROFS snapshotter는 이제 세 가지 무결성 수단을 제공합니다.
set_immutable— 레이어 blob에IMMUTABLE_FL을 걸어 삭제/개명/수정을 막고 dirty 데이터를 즉시 flush합니다. 하드웨어 결함으로 인한 데이터 손상은 못 잡습니다. 대가가 있는데, containerd 문서가 자체 측정치를 적어 뒀습니다 — EXT4에서tensorflow:2.19.0의 언팩 시간이 10.090초에서 21.074초로 108.86퍼센트 늘어남. 프로젝트 자체 측정이고 조건은 그 이미지, 그 파일시스템뿐이며, 런타임 성능에는 영향이 없다고 명시합니다.enable_fsverity— commit 시점에 fs-verity를 켜고 마운트 전에 상태를 검증합니다. 문서가 솔직히 적어 뒀듯, 컨테이너의 모든 이미지 읽기가 머클 해시 트리를 먼저 검증해야 하므로 런타임 오버헤드가 붙습니다.dmverity_mode— #12502로 들어온 신참. 레이어마다 dm-verity 디바이스를 만들어 read-only로 마운트합니다.
dm-verity 구현이 꽤 깔끔합니다. veritysetup CLI를 부르는 대신 containerd/go-dmverity 라이브러리로 머클 트리를 직접 만들고, 트리를 blob 안에 인라인으로 붙인 뒤 루트 해시와 오프셋만 layer.erofs.dmverity JSON에 따로 둡니다. 나머지 파라미터는 blob 안 슈퍼블록에 있어 마운트 때 자동 감지됩니다. 블록 크기는 일반 모드 4096바이트, tar-index 모드 512바이트(dm-verity의 logical_block_size 제약).
모드는 셋입니다. auto(기본, .dmverity 메타데이터가 있으면 쓰고 없으면 일반 EROFS로 마운트), on(전 레이어 강제, 없으면 실패), off(완전 비활성).
여기 함정이 있습니다. 문서가 경고를 굵게 달아 뒀는데, 이미 dm-verity 없이 언팩된 레이어가 있는 상태에서 dmverity_mode = "on"을 켜면 그 레이어들엔 .dmverity 파일이 없어 마운트가 실패합니다. 스냅샷을 정리하고 differ의 enable_dmverity = true와 함께 다시 pull해야 합니다. 기존 노드에 롤아웃할 생각이라면 이건 그냥 함정이 아니라 계획해야 할 마이그레이션입니다.
제안서 #12703은 여기서 한 발 더 나갑니다 — dm-verity 데이터가 있으면 그 루트 해시를 레이어 DiffID로 써야 한다는 것. 커널이 블록 단위로 검증하는 값과 이미지 config가 가리키는 값이 같아진다는 뜻인데, 아직 제안서입니다.
값을 치러야 하는 것들
켜기 전에 알아야 할 것들을 모아 두겠습니다. 대부분 containerd의 EROFS snapshotter 문서에 있습니다.
커널. EROFS 모듈이 필요하고 Linux 5.4 이상입니다(modprobe erofs). 다만 진짜 원하는 건 file-backed mount인데, 그건 Linux 6.12 이상입니다. 그 아래에서는 loop 디바이스를 거치게 됩니다. dm-verity를 쓰려면 CONFIG_DM_VERITY와 device-mapper 모듈이 추가로 필요합니다.
외부 바이너리. 네이티브 레이어가 아닌 평범한 이미지를 EROFS로 변환하려면 mkfs.erofs가 있어야 합니다. 문서 기준 erofs-utils 1.7 이상, 재현 가능 빌드용 -T0 --mkfs-time은 1.8 이상, 불필요한 tar 재정렬을 피하는 --sort=none은 1.8.2 이상. 즉 containerd 바이너리 하나로 끝나지 않고 노드 이미지에 패키지 의존성이 하나 늘어납니다.
명시적 지정. EROFS snapshotter는 기본값이 아닙니다. --snapshotter erofs를 주거나 설정에서 지정해야 하고, differ 우선순위도 손대야 합니다(default = ["erofs","walking"]).
메인테이너 본인의 라벨. containerd의 EROFS 트래킹 이슈 #11340은 네이티브 blob 관련 PR들을 이렇게 묶어 놨습니다 — "Native EROFS blob support in content store and image (experimental)". 실험적이라는 건 제 평가가 아니라 프로젝트의 표기입니다. 같은 목록에서 go-erofs 네이티브 라이브러리 통합은 아직 미완입니다.
생태계. 이게 아마 가장 큰 벽입니다. 지금 레지스트리에 있는 EROFS 네이티브 이미지는 사실상 프로젝트 관계자가 올린 테스트 아티팩트입니다. 표준 빌드 파이프라인이 EROFS 레이어를 뱉지 않고, 주요 레지스트리·스캐너·서명 도구가 이 벤더 media type을 이해한다는 보장도 없습니다. 이미지 빌드 파이프라인 전반은 Docker BuildKit과 OCI 이미지 레이어 편에서 다뤘는데, 그쪽 세계는 아직 tar입니다.
벤치마크는 확인 못 했습니다. containerd 문서에 Top25 이미지와 대형 AI 이미지 언팩 벤치마크가 실려 있지만, 숫자가 PNG 이미지 안에만 있고 텍스트로는 없습니다. 게다가 조건이 문서에 적혀 있듯 containerd 2.2.1, 로컬 레지스트리, 병렬 언팩 없음입니다. 확인할 수 없는 숫자는 인용하지 않겠습니다. 웹 검색 스니펫에서 "WordPress 이미지 14퍼센트 개선" 같은 값이 돌아다니는데, 원문 문서를 받아 grep해 보면 그런 문장은 없습니다.
표준은 어디에 있나
한 발 물러서서 보면 이 이야기의 진짜 주제는 EROFS가 아니라 OCI 표준화의 속도입니다.
containerd가 쓴 media type은 application/vnd.erofs.layer.v1입니다. org.opencontainers.*가 아닙니다. 애노테이션도 dev.containerd.*이고, 제안서 #12703이 각주로 이렇게 적어 뒀습니다 — "Future Goal: 채택이 넓어지면 dev.containerd.* 애노테이션을 표준화된 네임스페이스(예: org.opencontainers.*)로 전환한다."
그럼 OCI 쪽 문은 어떤 상태일까요. image-spec 저장소의 관련 이슈들을 날짜와 함께 늘어놓으면 그림이 선명합니다.
| 이슈 | 열린 날 | 상태 |
|---|---|---|
| #815 eStargz 명세 추가 (지연 풀 지원) | 2020-12-09 | open, 마지막 갱신 2021-10-21, 댓글 2개 |
| #936 압축 tar를 랜덤 액세스 포맷으로 대체 | 2022-08-15 | open |
| #1191 erofs/squashfs 레이어 media type 추가 | 2024-05-29 | open, 댓글 18개 |
지연 풀을 스펙에 넣자는 제안이 2020년 12월에 열려서 2021년 10월 이후 5년 가까이 손이 안 닿았습니다. EROFS 레이어 타입 이슈는 2년 넘게 열려 있습니다. #1191의 문제 정의는 지금 읽어도 그대로 유효한데 — 큰 아티팩트는 (1) 내려받는 데 너무 오래 걸리고 (2) 푸는 데 너무 오래 걸린다, 그리고 이 이슈는 (2)를 다루기 시작한다 — 그 "시작"이 2년째입니다.
그래서 containerd는 기다리지 않고 벤더 타입으로 먼저 쏜 겁니다. 이건 비난이 아니라 관찰입니다. 실제로 굴러가는 구현이 있어야 표준화 논의에 살이 붙는 것도 사실이니까요. 다만 이걸 쓴다는 건 표준이 아닌 것에 의존한다는 뜻이고, 표준화 과정에서 media type이나 애노테이션 이름이 바뀔 수 있다는 뜻이기도 합니다. 제안서 스스로 그 가능성을 적어 놨습니다.
그래서, 지금 켜야 하나
켜 볼 만한 경우
- 노드에서 언팩이 실제 병목임이 측정으로 확인된 경우. 수 GB짜리 AI 이미지에서 파일 수가 많고 CPU/IO가 언팩에 갈려 나가는 상황이라면, 2.1부터 있던 EROFS snapshotter + differ만으로도(네이티브 레이어 없이) 얻을 게 있습니다.
mkfs.erofs로 blob을 찍어 내는 게 파일별 추출보다 유리하고, GC도 파일 수만 개 삭제가 아니라 blob 하나 삭제입니다. - VM 기반 런타임을 쓰는 경우. containerd 문서가 이 용도를 명시적으로 듭니다 — Kata 같은 VM 컨테이너에서 이미지 레이어를 virtiofs나 9p 대신 EROFS로 패스스루하면 성능과 메모리 풋프린트가 낫고, gVisor도 EROFS를 지원합니다.
- 블록 단위 무결성이 요구사항인 경우. dm-verity나 fs-verity를 레이어마다 강제해야 하는 규제 환경이라면, 이건 overlayfs snapshotter로는 잘 안 되는 일입니다. 문서가 이유를 설명하는데,
FS_IMMUTABLE_FL과 fs-verity는 서브트리가 아니라 개별 파일을 보호하는 수단이라 파일이 수만 개인 overlayfs 레이어엔 효율이 안 나옵니다. EROFS는 레이어가 파일 하나라 자연스럽게 맞습니다. - 쓰기 레이어에 디스크 쿼터를 걸어야 하는 경우.
default_size로 고정 크기 블록 디바이스를 overlayfs upper로 줄 수 있습니다.
아직 아닌 경우
- 문제가 언팩이 아니라 다운로드인 경우. EROFS 네이티브 레이어는 여기에 도움이 안 되고, 무압축이면 오히려 해롭습니다. 지연 로딩이 필요하면 eStargz/SOCI/Nydus 쪽을 보거나, 그냥 병렬로 빨리 받는 쪽을 보십시오.
- 네이티브 EROFS 레이어를 배포하고 싶은 경우. 빌드 파이프라인이 없고, media type이 표준이 아니며, 레지스트리 주변 도구들이 이해한다는 보장이 없습니다.
- 노드 커널이 6.12 미만이거나 노드 이미지에 erofs-utils를 넣기 곤란한 경우.
- experimental 딱지가 부담스러운 경우. 프로덕션에서 이 라벨의 의미는 "설정 표면과 온디스크 포맷이 마이너 릴리스에서 바뀔 수 있다"입니다.
한 가지 덧붙이면, EROFS snapshotter를 켜는 것과 EROFS 네이티브 레이어를 받는 것은 별개입니다. 앞의 것은 2.1부터 있었고 오늘 당장 평가해 볼 만합니다. 뒤의 것이 2.3의 새 이야기이고, 아직 실험적입니다. 이 둘을 섞어서 판단하면 안 됩니다. containerd의 이미지 처리 전반이 궁금하다면 containerd 이미지 관리 편도 참고하십시오.
마치며
정리하면 이렇습니다. containerd 2.3(2026-04-30, 첫 연간 LTS)은 application/vnd.erofs.layer.v1과 +zstd media type을 추가해, 레지스트리에서 EROFS 파일시스템 이미지를 그대로 받아 마운트하는 경로를 열었습니다. 압축 없는 네이티브 레이어의 언팩은 코드상 blob 복사 한 번으로 끝나고, os.features로 한 태그가 EROFS 클라이언트와 평범한 클라이언트를 동시에 서빙할 수 있으며, dm-verity로 레이어마다 블록 단위 무결성을 걸 수 있습니다.
대신 지연 로딩은 없습니다 — 청크 테이블 설계는 제안서에 있고, 구현 PR은 열려 있고, 그 PR이 스스로 "테이블은 쓰지만 소비하지 않는다"고 적어 뒀습니다. media type은 벤더 타입이고, OCI 쪽 문은 2년 넘게 열려만 있습니다. 무압축이면 와이어 바이트를 더 쓰고, zstd로 되찾으면 압축 해제 패스가 돌아옵니다. 커널 6.12와 erofs-utils가 필요하고, 메인테이너가 experimental로 표시해 뒀습니다.
이 글에서 하나만 가져간다면 이것이었으면 합니다 — 컨테이너 이미지 최적화 이야기에서 "빠르다"는 말이 나오면, 다운로드가 빠른 건지 언팩이 빠른 건지부터 물으십시오. 지난 5년간 이 바닥의 화제는 대부분 전자였고, containerd 2.3이 실제로 배에 실은 건 후자입니다. 당신 노드에서 어느 쪽이 아픈지는 릴리스 노트가 아니라 프로파일이 답합니다.
참고 자료
- containerd 2.3.0 릴리스 노트 — EROFS 네이티브 이미지, 첫 연간 LTS
- containerd EROFS snapshotter 문서 (v2.3.0)
- PR #12567 — Add EROFS layer media type
- PR #13185 — erofs-differ: support zstd-wrapped EROFS layers
- PR #13091 — Add os.features support for EROFS native container images
- PR #12502 — Add dmverity support to the erofs snapshotter using go-dmverity
- PR #12703 — EROFS 레이어 포맷 제안서 (draft, 미머지)
- PR #12764 — Seekable-erofs (미머지, 지연 로딩 미구현)
- Issue #11340 — EROFS Support and Improvements 트래킹
- OCI image-spec — image-index.md의 os.features 정의
- OCI image-spec Issue #1191 — erofs/squashfs 레이어 media type
- OCI image-spec Issue #815 — eStargz 지연 풀 명세
- containerd 릴리스 정책 — LTS와 지원 기간
- endoflife.date — containerd 릴리스/EOL 표
- EROFS 파일시스템 공식 문서
- 컨테이너 런타임 비교 — containerd, runc, Kata, gVisor (관련 글)
현재 단락 (1/136)
컨테이너 이미지 풀이 느리다고 할 때, 사실 두 개의 다른 문제가 한 단어에 뭉쳐 있습니다.