From 9d1c0e5ddaa3dc68886117357ddc75536a38258c Mon Sep 17 00:00:00 2001 From: Dan Brown Date: Mon, 6 Oct 2025 13:06:12 +0100 Subject: [PATCH] Dev: Played with an all-in-one docker environment --- dev/docker/Dockerfile | 70 ++++++++++++++++++++--------------- dev/docker/apache.conf | 34 +++++++++++++++++ dev/docker/enter.sh | 14 +++++++ dev/docker/entrypoint.app.sh | 15 -------- dev/docker/entrypoint.node.sh | 8 ---- dev/docker/entrypoint.sh | 23 ++++++++++++ dev/docker/init.db/01.sql | 5 --- dev/docker/setup.sql | 12 ++++++ dev/docker/supervisord.conf | 23 ++++++++++++ docker-compose.yml | 44 ++++++++-------------- 10 files changed, 161 insertions(+), 87 deletions(-) create mode 100644 dev/docker/apache.conf create mode 100644 dev/docker/enter.sh delete mode 100755 dev/docker/entrypoint.app.sh delete mode 100755 dev/docker/entrypoint.node.sh create mode 100644 dev/docker/entrypoint.sh delete mode 100644 dev/docker/init.db/01.sql create mode 100644 dev/docker/setup.sql create mode 100644 dev/docker/supervisord.conf diff --git a/dev/docker/Dockerfile b/dev/docker/Dockerfile index edab90ca1..46f29f8a1 100644 --- a/dev/docker/Dockerfile +++ b/dev/docker/Dockerfile @@ -1,38 +1,48 @@ -FROM php:8.3-apache +FROM ubuntu:24.04 -# Install additional dependencies -RUN apt-get update && \ +# Accept build arguments +ARG USER_ID=1000 +ARG GROUP_ID=1000 +ARG USERNAME=devuser + +# Install dependencies and some build env tools +RUN export DEBIAN_FRONTEND=noninteractive && \ + apt-get update && \ apt-get install -y \ - git \ - zip \ - unzip \ - libfreetype-dev \ - libjpeg62-turbo-dev \ - libldap2-dev \ - libpng-dev \ - libzip-dev \ - wait-for-it && \ - rm -rf /var/lib/apt/lists/* + bash git tmux vim nano htop curl supervisor unzip sudo \ + mysql-server-8.0 apache2 php8.3 \ + php8.3-fpm php8.3-curl php8.3-mbstring php8.3-ldap php8.3-xml php8.3-zip php8.3-gd php8.3-mysql php8.3-xdebug -# Install PHP extensions -RUN docker-php-ext-configure ldap --with-libdir="lib/$(gcc -dumpmachine)" && \ - docker-php-ext-configure gd --with-freetype --with-jpeg && \ - docker-php-ext-install -j$(nproc) pdo_mysql gd ldap zip && \ - pecl install xdebug && \ - docker-php-ext-enable xdebug +# Create group and user with specific IDs, and give user sudo access (for service management) +RUN userdel -r ubuntu && \ + groupadd -g ${GROUP_ID} ${USERNAME} && \ + useradd -u ${USER_ID} -g ${GROUP_ID} -m -s /bin/bash ${USERNAME} && \ + echo "${USERNAME} ALL=(ALL) NOPASSWD:ALL" >> /etc/sudoers -# Install composer -RUN curl -sS https://getcomposer.org/installer | php -- --install-dir=/usr/local/bin --filename=composer +# Install build tools (composer/node/npm) +RUN curl -sS https://getcomposer.org/installer | php -- --install-dir=/usr/local/bin --filename=composer && \ + mkdir -p "/home/${USERNAME}/.nvm" && export NVM_DIR="/home/${USERNAME}/.nvm" && curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.3/install.sh | bash && \ + \. "/home/${USERNAME}/.nvm/nvm.sh" && \ + nvm install 22 && \ + chown -R ${USERNAME} "/home/${USERNAME}/.nvm" && \ + echo 'export NVM_DIR="${HOME}/.nvm" && source "$NVM_DIR/nvm.sh"' >> "/home/${USERNAME}/.bashrc" -# Configure apache -RUN a2enmod rewrite && \ - sed -ri -e 's!/var/www/html!${APACHE_DOCUMENT_ROOT}!g' /etc/apache2/sites-available/*.conf && \ - sed -ri -e 's!/var/www/!${APACHE_DOCUMENT_ROOT}!g' /etc/apache2/apache2.conf /etc/apache2/conf-available/*.conf +# Configure apache, php & mysql +RUN a2dissite 000-default.conf && \ + a2enmod rewrite proxy_fcgi setenvif && \ + a2enconf php8.3-fpm && \ + sed -i "s/www-data/${USERNAME}/g" "/etc/php/8.3/fpm/pool.d/www.conf" && \ + sed -i "s/www-data/${USERNAME}/g" "/etc/apache2/envvars" && \ + chmod 755 /var/run/mysqld -# Use the default production configuration and update it as required -RUN mv "$PHP_INI_DIR/php.ini-production" "$PHP_INI_DIR/php.ini" && \ - sed -i 's/memory_limit = 128M/memory_limit = 512M/g' "$PHP_INI_DIR/php.ini" - -ENV APACHE_DOCUMENT_ROOT="/app/public" +# Copy required configuration & entrypoint script +COPY supervisord.conf /etc/supervisor/conf.d/supervisord.conf +COPY apache.conf /etc/apache2/sites-enabled/bookstack.conf +COPY setup.sql /setup.sql +COPY entrypoint.sh /entrypoint.sh +# Set our user, working directory, entrypoint and default command +USER ${USERNAME} WORKDIR /app +ENTRYPOINT ["/entrypoint.sh"] +CMD ["/bin/bash"] diff --git a/dev/docker/apache.conf b/dev/docker/apache.conf new file mode 100644 index 000000000..86cb0b22e --- /dev/null +++ b/dev/docker/apache.conf @@ -0,0 +1,34 @@ + + DocumentRoot /app/public/ + + + Options Indexes FollowSymLinks + AllowOverride None + Require all granted + + + Options -MultiViews -Indexes + + + RewriteEngine On + + # Handle Authorization Header + RewriteCond %{HTTP:Authorization} . + RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}] + + # Redirect Trailing Slashes If Not A Folder... + RewriteCond %{REQUEST_FILENAME} !-d + RewriteCond %{REQUEST_URI} (.+)/$ + RewriteRule ^ %1 [L,R=301] + + # Handle Front Controller... + RewriteCond %{REQUEST_FILENAME} !-d + RewriteCond %{REQUEST_FILENAME} !-f + RewriteRule ^ index.php [L] + + + + ErrorLog ${APACHE_LOG_DIR}/error.log + CustomLog ${APACHE_LOG_DIR}/access.log combined + + \ No newline at end of file diff --git a/dev/docker/enter.sh b/dev/docker/enter.sh new file mode 100644 index 000000000..47786207b --- /dev/null +++ b/dev/docker/enter.sh @@ -0,0 +1,14 @@ +#!/usr/bin/env bash + +# Auto-detect your user ID +USER_ID=$(id -u) +GROUP_ID=$(id -g) +USERNAME=$(whoami) + +# Export variables +export USER_ID +export GROUP_ID +export USERNAME + +# Build & start the stack +docker-compose up -d --remove-orphans app && docker compose attach app \ No newline at end of file diff --git a/dev/docker/entrypoint.app.sh b/dev/docker/entrypoint.app.sh deleted file mode 100755 index b09edda88..000000000 --- a/dev/docker/entrypoint.app.sh +++ /dev/null @@ -1,15 +0,0 @@ -#!/bin/bash - -set -e - -env - -if [[ -n "$1" ]]; then - exec "$@" -else - composer install - wait-for-it db:3306 -t 45 - php artisan migrate --database=mysql --force - chown -R www-data storage public/uploads bootstrap/cache - exec apache2-foreground -fi diff --git a/dev/docker/entrypoint.node.sh b/dev/docker/entrypoint.node.sh deleted file mode 100755 index a8f33fd3d..000000000 --- a/dev/docker/entrypoint.node.sh +++ /dev/null @@ -1,8 +0,0 @@ -#!/bin/sh - -set -e - -npm install -npm rebuild node-sass - -SHELL=/bin/sh exec npm run watch diff --git a/dev/docker/entrypoint.sh b/dev/docker/entrypoint.sh new file mode 100644 index 000000000..e9222cb68 --- /dev/null +++ b/dev/docker/entrypoint.sh @@ -0,0 +1,23 @@ +#!/bin/bash + +echo "Starting services..." + +# Start supervisord in background +sudo /usr/bin/supervisord -sc /etc/supervisor/conf.d/supervisord.conf & + +# Wait for MySQL to start +echo "Waiting for MySQL to be ready..." +for i in {1..30}; do + if sudo mysqladmin -u root ping &>/dev/null; then + break + fi + sleep 1 +done + +# Running MySQL startup script +echo "Setting up database..." +sudo mysql -u root < /setup.sql + +# Execute whatever command was passed (default: /bin/bash) +echo "Setup done! Dropping you to shell-window or command ($@)" +exec "$@" \ No newline at end of file diff --git a/dev/docker/init.db/01.sql b/dev/docker/init.db/01.sql deleted file mode 100644 index 2536c3f80..000000000 --- a/dev/docker/init.db/01.sql +++ /dev/null @@ -1,5 +0,0 @@ -# create test database -CREATE DATABASE IF NOT EXISTS `bookstack-test`; - -# grant rights -GRANT ALL PRIVILEGES ON `bookstack-test`.* TO 'bookstack-test'@'%'; diff --git a/dev/docker/setup.sql b/dev/docker/setup.sql new file mode 100644 index 000000000..141a212ef --- /dev/null +++ b/dev/docker/setup.sql @@ -0,0 +1,12 @@ +-- Create databases +CREATE DATABASE IF NOT EXISTS `bookstack`; +CREATE DATABASE IF NOT EXISTS `bookstack-test`; + +-- Create users +CREATE USER IF NOT EXISTS 'bookstack'@'%' IDENTIFIED BY 'bookstack'; +CREATE USER IF NOT EXISTS 'bookstack-test'@'%' IDENTIFIED BY 'bookstack-test'; + +-- Grant rights +GRANT ALL PRIVILEGES ON `bookstack`.* to 'bookstack'@'%'; +GRANT ALL PRIVILEGES ON `bookstack-test`.* TO 'bookstack-test'@'%'; +FLUSH PRIVILEGES; diff --git a/dev/docker/supervisord.conf b/dev/docker/supervisord.conf new file mode 100644 index 000000000..1818a9307 --- /dev/null +++ b/dev/docker/supervisord.conf @@ -0,0 +1,23 @@ +[supervisord] +nodaemon=true +logfile=/var/log/supervisor/supervisord.log +pidfile=/var/run/supervisord.pid + +[program:apache2] +command=/usr/sbin/apache2ctl -D FOREGROUND +autostart=true +autorestart=true +stdout_logfile=/var/log/supervisor/apache2.log +stderr_logfile=/var/log/supervisor/apache2.err + +[program:php-fpm] +command=/usr/sbin/php-fpm8.3 -F +autostart=true +autorestart=true +stdout_logfile=/var/log/supervisor/php-fpm.log + +[program:mysql] +command=/usr/sbin/mysqld --performance-schema=off +autostart=true +autorestart=true +stdout_logfile=/var/log/supervisor/mysql.log \ No newline at end of file diff --git a/docker-compose.yml b/docker-compose.yml index f4c3a64c6..d36c8772b 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -5,47 +5,33 @@ volumes: db: {} services: - db: - image: mysql:8.4 - environment: - MYSQL_DATABASE: bookstack-dev - MYSQL_USER: bookstack-test - MYSQL_PASSWORD: bookstack-test - MYSQL_RANDOM_ROOT_PASSWORD: 'true' - volumes: - - ./dev/docker/init.db:/docker-entrypoint-initdb.d - - db:/var/lib/mysql app: build: - context: . - dockerfile: ./dev/docker/Dockerfile + context: ./dev/docker + args: + USER_ID: ${USER_ID:-1000} + GROUP_ID: ${GROUP_ID:-1000} + USERNAME: ${USERNAME:-devuser} environment: APP_URL: http://localhost:${DEV_PORT:-8080} DB_CONNECTION: mysql - DB_HOST: db + DB_HOST: localhost DB_PORT: 3306 - DB_DATABASE: bookstack-dev - DB_USERNAME: bookstack-test - DB_PASSWORD: bookstack-test - TEST_DATABASE_URL: mysql://bookstack-test:bookstack-test@db/bookstack-test + DB_DATABASE: bookstack + DB_USERNAME: bookstack + DB_PASSWORD: bookstack + TEST_DATABASE_URL: mysql://bookstack-test:bookstack-test@localhost/bookstack-test MAIL_DRIVER: smtp MAIL_HOST: mailhog MAIL_PORT: 1025 ports: - ${DEV_PORT:-8080}:80 + - ${DEV_DB_PORT:-33066}:3306 volumes: - - ./:/app - - ./dev/docker/php/conf.d/xdebug.ini:/usr/local/etc/php/conf.d/docker-php-ext-xdebug.ini - entrypoint: /app/dev/docker/entrypoint.app.sh - extra_hosts: - - "host.docker.internal:host-gateway" - node: - image: node:22-alpine - working_dir: /app - user: node - volumes: - - ./:/app - entrypoint: /app/dev/docker/entrypoint.node.sh + - ./:/app:z + - db:/var/lib/mysql + stdin_open: true + tty: true mailhog: image: mailhog/mailhog ports: