IT/컨테이너 19

Docker BuildKit 캐시 마운트, CI에서 이렇게 쓰면 빌드가 확 빨라진다

CI에서 이미지 빌드가 답답할 때가 있다. Dockerfile에 COPY . . 한 줄 아래에 npm ci나 pip install을 넣어놨는데, 소스 하나만 바뀌어도 매번 의존성을 처음부터 다시 받는다. 결국 5분씩 걸리던 빌드가 CI 러너 열댓 대에서 동시에 돌면서 팀 전체 개발 흐름을 갉아먹는다. 이 글은 BuildKit의 --mount=type=cache를 CI 파이프라인에 어떻게 붙이는지, 그리고 ephemeral 러너 환경에서 캐시를 어떻게 살려두는지 정리한 가이드다. 실제로 우리 팀에서 프론트/백엔드 이미지 30여 개에 이걸 굴려보고 정리한 내용이다.왜 layer cache만으로는 부족한가BuildKit 없이도 Docker는 layer cache를 쓴다. RUN npm ci 라인이 바뀌지 않으..

IT/컨테이너 2026.08.06

containerd snapshotter 내부 - overlay2에서 stargz로 넘어갈 때 실제로 무슨 일이 벌어지나

컨테이너 이미지를 pull하고 시작할 때, 표면적으로는 그냥 kubectl apply 한 방이면 끝나는 것처럼 보인다. 근데 사실 그 아래에서는 containerd가 snapshotter라는 놈을 통해 파일시스템 레이어를 조립하고 마운트하는 꽤 정교한 과정이 돌아간다. 대부분은 overlay2를 그냥 쓰고 지나가지만, 몇 달 전부터 우리 팀에서 콜드스타트 지연을 잡느라 stargz-snapshotter를 검토하면서, 이 계층이 실제로 뭘 하고 있는지 다시 파헤쳐볼 일이 생겼다.지난 2월에 stargz 관련 lazy pulling이 다시 주목받으면서 관련 글이 여럿 올라왔는데, 대부분 "빠르다"에서 멈춰 있다. 사실 내부적으로 뭐가 바뀌는지 짚어봐야 언제 써야 하는지 판단할 수 있다. 그래서 이번 글에서는..

IT/컨테이너 2026.07.31

컨테이너 이미지 lazy pulling, 사실 내부적으로는 이렇게 돌아간다 - SOCI 뜯어보기

요즘 팀 슬랙에 EKS 노드 스케일 아웃 후 파드가 Running까지 도달하는 데 걸리는 시간 얘기가 자주 올라온다. GPU 노드에 20GB짜리 추론 이미지를 올려야 하는데, 이미지 pull에만 3분 넘게 걸린다. 트래픽 스파이크가 오고 나서야 노드가 뜨기 시작하면 사실상 늦다.이 문제 해결책으로 몇 년 전부터 계속 언급되는 게 lazy pulling이다. 이미지 전체를 미리 받지 않고, 컨테이너가 실제로 파일을 요청할 때만 해당 range를 원격 registry에서 가져다가 마운트해주는 방식. 개념은 단순한데 내부 동작이 꽤 재밌어서 이번에 SOCI(Seekable OCI) snapshotter 코드를 좀 뜯어봤다. 정리해둔다.OCI 이미지가 어떻게 생겨먹었길래 lazy pulling이 되는가우선 왜 ..

IT/컨테이너 2026.07.25

컨테이너 메모리 제한, 내부적으로는 뭘 어떻게 하는 걸까

resources.limits.memory: 512Mi 한 줄. 이게 사실 얼마나 복잡한 일을 시키는 건지, 최근에 팀 내부에서 OOM 관련 장애를 하나 겪고 나서야 제대로 파봤다. 대충 "커널이 알아서 죽여준다" 수준으로만 알고 있었는데, cgroup v2로 넘어오면서 동작이 꽤 달라졌다는 걸 그제서야 알았다.이 글은 그때 정리한 노트에 가깝다. Kubernetes에서 메모리 limit이 실제로 커널까지 내려가서 어떤 파일에 어떤 값이 쓰이고, OOM이 터질 때 어떤 순서로 뭐가 일어나는지 — 이게 왜 최근 몇 년 사이 근본적으로 바뀌었는지 순서대로 짚어본다.메모리 limit이 커널로 내려가는 경로파드 매니페스트에 limits.memory: 512Mi를 적었다고 하자. 이 값은 kubelet → CRI..

IT/컨테이너 2026.07.22

BuildKit cache mount 하나 잘못 붙였다가 CI가 두 배 느려진 이야기

지난 주 화요일 아침에 백엔드 팀장이 슬랙 DM으로 물어봤다. "요즘 CI가 왜 이렇게 느려요? 예전에는 8분이면 됐는데 요새는 20분 넘게 걸리는 것 같은데." 확인해보니 정말 그랬다. Go 서비스 하나의 build job이 12분에서 19분으로 늘어나 있었다. 뭐 변경한 것도 없는데.내가 저 CI를 마지막으로 만진 게 6월 초였다. --mount=type=cache를 붙여서 Go module 다운로드를 캐싱하도록 바꿨다. 그때는 확실히 빨라졌다. 첫 빌드가 14분, 두 번째부터는 5분대. 팀 슬랙에 자랑까지 했다. 그런데 한 달 반이 지난 지금은 20분이 나오고 있었다.처음엔 러너 탓인 줄 알았다첫 번째 추측은 GitHub Actions runner가 지역별로 느려졌나 하는 것이었다. 요새 self-..

