diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 000000000..1ad6e1440 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,28 @@ +# Slim context: web image uses script.sh only; db image uses install/assets/install.sql — exclude bulky dirs. + +.git +.github + +application/ +system/ +src/ +assets/ +images/ +updates/ +uploads/ +backup/ +cypress/ + +node_modules +**/node_modules + +.vscode/ +.idea/ + +*.md +package.json +package-lock.json +cypress.config.js + +.env +.env.* diff --git a/.env.sample b/.env.sample index 2ff3bc361..9f24ee28a 100644 --- a/.env.sample +++ b/.env.sample @@ -6,4 +6,10 @@ MYSQL_HOST=db MYSQL_PORT=3306 BASE_LOCATOR=IO91WM WEBSITE_URL=http://localhost -DIRECTORY=/var/www/html \ No newline at end of file +DIRECTORY=/var/www/html + +# Docker images (GitHub Container Registry). Override for forks, e.g. ghcr.io/yourusername +# CLOUDLOG_IMAGE_REGISTRY=ghcr.io/magicbug +# CLOUDLOG_IMAGE_TAG=latest +# +# Compose: development uses docker-compose.yml (default); production uses docker-compose.prod.yml diff --git a/.github/workflows/cypress-tests.yml b/.github/workflows/cypress-tests.yml index 0436c50ba..b5ac925a5 100644 --- a/.github/workflows/cypress-tests.yml +++ b/.github/workflows/cypress-tests.yml @@ -48,7 +48,7 @@ jobs: sudo chmod +x /usr/local/bin/docker-compose - name: Build Docker services - run: docker-compose up -d + run: docker-compose up -d --build - name: Wait for services to start run: | diff --git a/.github/workflows/docker-publish.yml b/.github/workflows/docker-publish.yml new file mode 100644 index 000000000..4adbd6f5b --- /dev/null +++ b/.github/workflows/docker-publish.yml @@ -0,0 +1,61 @@ +name: Publish Docker images + +on: + push: + tags: + workflow_dispatch: + +permissions: + contents: read + packages: write + +jobs: + build-and-push: + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + include: + - dockerfile: Dockerfile + image: cloudlog-web + - dockerfile: Dockerfile-db + image: cloudlog-db + + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Set up QEMU + uses: docker/setup-qemu-action@v3 + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + + - name: Log in to GitHub Container Registry + uses: docker/login-action@v3 + with: + registry: ghcr.io + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: Extract Docker metadata + id: meta + uses: docker/metadata-action@v5 + with: + images: ghcr.io/${{ github.repository_owner }}/${{ matrix.image }} + tags: | + type=semver,pattern={{version}} + type=sha + type=raw,value=latest,enable=${{ github.ref_type == 'tag' }} + + - name: Build and push + uses: docker/build-push-action@v6 + with: + context: . + file: ${{ matrix.dockerfile }} + push: true + platforms: linux/amd64,linux/arm64 + tags: ${{ steps.meta.outputs.tags }} + labels: ${{ steps.meta.outputs.labels }} + cache-from: type=gha + cache-to: type=gha,mode=max diff --git a/Dockerfile b/Dockerfile index c3c516f8c..3720c3156 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,39 +1,30 @@ -# Use the official image for PHP and Apache FROM php:7.4-apache -# Set the working directory to /var/www/html WORKDIR /var/www/html -# Install system dependencies, including git and libxml2 -RUN apt-get update && apt-get install -y \ - libcurl4-openssl-dev \ - libxml2-dev \ - libzip-dev \ - zlib1g-dev \ - libpng-dev \ - libonig-dev \ - default-mysql-client \ - curl \ - && apt-get clean \ +# Single layer: APT cleanup + PHP extensions (curl used by application PHP code) +RUN apt-get update \ + && DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends \ + libcurl4-openssl-dev \ + libxml2-dev \ + libzip-dev \ + zlib1g-dev \ + libpng-dev \ + libonig-dev \ + default-mysql-client \ && rm -rf /var/lib/apt/lists/* \ - && docker-php-ext-install pdo_mysql \ - && docker-php-ext-install mysqli \ - && docker-php-ext-install gd \ - && docker-php-ext-install mbstring \ - && docker-php-ext-install zip \ - && docker-php-ext-install xml \ + && docker-php-ext-install -j"$(nproc)" curl pdo_mysql mysqli gd mbstring zip xml \ && a2enmod rewrite -# Copy script.sh and make it executable COPY script.sh /usr/local/bin/startup.sh RUN sed -i 's/\r$//' /usr/local/bin/startup.sh && chmod +x /usr/local/bin/startup.sh -# Configure PHP for larger file uploads (30MB) -RUN echo "upload_max_filesize = 30M" >> /usr/local/etc/php/conf.d/uploads.ini \ - && echo "post_max_size = 35M" >> /usr/local/etc/php/conf.d/uploads.ini \ - && echo "memory_limit = 64M" >> /usr/local/etc/php/conf.d/uploads.ini \ - && echo "max_execution_time = 300" >> /usr/local/etc/php/conf.d/uploads.ini \ - && echo "max_input_time = 300" >> /usr/local/etc/php/conf.d/uploads.ini +RUN printf '%s\n' \ + 'upload_max_filesize = 30M' \ + 'post_max_size = 35M' \ + 'memory_limit = 64M' \ + 'max_execution_time = 300' \ + 'max_input_time = 300' \ + > /usr/local/etc/php/conf.d/uploads.ini -# Expose port 80 -EXPOSE 80 \ No newline at end of file +EXPOSE 80 diff --git a/docker-compose.yml b/docker-compose.yml index 96d55ec26..95f440248 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,9 +1,18 @@ +# Development stack — local code, optional local image build. +# docker compose up -d +# docker compose build && docker compose up -d # without registry images +# +# Production: use docker-compose.prod.yml + networks: mynet: services: web: - build: . + image: ghcr.io/magicbug/cloudlog-web:latest + build: + context: . + dockerfile: Dockerfile env_file: - .env ports: @@ -19,6 +28,7 @@ services: restart: on-failure db: + image: ghcr.io/magicbug/cloudlog-db:latest build: context: . dockerfile: Dockerfile-db diff --git a/script.sh b/script.sh index 4a16f7bc0..330610b7e 100755 --- a/script.sh +++ b/script.sh @@ -1,24 +1,28 @@ #!/bin/bash -# Define the file path for .env and the file to modify -if [ -f "./.env" ]; then - ENV_FILE="./.env" -else - ENV_FILE="./.env.sample" -fi +# App root (Dockerfile WORKDIR); ensures ./.env resolves even if the process cwd differs +cd /var/www/html || exit 1 + CONFIG_FILE="install/config/config.php" DATABASE_FILE="install/config/database.php" DEST_DIR="application/config" -# Check if .env file exists -if [ ! -f "$ENV_FILE" ]; then - echo ".env file not found!" +# Load variables: prefer files on the bind mount; otherwise use env already injected by Compose (env_file) +if [ -f "./.env" ]; then + # shellcheck disable=SC1091 + source "./.env" +elif [ -f "./.env.sample" ]; then + # shellcheck disable=SC1091 + source "./.env.sample" +elif [ -n "${MYSQL_DATABASE:-}" ] && [ -n "${MYSQL_USER:-}" ] && [ -n "${MYSQL_PASSWORD:-}" ] && \ + [ -n "${MYSQL_HOST:-}" ] && [ -n "${BASE_LOCATOR:-}" ] && [ -n "${WEBSITE_URL:-}" ] && [ -n "${DIRECTORY:-}" ]; then + : +else + echo ".env file not found under /var/www/html and required variables are not set in the environment." + echo "Add .env next to docker-compose.yml (bind-mounted as /var/www/html) or pass variables via Compose env_file / environment." exit 1 fi -# Read the .env file -source $ENV_FILE - # Check if MYSQL_DATABASE is set if [ -z "${MYSQL_DATABASE}" ]; then echo "MYSQL_DATABASE is not set in .env file!"