I develop web apps using Python/Django for my work and run them as Docker containers. There are about 150 Python libraries to install, so the container images are getting large and taking a long time to upload and download.
I use a multi-stage build (and an AWS ECR image scan) to reduce the container image size. Finally, I test how much I could be reduced the container image size (and vulnerability) for each pattern.
Original dockerfile
FROM python:3.7.13-bullseye
ENV PYTHONUNBUFFERED 1
ENV PIPENV_TIMEOUT 600
# Install git command because some python libraries install directly from GitHub
RUN apt-get -y update && \
apt-get -y upgrade && \
apt-get -y dist-upgrade && \
apt-get -y install gcc git mecab libmecab-dev mecab-ipadic mecab-ipadic-utf8 swig fonts-vlgothic poppler-utils libglib2.0-0 libsm6 libxrender1 libxext6 && \
apt-get autoclean -y && apt-get clean && rm -rf /var/cache/apt/* /var/lib/apt/lists/*
RUN groupadd -r app && useradd --no-log-init -r -g app app
USER app
COPY --chown=app:app . /home/app
WORKDIR /home/app
ENV PATH="/home/app/.local/bin:${PATH}"
RUN pip install --upgrade pip && pip install pipenv
RUN pipenv install --ignore-pipfile --deploy --system
EXPOSE 8000
CMD gunicorn config.wsgi -b 0.0.0.0:8000 --log-level=info
1999.66MB (2 critical + 369 others (details)). The volume is almost 2 GB and includes two critical vulnerabilities.
Use lightweight base images
I use the python:3.7.13-slim-bullseye image, which is lighter than the python:3.7.13-bullseye image. Note that the image with “slim” is the smallest image that excludes infrequently used tools and libraries.
FROM python:3.7.13-slim-bullseye
ENV PYTHONUNBUFFERED 1
ENV PIPENV_TIMEOUT 600
RUN apt-get -y update && \
apt-get -y upgrade && \
apt-get -y dist-upgrade && \
apt-get -y install gcc git mecab libmecab-dev mecab-ipadic mecab-ipadic-utf8 swig fonts-vlgothic poppler-utils libglib2.0-0 libsm6 libxrender1 libxext6 && \
apt-get autoclean -y && apt-get clean && rm -rf /var/cache/apt/* /var/lib/apt/lists/*
RUN groupadd -r app && useradd --no-log-init -r -g app app
USER app
COPY --chown=app:app . /home/app
WORKDIR /home/app
ENV PATH="/home/app/.local/bin:${PATH}"
RUN pip install --upgrade pip && pip install pipenv
RUN pipenv install --ignore-pipfile --deploy --system
EXPOSE 8000
CMD gunicorn config.wsgi -b 0.0.0.0:8000 --log-level=info
1805.31MB (1 critical + 236 others (details)), reducing volume by 200MB and one critical vulnerability.
Use multi-stage build
I create a container image with a multi-stage build, copying the pip-installed libraries into the runtime container image.
FROM python:3.7.13-bullseye as builder
ENV PYTHONUNBUFFERED 1
ENV PIPENV_TIMEOUT 600
RUN apt-get -y update && \
apt-get -y upgrade && \
apt-get -y dist-upgrade && \
apt-get -y install gcc git mecab libmecab-dev mecab-ipadic mecab-ipadic-utf8 swig fonts-vlgothic poppler-utils libglib2.0-0 libsm6 libxrender1 libxext6
COPY Pipfile Pipfile.lock /app/
WORKDIR /app
RUN pip install --upgrade pip && pip install pipenv
RUN pipenv install --ignore-pipfile --deploy --system
FROM python:3.7.13-slim-bullseye as runner
ENV PYTHONUNBUFFERED 1
RUN apt-get -y update && \
apt-get -y upgrade && \
apt-get -y dist-upgrade && \
apt-get -y install mecab libmecab-dev mecab-ipadic mecab-ipadic-utf8 swig fonts-vlgothic poppler-utils libglib2.0-0 libsm6 libxrender1 libxext6 && \
apt-get autoclean -y && apt-get clean && rm -rf /var/cache/apt/* /var/lib/apt/lists/*
RUN groupadd -r app && useradd --no-log-init -r -g app app
USER app
COPY --chown=app:app . /home/app
WORKDIR /home/app
COPY --from=builder /usr/local/lib/python3.7/site-packages /usr/local/lib/python3.7/site-packages
COPY --from=builder /usr/local/bin /usr/local/bin
EXPOSE 8000
CMD gunicorn config.wsgi -b 0.0.0.0:8000 --log-level=info
947.26 MB (1 high + 106 others (details)). The volume is less than 1GB, and the container image has no critical vulnerability.
Do not install unnecessary packages.
Run apt-get with –no-install-recommends. You can suppress the installation of recommended packages by passing the –no-install-recommends option to the apt command.
FROM python:3.7.13-bullseye as builder
ENV PYTHONUNBUFFERED 1
ENV PIPENV_TIMEOUT 600
RUN apt-get -y update && \
apt-get -y upgrade && \
apt-get -y dist-upgrade && \
apt-get -y install gcc git mecab libmecab-dev mecab-ipadic mecab-ipadic-utf8 swig fonts-vlgothic poppler-utils libglib2.0-0 libsm6 libxrender1 libxext6
COPY Pipfile Pipfile.lock /app/
WORKDIR /app
RUN pip install --upgrade pip && pip install pipenv
RUN pipenv install --ignore-pipfile --deploy --system
FROM python:3.7.13-slim-bullseye as runner
ENV PYTHONUNBUFFERED 1
RUN apt-get -y update && \
apt-get -y upgrade && \
apt-get -y dist-upgrade && \
apt-get -y install --no-install-recommends mecab libmecab-dev mecab-ipadic mecab-ipadic-utf8 swig fonts-vlgothic poppler-utils libglib2.0-0 libsm6 libxrender1 libxext6 && \
apt-get autoclean -y && apt-get clean && rm -rf /var/cache/apt/* /var/lib/apt/lists/*
RUN groupadd -r app && useradd --no-log-init -r -g app app
USER app
COPY --chown=app:app . /home/app
WORKDIR /home/app
COPY --from=builder /usr/local/lib/python3.7/site-packages /usr/local/lib/python3.7/site-packages
COPY --from=builder /usr/local/bin /usr/local/bin
EXPOSE 8000
CMD gunicorn config.wsgi -b 0.0.0.0:8000 --log-level=info
927.14 MB (1high + 104 other (details)), and the volume is reduced by another 20MB.
Finally
There may be various other lightweight techniques besides those mentioned above. Still, I think this is the first method you should practice if you want to make container images light because you can reduce half the volume by doing a multi-stage build.
コメント