Add Docker configuration with Node.js server and maintenance page
This commit is contained in:
parent
7ce9623467
commit
57aaab43f1
@ -1,55 +1,127 @@
|
|||||||
# Use Node 18 Alpine as the base image for smaller size
|
# Self-contained Dockerfile that creates all necessary files
|
||||||
FROM node:18-alpine AS base
|
FROM node:16-alpine
|
||||||
|
|
||||||
# Install dependencies only when needed
|
# Create app directory
|
||||||
FROM base AS deps
|
|
||||||
# Check https://github.com/nodejs/docker-node/tree/b4117f9333da4138b03a546ec926ef50a31506c3#nodealpine to understand why libc6-compat might be needed.
|
|
||||||
RUN apk add --no-cache libc6-compat
|
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
|
|
||||||
# Copy package.json and package-lock.json
|
# Create server.js file directly in the Dockerfile
|
||||||
COPY package.json package-lock.json* ./
|
RUN echo 'const http = require("http");\n\
|
||||||
RUN npm ci
|
const fs = require("fs");\n\
|
||||||
|
const path = require("path");\n\
|
||||||
# Rebuild the source code only when needed
|
\n\
|
||||||
FROM base AS builder
|
// Create the src/app directory if it doesn\'t exist\n\
|
||||||
WORKDIR /app
|
fs.mkdirSync(path.join(__dirname, "src", "app"), { recursive: true });\n\
|
||||||
COPY --from=deps /app/node_modules ./node_modules
|
\n\
|
||||||
COPY . .
|
// Create a simple HTML file\n\
|
||||||
|
const htmlContent = `<!DOCTYPE html>\n\
|
||||||
|
<html lang="en">\n\
|
||||||
|
<head>\n\
|
||||||
|
<meta charset="UTF-8">\n\
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">\n\
|
||||||
|
<title>My Favorites - Maintenance</title>\n\
|
||||||
|
<style>\n\
|
||||||
|
body {\n\
|
||||||
|
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;\n\
|
||||||
|
background-color: #f5f5f0;\n\
|
||||||
|
color: #333;\n\
|
||||||
|
display: flex;\n\
|
||||||
|
flex-direction: column;\n\
|
||||||
|
align-items: center;\n\
|
||||||
|
justify-content: center;\n\
|
||||||
|
height: 100vh;\n\
|
||||||
|
margin: 0;\n\
|
||||||
|
padding: 20px;\n\
|
||||||
|
text-align: center;\n\
|
||||||
|
}\n\
|
||||||
|
.container {\n\
|
||||||
|
max-width: 600px;\n\
|
||||||
|
padding: 40px;\n\
|
||||||
|
background-color: white;\n\
|
||||||
|
border-radius: 8px;\n\
|
||||||
|
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);\n\
|
||||||
|
}\n\
|
||||||
|
h1 {\n\
|
||||||
|
color: #3b82f6;\n\
|
||||||
|
margin-bottom: 16px;\n\
|
||||||
|
}\n\
|
||||||
|
p {\n\
|
||||||
|
line-height: 1.6;\n\
|
||||||
|
margin-bottom: 24px;\n\
|
||||||
|
}\n\
|
||||||
|
</style>\n\
|
||||||
|
</head>\n\
|
||||||
|
<body>\n\
|
||||||
|
<div class="container">\n\
|
||||||
|
<h1>My Favorites</h1>\n\
|
||||||
|
<p>Our application is currently undergoing maintenance. We\'ll be back shortly with a collection of books, movies, series, and more that have made an impression.</p>\n\
|
||||||
|
<p>Thank you for your patience!</p>\n\
|
||||||
|
</div>\n\
|
||||||
|
</body>\n\
|
||||||
|
</html>`;\n\
|
||||||
|
\n\
|
||||||
|
fs.writeFileSync(path.join(__dirname, "src", "app", "index.html"), htmlContent);\n\
|
||||||
|
\n\
|
||||||
|
// Create HTTP server\n\
|
||||||
|
const server = http.createServer((req, res) => {\n\
|
||||||
|
console.log(`Request received: ${req.method} ${req.url}`);\n\
|
||||||
|
\n\
|
||||||
|
// Health check endpoint\n\
|
||||||
|
if (req.url === "/health" || req.url === "/api/health") {\n\
|
||||||
|
res.writeHead(200, { "Content-Type": "application/json" });\n\
|
||||||
|
res.end(JSON.stringify({ status: "ok", timestamp: new Date().toISOString() }));\n\
|
||||||
|
return;\n\
|
||||||
|
}\n\
|
||||||
|
\n\
|
||||||
|
// Serve static HTML for all other routes\n\
|
||||||
|
const indexPath = path.join(__dirname, "src", "app", "index.html");\n\
|
||||||
|
fs.readFile(indexPath, (err, content) => {\n\
|
||||||
|
if (err) {\n\
|
||||||
|
res.writeHead(500);\n\
|
||||||
|
res.end("Error loading index.html");\n\
|
||||||
|
console.error("Error serving index.html:", err);\n\
|
||||||
|
return;\n\
|
||||||
|
}\n\
|
||||||
|
\n\
|
||||||
|
res.writeHead(200, { "Content-Type": "text/html" });\n\
|
||||||
|
res.end(content);\n\
|
||||||
|
});\n\
|
||||||
|
});\n\
|
||||||
|
\n\
|
||||||
|
// Start the server\n\
|
||||||
|
const PORT = process.env.PORT || 3000;\n\
|
||||||
|
server.listen(PORT, () => {\n\
|
||||||
|
console.log(`Server running on port ${PORT}`);\n\
|
||||||
|
console.log(`Environment: ${process.env.NODE_ENV || "development"}`);\n\
|
||||||
|
});\n\
|
||||||
|
\n\
|
||||||
|
// Handle errors\n\
|
||||||
|
server.on("error", (err) => {\n\
|
||||||
|
console.error("Server error:", err);\n\
|
||||||
|
});\n\
|
||||||
|
\n\
|
||||||
|
// Handle process termination\n\
|
||||||
|
process.on("SIGTERM", () => {\n\
|
||||||
|
console.log("SIGTERM received, shutting down gracefully");\n\
|
||||||
|
server.close(() => {\n\
|
||||||
|
console.log("Server closed");\n\
|
||||||
|
process.exit(0);\n\
|
||||||
|
});\n\
|
||||||
|
});\n\
|
||||||
|
\n\
|
||||||
|
process.on("uncaughtException", (err) => {\n\
|
||||||
|
console.error("Uncaught exception:", err);\n\
|
||||||
|
});\n\
|
||||||
|
\n\
|
||||||
|
process.on("unhandledRejection", (reason) => {\n\
|
||||||
|
console.error("Unhandled rejection:", reason);\n\
|
||||||
|
});' > server.js
|
||||||
|
|
||||||
# Set environment variables
|
# Set environment variables
|
||||||
ENV NEXT_TELEMETRY_DISABLED 1
|
ENV NODE_ENV=production
|
||||||
|
ENV PORT=3000
|
||||||
# Build the application
|
|
||||||
RUN npm run build
|
|
||||||
|
|
||||||
# Production image, copy all the files and run next
|
|
||||||
FROM base AS runner
|
|
||||||
WORKDIR /app
|
|
||||||
|
|
||||||
ENV NODE_ENV production
|
|
||||||
ENV NEXT_TELEMETRY_DISABLED 1
|
|
||||||
|
|
||||||
RUN addgroup --system --gid 1001 nodejs
|
|
||||||
RUN adduser --system --uid 1001 nextjs
|
|
||||||
|
|
||||||
# Copy necessary files from the builder stage
|
|
||||||
COPY --from=builder /app/public ./public
|
|
||||||
|
|
||||||
# Set the correct permissions
|
|
||||||
RUN mkdir .next
|
|
||||||
RUN chown nextjs:nodejs .next
|
|
||||||
|
|
||||||
# Automatically leverage output traces to reduce image size
|
|
||||||
COPY --from=builder --chown=nextjs:nodejs /app/.next/standalone ./
|
|
||||||
COPY --from=builder --chown=nextjs:nodejs /app/.next/static ./.next/static
|
|
||||||
|
|
||||||
USER nextjs
|
|
||||||
|
|
||||||
|
# Expose the port
|
||||||
EXPOSE 3000
|
EXPOSE 3000
|
||||||
|
|
||||||
ENV PORT 3000
|
# Start the server
|
||||||
ENV HOSTNAME "0.0.0.0"
|
|
||||||
|
|
||||||
# Start the application
|
|
||||||
CMD ["node", "server.js"]
|
CMD ["node", "server.js"]
|
||||||
|
|||||||
16
my-favorites-app/docker-compose.yml
Normal file
16
my-favorites-app/docker-compose.yml
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
version: '3'
|
||||||
|
|
||||||
|
services:
|
||||||
|
app:
|
||||||
|
build: .
|
||||||
|
ports:
|
||||||
|
- "3000:3000"
|
||||||
|
environment:
|
||||||
|
- NODE_ENV=production
|
||||||
|
- PORT=3000
|
||||||
|
restart: always
|
||||||
|
healthcheck:
|
||||||
|
test: ["CMD", "wget", "--spider", "http://localhost:3000/health"]
|
||||||
|
interval: 10s
|
||||||
|
timeout: 5s
|
||||||
|
retries: 3
|
||||||
Loading…
x
Reference in New Issue
Block a user