Files
xiaoxia-saas/infra/docker/worker.Dockerfile
T
xiaoxia b371e484fb
Preview Deploy / Deploy Preview Environment (pull_request) Successful in 40s
AI Code Review / AI Code Review (pull_request) Successful in 2m10s
PR Automation / Auto Approve on CI Green (pull_request) Successful in 2m23s
PR Automation / Auto Merge on CI Green + Approved (pull_request) Successful in 3m24s
Preview Cleanup / Cleanup Preview Environment (pull_request) Successful in 20s
CI/CD Pipeline / Frontend Unit Tests (pull_request) Failing after 1363h11m2s
CI/CD Pipeline / Production Browser E2E (pull_request) Failing after 1363h11m38s
CI/CD Pipeline / Deploy Production (pull_request) Failing after 1363h11m38s
CI/CD Pipeline / Build Production Worker Image (pull_request) Failing after 1363h11m40s
CI/CD Pipeline / Build Production Web Image (pull_request) Failing after 1363h11m40s
CI/CD Pipeline / Staging API Integration Tests (pull_request) Failing after 1363h11m42s
CI/CD Pipeline / Staging E2E Tests (pull_request) Failing after 1363h11m42s
CI/CD Pipeline / Build Staging Worker Image (pull_request) Failing after 1363h11m44s
CI/CD Pipeline / Build Staging Web Image (pull_request) Failing after 1363h11m44s
CI/CD Pipeline / Build Staging API Image (pull_request) Failing after 1363h11m44s
CI/CD Pipeline / Check if frontend-only change (pull_request) Has been skipped
CI/CD Pipeline / Validate Code Quality And Tests (pull_request) Has been skipped
CI/CD Pipeline / Unit Tests (pull_request) Has been skipped
CI/CD Pipeline / Integration Tests (pull_request) Has been skipped
CI/CD Pipeline / Frontend Lint (pull_request) Has been skipped
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (pull_request) Failing after 1363h43m54s
CI/CD Pipeline / Build Production API Image (pull_request) Failing after 1363h43m54s
CI/CD Pipeline / ACR Image Cleanup (pull_request) Failing after 1363h43m52s
fix(worker): ffmpeg下载脚本改为纯sh兼容,修复dash数组语法错误
问题:#686引入了bash数组语法 FFMPEG_SOURCES=(...),但worker基础镜像
的/bin/sh是dash,不支持数组,导致Worker Build报
Syntax error: "(" unexpected

修复:
- 移除数组,改用 for src in "url1" "url2" "url3"; do 的纯sh写法
- 所有语法保持POSIX sh兼容,确保dash下能正常运行
- 保留所有原有功能:三源重试、tar校验、坏包清缓存、二进制校验
2026-07-21 20:17:21 +08:00

