From 1000464b4a75a911b16729a062e79417136313e2 Mon Sep 17 00:00:00 2001 From: jon brookes Date: Sun, 25 Jan 2026 16:03:51 +0000 Subject: [PATCH] added container config --- .gitignore | 1 + .woodpecker/share-lt-build.yaml | 67 ++++++++++++++++++++++++++ Dockerfile.phpfpm | 84 +++++++++++++++++++++++++++++++++ cmd/build_prod_container.sh | 11 +++++ cmd/docker-entrypoint.sh | 36 ++++++++++++++ docker/php/conf.d/opcache.ini | 8 ++++ docker/supervisord.conf | 35 ++++++++++++++ 7 files changed, 242 insertions(+) create mode 100644 .woodpecker/share-lt-build.yaml create mode 100644 Dockerfile.phpfpm create mode 100755 cmd/build_prod_container.sh create mode 100644 cmd/docker-entrypoint.sh create mode 100644 docker/php/conf.d/opcache.ini create mode 100644 docker/supervisord.conf diff --git a/.gitignore b/.gitignore index ac23ed3..3d34314 100644 --- a/.gitignore +++ b/.gitignore @@ -27,3 +27,4 @@ yarn-error.log log*.txt .envrc database/backups +*backup.tar.gz diff --git a/.woodpecker/share-lt-build.yaml b/.woodpecker/share-lt-build.yaml new file mode 100644 index 0000000..f9c7a16 --- /dev/null +++ b/.woodpecker/share-lt-build.yaml @@ -0,0 +1,67 @@ +when: + - event: push + branch: dev +steps: + build-local: + image: docker:share-lt-build + privileged: true + # environment: + # DOCKER_TLS_CERTDIR: /certs + volumes: + - /var/run/docker.sock:/var/run/docker.sock + commands: + - echo "Pulling base images to ensure latest layers..." + - docker pull --quiet php:8.4-fpm-alpine3.23 || true + - echo "Try to pull previous image to use as cache ..." + - docker pull quay.io/marshyon/share-lt:latest || true + - echo "Building image for testing (amd64 only for CI compatibility)..." + - docker build --platform linux/amd64 --cache-from=quay.io/marshyon/share-lt:latest -t share-lt:test . + - echo "Tagging test image as quay.io/marshyon/share-lt:v0.0.2..." + - docker tag share-lt:test quay.io/marshyon/share-lt:v0.0.2 + - echo "Generating SBOM..." + - docker run --rm -v /var/run/docker.sock:/var/run/docker.sock anchore/syft:latest scan quay.io/marshyon/share-lt:v0.0.2 -o cyclonedx-json > sbom.json + scan-vulnerabilities: + image: aquasec/trivy:0.67.2 + privileged: true + volumes: + - /var/run/docker.sock:/var/run/docker.sock + commands: + - echo "Ensuring latest Trivy image is pulled..." + - docker pull aquasec/trivy:latest || true + - echo "Scanning for vulnerabilities via Docker daemon..." + # Scan the image present in the Docker daemon; fail on CRITICAL severities + - trivy image --exit-code 1 --severity CRITICAL --no-progress share-lt:test + # Run a full scan without failing just for logs + - trivy image --severity HIGH,MEDIUM,LOW --no-progress share-lt:test + - echo "Generating vulnerability report..." + - trivy image --format cyclonedx --output trivy-vuln-bom.json share-lt:test + - echo "Vulnerability Summary:" + - trivy image --format table share-lt:test | tee trivy-vuln-summary.txt + publish: + image: woodpeckerci/plugin-docker-buildx + privileged: true + settings: + registry: quay.io + repo: quay.io/marshyon/share-lt + # platforms: linux/amd64,linux/arm64 + platforms: linux/amd64 + tags: + - v0.0.2 + - latest + username: + from_secret: QUAY_USERNAME + password: + from_secret: QUAY_PASSWORD + upload-sbom: + image: cgr.dev/chainguard/cosign:latest + privileged: true + volumes: + - /var/run/docker.sock:/var/run/docker.sock + environment: + COSIGN_REGISTRY_USERNAME: + from_secret: QUAY_USERNAME + COSIGN_REGISTRY_PASSWORD: + from_secret: QUAY_PASSWORD + commands: + - cosign attach sbom --sbom sbom.json quay.io/marshyon/share-lt:v0.0.2 || echo "SBOM attach failed" + - echo "Done - trivy report saved to workspace for manual review" \ No newline at end of file diff --git a/Dockerfile.phpfpm b/Dockerfile.phpfpm new file mode 100644 index 0000000..a8a8a85 --- /dev/null +++ b/Dockerfile.phpfpm @@ -0,0 +1,84 @@ +FROM php:8.4-fpm-alpine3.23 + +ENV APP_ENV=production +ENV APP_DEBUG=false + +WORKDIR /var/www + +RUN apk update && apk add --no-cache \ + build-base \ + libpng-dev \ + libjpeg-turbo-dev \ + freetype-dev \ + zip \ + jpegoptim optipng pngquant gifsicle \ + vim \ + unzip \ + git \ + curl \ + libzip-dev \ + oniguruma-dev \ + nodejs \ + npm \ + icu-dev \ + sqlite-dev \ + sqlite-libs \ + nginx \ + supervisor \ + su-exec \ + tini + +RUN rm -rf /var/cache/apk/* + +RUN docker-php-ext-install mbstring zip exif pcntl intl gd pdo pdo_sqlite bcmath + +RUN curl -sS https://getcomposer.org/installer | php -- --install-dir=/usr/local/bin --filename=composer + +# RUN addgroup -g 1000 www +# RUN adduser -u 1000 -G www -s /bin/sh -D www + +# # Configure PHP-FPM to run as www user +# RUN sed -i 's/user = www-data/user = www/g' /usr/local/etc/php-fpm.d/www.conf && \ +# sed -i 's/group = www-data/group = www/g' /usr/local/etc/php-fpm.d/www.conf + +# Copy application code (includes database/migrations/) +COPY . /var/www + + +# DEBUG - SHOW ME WHAT WAS COPIED +# RUN echo "===== CONTENTS OF /var/www/database =====" && ls -la /var/www/database/ +# RUN echo "===== CONTENTS OF /var/www/database/migrations =====" && ls -la /var/www/database/migrations/ + + + +# Install dependencies +RUN composer install --optimize-autoloader --no-dev +RUN npm install +RUN npm run build + +# Copy entrypoint script +COPY cmd/docker-entrypoint.sh /usr/local/bin/docker-entrypoint.sh +RUN chmod +x /usr/local/bin/docker-entrypoint.sh + +# RUN chown -R www:www /var/www + +# add supervisord config and a log dir (kept before switching to non-root user) +COPY ./docker/supervisord.conf /etc/supervisord.conf +RUN mkdir -p /var/log/supervisor \ + && mkdir -p /run/nginx /var/cache/nginx /var/lib/nginx /var/tmp/nginx \ + && chown -R root:root /run/nginx /var/cache/nginx /var/lib/nginx /var/tmp/nginx + +# Test nginx config at build time +RUN nginx -t + +# keep running as root so supervisord starts nginx/php-fpm as root (nginx needs root for master process) +# we will use su-exec in entrypoint to run maintenance steps as www, preserving previous behaviour + +EXPOSE 8889 + +# Keep entrypoint script as before; entrypoint runs startup tasks then supervisord becomes PID 1 +# ENTRYPOINT ["docker-entrypoint.sh"] +# CMD ["/usr/bin/supervisord", "-n", "-c", "/etc/supervisord.conf"] + +ENTRYPOINT ["/sbin/tini", "--", "/usr/local/bin/docker-entrypoint.sh"] +CMD ["/usr/bin/supervisord", "-n", "-c", "/etc/supervisord.conf"] diff --git a/cmd/build_prod_container.sh b/cmd/build_prod_container.sh new file mode 100755 index 0000000..319af02 --- /dev/null +++ b/cmd/build_prod_container.sh @@ -0,0 +1,11 @@ +#!/usr/bin/env bash + +LARAVEL_CONTAINER_NAME="quay.io/marshyon/share-lt" +CONTAINER_LABEL="0.0.2" +CACHE="--no-cache" +CACHE="" + +docker build \ + $CACHE \ + -t ${LARAVEL_CONTAINER_NAME}:${CONTAINER_LABEL} \ + -f Dockerfile.phpfpm . diff --git a/cmd/docker-entrypoint.sh b/cmd/docker-entrypoint.sh new file mode 100644 index 0000000..b8736db --- /dev/null +++ b/cmd/docker-entrypoint.sh @@ -0,0 +1,36 @@ +#!/bin/sh +set -e + +run_as_www() { + # prefer su-exec (alpine), fallback to runuser if available, otherwise run directly + if command -v su-exec >/dev/null 2>&1; then + su-exec www "$@" + elif command -v runuser >/dev/null 2>&1; then + runuser -u www -- "$@" + else + "$@" + fi +} + +# Build front-end assets if Vite manifest is missing +if [ ! -f /var/www/public/build/manifest.json ]; then + echo "Building front-end assets (vite)..." + run_as_www npm ci + run_as_www npm run build +fi + +# Wait for database directory to be mounted +if [ ! -f /var/www/database/database.sqlite ]; then + echo "Creating database..." + # create the sqlite file as the www user so ownership matches app files + run_as_www sh -c 'touch /var/www/database/database.sqlite' + run_as_www php artisan migrate --force +fi + +# Fix storage permissions +echo "Fixing storage permissions..." +chown -R www:www /var/www/storage /var/www/bootstrap/cache +chmod -R 775 /var/www/storage /var/www/bootstrap/cache + +# Execute the main command +exec "$@" diff --git a/docker/php/conf.d/opcache.ini b/docker/php/conf.d/opcache.ini new file mode 100644 index 0000000..b5358a9 --- /dev/null +++ b/docker/php/conf.d/opcache.ini @@ -0,0 +1,8 @@ +opcache.enable=1 +opcache.enable_cli=0 +opcache.memory_consumption=256 +opcache.interned_strings_buffer=16 +opcache.max_accelerated_files=100000 +opcache.validate_timestamps=0 +opcache.revalidate_freq=0 +opcache.save_comments=1 diff --git a/docker/supervisord.conf b/docker/supervisord.conf new file mode 100644 index 0000000..84dbadd --- /dev/null +++ b/docker/supervisord.conf @@ -0,0 +1,35 @@ +[supervisord] +nodaemon=true +logfile=/var/log/supervisor/supervisord.log +loglevel=info + +[program:php-fpm] +command=/usr/local/sbin/php-fpm -F +autostart=true +autorestart=true +startretries=3 +stdout_logfile=/dev/stdout +stdout_logfile_maxbytes=0 +stderr_logfile=/dev/stderr +stderr_logfile_maxbytes=0 + +[program:nginx] +command=/usr/sbin/nginx -g "daemon off;" +autostart=true +autorestart=true +startretries=3 +stdout_logfile=/dev/stdout +stdout_logfile_maxbytes=0 +stderr_logfile=/dev/stderr +stderr_logfile_maxbytes=0 + +[program:queue-worker] +command=su-exec www /usr/local/bin/php /var/www/artisan queue:work --sleep=3 --tries=3 --max-time=3600 +autostart=true +autorestart=true +startretries=3 +stdout_logfile=/dev/stdout +stdout_logfile_maxbytes=0 +stderr_logfile=/dev/stderr +stderr_logfile_maxbytes=0 +stopwaitsecs=3600