dockerfile 构建项目镜像

一、通用打包原则

  1. 采用 轻量化基础镜像(如 slim,alpine版本)减少镜像体积
  2. 分层构建/复制,利用Docker缓存机制,加速构建;
  3. 非root用户运行容器,提升安全性
  4. 明确暴露端口、指定启动命令,规范容器启动;
  5. 分离依赖安装与代码复制(先装依赖,再复制代码,避免依赖变更时重复构建)。

二、FastAPI项目 Dockerfile

  1. 项目目录结构

    fastapi-project/
    ├── app/                  # 项目核心代码
    │   ├── __init__.py
    │   ├── main.py           # 入口文件(含 FastAPI 实例)
    │   └── routes/           # 路由模块(可选)
    ├── requirements.txt      # 依赖清单
    └── Dockerfile            # 本次编写的 Dockerfile
    
  2. requirements.txt 示例

    fastapi==0.104.1
    uvicorn[standard]==0.24.0  # ASGI 服务器(standard 含 websocket 支持)
    python-multipart==0.0.6    # 处理表单数据(可选)
    pydantic==2.5.2            # 数据校验(FastAPI 依赖)
    
  3. Dockerfile 完整代码

    # 阶段1:基础镜像(Python 3.11 轻量化版本,含基础编译环境)
    FROM python:3.11-slim AS base
    # 设置环境变量:Python 不生成 .pyc 文件,不缓冲输出
    ENV PYTHONDONTWRITEBYTECODE=1
    ENV PYTHONUNBUFFERED=1
    # 设置工作目录(容器内)
    WORKDIR /app
    # 安装系统依赖(解决 Python 依赖编译问题,如 cryptography)
    RUN apt-get update && apt-get install -y --no-install-recommends \
        gcc \
        libpq-dev \  # 若使用 PostgreSQL 数据库需添加(可选)
        && rm -rf /var/lib/apt/lists/*  # 清理缓存,减少镜像体积
    
    # 阶段2:安装依赖(利用 Docker 缓存,依赖不变则不重新构建)
    FROM base AS deps
    # 复制依赖清单到容器
    COPY requirements.txt .
    # 升级 pip,安装依赖到指定目录(便于后续复制)
    RUN pip install --upgrade pip && \
        pip install --no-cache-dir -r requirements.txt -t /app/deps
    
    # 阶段3:构建最终镜像(仅包含运行时依赖,最小化体积)
    FROM base AS final
    # 创建非 root 用户(安全最佳实践)
    RUN groupadd -r appuser && useradd -r -g appuser appuser
    # 复制依赖(从 deps 阶段)
    COPY --from=deps /app/deps /app/deps
    # 将依赖目录添加到 Python 路径
    ENV PYTHONPATH=/app/deps
    # 复制项目代码(仅复制必要文件,避免冗余)
    COPY ./app /app/app
    # 切换到非 root 用户
    USER appuser
    # 暴露 FastAPI 运行端口(与 uvicorn 启动命令一致)
    EXPOSE 8000
    # 启动命令:uvicorn 启动 FastAPI,支持热重载(生产环境关闭 reload)
    CMD ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "8000", "--workers", "4"]
    
  4. 构建与运行命令

    # 构建镜像(镜像名 fastapi-app,标签 v1)
    docker build -t fastapi-app:v1 .
    
    # 运行容器(端口映射 8000:8000,后台运行,容器名 fastapi-server)
    docker run -d -p 8000:8000 --name fastapi-server fastapi-app:v1
    
    # 查看日志
    docker logs -f fastapi-server
    
  5. 关键说明

    • workers 数量:推荐设置为 CPU核心数 * 2 + 1(如 4 核 CPU 设为 9);
    • 生产环境优化:关闭 --reload,添加 --proxy-headers(支持反向代理);
    • 镜像体积:slim 基础镜像约 100MB,最终镜像约 150-200MB(远小于完整版 Python 镜像)。

三、django 项目构建Dockerfile

  1. 项目目录

    django-project/
    ├── project/              # 项目配置目录(django-admin startproject 生成)
    │   ├── __init__.py
    │   ├── settings.py
    │   ├── urls.py
    │   └── wsgi.py
    ├── app/                  # 业务应用(python manage.py startapp app)
    ├── static/               # 静态文件(收集后目录)
    ├── media/                # 媒体文件(用户上传)
    ├── requirements.txt      # 依赖清单
    ├── manage.py
    └── Dockerfile
    
  2. requirements.txt 示例

    django==4.2.7
    gunicorn==21.2.0  # WSGI 服务器(生产环境替代 runserver)
    whitenoise==6.5.0 # 静态文件服务(无需 Nginx 也可提供静态文件)
    psycopg2-binary==2.9.9  # PostgreSQL 驱动(可选,根据数据库调整)
    django-cors-headers==4.3.0  # 跨域支持(可选)
    
  3. Dockerfile 完整代码

    # 基础镜像(Python 3.11 轻量化版本)
    FROM python:3.11-slim
    
    # 环境变量配置
    ENV PYTHONDONTWRITEBYTECODE=1
    ENV PYTHONUNBUFFERED=1
    ENV DJANGO_SETTINGS_MODULE=project.settings  # 指定 Django 配置文件
    ENV DJANGO_DEBUG=False  # 生产环境关闭 Debug
    
    # 工作目录
    WORKDIR /app
    
    # 安装系统依赖(解决 psycopg2 等依赖编译问题)
    RUN apt-get update && apt-get install -y --no-install-recommends \
        gcc \
        libpq-dev \
        && rm -rf /var/lib/apt/lists/*
    
    # 升级 pip,安装依赖
    COPY requirements.txt .
    RUN pip install --upgrade pip && \
        pip install --no-cache-dir -r requirements.txt
    
    # 复制项目代码
    COPY . .
    
    # 收集静态文件(Django 必须步骤,需确保 settings.py 配置 STATIC_ROOT)
    RUN python manage.py collectstatic --noinput
    
    # 创建非 root 用户
    RUN groupadd -r djangouser && useradd -r -g djangouser djangouser
    # 授权静态文件和媒体文件目录(避免权限问题)
    RUN chown -R djangouser:djangouser /app/static /app/media
    USER djangouser
    
    # 暴露端口(gunicorn 运行端口)
    EXPOSE 8000
    
    # 启动命令:gunicorn 启动 Django,配合 whitenoise 提供静态文件
    CMD ["gunicorn", "--bind", "0.0.0.0:8000", "--workers", "4", "project.wsgi:application"]
    
  4. Django 配置补充(settings.py)

    需配合Dockerfile调整以下配置:

    # 允许所有主机访问(生产环境需指定具体域名,如 ALLOWED_HOSTS = ["api.example.com"])
    ALLOWED_HOSTS = ["*"]
    
    # 静态文件配置(配合 whitenoise)
    STATIC_URL = "/static/"
    STATIC_ROOT = BASE_DIR / "static"  # 与 Dockerfile 中 collectstatic 对应
    STATICFILES_STORAGE = "whitenoise.storage.CompressedManifestStaticFilesStorage"
    
    # 媒体文件配置(可选,用户上传文件存储目录)
    MEDIA_URL = "/media/"
    MEDIA_ROOT = BASE_DIR / "media"
    
  5. 构建与运行命令

    # 构建镜像
    docker build -t django-app:v1 .
    
    # 运行容器(映射端口 8000:8000,挂载媒体文件目录(持久化))
    docker run -d -p 8000:8000 \
      -v ./media:/app/media \  # 本地目录挂载到容器,持久化用户上传文件
      --name django-server django-app:v1
    
    # 执行数据库迁移(首次运行或模型变更时)
    docker exec -it django-server python manage.py migrate
    
  6. 关键说明

    • 静态文件:生产环境推荐用 Nginx 代理静态文件(性能更好),此时可删除 whitenoise 依赖,Dockerfile 中无需 collectstatic
    • 数据库:若使用外部数据库(如 MySQL/PostgreSQL),需通过环境变量传递连接信息(如 DJANGO_DB_HOST),避免硬编码;
    • 安全优化:生产环境需设置 SECRET_KEY 为环境变量,禁止 ALLOWED_HOSTS = ["*"]

四、SpringBoot项目Dockerfile

  1. 项目目录结构

    springboot-project/
    ├── src/                  # 源代码目录
    ├── pom.xml               # Maven 依赖配置(若用 Gradle 则为 build.gradle)
    └── Dockerfile
    
  2. 核心依赖(pom.xml)

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <version>3.2.0</version>  # 与 SpringBoot 版本一致
                <executions>
                    <execution>
                        <goals>
                            <goal>repackage</goal>  # 打包为可执行 jar
                        </goals>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>
    
  3. dockerfile

    采用 多阶段构建 分离构建环境和运行环境,最小化镜像体积

    # 阶段1:构建阶段(使用 Maven 镜像编译打包)
    FROM maven:3.8.8-openjdk17 AS builder
    
    # 工作目录
    WORKDIR /app
    
    # 复制 Maven 配置文件(先复制 pom.xml,利用缓存)
    COPY pom.xml .
    
    # 下载依赖(依赖不变时,直接使用缓存,无需重新下载)
    RUN mvn dependency:go-offline -B
    
    # 复制源代码
    COPY src ./src
    
    # 编译打包(跳过测试,加速构建)
    RUN mvn clean package -DskipTests
    
    # 提取可执行 jar 包(SpringBoot 打包后在 target 目录,名称格式:项目名-版本.jar)
    # 此处假设打包后的 jar 名为 app.jar(可通过 pom.xml 配置 finalName 固定名称)
    RUN cp target/*.jar app.jar && \
        # 解压 jar 包(优化运行时启动速度,可选)
        java -Djarmode=layertools -jar app.jar extract
    
    # 阶段2:运行阶段(使用轻量级 OpenJDK 镜像,仅含运行时)
    FROM openjdk:17-jdk-slim
    
    # 环境变量配置(SpringBoot 配置)
    ENV SPRING_PROFILES_ACTIVE=prod  # 激活生产环境配置
    ENV JAVA_OPTS="-Xms512m -Xmx1024m"  # JVM 内存配置(根据服务器调整)
    
    # 工作目录
    WORKDIR /app
    
    # 从构建阶段复制解压后的分层文件(利用 Docker 缓存,加速启动)
    COPY --from=builder /app/dependencies/ ./
    COPY --from=builder /app/spring-boot-loader/ ./
    COPY --from=builder /app/snapshot-dependencies/ ./
    COPY --from=builder /app/application/ ./
    
    # 创建非 root 用户
    RUN groupadd -r springuser && useradd -r -g springuser springuser
    USER springuser
    
    # 暴露 SpringBoot 默认端口
    EXPOSE 8080
    
    # 启动命令(通过 SpringBoot 分层启动器启动,优化内存和启动速度)
    ENTRYPOINT ["sh", "-c", "java ${JAVA_OPTS} org.springframework.boot.loader.launch.JarLauncher"]
    
  4. 简化版 Dockerfile(单阶段,适合快速测试)

    若无需分层优化,可使用单阶段构建(镜像体积稍大):

    FROM openjdk:17-jdk-slim
    
    WORKDIR /app
    
    # 复制本地打包好的 jar 包到容器(需先本地执行 mvn package)
    COPY target/*.jar app.jar
    
    ENV SPRING_PROFILES_ACTIVE=prod
    EXPOSE 8080
    
    # 直接启动 jar 包
    ENTRYPOINT ["java", "-jar", "app.jar"]
    
  5. 构建与运行命令

    # 多阶段构建(推荐)
    docker build -t springboot-app:v1 .
    
    # 运行容器(端口映射 8080:8080,传递环境变量)
    docker run -d -p 8080:8080 \
      -e SPRING_DATASOURCE_URL=jdbc:mysql://mysql-host:3306/dbname \  # 数据库连接(示例)
      -e SPRING_DATASOURCE_USERNAME=root \
      -e SPRING_DATASOURCE_PASSWORD=123456 \
      --name springboot-server springboot-app:v1
    
    # 查看日志
    docker logs -f springboot-server
    
  6. 关键说明

    • 多阶段构建优势:构建阶段镜像约 1GB+,运行阶段镜像仅 300-400MB(大幅减少部署体积);
    • JVM 优化:通过 JAVA_OPTS 调整堆内存(-Xms 初始内存,-Xmx 最大内存),避免内存溢出;
    • 配置方式:生产环境通过环境变量(-e 参数)传递配置,避免硬编码 application.yml
    • 镜像选择openjdk:17-jdk-slim 适合需要运行时编译的场景,openjdk:17-jre-slim 体积更小(仅含 JRE,无 JDK)。
posted @ 2025-11-29 19:49  小郑[努力版]  阅读(8)  评论(0)    收藏  举报