forked from rohit-purandare/ShelfBridge
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathDockerfile
More file actions
116 lines (99 loc) · 6.32 KB
/
Dockerfile
File metadata and controls
116 lines (99 loc) · 6.32 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
# syntax=docker/dockerfile:1.4
# ===== BUILD STAGE =====
FROM node:20-alpine as builder
# Install build dependencies for native modules
RUN apk add --no-cache \
python3 \
make \
g++
# Set build environment variables
ENV npm_config_build_from_source=true \
npm_config_better_sqlite3_binary_host_mirror="" \
npm_config_sqlite3_binary_host_mirror="" \
npm_config_sqlite3_static_link=true \
npm_config_target_platform=linux \
PYTHON=/usr/bin/python3
WORKDIR /app
# Copy package files first for better caching
COPY package*.json ./
# Install dependencies and build native modules with comprehensive validation
RUN --mount=type=cache,target=/root/.npm \
--mount=type=cache,target=/tmp/build-cache \
set -e && \
echo "🔧 Installing dependencies with BuildKit cache..." && \
npm ci --omit=dev --ignore-scripts && \
echo "🔧 Building better-sqlite3 from source..." && \
npm rebuild better-sqlite3 --verbose && \
echo "🧪 COMPREHENSIVE BETTER-SQLITE3 TESTING:" && \
echo "Test 1: Basic module loading..." && \
node -e "const db = require('better-sqlite3'); console.log('✅ Module loads successfully');" && \
echo "Test 2: In-memory database creation..." && \
node -e "const db = require('better-sqlite3')(':memory:'); console.log('✅ In-memory DB works');" && \
echo "Test 3: Table creation and operations..." && \
node -e "const db = require('better-sqlite3')(':memory:'); db.exec('CREATE TABLE test (id INTEGER PRIMARY KEY, name TEXT)'); console.log('✅ Table creation works');" && \
echo "Test 4: Insert and query operations..." && \
node -e "const db = require('better-sqlite3')(':memory:'); db.exec('CREATE TABLE test (id INTEGER PRIMARY KEY, name TEXT)'); const stmt = db.prepare('INSERT INTO test (name) VALUES (?)'); stmt.run('test'); const row = db.prepare('SELECT * FROM test WHERE name = ?').get('test'); if (row.name !== 'test') throw new Error('Query failed'); console.log('✅ Insert/Query operations work');" && \
echo "Test 5: File database operations..." && \
node -e "const db = require('better-sqlite3')('/tmp/test.db'); db.exec('CREATE TABLE test (id INTEGER)'); db.exec('INSERT INTO test (id) VALUES (1)'); const count = db.prepare('SELECT COUNT(*) as count FROM test').get().count; if (count !== 1) throw new Error('File DB failed'); db.close(); require('fs').unlinkSync('/tmp/test.db'); console.log('✅ File database operations work');" && \
echo "Test 6: Transaction support..." && \
node -e "const db = require('better-sqlite3')(':memory:'); db.exec('CREATE TABLE test (id INTEGER)'); const transaction = db.transaction(() => { db.prepare('INSERT INTO test (id) VALUES (?)').run(1); db.prepare('INSERT INTO test (id) VALUES (?)').run(2); }); transaction(); const count = db.prepare('SELECT COUNT(*) as count FROM test').get().count; if (count !== 2) throw new Error('Transaction failed'); console.log('✅ Transaction support works');" && \
echo "Test 7: Prepared statements with parameters..." && \
node -e "const db = require('better-sqlite3')(':memory:'); db.exec('CREATE TABLE test (id INTEGER, value TEXT)'); const insert = db.prepare('INSERT INTO test (id, value) VALUES (?, ?)'); insert.run(1, 'hello'); insert.run(2, 'world'); const rows = db.prepare('SELECT * FROM test ORDER BY id').all(); if (rows.length !== 2 || rows[0].value !== 'hello') throw new Error('Prepared statements failed'); console.log('✅ Prepared statements work');" && \
echo "🎉 ALL BETTER-SQLITE3 TESTS PASSED - MODULE IS FULLY FUNCTIONAL!" && \
echo "🎯 BETTER-SQLITE3 IS NOW ROBUST AND PRODUCTION-READY!" && \
echo "🔧 VERIFYING ALPINE MUSL COMPATIBILITY..." && \
ldd --version 2>/dev/null || echo "Using musl libc (no ldd)" && \
echo "🔧 CHECKING BETTER-SQLITE3 SHARED LIBRARY DEPENDENCIES..." && \
ldd /app/node_modules/better-sqlite3/build/Release/better_sqlite3.node 2>/dev/null || echo "Static linking detected - no external dependencies" && \
echo "🎯 ALPINE MUSL COMPATIBILITY VERIFIED!"
# ===== RUNTIME STAGE =====
FROM node:20-alpine as runtime
# Install runtime dependencies (dumb-init for proper signal handling, and su-exec for user switching)
RUN apk add --no-cache \
su-exec \
dumb-init
WORKDIR /app
# Copy package files for reference
COPY package*.json ./
# Copy ONLY the compiled node_modules from builder stage (no build tools)
COPY --from=builder /app/node_modules ./node_modules
# Copy source code (includes config/config.yaml.example for reference)
COPY . .
# Copy entrypoint script and make it executable
COPY docker-entrypoint.sh /usr/local/bin/
RUN chmod +x /usr/local/bin/docker-entrypoint.sh
# Create template directory and copy sample config for auto-provisioning
# Only copy if the file exists (for development builds)
RUN mkdir -p /app/.config-template && \
if [ -f "/app/config/config.yaml.example" ]; then \
cp /app/config/config.yaml.example /app/.config-template/config.yaml.example; \
else \
echo "# Sample configuration file" > /app/.config-template/config.yaml.example; \
echo "# Copy this file to config.yaml and edit with your credentials" >> /app/.config-template/config.yaml.example; \
fi
# Create logs directory with proper permissions for node user
# Alpine's node user has UID 1000 by default
RUN mkdir -p logs data config && \
chmod 755 logs data config && \
chown -R node:node /app
# Add comprehensive health check to ensure better-sqlite3 is always working
# This performs multiple operations to catch any runtime issues
HEALTHCHECK --interval=30s --timeout=15s --start-period=20s --retries=3 \
CMD node -e " \
try { \
const db = require('better-sqlite3')(':memory:'); \
db.exec('CREATE TABLE health_check (id INTEGER PRIMARY KEY, timestamp TEXT)'); \
const stmt = db.prepare('INSERT INTO health_check (timestamp) VALUES (?)'); \
stmt.run(new Date().toISOString()); \
const count = db.prepare('SELECT COUNT(*) as count FROM health_check').get().count; \
if (count !== 1) throw new Error('Health check failed'); \
db.close(); \
} catch (e) { \
console.error('better-sqlite3 health check failed:', e.message); \
process.exit(1); \
} \
" || exit 1
# Container configuration
EXPOSE 3000
ENTRYPOINT ["/usr/local/bin/docker-entrypoint.sh"]
CMD ["npm", "start"]