163 lines
6.7 KiB
Docker
Executable File
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# ============================================================
# Worker Dockerfile - 优化版(多阶段构建 + 镜像瘦身 + cache mount加速)
# 优化项:
# 1. 多阶段构建:builder 阶段安装编译依赖,runtime 阶段只保留运行时
# 2. ffmpeg 静态编译替换:从 apt 安装(457MB) 改为静态二进制(~80MB)
# 3. Python 依赖瘦身:strip .so 调试符号 + 清理测试文件 + 清理缓存
# 4. pip cache mount:加速依赖下载(跨构建共享pip wheel缓存)
# 5. ffmpeg cache mount:避免每次重新下载静态编译包
# ============================================================
# ==================== Builder 阶段 ====================
FROM git.xiaoxiajianji.com/xiaoxia/base/python:3.12-slim AS builder
# 使用阿里云镜像加速
RUN sed -i 's|deb.debian.org|mirrors.aliyun.com|g' /etc/apt/sources.list.d/debian.sources 2>/dev/null || \
sed -i 's|deb.debian.org|mirrors.aliyun.com|g' /etc/apt/sources.list 2>/dev/null || true
# 安装编译工具(仅 builder 需要)
RUN apt-get update && apt-get install -y --no-install-recommends \
gcc \
g++ \
python3-dev \
binutils \
wget \
xz-utils \
&& rm -rf /var/lib/apt/lists/*
# ---- 下载静态编译 ffmpeg(带缓存+完整性校验+多源重试)----
# 注意:必须用纯sh语法(dash兼容),不能用bash数组、[[ ]]等特性
# 修复策略:1.三源下载 2.tar完整性校验 3.损坏删缓存重试 4.二进制可执行校验
RUN --mount=type=cache,target=/tmp/ffmpeg-cache,sharing=locked \
cd /tmp \
&& FFMPEG_FILE="/tmp/ffmpeg-cache/ffmpeg-release-amd64-static.tar.xz" \
&& download_ok=0 \
&& for src in \
"https://johnvansickle.com/ffmpeg/releases/ffmpeg-release-amd64-static.tar.xz" \
"https://mirrors.tuna.tsinghua.edu.cn/ffmpeg/releases/ffmpeg-release-amd64-static.tar.xz" \
"https://mirrors.ustc.edu.cn/ffmpeg/releases/ffmpeg-release-amd64-static.tar.xz"; \
do \
if [ $download_ok -eq 0 ] && [ -f "$FFMPEG_FILE" ] && tar -tf "$FFMPEG_FILE" >/dev/null 2>&1; then \
echo "[ffmpeg] cache valid, skip download"; \
download_ok=1; \
break; \
fi; \
rm -f "$FFMPEG_FILE"; \
echo "[ffmpeg] downloading from $src"; \
if wget -q --tries=3 --timeout=30 -O "$FFMPEG_FILE" "$src"; then \
if tar -tf "$FFMPEG_FILE" >/dev/null 2>&1; then \
echo "[ffmpeg] download OK, tar valid"; \
download_ok=1; \
break; \
else \
echo "[ffmpeg] corrupted file, removing cache"; \
rm -f "$FFMPEG_FILE"; \
fi; \
fi; \
done \
&& if [ $download_ok -eq 0 ]; then echo "[ffmpeg] ALL SOURCES FAILED"; exit 1; fi \
&& tar xf "$FFMPEG_FILE" \
&& cp ffmpeg-*-amd64-static/ffmpeg /usr/local/bin/ffmpeg \
&& cp ffmpeg-*-amd64-static/ffprobe /usr/local/bin/ffprobe \
&& chmod +x /usr/local/bin/ffmpeg /usr/local/bin/ffprobe \
&& ffmpeg -version >/dev/null 2>&1 && ffprobe -version >/dev/null 2>&1 \
&& echo "[ffmpeg] binary valid" \
&& rm -rf ffmpeg-*
# ---- 安装 Python 依赖 ----
WORKDIR /tmp
# 创建 venv
RUN python -m venv /opt/venv
ENV PATH="/opt/venv/bin:$PATH"
# 基础依赖
COPY requirements-base.txt /tmp/requirements-base.txt
RUN --mount=type=cache,target=/root/.cache/pip,sharing=locked \
pip install --no-cache-dir -i https://mirrors.aliyun.com/pypi/simple/ --trusted-host mirrors.aliyun.com \
-r /tmp/requirements-base.txt \
&& rm /tmp/requirements-base.txt
# Worker 专属大包
COPY requirements-worker.txt /tmp/requirements-worker.txt
RUN --mount=type=cache,target=/root/.cache/pip,sharing=locked \
pip install --no-cache-dir -i https://mirrors.aliyun.com/pypi/simple/ --trusted-host mirrors.aliyun.com \
-r /tmp/requirements-worker.txt \
&& rm /tmp/requirements-worker.txt
# 业务依赖
COPY requirements.txt /tmp/requirements.txt
RUN --mount=type=cache,target=/root/.cache/pip,sharing=locked \
pip install --no-cache-dir -i https://mirrors.aliyun.com/pypi/simple/ --trusted-host mirrors.aliyun.com \
-r /tmp/requirements.txt \
&& rm /tmp/requirements.txt
# ---- Python 依赖瘦身 ----
# 1. strip .so 文件的调试符号(节省约 80-100MB)
RUN find /opt/venv -name "*.so" -type f -exec strip --strip-all {} \; 2>/dev/null || true
# 2. 清理测试文件(节省约 20MB)
RUN find /opt/venv -type d -name "tests" -exec rm -rf {} + 2>/dev/null; \
find /opt/venv -type d -name "test" -exec rm -rf {} + 2>/dev/null; \
find /opt/venv -name "test_*.py" -delete 2>/dev/null || true
# 3. 清理 .pyc 缓存和 __pycache__(节省约 10MB,运行时按需生成)
RUN find /opt/venv -type d -name "__pycache__" -exec rm -rf {} + 2>/dev/null; \
find /opt/venv -name "*.pyc" -delete 2>/dev/null || true
# 4. 清理 dist-info 中的文档
RUN find /opt/venv -name "*.dist-info" -type d -exec sh -c 'rm -f "$1"/DESCRIPTION.rst "$1"/INSTALLER "$1"/LICENSE* "$1"/WHEEL "$1"/entry_points.txt' _ {} \; 2>/dev/null || true
# ==================== Runtime 阶段 ====================
FROM git.xiaoxiajianji.com/xiaoxia/base/python:3.12-slim AS runtime
# 构建参数:版本号
ARG APP_VERSION=dev
# 使用阿里云镜像加速
RUN sed -i 's|deb.debian.org|mirrors.aliyun.com|g' /etc/apt/sources.list.d/debian.sources 2>/dev/null || \
sed -i 's|deb.debian.org|mirrors.aliyun.com|g' /etc/apt/sources.list 2>/dev/null || true
# 安装最小运行时依赖(opencv-python-headless 需要 libglib2.0-0)
RUN apt-get update && apt-get install -y --no-install-recommends \
libglib2.0-0 \
&& rm -rf /var/lib/apt/lists/*
# 从 builder 复制 ffmpeg 静态二进制
COPY --from=builder /usr/local/bin/ffmpeg /usr/local/bin/ffmpeg
COPY --from=builder /usr/local/bin/ffprobe /usr/local/bin/ffprobe
# 从 builder 复制 Python 虚拟环境
COPY --from=builder /opt/venv /opt/venv
# 设置工作目录
WORKDIR /app
# 复制应用代码
COPY apps/worker/ /app/apps/worker/
COPY apps/api/app/config.py /app/apps/api/app/config.py
COPY apps/api/app/core/ /app/apps/api/app/core/
COPY packages/ /app/packages/
COPY alembic.ini /app/alembic.ini
COPY migrations/ /app/migrations/
# 复制 Worker 启动脚本
COPY infra/docker/entrypoint-worker.sh /usr/local/bin/entrypoint-worker.sh
RUN chmod +x /usr/local/bin/entrypoint-worker.sh
# 设置 Python 路径
ENV PATH="/opt/venv/bin:$PATH"
ENV PYTHONPATH=/app:/app/packages
ENV PYTHONUNBUFFERED=1
ENV APP_VERSION=$APP_VERSION
# 创建非 root 用户运行 Worker
RUN groupadd -r celery && useradd -r -g celery -d /app -s /sbin/nologin celery \
&& mkdir -p /app/generated && chown celery:celery /app/generated
USER celery
# Worker 入口点
WORKDIR /app/apps/worker
CMD ["/usr/local/bin/entrypoint-worker.sh"]