马春杰杰 Exit Reader Mode

好用的Dockerfile模板

下面是一个我目前用起来比较好的Dockerfile模板,后续其他项目可以在这个基础上比较快速的创建。

在此备份一下。

# syntax=docker/dockerfile:1

############################################
# 1) Base
############################################
ARG PYTHON_IMAGE=docker.1ms.run/library/python:3.10-slim-bookworm
FROM ${PYTHON_IMAGE}

WORKDIR /app

############################################
# 2) Common ENV
############################################
ENV TZ=Asia/Shanghai \
    PYTHONDONTWRITEBYTECODE=1 \
    PYTHONUNBUFFERED=1 \
    PIP_DISABLE_PIP_VERSION_CHECK=1 \
    PIP_NO_CACHE_DIR=1

############################################
# 3) Debian mirror (Aliyun)
############################################
RUN sed -i 's|http://deb.debian.org|http://mirrors.aliyun.com|g' /etc/apt/sources.list 2>/dev/null || true; \
    sed -i 's|http://security.debian.org|http://mirrors.aliyun.com/debian-security|g' /etc/apt/sources.list 2>/dev/null || true; \
    if [ -f /etc/apt/sources.list.d/debian.sources ]; then \
        sed -i 's|http://deb.debian.org/debian|http://mirrors.aliyun.com/debian|g' /etc/apt/sources.list.d/debian.sources; \
        sed -i 's|http://security.debian.org/debian-security|http://mirrors.aliyun.com/debian-security|g' /etc/apt/sources.list.d/debian.sources; \
    fi

############################################
# 4) System deps
# - BASE_DEP: 通用依赖
# - (optional) CHROME_DEP: 仅在 INSTALL_CHROME=true 时安装
############################################
ARG INSTALL_CHROME=false

