diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000000..b92e03c762 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,28 @@ +# Taken from .gitignore +/assets/.parcel-cache +/data/favicons/*.png +/data/favicons/*.jpg +/data/thumbnails/*.png +/data/thumbnails/*.jpg +/data/cache/*.spc +/data/logs/*.log +/data/sqlite/*.db +/public +docs/public/ +docs/static/processed_images/ +user.css +user.js +*.ini +node_modules +.env +vendor/ +.php_cs.cache +__pycache__ + +# Regular docker ignore +.dockerignore +Dockerfile +.git +.github +.gitignore +*.md diff --git a/.github/workflows/publish-container.yml b/.github/workflows/publish-container.yml new file mode 100644 index 0000000000..3615c6057a --- /dev/null +++ b/.github/workflows/publish-container.yml @@ -0,0 +1,46 @@ +# According to https://docs.github.com/en/packages/managing-github-packages-using-github-actions-workflows/publishing-and-installing-a-package-with-github-actions#upgrading-a-workflow-that-accesses-ghcrio +name: Create and publish a Container image + +on: + push: + tags: + - '*' + branches: + - master + - docker + +env: + REGISTRY: ghcr.io + IMAGE_NAME: ${{ github.repository }} + +jobs: + build-and-push-image: + runs-on: ubuntu-latest + permissions: + contents: read + packages: write + + steps: + - name: Checkout repository + uses: actions/checkout@v4.1.1 + + - name: Log in to the Container registry + uses: docker/login-action@v3.2.0 + with: + registry: ${{ env.REGISTRY }} + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: Extract metadata (tags, labels) for Docker + id: meta + uses: docker/metadata-action@v5.0.0 + with: + images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} + + - name: Build and push Docker image + uses: docker/build-push-action@v5 + with: + push: true + file: Dockerfile + tags: ${{ steps.meta.outputs.tags }} + labels: ${{ steps.meta.outputs.labels }} diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000000..b3a97cb543 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,59 @@ +# syntax=docker/dockerfile:1.9@sha256:5510f694edfe648d961b59dcf217026485e560d2663c73e45067b8c8d7a6d247 + +### Stage 1: build client +FROM node:20 AS client-builder +WORKDIR /client-builder + +# Install node packages +RUN --mount=type=bind,source=package.json,target=package.json \ + --mount=type=bind,source=client/package.json,target=client/package.json \ + --mount=type=bind,source=client/package-lock.json,target=client/package-lock.json \ + --mount=type=cache,sharing=locked,id=npmcache,mode=0777,target=/root/.npm \ + npm run install-dependencies-ci:client + +# Build client +COPY client/ client/ +RUN --mount=type=bind,source=package.json,target=package.json \ + --mount=type=bind,source=client/package.json,target=client/package.json \ + --mount=type=bind,source=client/package-lock.json,target=client/package-lock.json \ + --mount=type=cache,sharing=locked,id=npmcache,mode=0777,target=/root/.npm \ + npm run build + + +### Stage 2: final container +FROM php:8.3-apache +# Install runtime & development package dependencies & php extensions +# then clean-up dev package dependencies +RUN export DEBIAN_FRONTEND=noninteractive \ + && apt update \ + && apt install -y --no-install-recommends \ + unzip \ + libjpeg62-turbo libpng16-16 libpq5 libonig5 libtidy5deb1 \ + libjpeg62-turbo-dev libpng-dev libpq-dev libonig-dev libtidy-dev \ + && update-ca-certificates --fresh \ + && docker-php-ext-configure gd --with-jpeg \ + && docker-php-ext-install -j$(nproc) gd mbstring pdo_pgsql pdo_mysql tidy \ + && apt remove -y libjpeg62-turbo-dev libpng-dev libpq-dev libonig-dev libtidy-dev \ + && apt autoremove -y \ + && apt clean \ + && rm -rf /var/lib/apt/lists/* + +# Install Apache modules +RUN a2enmod headers rewrite + +# Install Selfoss PHP dependencies +RUN --mount=type=bind,source=composer.json,target=composer.json \ + --mount=type=bind,source=composer.lock,target=composer.lock \ + --mount=type=bind,from=composer:2,source=/usr/bin/composer,target=/usr/bin/composer \ + COMPOSER_ALLOW_SUPERUSER=1 composer install --optimize-autoloader --no-dev + +# Install Selfoss and copy frontend from the first stage +WORKDIR /var/www/html +COPY . . +COPY --from=client-builder /client-builder/public /var/www/html/public + +# Use www-data user as owner and drop root user +RUN chown -R www-data:www-data /var/www/html/data +USER www-data + +VOLUME /var/www/html/data diff --git a/package.json b/package.json index 3a73a66792..35e71fdafc 100644 --- a/package.json +++ b/package.json @@ -32,6 +32,7 @@ "fix:helpers:cs": "black utils/ tests/", "install-dependencies": "npm run install-dependencies:client && npm run install-dependencies:server", "install-dependencies:client": "npm install --production=false --prefix client/", + "install-dependencies-ci:client": "npm ci --prefix client/", "install-dependencies:server": "composer install --dev", "test:server": "composer run-script test", "test:integration": "python3 tests/integration/run.py",