Pythonの機械学習用Docker imageのサイズ削減方法の紹介 という大変有益な M3 blog を twitter で見かけたので、便乗して自分が使っている Dockerfile との違いを簡単に書いてみようと思う。こちらは dashboard 用 Dockerfile であり機械学習用ではないので参考扱い程度に見てもらえればと。なお以下の内容が優れているとは思えないので better idea ある方にツッコミもらえれば幸いです。そしていつもながらインターネットの向こうの誰か1人に役に立ってもらえればも。なお、streamlit は大変便利。
結論
同じ部分
- poetry で version 管理
- multi-stage build を使う
- docker build は dev, prod で cache が効く
違う部分
- builder にて apt install を使わないなので builder も slim image を使う
- poetry install は使わず poetry export を使う(実行イメージにはpoetry入れない)。そして requirements.txt と requirements-dev.txt を作成。
- docker-compose.yml で dev, prod 切り替え
- vscode を使い remote-container で開けば、開発環境側に python が不要。
code
build
少し前は .env
内で STAGE=
と環境変数を定義していたが、書き換えがめんどくさいのでやめた。
# dev build
STAGE=dev docker-compose build
# prod build
docker-compose up build
Dockerfile
FROM python:3.8.5-slim as builder
WORKDIR /work/src
RUN pip install --upgrade pip && pip install poetry
COPY pyproject.toml poetry.lock ./
RUN poetry export --without-hashes -f requirements.txt > requirements.txt
RUN poetry export --without-hashes --dev -f requirements.txt > requirements-dev.txt
RUN pip install -r requirements.txt
### for dev.
FROM python:3.8.5-slim as dev
ENV PYTHONUNBUFFERED=1
WORKDIR /work/src
COPY --from=builder /usr/local/lib/python3.8/site-packages /usr/local/lib/python3.8/site-packages
# need to copy if python package is installed in /usr/local/bin
COPY --from=builder /usr/local/bin/streamlit /usr/local/bin/streamlit
COPY src/ ./
# for dev packages
COPY --from=builder /work/src/requirements-dev.txt requirements-dev.txt
RUN pip install -r requirements-dev.txt
COPY tests/ ./
EXPOSE 8501
CMD ["streamlit", "run", "hello.py"]
### for prod
FROM python:3.8.5-slim as prod
ENV PYTHONUNBUFFERED=1
WORKDIR /work/src
COPY --from=builder /usr/local/lib/python3.8/site-packages /usr/local/lib/python3.8/site-packages
# need to copy if python package is installed in /usr/local/bin
COPY --from=builder /usr/local/bin/streamlit /usr/local/bin/streamlit
COPY src/ ./
EXPOSE 8501
CMD ["streamlit", "run", "hello.py"]
docker-compose.yml
version: '3'
services:
app:
build:
context: .
target: ${STAGE:-prod}
image: "internal-dashboard_app_${STAGE:-prod}"
container_name: "internal-dashboard_${STAGE:-prod}"
volumes:
- ./src:/work/src
ports:
- "8501:8501"
restart: always
command: ["streamlit", "run", "hello.py"]
感想
tests の path 問題をどう対処するかいつも悩んでます。
以上。