IT/컨테이너 2026.07.14

distroless 파드 디버깅, kubectl debug --profile 만 알면 된다

이거 모르는 분 꽤 많더라. 어제 팀원이 "distroless 이미지로 바꿨더니 이제 파드 안 들여다볼 수가 없어요"라고 물어봐서, 그 자리에서 알려준 팁. 사실 별 것도 아닌데 정리해두면 다음에 또 물어보는 사람 나오니까.상황distroless 베이스로 만든 컨테이너는 셸도 없고 cat도 없다. 그러니 kubectl exec -it pod -- sh 는 당연히 안 먹힌다. 예전에는 어쩔 수 없이 debug용 이미지 하나 더 만들거나, 파드를 아예 복제해서 이미지만 갈아끼우거나 했었다. 근데 Kubernetes 1.25부터 ephemeral container가 stable 됐고, kubectl debug 로 훨씬 편해졌다.문제는 그냥 kubectl debug pod/foo -it --image=busyb..

IT/컨테이너 2026.07.06

Docker BuildKit 캐시, 사실 내부적으로는 이렇게 돌아간다

BuildKit을 쓰기 시작한 지 꽤 됐다. DOCKER_BUILDKIT=1 넣는 건 이제 반사적으로 나온다. 그런데 얼마 전 팀 내부에서 "왜 RUN apt-get install이 캐시된 건 알겠는데, --mount=type=cache를 걸었을 때 도대체 뭐가 저장되고 뭐가 재사용되는 거냐"는 질문을 받고 답을 얼버무렸다. 그날 저녁에 소스와 문서를 뒤져가며 정리한 내용을 여기 남긴다.이 글은 실행 가이드는 아니다. BuildKit이 캐시를 어떻게 표현하고, 어디에 저장하고, 어떤 기준으로 재사용을 판단하는지 흐름을 따라간다. docker buildx build --cache-to=type=registry 를 쳤을 때 그 뒤에서 일어나는 일이 궁금한 사람이 대상이다.LLB — 캐시의 진짜 단위먼저 알아..

IT/컨테이너 2026.07.04

Docker BuildKit cache mount, 이거 모르면 CI에서 매번 손해 본다

이거 모르는 분 꽤 많더라. RUN --mount=type=cache 한 줄로 npm/pip install 시간을 절반 이하로 줄일 수 있다. 그런데 실무에서 제대로 세팅한 걸 보기는 의외로 드물다.뭐가 문제냐기본 Dockerfile로 이미지 빌드하면, COPY package*.json ./ 다음에 RUN npm ci 하는 패턴을 쓸 거다. 여기서 lock 파일이 바뀌면 그 아래 레이어 캐시가 전부 무효화되고, npm ci가 처음부터 다시 돈다. 패키지 하나 추가했을 뿐인데 400개 다운로드를 다시 하는 셈이다.우리 팀은 프론트 모노레포에 workspace 20개가 물려 있는데, 어떤 워크스페이스 하나만 라이브러리 하나 올려도 CI 이미지 빌드가 3분 넘게 걸렸다. 노드 하나 이슈면 그러려니 하는데 매번..

IT/컨테이너 2026.07.01

Dockerfile COPY --link, 다들 쓴다는데 진짜 좋을까

COPY --link 얘기는 한 2년 전부터 컨퍼런스마다 단골 메뉴였다. "그냥 다 붙여라, 캐시 효율이 미친다"는 식의 글도 많고. 우리 팀도 어느 순간부터 거의 자동 반사처럼 모든 COPY 앞에 --link를 박아 넣고 있었다. 근데 최근에 좀 다른 얘기가 돌더라.올해 2월에 Depot 블로그에서 "왜 COPY --link 쓰지 말아야 하는지"라는 글이 올라와서 한 번 더 시끌시끌했다. 한 줄로 요약하면 "BuildKit이 --link 레이어를 다루는 방식 때문에 오히려 빌드가 느려지는 케이스가 꽤 있다"는 거. 우리 팀에서도 비슷한 케이스를 한 번 만난 적이 있어서 정리해둔다.--link가 손해 보는 케이스가장 흔한 패턴이 이거다.FROM node:20-alpine AS buildWORKDIR /a..

IT/컨테이너 2026.06.28

containerd config_path, 이거 모르는 분 꽤 많더라

오늘 알게 된 건데, 아직도 노드마다 /etc/containerd/config.toml 안에 레지스트리별 auth를 박아두고 운영하는 팀이 생각보다 많다. 우리 팀도 작년까지 그랬다. 사내 Harbor, ECR, GHCR, Docker Hub 미러까지 네 개를 한 파일에 우겨넣다 보니 누가 한 줄만 잘못 건드려도 컨테이너런타임 재시작이 필요했다.근데 containerd 1.5에서 추가되고 1.7 이후로는 사실상 표준이 된 config_path 방식 쓰면 이 짓을 안 해도 된다. 노드 재시작 없이, hot reload로 레지스트리 설정만 바꿀 수 있다.핵심은 디렉터리 구조/etc/containerd/config.toml에는 딱 한 줄만 둔다.[plugins."io.containerd.grpc.v1.cri"..

IT/컨테이너 2026.06.21