RUN apt-get update && apt-get install -y --no-install-recommends \
    # ---- common build/runtime deps ----
    gcc \
    libffi-dev \
    libssl-dev \
    libxml2-dev \
    libxslt1-dev \
    zlib1g-dev \
    openssh-client \
    iputils-ping \
    wget \
    gnupg \
    curl \
    ca-certificates \
    unzip \
    tini \
    && if [ "${INSTALL_CHROME}" = "true" ]; then \
      apt-get install -y --no-install-recommends \
        # ---- chrome runtime deps ----
        fonts-liberation \
        libasound2 \
        libatk-bridge2.0-0 \
        libatk1.0-0 \
        libc6 \
        libcairo2 \
        libcups2 \
        libdbus-1-3 \
        libexpat1 \
        libfontconfig1 \
        libgbm1 \
        libgcc1 \
        libglib2.0-0 \
        libgtk-3-0 \
        libnspr4 \
        libnss3 \
        libpango-1.0-0 \
        libpangocairo-1.0-0 \
        libstdc++6 \
        libx11-6 \
        libx11-xcb1 \
        libxcb1 \
        libxcomposite1 \
        libxcursor1 \
        libxdamage1 \
        libxext6 \
        libxfixes3 \
        libxi6 \
        libxrandr2 \
        libxrender1 \
        libxss1 \
        libxtst6 \
        xdg-utils \
        libu2f-udev \
        libvulkan1 \
        fonts-noto-cjk; \
    fi \
    && rm -rf /var/lib/apt/lists/*

############################################
# 5) pip mirror (Aliyun)
############################################
ARG PIP_INDEX_URL=https://mirrors.aliyun.com/pypi/simple/
ARG PIP_TRUSTED_HOST=mirrors.aliyun.com
RUN pip config set global.index-url ${PIP_INDEX_URL} && \
    pip config set global.trusted-host ${PIP_TRUSTED_HOST}

############################################
# 6) Create non-root user
############################################
ARG APP_USER=vpms
ARG APP_UID=1000
ARG APP_GID=1001

RUN groupadd -g ${APP_GID} ${APP_USER} && \
    useradd -m -s /bin/bash -u ${APP_UID} -g ${APP_GID} ${APP_USER}

############################################
# 7) Optional: Install Chrome for Testing + chromedriver
# 保持你项目现有默认路径结构(如需改可以覆写 ENV)
############################################
ENV CHROME_HOME=/home/${APP_USER}/chromefortest \
    CHROME_BINARY_PATH=/home/${APP_USER}/chromefortest/chrome-headless-shell-linux64/chrome-headless-shell \
    CHROME_DRIVER_PATH=/home/${APP_USER}/chromefortest/chromedriver-linux64/chromedriver

ARG CHROME_HEADLESS_SHELL_URL=""
ARG CHROMEDRIVER_URL=""

RUN if [ "${INSTALL_CHROME}" = "true" ]; then \
      set -eux; \
      install -d -m 0755 ${CHROME_HOME}; \
      if [ -z "${CHROME_HEADLESS_SHELL_URL}" ] || [ -z "${CHROMEDRIVER_URL}" ]; then \
        echo "ERROR: INSTALL_CHROME=true but CHROME_HEADLESS_SHELL_URL/CHROMEDRIVER_URL is empty" >&2; \
        exit 1; \
      fi; \
      curl -fL --retry 8 --retry-all-errors --retry-delay 2 --connect-timeout 10 --max-time 300 \
        "${CHROME_HEADLESS_SHELL_URL}" -o /tmp/chrome-headless-shell.zip; \
      curl -fL --retry 8 --retry-all-errors --retry-delay 2 --connect-timeout 10 --max-time 300 \
        "${CHROMEDRIVER_URL}" -o /tmp/chromedriver.zip; \
      unzip -q /tmp/chrome-headless-shell.zip -d ${CHROME_HOME}; \
      unzip -q /tmp/chromedriver.zip -d ${CHROME_HOME}; \
      chown -R ${APP_USER}:${APP_USER} ${CHROME_HOME}; \
      chmod +x ${CHROME_BINARY_PATH}; \
      chmod +x ${CHROME_DRIVER_PATH}; \
      rm -f /tmp/chrome-headless-shell.zip /tmp/chromedriver.zip; \
    fi

# 可选验证(安装浏览器时)
RUN if [ "${INSTALL_CHROME}" = "true" ]; then \
      su -s /bin/sh -c "${CHROME_BINARY_PATH} --no-sandbox --version" ${APP_USER}; \
      su -s /bin/sh -c "${CHROME_DRIVER_PATH} --version" ${APP_USER}; \
    fi

############################################
# 8) Python deps (cache-friendly)
############################################
COPY requirements.txt /app/requirements.txt
RUN pip install -r /app/requirements.txt

############################################
# 9) Copy project code
############################################
COPY . /app

############################################
# 10) Runtime dirs & permissions
############################################
ENV DATA_DIR=/home/${APP_USER}/data \
    LOG_DIR=/home/${APP_USER}/logs \
    SSH_DIR=/home/${APP_USER}/.ssh

RUN mkdir -p ${DATA_DIR} ${LOG_DIR} ${SSH_DIR} && \
    chown -R ${APP_USER}:${APP_USER} /home/${APP_USER} && \
    chown -R ${APP_USER}:${APP_USER} /app

############################################
# 11) Runtime config
############################################
USER ${APP_USER}

# 端口可改
ARG APP_PORT=8088
ENV PORT=${APP_PORT}
EXPOSE ${APP_PORT}

# 健康检查:默认探测 /,可用 HEALTHCHECK_PATH 覆写
ENV HEALTHCHECK_PATH=/
HEALTHCHECK --interval=30s --timeout=10s --start-period=40s --retries=3 \
  CMD curl -fsS "http://localhost:${PORT}${HEALTHCHECK_PATH}" || exit 1

# 用 tini 做 PID1(更稳,信号/僵尸进程处理更好)
ENTRYPOINT ["/usr/bin/tini", "--"]

# 默认启动命令:可在 docker run 时覆盖
# 比如 Flask:CMD ["python","app.py","--host=0.0.0.0"]
CMD ["python", "app.py"]

使用的时候也非常简单,比如最简单的一个flask项目:

docker build -t myapp:v1 .
docker run -d --name myapp --net=host myapp:v1

如果需要用到Chrome,那就:

docker build -t myapp:v1 \
  --build-arg INSTALL_CHROME=true \
  --build-arg CHROME_HEADLESS_SHELL_URL="https://one.machunjie.com/.../chrome-headless-shell-linux64-122.0.6261.94.zip" \
  --build-arg CHROMEDRIVER_URL="https://one.machunjie.com/.../chromedriver-linux64-122.0.6261.94.zip" \
  .