mirror of
https://github.com/ZHANGTIANYAO1/teamspeak-music-bot.git
synced 2026-10-02 04:52:50 +08:00
fix: resolve Docker FFmpeg SIGSEGV crash and build failures (#24)
The ffmpeg-static npm package bundles a pre-compiled binary that passes `ffmpeg -version` but crashes with SIGSEGV during actual audio processing inside Docker containers (incompatible glibc/missing shared libraries). Changes: - Install system FFmpeg via apt-get in Docker production stage, which is always compatible with the container runtime - Reverse FFmpeg resolution priority in player.ts: prefer system FFmpeg, fall back to ffmpeg-static (for non-Docker environments like Windows) - Optimize Dockerfile multi-stage build: compile native modules (opus, better-sqlite3) in builder stage and copy to production, eliminating the need for build tools (python3, make, g++) in the production image - Fix qq-music-api dependency from file:../qq-music-api (path outside Docker build context, breaks npm ci) to npm registry ^2.2.10 https://claude.ai/code/session_01JAV8sBokoifKh4Hc8XbJws
This commit is contained in:
5 files changed
+649
-394
No files matched your search
Generated
+618
-371
File diff suppressed because it is too large.
Load diff
+1
-1
@@ -17,7 +17,7 @@
|
|||||||
"@discordjs/opus": "^0.10.0",
|
"@discordjs/opus": "^0.10.0",
|
||||||
"@honeybbq/teamspeak-client": "^0.2.1",
|
"@honeybbq/teamspeak-client": "^0.2.1",
|
||||||
"@koa/router": "^15.4.0",
|
"@koa/router": "^15.4.0",
|
||||||
"@sansenjian/qq-music-api": "file:../qq-music-api",
|
"@sansenjian/qq-music-api": "^2.2.10",
|
||||||
"axios": "^1.14.0",
|
"axios": "^1.14.0",
|
||||||
"better-sqlite3": "^12.8.0",
|
"better-sqlite3": "^12.8.0",
|
||||||
"chalk": "^5.6.2",
|
"chalk": "^5.6.2",
|
||||||
|
|||||||
+10
-13
@@ -25,30 +25,27 @@ RUN cd web && npm ci
|
|||||||
COPY . .
|
COPY . .
|
||||||
RUN npm run build
|
RUN npm run build
|
||||||
|
|
||||||
|
# Install production dependencies (with native addons compiled) in the builder
|
||||||
|
# so we don't need build tools in the production image.
|
||||||
|
RUN rm -rf node_modules && npm ci --production && npm cache clean --force
|
||||||
|
|
||||||
# --- Stage 2: Production image ---
|
# --- Stage 2: Production image ---
|
||||||
FROM node:20-slim
|
FROM node:20-slim
|
||||||
|
|
||||||
# Install only runtime native build tools (needed for native module rebuild)
|
# Install system FFmpeg — the ffmpeg-static npm package bundles a pre-compiled
|
||||||
|
# binary that can SIGSEGV inside Docker (incompatible glibc / missing libs).
|
||||||
|
# System-installed FFmpeg is always compatible with the container runtime.
|
||||||
RUN apt-get update && apt-get install -y --no-install-recommends \
|
RUN apt-get update && apt-get install -y --no-install-recommends \
|
||||||
python3 make g++ && \
|
ffmpeg && \
|
||||||
rm -rf /var/lib/apt/lists/*
|
rm -rf /var/lib/apt/lists/*
|
||||||
|
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
|
|
||||||
# Copy built output
|
# Copy built output and pre-compiled production node_modules from builder
|
||||||
COPY --from=builder /app/dist ./dist
|
COPY --from=builder /app/dist ./dist
|
||||||
COPY --from=builder /app/web/dist ./web/dist
|
COPY --from=builder /app/web/dist ./web/dist
|
||||||
COPY --from=builder /app/package*.json ./
|
COPY --from=builder /app/package*.json ./
|
||||||
|
COPY --from=builder /app/node_modules ./node_modules
|
||||||
# Install production dependencies (includes ffmpeg-static, opus, sqlite3)
|
|
||||||
# These need to compile native addons inside the container
|
|
||||||
RUN npm ci --production && npm cache clean --force
|
|
||||||
|
|
||||||
# Remove build tools to reduce image size
|
|
||||||
RUN apt-get purge -y python3 make g++ && apt-get autoremove -y && \
|
|
||||||
rm -rf /var/lib/apt/lists/*
|
|
||||||
|
|
||||||
# FFmpeg is bundled via ffmpeg-static — no system ffmpeg needed
|
|
||||||
|
|
||||||
# Data directory for database, cookies, logs
|
# Data directory for database, cookies, logs
|
||||||
RUN mkdir -p /app/data
|
RUN mkdir -p /app/data
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
# TSMusicBot — Docker Compose
|
# TSMusicBot — Docker Compose
|
||||||
# 一键部署:docker-compose up -d
|
# 一键部署:docker-compose up -d
|
||||||
#
|
#
|
||||||
# 所有依赖已内置(Node.js, FFmpeg, Opus 编码器)
|
# 所有依赖已内置(Node.js, FFmpeg, Opus 编码器)无需安装任何额外软件
|
||||||
# 无需安装任何额外软件
|
# FFmpeg 使用系统包管理器安装,确保容器内兼容性
|
||||||
|
|
||||||
services:
|
services:
|
||||||
tsmusicbot:
|
tsmusicbot:
|
||||||
|
|||||||
+18
-7
@@ -35,28 +35,39 @@ function ffmpegWorks(bin: string): boolean {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Resolved once at module load — prefer bundled ffmpeg-static, fall back to system. */
|
/**
|
||||||
|
* Resolved once at module load.
|
||||||
|
*
|
||||||
|
* Priority: system FFmpeg → bundled ffmpeg-static.
|
||||||
|
*
|
||||||
|
* System-installed FFmpeg is always compatible with the running OS/container,
|
||||||
|
* while the pre-compiled binary from ffmpeg-static can SIGSEGV in Docker
|
||||||
|
* (passes `ffmpeg -version` but crashes during actual audio processing due to
|
||||||
|
* incompatible glibc or missing shared libraries).
|
||||||
|
*/
|
||||||
const resolvedFfmpeg: string = (() => {
|
const resolvedFfmpeg: string = (() => {
|
||||||
|
// 1. Prefer system-installed FFmpeg (always compatible with the runtime)
|
||||||
|
if (ffmpegWorks("ffmpeg")) {
|
||||||
|
return "ffmpeg";
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2. Fall back to bundled ffmpeg-static binary
|
||||||
// On Windows, ffmpeg-static may return a path with backslashes; on Linux/macOS
|
// On Windows, ffmpeg-static may return a path with backslashes; on Linux/macOS
|
||||||
// it may return a Windows .exe path if node_modules was copied cross-platform.
|
// it may return a Windows .exe path if node_modules was copied cross-platform.
|
||||||
const isWinPath = ffmpegPath ? /\\/.test(ffmpegPath) || ffmpegPath.endsWith(".exe") : false;
|
const isWinPath = ffmpegPath ? /\\/.test(ffmpegPath) || ffmpegPath.endsWith(".exe") : false;
|
||||||
const onWindows = process.platform === "win32";
|
const onWindows = process.platform === "win32";
|
||||||
|
|
||||||
// Only try bundled binary if platform matches
|
|
||||||
if (ffmpegPath && (onWindows === isWinPath)) {
|
if (ffmpegPath && (onWindows === isWinPath)) {
|
||||||
if (isExecutable(ffmpegPath) && ffmpegWorks(ffmpegPath)) {
|
if (isExecutable(ffmpegPath) && ffmpegWorks(ffmpegPath)) {
|
||||||
return ffmpegPath;
|
return ffmpegPath;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Fall back to system ffmpeg
|
|
||||||
if (ffmpegWorks("ffmpeg")) {
|
|
||||||
return "ffmpeg";
|
|
||||||
}
|
|
||||||
// Last resort: always use "ffmpeg" so spawn error is clear, never use a cross-platform path
|
// Last resort: always use "ffmpeg" so spawn error is clear, never use a cross-platform path
|
||||||
return "ffmpeg";
|
return "ffmpeg";
|
||||||
})();
|
})();
|
||||||
|
|
||||||
/** Resolve ffmpeg binary: prefer bundled ffmpeg-static, fall back to system PATH. */
|
/** Resolve ffmpeg binary: prefer system PATH, fall back to bundled ffmpeg-static. */
|
||||||
function getFfmpegCommand(): string {
|
function getFfmpegCommand(): string {
|
||||||
return resolvedFfmpeg;
|
return resolvedFfmpeg;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in new issue
Block a user