diff --git a/Dockerfile b/Dockerfile index 0405677..86fdc57 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,57 +1,39 @@ FROM node:23.7.0-alpine -RUN npm install -g npm@11.1.0 - -# Install dependencies with versions -RUN sysctl -w vm.overcommit_memory=1 && \ +# Install dependencies and setup environment in a single layer +RUN npm install -g npm@11.1.0 && \ apk add --no-cache \ - redis \ - mariadb \ - mariadb-client \ - tmux \ - mariadb-server-utils \ - mariadb-connector-c - -# Create non-root user -RUN addgroup -S appgroup && adduser -S appuser -G appgroup - -# Setup MariaDB with proper permissions -RUN mkdir -p /run/mysqld /var/lib/mysql /var/log/mysql && \ - chown -R mysql:mysql /run/mysqld && \ - chown -R mysql:mysql /var/lib/mysql && \ - chown -R mysql:mysql /var/log/mysql && \ - chmod 777 /run/mysqld && \ - chmod 777 /var/lib/mysql && \ - chmod 777 /var/log/mysql && \ + redis \ + mariadb \ + mariadb-client \ + tmux \ + mariadb-server-utils \ + mariadb-connector-c && \ + # Create non-root user and groups + addgroup -S appgroup && \ + adduser -S appuser -G appgroup && \ + adduser appuser mysql && \ + # Setup MariaDB directories and permissions + mkdir -p /run/mysqld /var/lib/mysql /var/log/mysql && \ + chown -R mysql:mysql /run/mysqld /var/lib/mysql /var/log/mysql && \ + chmod 755 /run/mysqld /var/lib/mysql /var/log/mysql && \ mysql_install_db --user=mysql --datadir=/var/lib/mysql && \ touch /var/log/mysql/error.log && \ chown mysql:mysql /var/log/mysql/error.log && \ - chmod 666 /var/log/mysql/error.log + chmod 644 /var/log/mysql/error.log WORKDIR /usr/src/app + +# Copy application files COPY package*.json ./ COPY start.sh ./start.sh COPY . . +# Setup application permissions RUN npm ci --only=production && \ chmod +x ./start.sh && \ chown -R appuser:appgroup . -# Grant necessary permissions to appuser -RUN adduser appuser mysql && \ - chmod 755 /var/lib/mysql && \ - mkdir -p /var/log/mysql && \ - chown -R mysql:mysql /var/log/mysql && \ - touch /var/log/mysql/error.log && \ - chown mysql:mysql /var/log/mysql/error.log - -# Grant necessary permissions to appuser -RUN adduser appuser mysql && \ -# Give full access to mysql directories -chmod -R 777 /var/lib/mysql && \ -chmod -R 777 /run/mysqld && \ -chmod -R 777 /var/log/mysql - USER appuser EXPOSE 80 6379 3306 diff --git a/start.sh b/start.sh index d6f0ad9..9eecb82 100644 --- a/start.sh +++ b/start.sh @@ -1,87 +1,81 @@ #!/bin/sh -set -e +set -eo pipefail # Configuration MAX_MYSQL_WAIT=60 APP_NAME="nodeapp" +MYSQL_SOCKET="/run/mysqld/mysqld.sock" +MYSQL_PID="/run/mysqld/mysqld.pid" +MYSQL_ERROR_LOG="/var/log/mysql/error.log" # Cleanup function cleanup() { - echo "Cleaning up..." + echo "Shutting down services..." tmux kill-session -t $APP_NAME 2>/dev/null || true - redis-cli shutdown || true - mysqladmin -u root shutdown || true + redis-cli shutdown 2>/dev/null || true + if [ -f "$MYSQL_PID" ]; then + mysqladmin -u root shutdown 2>/dev/null || true + fi exit 0 } -# Setup cleanup trap +# Error handler +error_handler() { + echo "Error occurred in script at line: $1" + cleanup + exit 1 +} + trap cleanup SIGTERM SIGINT +trap 'error_handler ${LINENO}' ERR # Start Redis echo "Starting Redis..." redis-server --daemonize yes -if ! redis-cli ping > /dev/null 2>&1; then - echo "Failed to start Redis" - exit 1 -fi +until redis-cli ping > /dev/null 2>&1; do + sleep 1 +done +echo "Redis started successfully" # Start MySQL echo "Starting MySQL..." - -# Start MariaDB with specific options mariadbd \ --datadir=/var/lib/mysql \ - --pid-file=/run/mysqld/mysqld.pid \ - --socket=/run/mysqld/mysqld.sock \ - --log-error=/var/log/mysql/error.log \ + --pid-file=$MYSQL_PID \ + --socket=$MYSQL_SOCKET \ + --log-error=$MYSQL_ERROR_LOG \ --bind-address=0.0.0.0 & -# Wait for MySQL with timeout +# Wait for MySQL echo "Waiting for MySQL to be ready..." COUNTER=0 -while true; do - if mysqladmin ping -h localhost --silent 2>/dev/null; then - break - fi - - if [ $COUNTER -gt $MAX_MYSQL_WAIT ]; then - echo "MySQL failed to start within $MAX_MYSQL_WAIT seconds" - echo "Last few lines of MySQL error log:" - tail -n 20 /var/log/mysql/error.log - exit 1 - fi - +until mysqladmin ping -h localhost --silent 2>/dev/null || [ $COUNTER -gt $MAX_MYSQL_WAIT ]; do echo "Still waiting... (${COUNTER}s)" sleep 2 COUNTER=$((COUNTER+2)) done -echo "MySQL is ready!" -# Run migrations with error handling -echo "Running database migrations..." -if ! npx mikro-orm-esm migration:up; then - echo "Migration failed" +if [ $COUNTER -gt $MAX_MYSQL_WAIT ]; then + echo "MySQL failed to start within $MAX_MYSQL_WAIT seconds" + echo "Last few lines of MySQL error log:" + tail -n 20 $MYSQL_ERROR_LOG exit 1 fi +echo "MySQL is ready!" -# Start application in tmux +# Run migrations +echo "Running database migrations..." +npx mikro-orm-esm migration:up + +# Start application echo "Starting application..." tmux new-session -d -s $APP_NAME "npm run start" echo "App is running in tmux session. Attach with: tmux attach-session -t $APP_NAME" -# Monitor key processes +# Monitor processes while true; do - if ! redis-cli ping > /dev/null 2>&1; then - echo "Redis died" - exit 1 - fi - if ! mysqladmin ping -h localhost --silent; then - echo "MySQL died" - exit 1 - fi - if ! tmux has-session -t $APP_NAME 2>/dev/null; then - echo "Application died" - exit 1 - fi sleep 30 + redis-cli ping > /dev/null 2>&1 || { echo "Redis died"; exit 1; } + mysqladmin ping -h localhost --silent || { echo "MySQL died"; exit 1; } + tmux has-session -t $APP_NAME 2>/dev/null || { echo "Application died"; exit 1; } done \ No newline at end of file