diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..612b445 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,50 @@ +# Node.js / npm +/node_modules +/public/hot +/public/storage + +# Assets +/public/build +/public/js +/public/css + +# PHP / Laravel +/bootstrap/cache/*.php +/storage/app/private +/storage/app/public/* +/storage/app/torrents +/storage/framework/cache/data/* +/storage/framework/sessions/* +/storage/framework/views/*.php +/storage/logs/*.log +/storage/*.key +/vendor + +# Env +.env +.env.backup +.env.ci +.env.local +.env.docker.example + +# Testing +/tests +/phpunit.xml +.phpunit.result.cache +/phpstan.neon.dist +/pint.json + +# Tooling +npm-debug.log +yarn-error.log + +# IDEs +/.idea +/.vscode + +# Docker +Dockerfile +docker-compose.yml + +# CI +/.github diff --git a/.env.docker.example b/.env.docker.example new file mode 100644 index 0000000..4aad596 --- /dev/null +++ b/.env.docker.example @@ -0,0 +1,27 @@ +APP_NAME=Cachent +APP_ENV=local +APP_KEY= +APP_DEBUG=true +APP_URL=http://localhost:8000 + +APP_LOCALE=en +APP_FALLBACK_LOCALE=en + +LOG_CHANNEL=stack +LOG_STACK=single +LOG_DEPRECATIONS_CHANNEL=null +LOG_LEVEL=debug + +DB_CONNECTION=mysql +DB_HOST=database +DB_PORT=3306 +DB_DATABASE=cachent +DB_USERNAME=cachent +DB_PASSWORD=cachent + +SESSION_DRIVER=database +SESSION_LIFETIME=120 + +CACHE_STORE=file +QUEUE_CONNECTION=sync +FILESYSTEM_DISK=local diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 0000000..260117b --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,51 @@ +name: Release + +on: + push: + tags: + - 'v*' + +jobs: + docker: + runs-on: ubuntu-latest + permissions: + contents: read + packages: write + name: Docker + steps: + + - name: Checkout + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + + - name: Login to Docker Hub + uses: docker/login-action@dbcb813823bdd20940b903addbd779551569679f # v4.6.0 + with: + registry: ghcr.io + username: ${{ github.repository_owner }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: Set up QEMU + uses: docker/setup-qemu-action@1f40c72289eff860ee54a304f1438e3cff362e0a # v4.3.0 + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@37fe631027851001ddb9b187196cc803df7f5f0e # v4.3.0 + + - name: Extract metadata (tags, labels) for Docker + id: meta + uses: docker/metadata-action@dc802804100637a589fabce1cb79ff13a1411302 # v6.2.0 + with: + images: ghcr.io/${{ github.repository }} + tags: | + type=semver,pattern={{version}} + type=semver,pattern={{major}} + + - name: Build and push + uses: docker/build-push-action@53b7df96c91f9c12dcc8a07bcb9ccacbed38856a # v7.3.0 + with: + context: . + push: true + platforms: linux/amd64,linux/arm64 + build-args: | + APP_VERSION=${{ github.ref_name }} + tags: ${{ steps.meta.outputs.tags }} + labels: ${{ steps.meta.outputs.labels }} diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..b5f68e6 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,60 @@ +# syntax=docker/dockerfile:1 + +FROM serversideup/php:8.4-fpm-nginx-alpine AS base + +USER root + +# Only bcmath is missing from the image's default extension set, which already +# provides opcache, pcntl, pdo_mysql, pdo_pgsql, redis and zip +RUN install-php-extensions bcmath + +USER www-data + +FROM base AS composer_builder + +COPY --chown=www-data:www-data composer.json composer.lock ./ + +# The application source is not present in this stage, so the optimised +# autoloader is generated in the final stage once the source is available. +RUN composer install \ + --no-dev \ + --no-scripts \ + --no-autoloader \ + --no-interaction \ + --no-progress + +FROM node:lts-alpine AS npm_install + +WORKDIR /app + +COPY package.json package-lock.json ./ + +RUN npm ci + +COPY vite.config.js ./ +COPY resources ./resources + +# Tailwind scans Blade templates and stylesheets shipped by the dependencies +COPY --from=composer_builder /var/www/html/vendor ./vendor + +RUN npm run build + +FROM base AS final + +ARG APP_VERSION +ENV APP_VERSION=${APP_VERSION} + +# The image ships with OPcache installed but disabled +ENV PHP_OPCACHE_ENABLE=1 + +COPY --chown=www-data:www-data . ./ + +COPY --from=npm_install --chown=www-data:www-data /app/public/build ./public/build +COPY --from=composer_builder --chown=www-data:www-data /var/www/html/vendor ./vendor + +RUN composer dump-autoload --no-dev --optimize + +RUN ln -s /data/torrents ./storage/app/torrents + +RUN php artisan event:cache +RUN php artisan view:cache diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..c339b91 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,51 @@ +services: + app: + build: + context: . + dockerfile: Dockerfile + environment: + # Set to `true` for production environments + AUTORUN_ENABLED: "false" + DB_CONNECTION: ${DB_CONNECTION} + DB_HOST: ${DB_HOST} + DB_DATABASE: ${DB_DATABASE} + DB_USERNAME: ${DB_USERNAME} + DB_PASSWORD: ${DB_PASSWORD} + # Keep changes to the bind mounted source visible without a rebuild + PHP_OPCACHE_ENABLE: 0 + tty: true + ports: + - '8000:8080' + volumes: + - .:/var/www/html + depends_on: + database: + condition: service_healthy + networks: + - cachent + + database: + image: mariadb:lts + environment: + MARIADB_RANDOM_ROOT_PASSWORD: true + MARIADB_DATABASE: ${DB_DATABASE} + MARIADB_USER: ${DB_USERNAME} + MARIADB_PASSWORD: ${DB_PASSWORD} + volumes: + - database:/var/lib/mysql + ports: + - '3306:3306' + healthcheck: + test: ['CMD', 'healthcheck.sh', '--connect', '--innodb_initialized'] + interval: 10s + timeout: 5s + retries: 5 + networks: + - cachent + +networks: + cachent: + driver: bridge + +volumes: + database: