티스토리 뷰
반응형
1. 생성된 레이어 재사용(캐싱)
기존코드1
문제점
- Docker이미지 빌드시 Dockerfile의 각 명령어를 실행 → 해당 결과들을 새로운 레이어로 저장한다.
- 아래 코드는 소스 코드중 어떤 파일이든 변경되면 COPY ./ ./ 이후의 모든 레이어가 다시 빌드된다
→ 소스의 작은 변경이라도 RUN npm install 가 다시 실행된다.
FROM node:10
WORKDIR /usr/src/app
COPY ./ ./
RUN npm install
CMD ["node","server.js"]
수정코드1
수정된 이유
- package.json 먼저 복사
- package.json에 변경사항이 없다 → RUN npm install 명령어 까지의 모든 레이어 캐싱되어 재사용(npm 재설치 없이 빠르게 빌드 가능)
- package.json에 변경사항이 있다 → RUN npm install 실행
- 이후 코드를 수정한 부분이 있는 COPY ./ ./ 를 복사
FROM node:10
WORKDIR /usr/src/app
COPY package.json ./
RUN npm install
COPY ./ ./
CMD ["node","server.js"]
기존코드2
문제점
- 모든 파일을 한번에 복사한 후 필요한 Python 패키지를 설치하는 방식
FROM python:3.8-slim
COPY . /app
WORKDIR /app
RUN pip install -r requirements.txt
EXPOSE 8080
ENTRYPOINT ["python"]
CMD ["run.py"]
수정코드2
수정된 이유
- WORKDIR /app 의 순서 변경 → 작업 디렉토리를 명확히 하고, 모든 파일 경로와 명령 실행의 기준점을 설정하기 위함
- requirements.txt를 먼저 복사 → 변경이 없을 경우 pip install 단계를 다시 실행하지 않음(기존 레이어 재사용)
- 이후 COPY ./app 명령어로 application의 나머지 부분 복사 → 변경이 없을 경우 기존 레이어 재사용
FROM python:3.8-slim
WORKDIR /app
COPY requirements.txt ./requirements.txt
RUN pip install --no-cache-dir -r requirements.txt
COPY ./app
EXPOSE 8080
#ENTRYPOINT : 컨테이너가 시작될 때 실행할 기본 명령을 설정
#컨테이너가 시작될 때 항상 Python 인터프리터를 사용하여 지정된 파이썬 스크립트(CMD에서 지정된 run.py 같은)를 실행
ENTRYPOINT["python"]
CMD["run.py"]
캐싱
변경이 잦은 파일들은 Dockerfile의 뒤에 COPY하는것이 좋고, 의존성 파일(ex.requirements.txt)은 먼저 복사하는게 좋다.
- Docker이미지 빌드시 Dockerfile의 각 명령어를 실행하면서 해당 명령어의 결과 캐싱
- 만약 특정 명령어까지 변경사항이 없다면 Docker는 그 부분까지 캐싱된 결과(layer)를 재사용함
- 변경사항이 있는 명령어의 경우 이전의 캐시된 레이어를 사용할수 없으므로 그 명령어와 그 이후의 명령어들은 새로 실행되어 결과가 빌드됨
2. Dockerfile 최적화
더 작은 기본 이미지 사용
ex.multi-stage, 완전한 OS(ubuntu)대신 경량 Alpine Linux 이미지를 기본으로 사용
# 변경전
FROM ubuntu:20.04
RUN apt-get update && apt-get install -y python3-pip
...
# 변경후
FROM alpine:3.12
RUN apk add --no-cache python3 py3-pip
...
불필요한 파일 제거
.dockerignore 파일을 사용하여 빌드 컨텍스트에서 파일이나 디렉터리를 제외
# 버전관리 시스템 폴더
.git
.gitignore
.svn
.hg
# 빌드 도구 관련 파일 및 폴더
Dockerfile
Dockerfile.*
*docker-compose.yml
.dockerenv
#종속성 관련 폴더(파이썬)
.pip
.virtualenv
venv
.env
# 로그 파일 및 디렉토리
*.log
logs
# 임시파일 및 캐시파일
*.tmp
*.temp
*.cache
# 개발 도구 설정 파일
.vscode
.idea
*.swp
# 테스트 및 문서파일
tests
docs
doc
README.md
# 빌드 결과물 미 배포파일
dist
build
out
# 운영체제 관련 파일
.DS_Store
Thumbs.db
레이어 수 최소화
문제점 : 각 명령어는 새레이어를 생성함 → 레이어가 많으면 빌드 프로세스 속도 드려짐 → Docker image 크기 늘어남
RUN apt-get update
RUN apt-get install -y package1
RUN apt-get install -y package2
해결점 : RUN 명령을 사용해 여러 주문을 단일 명령어로 결합
RUN apt-get update && \
apt-get install -y package1 && \
apt-get install -y package2
ENV,올바른 CMD 및 ENTRYPOINT 사용
#ENV로 환경 설정 지정
FROM node:14
ENV NODE_ENV=production
#ENTRYPOINT로 Nginx 시작하라고 명령함
ENTRYPOINT ["nginx", "-g", "daemon off;"]
CMD ["-c", "/etc/nginx/nginx.conf"]
3. Multi-Stage Build사용
Multi-stage 코드
- Builder 단계: Builder 단계에서 빌드된 결과물 생성 및 이 중간결과물을 캐시함
- 이미지에 포함되는 파일(O) : 설치된 Python 패키지, application 코드(/app)
- 이미지에 제거되는 파일(X) :
- 소스코드 : 빌드를 위해 필요하지만, 실행파일이 생성되면 필요없음
- 빌드파일 : gradlew,gradle 등 빌드과정을 자동화하는 스크립트,설정파일은 빌드후에는 필요없음
- 중간 생성파일: 컴파일 과정에서 생성되는 클래스,로그 파일등은 필요없음
- Deployer단계 : Builder 단계에서 빌드된 결과물(이미지 레이어)를 가져와서 최종 이미지 구성
- COPY --from=builder 를 통해 Builder 단계에서 필요한 결과물만 가져온다(빌드에 필요한 패키지, 라이브러리, 빌드된 소스 코드 등)
# Builder 단계
FROM python:3.8-alpine AS builder
RUN apk update && apk add --no-cache make && apk add --no-cache libpq-dev g++
WORKDIR /app
COPY requirements* ./
RUN pip install --no-cache-dir -r requirements-prod.txt
COPY Makefile .
COPY src ./src
# Deployer(배포자) 단계
FROM python:3.8-alpine AS deployer
COPY --from=builder /usr/local/lib/python3.8/site-packages /usr/local/lib/python3.8/site-packages
COPY --from=builder /app /app
RUN apk update && apk add --no-cache make
WORKDIR /app
CMD ["make", "run-server"]
질문1. 만약 Builder 단계 혹은 Deployer(배포자) 단계에서 코드 수정이 생긴다면?
- Builder 단계 코드 수정시 : 만약 requirements.txt가 변경시 pip install 를 통해 재설치 및 새로운 중간결과물을 생성한다. 이후 변경된 중간결과물을 Deployer(배포자) 단계에서 재빌드되어 최종 이미지에 반영됨
- Deployer(배포자) 단계 코드 수정시 : 캐시된 Builder 단계의 결과물은 그대로 사용, Deployer(배포자) 단계에서 변경된 사항을 반영하기 위해 변경된 부분의 명령부터 이후의 모든 명령을 다시 실행
질문2. Multi-Stage Build에서 중간결과물을 사용해 특정 레이어의 결과물을 이전 단계(builder 단계)에서 가져와서 현재 이미지로 복사하는데, 일반 Docker 빌드와 레이어시에도 동일한가?
- 일반 Docker빌드시 각 명령어들이 순서대로 실행 → 새로운 레이어가 이전 레이어 위에 순차적으로 쌓임 → 최종 이미지 생성
- 일반 Docker빌드시 각 단계에서 생성된 레이어들을 건너뛰거나,선택적으로 사용하는게 아닌 모든 레이어가 최종 이미지에 포함됨
Multi-Stage Build
- FROM문을 사용해 단계별로 이미지를 구성하고, 마지막 단계에서만 필요한 파일을 가져온다.
- 그 결과, 최종 이미지를 크게 줄이고, 필요한 부분만 포함시킬 수 있다.
참고문서
https://benriemer.medium.com/speed-up-docker-desktop-d676c9fe82de
따라하며 배우는 도커와 CI환경 강의
https://blog.annotation-ai.com/python-docker-img-optimization/
반응형
'DOCKER' 카테고리의 다른 글
[DOCKER] Docker Compose (0) | 2024.01.08 |
---|---|
[Docker] Docker Volume (2) | 2024.01.02 |
[Docker] Docker Container2 - 코드로 보는 개념 (0) | 2023.12.26 |
[Docker] Docker Image (0) | 2023.12.26 |
[Docker] Docker Container1 - 기본 개념 (0) | 2023.12.21 |
댓글