Dmitry Figol
Systems Engineer, Cisco Systems
@dmfigol
FROM debian:stretch
COPY test.txt test.txt
RUN touch file.txt
CMD ["date"]
A place to store and share tagged images
Dockerfile
Dockerfile
Image
build, tag
Registry
push/pull
Container
run
CMD/Entrypoint
Resources (storage, networking, etc.)
Focus of this session
FROM python:3.7
WORKDIR /app
COPY . .
RUN pip install -r requirements.txt
CMD ["python", "main.py"]
976 Mb
-> % tree .
.
├── Dockerfile
├── main.py
├── my_project
│ ├── __init__.py
│ └── greet.py
├── poetry.lock
├── pyproject.toml
└── requirements.txt
-> % cat requirements.txt
requests
cryptography
Image | Size | Notes |
---|---|---|
python:3.7 / python:3.7-stretch | 929 Mb | Uses glibc and supports manylinux wheels |
python:3.7-slim-stretch | 147 Mb | |
python:3.7-alpine | 87 Mb | Uses
musl and does not support
manylinux wheels Python extensions should be compiled
Dependencies take less space |
when you care about build time
when you care about image size
FROM python:3.7-slim-stretch
WORKDIR /app
COPY . .
RUN pip install -r requirements.txt
CMD ["python", "main.py"]
976→193 Mb
FROM python:3.7-alpine
WORKDIR /app
COPY . .
RUN apk add --no-cache \
build-base \
gcc \
libffi-dev \
openssl-dev
RUN pip install -r requirements.txt
CMD ["python", "main.py"]
976→317 Mb
???
**/*.pyc
**/*.pyo
**/*.log
**/__pycache__
docs/_build
**/.ipynb_checkpoints
.venv/
.mypy_cache/
.pytest_cache/
.tox/
**/*.egg-info
pip-wheel-metadata/
FROM python:3.7-slim-stretch
WORKDIR /app
COPY my_project my_project
COPY main.py .
COPY requirements.txt .
RUN pip install -r requirements.txt
CMD ["python", "main.py"]
193→170 Mb
FROM python:3.7-alpine
WORKDIR /app
COPY my_project my_project
COPY main.py .
COPY requirements.txt .
RUN apk add --no-cache \
build-base \
gcc \
libffi-dev \
openssl-dev
RUN pip install -r requirements.txt
CMD ["python", "main.py"]
317→294 Mb
FROM python:3.7-alpine
WORKDIR /app
COPY my_project my_project
COPY main.py .
COPY requirements.txt .
RUN apk add --no-cache \
build-base \
gcc \
libffi-dev \
openssl-dev
RUN pip install -r requirements.txt
RUN apk del build-base \
gcc \
libffi-dev \
openssl-dev
CMD ["python", "main.py"]
294→294 Mb
FROM python:3.7-slim-stretch
WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY my_project my_project
COPY main.py .
CMD ["python", "main.py"]
170→166 Mb
FROM python:3.7-alpine
WORKDIR /app
ARG BUILD_DEPS="build-base gcc libffi-dev openssl-dev"
ARG RUNTIME_DEPS="libcrypto1.1 libssl1.1"
COPY requirements.txt .
RUN apk add --no-cache --virtual .build-deps ${BUILD_DEPS} \
&& pip install --no-cache-dir -r requirements.txt \
&& apk del .build-deps \
&& apk add --no-cache ${RUNTIME_DEPS}
COPY my_project my_project
COPY main.py .
CMD ["python", "main.py"]
294→106 Mb
FROM python:3.7-alpine
WORKDIR /app
ARG BUILD_DEPS="build-base gcc libffi-dev openssl-dev"
ARG RUNTIME_DEPS="libcrypto1.1 libssl1.1"
COPY requirements.txt .
RUN apk add --no-cache --virtual .build-deps ${BUILD_DEPS} \
&& pip install --no-cache-dir -r requirements.txt \
&& apk del .build-deps \
&& apk add --no-cache ${RUNTIME_DEPS} \
&& find /usr/local \
\( -type d -a -name test -o -name tests \) \
-o \( -type f -a -name '*.pyc' -o -name '*.pyo' \) \
-exec rm -rf '{}' \+
COPY my_project my_project
COPY main.py .
CMD ["python", "main.py"]
106→97 Mb
# Stage 1 - Install build dependencies
FROM python:3.7-alpine AS builder
WORKDIR /app
ARG BUILD_DEPS="build-base gcc libffi-dev openssl-dev"
RUN apk add --no-cache ${BUILD_DEPS} \
&& python -m venv .venv \
&& .venv/bin/pip install --no-cache-dir -U pip setuptools
COPY requirements.txt .
RUN .venv/bin/pip install --no-cache-dir -r requirements.txt \
&& find /app/.venv \
\( -type d -a -name test -o -name tests \) \
-o \( -type f -a -name '*.pyc' -o -name '*.pyo' \) \
-exec rm -rf '{}' \+
# Stage 2 - Copy only necessary files to the runner stage
FROM python:3.7-alpine
WORKDIR /app
ARG RUNTIME_DEPS="libcrypto1.1 libssl1.1"
RUN apk add --no-cache ${RUNTIME_DEPS}
COPY --from=builder /app /app
COPY my_project my_project
COPY main.py .
ENV PATH="/app/.venv/bin:$PATH"
CMD ["python", "main.py"]
97→101 Mb
FROM registry.gitlab.com/dmfigol/base-docker-images/python:3.7-alpine AS builder
WORKDIR /app
COPY requirements.txt .
RUN .venv/bin/pip install --no-cache-dir -r requirements.txt \
&& find /app/.venv \
\( -type d -a -name test -o -name tests \) \
-o \( -type f -a -name '*.pyc' -o -name '*.pyo' \) \
-exec rm -rf '{}' \+
FROM python:3.7-alpine
WORKDIR /app
ARG RUNTIME_DEPS="libcrypto1.1 libssl1.1"
RUN apk add --no-cache ${RUNTIME_DEPS}
COPY --from=builder /app /app
COPY my_project my_project
COPY main.py .
ENV PATH="/app/.venv/bin:$PATH"
CMD ["python", "main.py"]
PYTHONUNBUFFERED=1 # print to stdout without buffering
PYTHONDONTWRITEBYTECODE=1 # don't generate *.pyc files
# Stage 1 - Install build dependencies
FROM python:3.7-alpine AS builder
WORKDIR /app
ENV PATH="/root/.poetry/bin:$PATH"
ARG BUILD_DEPS="build-base gcc libffi-dev openssl-dev git curl"
RUN apk add --no-cache ${BUILD_DEPS} \
&& curl -sSL https://raw.githubusercontent.com/sdispater/poetry/master/get-poetry.py | python \
&& python -m venv .venv \
&& poetry config settings.virtualenvs.in-project true \
&& .venv/bin/pip install --no-cache-dir -U pip setuptools
COPY pyproject.toml .
COPY poetry.lock .
RUN poetry install --no-dev --no-interaction \
&& find /app/.venv \
\( -type d -a -name test -o -name tests \) \
-o \( -type f -a -name '*.pyc' -o -name '*.pyo' \) \
-exec rm -rf '{}' \+
COPY my_project my_project
# Install the project as a package
RUN poetry install --no-dev --no-interaction
# Stage 2 - Copy only necessary files to the runner stage
FROM python:3.7-alpine
WORKDIR /app
ARG RUNTIME_DEPS="libcrypto1.1 libssl1.1"
RUN apk add --no-cache ${RUNTIME_DEPS}
COPY --from=builder /app /app
COPY main.py .
ENV PATH="/app/.venv/bin:$PATH" \
PYTHONUNBUFFERED=1 \
PYTHONDONTWRITEBYTECODE=1
CMD ["python", "main.py"]
@dmfigol