You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为何Python脚本在Docker构建阶段未生成SQLite数据库文件?

Docker构建阶段无法生成SQLite数据库文件的问题分析与解决

问题场景

尝试在Docker构建阶段执行db_setup.py脚本生成SQLite数据库,执行docker compose build后无报错,但宿主机/data/streaming目录下未出现预期的数据库文件。手动进入容器终端执行该脚本,却能正常生成文件。

项目目录结构

/conf
  | /dev
  |   | /py
  |      | db_setup.py
  |      | Dockerfile
  | requirements.txt
/data
  | /streaming
        | # 期望在此处创建SQLite .db文件
.env
docker-compose.yml

相关文件内容

.env 文件

DB_ABS_PATH=/home/fs/data/streaming
DB_FILE_NAME=server-archive.db

docker-compose.yml 文件

version: '3.7'

services:
  app:
    build:
      context: .
      dockerfile: conf/dev/py/Dockerfile
    container_name: fs-py
    env_file:
      - .env
    volumes:
      - .:/home/fs
    ports:
      - ${SERVER_PORT_IN}:${SERVER_PORT_OUT}

Dockerfile 文件

FROM python:3.9.16

WORKDIR /home/fs

COPY . .

RUN pip install -r conf/requirements.txt
RUN python conf/dev/py/db_setup.py # 疑问针对此行

ENTRYPOINT [ "tail", "-f", "/dev/null" ]

db_setup.py 文件

import sqlite3
from dotenv import load_dotenv
from pathlib import Path
import os

load_dotenv(Path(".env"))

try:
    sqliteConnection = sqlite3.connect(Path(os.environ.get("DB_ABS_PATH"), os.environ.get("DB_FILE_NAME")))
    cursor = sqliteConnection.cursor()
    cursor.execute("""CREATE TABLE files(
        id INTEGER PRIMARY KEY,
        original_name VARCHAR(200) NOT NULL,
        actual_name VARCHAR(200) NOT NULL,
        created_at TIMESTAMP NOT NULL,
        deleted_at TIMESTAMP NULL
    );
    """)
    cursor.close()
except sqlite3.Error as err:
    print("Error while connecting to sqlite", err)
finally:
    if sqliteConnection:
        sqliteConnection.close()

问题原因

  1. 构建阶段无宿主机挂载:Docker构建过程中,docker-compose.yml中定义的volumes: - .:/home/fs并未生效,挂载是容器启动阶段才会执行的操作。因此构建阶段执行db_setup.py生成的数据库文件,是保存在镜像内部的/home/fs/data/streaming路径下,而非宿主机的对应目录。
  2. 容器启动时挂载覆盖镜像文件:当容器启动后,宿主机的.目录会挂载到容器内的/home/fs,这会覆盖镜像中该路径下的所有内容,包括构建阶段生成的数据库文件,所以你在宿主机看不到这个文件。

解决方法

方法1:将数据库初始化移到容器启动阶段(推荐)

把初始化脚本从构建阶段移到容器启动时执行,此时挂载已经生效,文件会直接生成在宿主机挂载的目录中:

  1. 在项目根目录创建启动脚本start.sh:
    #!/bin/bash
    # 执行数据库初始化
    python conf/dev/py/db_setup.py
    # 保持容器运行
    tail -f /dev/null
    
  2. 修改Dockerfile,移除构建阶段的RUN python conf/dev/py/db_setup.py,并添加启动脚本相关配置:
    FROM python:3.9.16
    
    WORKDIR /home/fs
    
    COPY . .
    
    RUN pip install -r conf/requirements.txt
    # 给启动脚本添加执行权限
    RUN chmod +x start.sh
    
    ENTRYPOINT ["./start.sh"]
    
  3. 重新构建并启动容器:
    docker compose build
    docker compose up -d
    

方法2:手动复制镜像内的数据库文件(不推荐)

如果必须在构建阶段生成文件,可以通过临时容器将镜像内的文件复制到宿主机:

  1. 构建镜像后创建临时容器:
    docker create --name temp-fs fs-py
    
  2. 复制数据库文件到宿主机目标目录:
    docker cp temp-fs:/home/fs/data/streaming/server-archive.db ./data/streaming/
    
  3. 删除临时容器:
    docker rm temp-fs
    
    此方法需要手动操作,且镜像会残留数据库文件,不符合Docker无状态镜像的设计原则,仅作为临时方案。

方法3:调整挂载策略(按需选择)

若不想修改初始化时机,可以调整挂载路径,避免覆盖镜像内的data/streaming目录:
在docker-compose.yml中调整挂载顺序,先单独挂载data/streaming再挂载根目录:

volumes:
  - ./data/streaming:/home/fs/data/streaming
  - .:/home/fs

但这种方式下,宿主机/data/streaming的内容会优先覆盖镜像内的对应目录,构建阶段生成的文件依然会被覆盖,仅当你不需要宿主机目录覆盖容器目录时适用,实用性较低。

内容的提问来源于stack exchange,提问作者Andrew Sharifikia

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.23 19:23:26