docker image 재사용, multi stage로 속도 개선하기

x·2024년 4월 5일
0

docker

목록 보기
5/5

cache layer를 사용하기 위해 변경이 잦은 부분은 하위로 build stage로 내린다. COPY . .은 모든 파일과 디렉토리를 복사하기 때문에 이 코드가 상위에 있으면 하위의 빌드를 다시하게 된다.
https://stackoverflow.com/questions/76483943/docker-multistage-build-why-not-caching-layer

docker compose -f docker-compose.yaml up -d --build 빌드할 때 속도가 너무 느렸다.

원인

  • 동일한 이미지를 재사용하지 않고 서비스마다 매번 이미지를 빌드한다.
  • pip install할 때 requirements.txt에 변경이 없음에도 매번 모든 패키지를 일일이 설치한다.

해결방법

  • 한번 만들어진 이미지를 다른 서비스에서 재사용한다.
  • multi stage를 적용하고 poetry를 사용해서 패키지 수정, 삭제, 추가가 없으면 캐싱된 이미지를 사용한다.

docker-compose.yaml에서 이미지 재사용

flask, celery, celery-beat 모두 불필요하게 같은 컨텍스트로 이미지 빌드를 하고 있다.

before

version: '3'

services:
    nginx:
        container_name: nginx
        build: 
            context: ./nginx
            dockerfile: dockerfile-dev
        ports:
            - 80:80
        volumes:
            - ./nginx/log:/var/log/nginx

    flask:
        container_name: flask
        image: flask-image
        env_file:
            - ./.env
            - DOCKER_BUILDKIT=1
        build: 
            context: ./flask
            dockerfile: dockerfile-dev
        command: /start.sh
        ports:
            - 5011:5011
        volumes:
            - ./flask:/flask

    celery:
        container_name: celery
        build: 
            context: ./flask
            dockerfile: dockerfile-dev
        env_file:
            - ./.env
        command: /celery_start.sh
        volumes:
            - ./flask:/flask
        depends_on:
            - flask

    celerybeat:
        container_name: celerybeat
        build: 
            context: ./flask
            dockerfile: dockerfile-dev
        env_file:
            - ./.env
        command: /celerybeat_start.sh
        volumes:
            - ./flask:/flask
        depends_on:
            - flask
            - celery

flask-image를 celery와 celery-beat에서 재사용한다.

after

version: '3'

services:
    nginx:
        container_name: nginx
        build: 
            context: ./nginx
            dockerfile: dockerfile-dev
        ports:
            - 80:80
        volumes:
            - ./nginx/log:/var/log/nginx

    flask:
        container_name: flask
        image: flask-image
        env_file:
            - ./.env
            - DOCKER_BUILDKIT=1
        build: 
            context: ./flask
            dockerfile: dockerfile-dev
        command: /start.sh
        ports:
            - 5011:5011
        volumes:
            - ./flask:/flask

    celery:
        container_name: celery
        image: flask-image
        env_file:
            - ./.env
        command: /celery_start.sh
        volumes:
            - ./flask:/flask
        depends_on:
            - flask

    celerybeat:
        container_name: celerybeat
        image: flask-image
        env_file:
            - ./.env
        command: /celerybeat_start.sh
        volumes:
            - ./flask:/flask
        depends_on:
            - flask
            - celery

dockerfile에서 multi-stage 적용, poetry로 패키지 설치

첫 빌드 스테이지인 poetry-base에서 poetry를 설치하고 toml, lock 파일을 복사하고 poetry install로 패키지 설치를 한다.

기존 환경변수 경로들인 $PATH에 poetry 경로도 추가해줌
ENV PATH="$PATH:$POETRY_HOME/bin"

가상환경을 생성하지 않은 이유, 도커 컨테이너는 이미 독립되어 있기 때문.
POETRY_VIRTUALENVS_CREATE=false

# syntax=docker/dockerfile:1.3

FROM --platform=linux/amd64 python:3.9.2-slim-buster AS poetry-base

ENV POETRY_NO_INTERACTION=1 \
	POETRY_VIRTUALENVS_CREATE=false \
	POETRY_HOME="/opt/poetry" \
	POETRY_VERSION=1.4.2 
ENV PATH="$PATH:$POETRY_HOME/bin"

RUN	apt-get update && apt-get install curl -yqq 
RUN	curl -sSL https://install.python-poetry.org | python3 - --version 1.4.2

WORKDIR /flask

COPY pyproject.toml pyproject.toml
COPY poetry.lock poetry.lock
RUN	poetry install --no-interaction --no-ansi --no-root 

FROM poetry-base AS setting

ENV PYTHONUNBUFFERED 1
ENV PYTHONDONTWRITEBYTECODE 1

WORKDIR /flask

COPY . .

COPY ./entrypoint.sh /entrypoint.sh

RUN chmod +x /entrypoint.sh 

FROM setting AS app

ENTRYPOINT ["/entrypoint.sh"]

0개의 댓글