test this
This commit is contained in:
@@ -1,39 +0,0 @@
|
|||||||
# Dependencies
|
|
||||||
node_modules
|
|
||||||
npm-debug.log
|
|
||||||
yarn-debug.log
|
|
||||||
yarn-error.log
|
|
||||||
|
|
||||||
# Next.js build output
|
|
||||||
.next
|
|
||||||
out
|
|
||||||
|
|
||||||
# Environment files
|
|
||||||
.env
|
|
||||||
.env.local
|
|
||||||
.env.development.local
|
|
||||||
.env.test.local
|
|
||||||
.env.production.local
|
|
||||||
|
|
||||||
# Version control
|
|
||||||
.git
|
|
||||||
.gitignore
|
|
||||||
|
|
||||||
# IDE files
|
|
||||||
.idea
|
|
||||||
.vscode
|
|
||||||
*.swp
|
|
||||||
*.swo
|
|
||||||
|
|
||||||
# OS files
|
|
||||||
.DS_Store
|
|
||||||
Thumbs.db
|
|
||||||
|
|
||||||
# Docker files
|
|
||||||
Dockerfile
|
|
||||||
.dockerignore
|
|
||||||
manage_container.sh
|
|
||||||
|
|
||||||
# Additional files
|
|
||||||
posts/admin.json
|
|
||||||
posts/admin.json.tmp
|
|
||||||
@@ -1 +1,2 @@
|
|||||||
NEXT_PUBLIC_BLOG_OWNER=Rattatwinko
|
NEXT_PUBLIC_BLOG_OWNER=Rattatwinko
|
||||||
|
PORT=8080
|
||||||
50
Dockerfile
50
Dockerfile
@@ -1,57 +1,23 @@
|
|||||||
# Build stage
|
# Use the official Node.js image as the base image
|
||||||
FROM node:18-alpine AS builder
|
FROM node:14
|
||||||
|
|
||||||
# Set working directory
|
# Set the working directory
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
|
|
||||||
# Copy package files
|
# Copy package.json and package-lock.json
|
||||||
COPY package*.json ./
|
COPY package*.json ./
|
||||||
|
|
||||||
# First install only production dependencies
|
# Install dependencies
|
||||||
RUN npm install --omit=dev
|
RUN npm install
|
||||||
|
|
||||||
# Copy source code and config files
|
# Copy the rest of the application code
|
||||||
COPY . .
|
COPY . .
|
||||||
|
|
||||||
# Build the application
|
# Build the application
|
||||||
RUN npm run build
|
RUN npm run build
|
||||||
|
|
||||||
# Production stage
|
# Expose the port the app runs on
|
||||||
FROM node:18-alpine AS runner
|
|
||||||
|
|
||||||
# Set working directory
|
|
||||||
WORKDIR /app
|
|
||||||
|
|
||||||
# Copy package files
|
|
||||||
COPY --from=builder /app/package*.json ./
|
|
||||||
|
|
||||||
# Install production dependencies only
|
|
||||||
RUN npm install --omit=dev
|
|
||||||
|
|
||||||
# Copy necessary files from builder
|
|
||||||
COPY --from=builder /app/.next ./.next/
|
|
||||||
COPY --from=builder /app/public ./public/
|
|
||||||
COPY --from=builder /app/next.config.js ./
|
|
||||||
|
|
||||||
# Create a directory for markdown files
|
|
||||||
RUN mkdir -p /markdown
|
|
||||||
|
|
||||||
# Set environment variables
|
|
||||||
ENV NODE_ENV=production
|
|
||||||
ENV PORT=8080
|
|
||||||
ENV HOSTNAME=0.0.0.0
|
|
||||||
|
|
||||||
# Expose the port
|
|
||||||
EXPOSE 8080
|
EXPOSE 8080
|
||||||
|
|
||||||
# Health check
|
|
||||||
HEALTHCHECK --interval=30s --timeout=30s --start-period=5s --retries=3 \
|
|
||||||
CMD wget --no-verbose --tries=1 --spider http://localhost:8080/ || exit 1
|
|
||||||
|
|
||||||
# Start the application
|
# Start the application
|
||||||
CMD ["npm", "start"]
|
CMD ["npm", "start"]
|
||||||
|
|
||||||
# Do NOT copy posts/admin.json or posts/admin.json.tmp into the image
|
|
||||||
# These files are excluded via .dockerignore for security
|
|
||||||
# In production, mount the posts directory as a volume to persist posts and admin password
|
|
||||||
# If posts/admin.json does not exist, the default admin password is 'admin' (see README)
|
|
||||||
@@ -1,312 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
|
|
||||||
# Configuration
|
|
||||||
IMAGE_NAME="markdown-blog"
|
|
||||||
CONTAINER_NAME="markdown-blog-container"
|
|
||||||
PORT=8080
|
|
||||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
||||||
MARKDOWN_DIR="$SCRIPT_DIR" # Use the script's directory as the default markdown directory
|
|
||||||
|
|
||||||
# Colors for output
|
|
||||||
RED='\033[0;31m'
|
|
||||||
GREEN='\033[0;32m'
|
|
||||||
YELLOW='\033[1;33m'
|
|
||||||
BLUE='\033[0;34m'
|
|
||||||
NC='\033[0m' # No Color
|
|
||||||
|
|
||||||
# Function to check if Docker is running
|
|
||||||
check_docker() {
|
|
||||||
if ! docker info > /dev/null 2>&1; then
|
|
||||||
echo -e "${RED}Error: Docker is not running. Please start Docker and try again.${NC}"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
# Function to check if container exists
|
|
||||||
container_exists() {
|
|
||||||
docker ps -a --format '{{.Names}}' | grep -q "^${CONTAINER_NAME}$"
|
|
||||||
}
|
|
||||||
|
|
||||||
# Function to check if container is running
|
|
||||||
container_running() {
|
|
||||||
docker ps --format '{{.Names}}' | grep -q "^${CONTAINER_NAME}$"
|
|
||||||
}
|
|
||||||
|
|
||||||
# Function to check container health
|
|
||||||
check_container_health() {
|
|
||||||
local health_status
|
|
||||||
health_status=$(docker inspect --format='{{.State.Health.Status}}' "$CONTAINER_NAME" 2>/dev/null)
|
|
||||||
if [ "$health_status" = "healthy" ]; then
|
|
||||||
return 0
|
|
||||||
else
|
|
||||||
return 1
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
# Fun spinner and jokes for npm build (right-aligned, rainbow)
|
|
||||||
npm_spinner_right() {
|
|
||||||
local pid=$1
|
|
||||||
local delay=0.15
|
|
||||||
local spinstr='|/-\\'
|
|
||||||
local jokes=(
|
|
||||||
"NPM is downloading the entire internet..."
|
|
||||||
"TypeScript: It's like JavaScript, but with more errors!"
|
|
||||||
"JavaScript: Where '1' + 1 = '11'!"
|
|
||||||
"NPM: Installing 1000 dependencies for 'hello world'..."
|
|
||||||
"TypeScript: Making JavaScript developers feel safe (sometimes)."
|
|
||||||
)
|
|
||||||
local colors=(31 33 32 36 34 35) # Red, Yellow, Green, Cyan, Blue, Magenta
|
|
||||||
local joke_index=0
|
|
||||||
tput civis # Hide cursor
|
|
||||||
while kill -0 "$pid" 2>/dev/null; do
|
|
||||||
local temp="${spinstr#?}"
|
|
||||||
local cols=$(tput cols)
|
|
||||||
local msg="[%c] %s"
|
|
||||||
local joke="${jokes[$joke_index]}"
|
|
||||||
local out
|
|
||||||
printf -v out "$msg" "$spinstr" "$joke"
|
|
||||||
local pad=$((cols - ${#out} - 1))
|
|
||||||
[ $pad -lt 0 ] && pad=0
|
|
||||||
# Rainbow coloring
|
|
||||||
local rainbow=""
|
|
||||||
local i=0
|
|
||||||
local len=${#out}
|
|
||||||
while [ $i -lt $len ]; do
|
|
||||||
local c="${out:$i:1}"
|
|
||||||
local color=${colors[$((i % ${#colors[@]}))]}
|
|
||||||
rainbow+="\033[${color}m$c\033[0m"
|
|
||||||
i=$((i+1))
|
|
||||||
done
|
|
||||||
printf "\r%*s%s" $pad "" "$rainbow"
|
|
||||||
spinstr=$temp${spinstr%$temp}
|
|
||||||
sleep $delay
|
|
||||||
joke_index=$(( (joke_index + 1) % ${#jokes[@]} ))
|
|
||||||
done
|
|
||||||
printf "\r"
|
|
||||||
tput cnorm # Restore cursor
|
|
||||||
}
|
|
||||||
|
|
||||||
# Function to build the Docker image (show spinner/jokes only during npm ci)
|
|
||||||
build_image() {
|
|
||||||
echo -e "${YELLOW}Building Docker image...${NC}"
|
|
||||||
local pipe=$(mktemp -u)
|
|
||||||
mkfifo "$pipe"
|
|
||||||
(docker build -t "$IMAGE_NAME" . | tee "$pipe") &
|
|
||||||
build_pid=$!
|
|
||||||
while read -r line; do
|
|
||||||
echo "$line"
|
|
||||||
if [[ "$line" == *"RUN npm ci"* ]]; then
|
|
||||||
sleep 1
|
|
||||||
npm_spinner_right "$build_pid" &
|
|
||||||
spinner_pid=$!
|
|
||||||
wait "$build_pid"
|
|
||||||
kill "$spinner_pid" 2>/dev/null
|
|
||||||
break
|
|
||||||
fi
|
|
||||||
done < "$pipe"
|
|
||||||
wait "$build_pid"
|
|
||||||
rm -f "$pipe"
|
|
||||||
if [ $? -ne 0 ]; then
|
|
||||||
echo -e "${RED}Error: Failed to build Docker image. Check logs above.${NC}"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
echo -e "${GREEN}Docker image built successfully!${NC}"
|
|
||||||
}
|
|
||||||
|
|
||||||
# Function to start the container
|
|
||||||
start_container() {
|
|
||||||
echo -e "${YELLOW}Starting container...${NC}"
|
|
||||||
if container_exists; then
|
|
||||||
if container_running; then
|
|
||||||
echo -e "${YELLOW}Container is already running.${NC}"
|
|
||||||
return
|
|
||||||
else
|
|
||||||
echo -e "${YELLOW}Restarting existing container...${NC}"
|
|
||||||
docker start "$CONTAINER_NAME" || {
|
|
||||||
echo -e "${RED}Error: Failed to start container.${NC}"
|
|
||||||
exit 1
|
|
||||||
}
|
|
||||||
fi
|
|
||||||
else
|
|
||||||
echo -e "${BLUE}Creating and starting new container...${NC}"
|
|
||||||
docker run -d \
|
|
||||||
--name "$CONTAINER_NAME" \
|
|
||||||
-p "$PORT:8080" \
|
|
||||||
-v "$MARKDOWN_DIR:/markdown" \
|
|
||||||
--restart unless-stopped \
|
|
||||||
--health-cmd="curl -f http://localhost:8080/ || exit 1" \
|
|
||||||
--health-interval=30s \
|
|
||||||
--health-timeout=10s \
|
|
||||||
--health-retries=3 \
|
|
||||||
"$IMAGE_NAME" || {
|
|
||||||
echo -e "${RED}Error: Failed to create container.${NC}"
|
|
||||||
exit 1
|
|
||||||
}
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Wait for container to be healthy
|
|
||||||
echo -e "${YELLOW}Waiting for container to be ready...${NC}"
|
|
||||||
local max_attempts=30
|
|
||||||
local attempt=1
|
|
||||||
while [ $attempt -le $max_attempts ]; do
|
|
||||||
if check_container_health; then
|
|
||||||
echo -e "${GREEN}Container is healthy! Access it at: http://localhost:$PORT${NC}"
|
|
||||||
return
|
|
||||||
fi
|
|
||||||
printf "."
|
|
||||||
sleep 1
|
|
||||||
attempt=$((attempt + 1))
|
|
||||||
done
|
|
||||||
echo -e "${RED}Error: Container did not become healthy. Check logs with './manage_container.sh logs'.${NC}"
|
|
||||||
exit 1
|
|
||||||
}
|
|
||||||
|
|
||||||
# Function to stop the container
|
|
||||||
stop_container() {
|
|
||||||
echo -e "${YELLOW}Stopping container...${NC}"
|
|
||||||
if ! container_exists; then
|
|
||||||
echo -e "${YELLOW}Container does not exist.${NC}"
|
|
||||||
return
|
|
||||||
fi
|
|
||||||
docker stop "$CONTAINER_NAME" || {
|
|
||||||
echo -e "${RED}Error: Failed to stop container.${NC}"
|
|
||||||
exit 1
|
|
||||||
}
|
|
||||||
echo -e "${GREEN}Container stopped successfully.${NC}"
|
|
||||||
}
|
|
||||||
|
|
||||||
# Function to remove the container
|
|
||||||
remove_container() {
|
|
||||||
echo -e "${YELLOW}Removing container...${NC}"
|
|
||||||
if ! container_exists; then
|
|
||||||
echo -e "${YELLOW}Container does not exist.${NC}"
|
|
||||||
return
|
|
||||||
fi
|
|
||||||
if container_running; then
|
|
||||||
stop_container
|
|
||||||
fi
|
|
||||||
docker rm "$CONTAINER_NAME" || {
|
|
||||||
echo -e "${RED}Error: Failed to remove container.${NC}"
|
|
||||||
exit 1
|
|
||||||
}
|
|
||||||
echo -e "${GREEN}Container removed successfully.${NC}"
|
|
||||||
}
|
|
||||||
|
|
||||||
# Function to restart the container
|
|
||||||
restart_container() {
|
|
||||||
echo -e "${YELLOW}Restarting container...${NC}"
|
|
||||||
if ! container_exists; then
|
|
||||||
echo -e "${YELLOW}Container does not exist. Starting new one...${NC}"
|
|
||||||
start_container
|
|
||||||
return
|
|
||||||
fi
|
|
||||||
docker restart "$CONTAINER_NAME" || {
|
|
||||||
echo -e "${RED}Error: Failed to restart container.${NC}"
|
|
||||||
exit 1
|
|
||||||
}
|
|
||||||
echo -e "${GREEN}Container restarted successfully.${NC}"
|
|
||||||
}
|
|
||||||
|
|
||||||
# Function to view logs
|
|
||||||
view_logs() {
|
|
||||||
echo -e "${YELLOW}Viewing logs...${NC}"
|
|
||||||
if ! container_exists; then
|
|
||||||
echo -e "${RED}Error: Container does not exist.${NC}"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
docker logs -f "$CONTAINER_NAME"
|
|
||||||
}
|
|
||||||
|
|
||||||
# Function to show container status
|
|
||||||
show_status() {
|
|
||||||
echo -e "${YELLOW}Container Status:${NC}"
|
|
||||||
if ! container_exists; then
|
|
||||||
echo -e "${RED}Container does not exist.${NC}"
|
|
||||||
return
|
|
||||||
fi
|
|
||||||
if container_running; then
|
|
||||||
local health_status
|
|
||||||
health_status=$(docker inspect --format='{{.State.Health.Status}}' "$CONTAINER_NAME" 2>/dev/null)
|
|
||||||
echo -e "${GREEN}Container is running.${NC}"
|
|
||||||
echo -e "Health: ${health_status}"
|
|
||||||
echo -e
|
|
||||||
else
|
|
||||||
echo -e "${YELLOW}Container exists but is not running${NC}"
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
# Function to auto-deploy: remove old container, build fresh image, start new container
|
|
||||||
autodeploy() {
|
|
||||||
echo -e "${YELLOW}Auto-deploying: remove old container, build fresh image, start new container...${NC}"
|
|
||||||
remove_container
|
|
||||||
echo -e "${YELLOW}Building Docker image (no cache)...${NC}"
|
|
||||||
build_image
|
|
||||||
start_container
|
|
||||||
}
|
|
||||||
|
|
||||||
# Check Docker is running before proceeding
|
|
||||||
check_docker
|
|
||||||
|
|
||||||
# Main script logic
|
|
||||||
case "$1" in
|
|
||||||
build)
|
|
||||||
build_image
|
|
||||||
;;
|
|
||||||
start)
|
|
||||||
start_container
|
|
||||||
;;
|
|
||||||
stop)
|
|
||||||
stop_container
|
|
||||||
;;
|
|
||||||
restart)
|
|
||||||
restart_container
|
|
||||||
;;
|
|
||||||
logs)
|
|
||||||
view_logs
|
|
||||||
;;
|
|
||||||
status)
|
|
||||||
show_status
|
|
||||||
;;
|
|
||||||
remove)
|
|
||||||
remove_container
|
|
||||||
;;
|
|
||||||
autodeploy)
|
|
||||||
autodeploy
|
|
||||||
;;
|
|
||||||
*)
|
|
||||||
echo "Usage: $0 {build|start|stop|restart|logs|status|remove|autodeploy}"
|
|
||||||
exit 1
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
|
|
||||||
# Record script start time
|
|
||||||
SCRIPT_START_TIME=$(date +%s)
|
|
||||||
exit 0
|
|
||||||
|
|
||||||
# At the very end, print a marathon joke with elapsed time
|
|
||||||
SCRIPT_END_TIME=$(date +%s)
|
|
||||||
ELAPSED=$((SCRIPT_END_TIME - SCRIPT_START_TIME))
|
|
||||||
MIN=$((ELAPSED / 60))
|
|
||||||
SEC=$((ELAPSED % 60))
|
|
||||||
HOUR=$((ELAPSED / 3600))
|
|
||||||
DAY=$((ELAPSED / 86400))
|
|
||||||
|
|
||||||
if [ $ELAPSED -lt 60 ]; then
|
|
||||||
TIME_STR="$ELAPSED seconds"
|
|
||||||
elif [ $ELAPSED -lt 3600 ]; then
|
|
||||||
TIME_STR="$MIN minutes, $SEC seconds"
|
|
||||||
elif [ $ELAPSED -lt 86400 ]; then
|
|
||||||
TIME_STR="$HOUR hours, $(( (ELAPSED % 3600) / 60 )) minutes"
|
|
||||||
else
|
|
||||||
TIME_STR="$DAY days, $(( (ELAPSED % 86400) / 3600 )) hours"
|
|
||||||
fi
|
|
||||||
|
|
||||||
JOKES=(
|
|
||||||
"Marathon complete! NPM wasted: $TIME_STR."
|
|
||||||
"Build finished! JavaScript has evolved $TIME_STR into a new framework."
|
|
||||||
"Done! TypeScript found $TIME_STR worth of new types."
|
|
||||||
"Success! NPM installed $TIME_STR of dependencies you'll never use."
|
|
||||||
"Victory! You survived $TIME_STR of NPM's existential dread."
|
|
||||||
)
|
|
||||||
JOKE_INDEX=$((RANDOM % ${#JOKES[@]}))
|
|
||||||
echo -e "\n\033[1;32m${JOKES[$JOKE_INDEX]}\033[0m"
|
|
||||||
@@ -3,10 +3,9 @@ const nextConfig = {
|
|||||||
output: 'standalone',
|
output: 'standalone',
|
||||||
reactStrictMode: true,
|
reactStrictMode: true,
|
||||||
swcMinify: true,
|
swcMinify: true,
|
||||||
// Ensure we can access the app from outside the container
|
server: {
|
||||||
experimental: {
|
port: 8080,
|
||||||
outputFileTracingRoot: undefined,
|
},
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = nextConfig
|
module.exports = nextConfig
|
||||||
Reference in New Issue
Block a user