간단한 웹 서비스 돌리려고 로컬에서 도커 이미지 빌드해봤는데, 왜 이렇게 느린 건지 신기하다 싶어서요.
Dockerfile 자체는 되게 단순한 편인데, 막상 돌려보면 뭔가 병목 지점이 있는 느낌이랄까.
혹시 다들 경험적으로 느낀 건지, 로컬 환경에서 빌드 시간이 길어지는 이유가 있을까요?
단순히 내 컴퓨터 사양 문제인지, 아니면 뭔가 놓치고 있는 건지 궁금합니다.
와, 저도 그거 정말 체감했어요.
처음 도커 쓰기 시작할 때 다들 '이게 왜 이렇게 오래 걸리지?' 하는 거 저만 그런 거 아니죠?
질문자님 말씀대로 Dockerfile 자체는 간단한데 빌드가 느리게 느껴질 때가 많거든요.
단순히 사양 문제일 수도 있지만, 몇 가지 구조적인 이유들이 있어서요.
제가 겪어본 경험이랑 아는 선에서 최대한 자세히 정리해 드릴게요.
혹시 이거 보시고 '아, 이거였구나' 하는 거 있으면 좋겠습니다.
일단 결론부터 말씀드리자면, '병목 지점'은 보통 '이미지 레이어 캐싱'의 효율성 문제나, '로컬 환경 자체의 제약'에서 오는 경우가 많아요.
--- ###
1.
로컬 환경 자체의 제약과 오해 가장 먼저 생각해야 할 건, 로컬 PC의 자원 할당 문제예요.
도커가 아무리 최적화되어 있어도, 결국 돌리는 건 우리 컴퓨터잖아요.
① CPU와 메모리 부족 (가장 기본) * 만약 빌드하는 서비스가 백그라운드에서 무거운 컴파일 과정(예: 거대한 라이브러리 컴파일, 많은 패키지 설치)을 거친다면, 로컬 CPU 코어 수나 RAM 용량이 부족할 때 빌드가 극도로 느려집니다.
RUN apt-get update && apt-get install ... 같은 명령어로 외부 패키지를 많이 다운로드하거나, FROM으로 베이스 이미지를 가져올 때(예: FROM node:lts-alpine) 시간이 오래 걸린다면, 그건 전적으로 네트워크 속도와 Docker Hub 같은 레지스트리와의 통신 속도 문제입니다.RUN npm install 명령어를 실행했는데, 그 전에 COPY . . 같은 명령어로 소스 코드를 건드리는 부분이 있다면, 소스 코드가 변경될 때마다 그 이전의 모든 레이어 캐시가 무효화되고, npm install부터 처음부터 다시 돌게 됩니다.
실무 팁): package.json이나 package-lock.json 같은 의존성 파일만 먼저 복사해서 설치하는 게 핵심이에요.의존성 파일만 먼저 복사하여 레이어 캐시를 최대한 활용 WORKDIR /app COPY package*.json ./ RUN npm install # 여기서 의존성 설치가 이루어짐 (이 레이어는 파일이 바뀌지 않으면 재실행 안 함) # 2.
이제 소스 코드만 복사 COPY .
.
# 3.
필요한 경우에만 빌드 실행 RUN npm run build ``` 이렇게 하면 소스 코드(예: `src/` 폴더의 파일)만 수정했을 때는, `npm install` 단계는 건너뛰고 `COPY` 이후의 레이어만 다시 돌기 때문에 속도가 엄청나게 빨라집니다.
**② `RUN` 명령어의 분리 및 최적화** * 한 개의 `RUN` 명령어 안에 너무 많은 작업을 묶으면(예: `RUN apt-get update && apt-get install -y package1 package2 && rm -rf /var/lib/apt/lists/*`), 여러 단계를 거치는 것보다 빠르긴 하지만, 디버깅이나 나중에 특정 패키지만 재설치할 때 문제가 될 수 있어요.
* **권장:** 최대한 작업 단위를 나누되, 그 범위가 너무 작으면 오히려 오버헤드가 생길 수 있습니다.
보통은 **'패키지 설치' 덩어리**와 **'코드 컴파일' 덩어리**로 나누는 게 가장 직관적이고 효율적입니다.
* **청소 필수:** 패키지 설치 후 생성되는 캐시 파일(`apt-get clean`이나 `rm -rf /var/lib/apt/lists/*` 같은 명령어)는 **반드시** 같은 `RUN` 명령어 내에서 처리해주세요.
안 그러면 최종 이미지 크기만 커지고 빌드 과정에서 불필요한 데이터가 남게 됩니다.
**③ 베이스 이미지 선택의 중요성** * `FROM ubuntu:latest` 같은 거대한 운영체제 이미지를 베이스로 쓰면, 그 자체의 용량과 빌드할 때 포함되는 기본 패키지들 때문에 무겁고 느려질 수 있습니다.
* **대안:** 가능하면 `alpine` 버전을 사용하거나, 특정 런타임 환경만 제공하는 이미지를 쓰세요.
* 예: Node.js를 쓰신다면 `node:lts-alpine`을 쓰는 것이 일반 `node:lts`보다 훨씬 작고 가볍습니다.
* Alpine 계열은 리눅스 배포판 자체가 가벼워서 빌드 속도나 최종 이미지 크기 면에서 이득을 많이 봅니다.
--- ### 🛠️ 3.
고급 팁: Multi-Stage Build 사용하기 (필수 학습) 이게 질문자님이 느끼는 '느림'의 체감도를 가장 드라마틱하게 줄여주는 방법 중 하나이자, 가장 중요한 최적화 기법입니다.
**무슨 문제인가요?** 보통 빌드 과정에서는 개발용 의존성 패키지(컴파일러, 테스트 도구 등)가 필요합니다.
하지만 **최종적으로 서비스가 돌아갈 런타임 환경**에는 그 개발용 도구들이 필요 없어요.
만약 모든 도구를 포함해서 최종 이미지를 만들면, 최종 이미지 자체가 엄청나게 커지고, 그 커진 이미지 사이즈 때문에 전송하거나 로드할 때 체감이 느려질 수 있습니다.
**Multi-Stage Build의 원리:** 1.
**Stage 1 (빌더):** 무거운 환경에서 모든 빌드 과정을 수행합니다.
(예: Node.js v18이 설치된 환경에서 모든 라이브러리 설치 및 컴파일) 2.
**Stage 2 (최종):** 아주 가벼운 런타임 환경(예: `alpine` 또는 최소한의 런타임 OS)을 `FROM`으로 지정하고, Stage 1에서 빌드된 **결과물(아티팩트)**만 딱 복사해 옵니다.
**예시 구조 (개념만):** ```dockerfile # --- STAGE 1: 빌드 단계 --- FROM node:lts-buster AS builder # 무거운 빌드 환경 사용 WORKDIR /app COPY package*.json ./ RUN npm install COPY .
.
RUN npm run build # 여기서 모든 컴파일 및 빌드 수행 # --- STAGE 2: 최종 런타임 단계 --- FROM node:lts-alpine AS final # 가볍고 작은 최종 이미지 사용 WORKDIR /app # 빌드된 결과물만 복사해옴 (node_modules나 빌드 파일 같은 거) COPY --from=builder /app/dist ./dist COPY --from=builder /app/node_modules ./node_modules CMD ["node", "dist/server.js"] ``` **이걸 쓰면 뭐가 좋나요?** 1.
**이미지 크기 대폭 감소:** 최종 이미지에 불필요한 빌드 도구들이 남지 않습니다.
2.
**클린함:** 최종 환경이 필요한 최소한의 것만 갖게 되어 예측 가능성이 높아지고, 때로는 부팅/실행 속도 체감에 도움이 됩니다.
--- ### 📝 요약 및 체크리스트 질문자님의 상황에서 빌드 속도를 개선하기 위해 점검해 볼 우선순위는 다음과 같습니다.
1.
**✅ 의존성 설치 최적화:** `package.json` 복사 -> `npm install` -> `소스코드` 복사 순서로 레이어를 분리했는지 확인 (가장 효과 빠름).
2.
**✅ Multi-Stage Build 적용:** 빌드 결과물만 가져오는 방식으로 전환했는지 확인.
3.
**✅ 베이스 이미지 경량화:** 가능한 `alpine`이나 최소한의 런타임 이미지를 사용하고 있는지 확인.
4.
**✅ 캐시 활용 최대화:** 불필요한 `RUN` 명령으로 캐시를 무효화하는 부분이 없는지 코드 전반을 검토.
이 팁들만 적용해도 빌드 시간이 체감상으로 절반 이상 줄어드는 경우가 많으니, 너무 자책하지 마시고 '이건 도커의 작동 원리상 이렇게 하는 게 최적이다'라고 접근해보시면 좋을 것 같습니다.
혹시 어떤 언어(Node.js, Python, Java 등)로 빌드하고 계신지 알려주시면, 해당 언어에 특화된 캐싱 팁을 더 드릴 수 있을 것 같아요!
궁금한 점 있으면 또 물어보세요!
Hello! It looks like you're interested in this conversation, but you don't have an account yet.
Getting fed up of having to scroll through the same posts each visit? When you register for an account, you'll always come back to exactly where you were before, and choose to be notified of new replies (either via email, or push notification). You'll also be able to save bookmarks and upvote posts to show your appreciation to other community members.
With your input, this post could be even better 💗
등록 로그인