diff --git a/.claude/settings.json b/.claude/settings.json new file mode 100644 index 0000000..d68e71f --- /dev/null +++ b/.claude/settings.json @@ -0,0 +1,13 @@ +{ + "extraKnownMarketplaces": { + "specs": { + "source": { + "source": "github", + "repo": "specsnl/agent-specs" + } + } + }, + "enabledPlugins": { + "docker@specs": true + } +} diff --git a/.github/dependabot.yml b/.github/dependabot.yml index bbb4acc..c45e9c6 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -4,20 +4,38 @@ version: 2 updates: - package-ecosystem: docker - directory: "fpm" + directories: + - fpm + - apache schedule: interval: "daily" + labels: + - "docker" ignore: - - dependency-name: '*' - update-types: ["version-update:semver-major", "version-update:semver-minor"] - - package-ecosystem: docker - directory: "apache" - schedule: - interval: "daily" - ignore: - - dependency-name: '*' - update-types: ["version-update:semver-major", "version-update:semver-minor"] + - dependency-name: "*" + update-types: ["version-update:semver-major"] + - dependency-name: "php" + update-types: ["version-update:semver-minor"] + groups: + php: + patterns: + - "php" + php-extension-installer: + patterns: + - "mlocati/php-extension-installer" + composer: + patterns: + - "composer/composer" + node: + patterns: + - "node" - package-ecosystem: "github-actions" directory: "/" schedule: interval: "daily" + labels: + - "github-actions" + groups: + specsnl-github-actions: + patterns: + - "specsnl/github-actions*" diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 8be1d9d..a26a9a8 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -7,6 +7,7 @@ on: permissions: actions: write packages: write + contents: read concurrency: group: ${{ github.workflow }}-${{ github.ref }} @@ -14,32 +15,28 @@ concurrency: jobs: build: - uses: Ilyes512/github-actions/.github/workflows/build-php.yml@0.2.1 + uses: specsnl/github-actions/.github/workflows/build-php.yml@2.1.0 strategy: fail-fast: false matrix: - platform: - - linux/amd64 - - linux/arm64 + runs-on: + - os: ubuntu-24.04 + platform: linux/amd64 + - os: ubuntu-24.04-arm + platform: linux/arm64 docker: - dockerfile: fpm/Dockerfile image-name: ghcr.io/${{ github.repository }} - key: fpm - dockerfile: apache/Dockerfile image-name: ghcr.io/${{ github.repository }}/apache - key: apache with: - runner-os: ubuntu-22.04 - platform: ${{ matrix.platform }} + runs-on: ${{ matrix.runs-on.os }} + platform: ${{ matrix.runs-on.platform }} image-name: ${{ matrix.docker.image-name }} dockerfile: ${{ matrix.docker.dockerfile }} - cache-key: ${{ matrix.os }}-buildx-${{ matrix.platform }}-${{ matrix.docker.key }}-${{ github.ref_name }}-${{ github.sha }} - cache-restore-keys: | - ${{ matrix.os }}-buildx-${{ matrix.platform }}-${{ matrix.docker.key }}-${{ github.ref_name }}- - ${{ matrix.os }}-buildx-${{ matrix.platform }}-${{ matrix.docker.key }} merge: - uses: Ilyes512/github-actions/.github/workflows/merge-php.yml@0.2.1 + uses: specsnl/github-actions/.github/workflows/merge-php.yml@2.1.0 needs: build strategy: matrix: @@ -47,5 +44,5 @@ jobs: - ghcr.io/${{ github.repository }} - ghcr.io/${{ github.repository }}/apache with: - runner-os: ubuntu-22.04 + runs-on: ubuntu-24.04 image-name: ${{ matrix.image-name }} diff --git a/.github/workflows/pr.yml b/.github/workflows/pr.yml index 1301e6c..a80b116 100644 --- a/.github/workflows/pr.yml +++ b/.github/workflows/pr.yml @@ -6,40 +6,56 @@ on: permissions: actions: write packages: write + contents: read concurrency: group: ${{ github.workflow }}-${{ github.ref }} cancel-in-progress: true jobs: + check: + name: Dockerfiles match template + runs-on: ubuntu-24.04 + steps: + - name: Checkout + uses: actions/checkout@v7 + + - name: Setup Task + uses: go-task/setup-task@v2 + with: + version: 3.x + repo-token: ${{ secrets.GITHUB_TOKEN }} + + - name: Regenerate Dockerfiles + run: task generate + + - name: Fail if generated files differ + run: git diff --exit-code fpm/Dockerfile apache/Dockerfile + build: - uses: Ilyes512/github-actions/.github/workflows/build-php.yml@0.2.1 + needs: check + uses: specsnl/github-actions/.github/workflows/build-php.yml@2.1.0 strategy: fail-fast: false matrix: - platform: - - linux/amd64 - - linux/arm64 + runs-on: + - os: ubuntu-24.04 + platform: linux/amd64 + - os: ubuntu-24.04-arm + platform: linux/arm64 docker: - dockerfile: fpm/Dockerfile image-name: ghcr.io/${{ github.repository }} - key: fpm - dockerfile: apache/Dockerfile image-name: ghcr.io/${{ github.repository }}/apache - key: apache with: - runner-os: ubuntu-22.04 - platform: ${{ matrix.platform }} + runs-on: ${{ matrix.runs-on.os }} + platform: ${{ matrix.runs-on.platform }} image-name: ${{ matrix.docker.image-name }} dockerfile: ${{ matrix.docker.dockerfile }} - cache-key: ${{ matrix.os }}-buildx-${{ matrix.platform }}-${{ matrix.docker.key }}-pr-${{ github.event.number }}-${{ github.sha }} - cache-restore-keys: | - ${{ matrix.os }}-buildx-${{ matrix.platform }}-${{ matrix.docker.key }}-pr-${{ github.event.number }}- - ${{ matrix.os }}-buildx-${{ matrix.platform }}-${{ matrix.docker.key }}-pr- - ${{ matrix.os }}-buildx-${{ matrix.platform }}-${{ matrix.docker.key }}-main- merge: - uses: Ilyes512/github-actions/.github/workflows/merge-php.yml@0.2.1 + uses: specsnl/github-actions/.github/workflows/merge-php.yml@2.1.0 needs: build strategy: matrix: @@ -47,5 +63,5 @@ jobs: - ghcr.io/${{ github.repository }} - ghcr.io/${{ github.repository }}/apache with: - runner-os: ubuntu-22.04 + runs-on: ubuntu-24.04 image-name: ${{ matrix.image-name }} diff --git a/.github/workflows/tag.yml b/.github/workflows/tag.yml index 0028733..78171a5 100644 --- a/.github/workflows/tag.yml +++ b/.github/workflows/tag.yml @@ -7,6 +7,7 @@ on: permissions: actions: write packages: write + contents: read concurrency: group: ${{ github.workflow }}-${{ github.ref }} @@ -14,33 +15,28 @@ concurrency: jobs: build: - uses: Ilyes512/github-actions/.github/workflows/build-php.yml@0.2.1 + uses: specsnl/github-actions/.github/workflows/build-php.yml@2.1.0 strategy: fail-fast: false matrix: - platform: - - linux/amd64 - - linux/arm64 + runs-on: + - os: ubuntu-24.04 + platform: linux/amd64 + - os: ubuntu-24.04-arm + platform: linux/arm64 docker: - dockerfile: fpm/Dockerfile image-name: ghcr.io/${{ github.repository }} - key: fpm - dockerfile: apache/Dockerfile image-name: ghcr.io/${{ github.repository }}/apache - key: apache with: - runner-os: ubuntu-22.04 - platform: ${{ matrix.platform }} + runs-on: ${{ matrix.runs-on.os }} + platform: ${{ matrix.runs-on.platform }} image-name: ${{ matrix.docker.image-name }} dockerfile: ${{ matrix.docker.dockerfile }} - cache-key: ${{ matrix.os }}-buildx-${{ matrix.platform }}-${{ matrix.docker.key }}-${{ github.ref_name }}-${{ github.sha }} - cache-restore-keys: | - ${{ matrix.os }}-buildx-${{ matrix.platform }}-${{ matrix.docker.key }}-${{ github.ref_name }}- - ${{ matrix.os }}-buildx-${{ matrix.platform }}-${{ matrix.docker.key }}-main- - ${{ matrix.os }}-buildx-${{ matrix.platform }}-${{ matrix.docker.key }}- merge: - uses: Ilyes512/github-actions/.github/workflows/merge-php.yml@0.2.1 + uses: specsnl/github-actions/.github/workflows/merge-php.yml@2.1.0 needs: build strategy: matrix: @@ -48,5 +44,5 @@ jobs: - ghcr.io/${{ github.repository }} - ghcr.io/${{ github.repository }}/apache with: - runner-os: ubuntu-22.04 + runs-on: ubuntu-24.04 image-name: ${{ matrix.image-name }} diff --git a/Dockerfile.tmpl b/Dockerfile.tmpl new file mode 100644 index 0000000..9877664 --- /dev/null +++ b/Dockerfile.tmpl @@ -0,0 +1,181 @@ +# syntax=docker/dockerfile:1 +# check=error=true + +# Latest version of php-extension-installer: https://hub.docker.com/r/mlocati/php-extension-installer/tags +FROM {{ getenv "PHP_EXTENSION_INSTALLER_IMAGE" }} AS php_extension_installer + +# Latest version of {{ .image_label }}: {{ .image_url }} +FROM {{ getenv "BASE_IMAGE" }} AS runtime + +ARG DEBIAN_FRONTEND=noninteractive + +ARG XDG_CONFIG_HOME=/config +ENV XDG_CONFIG_HOME=$XDG_CONFIG_HOME + +ARG XDG_DATA_HOME=/data +ENV XDG_DATA_HOME=$XDG_DATA_HOME + +ARG XDG_CACHE_HOME=/cache +ENV XDG_CACHE_HOME=$XDG_CACHE_HOME + +# Latest version of event-extension: https://pecl.php.net/package/event +ARG PHP_EVENT_VERSION=3.1.6 +# Latest version of igbinary-extension: https://pecl.php.net/package/igbinary +ARG PHP_IGBINARY_VERSION=3.2.17RC1 +# Latest version of redis-extension: https://pecl.php.net/package/redis +ARG PHP_REDIS_VERSION=6.3.0 +# Latest version of amqp-extension: https://pecl.php.net/package/amqp +ARG PHP_AMQP_VERSION=2.2.0 + +ARG DEBIAN_SECURITY_SNAPSHOT=20260901T000000Z + +WORKDIR /var/www + +RUN --mount=type=bind,from=php_extension_installer,source=/usr/bin/install-php-extensions,target=/usr/local/bin/install-php-extensions \ + # Bullseye is EOL: + sed -i -E "s|^deb http://deb.debian.org/debian-security (.*)|deb [check-valid-until=no] http://snapshot.debian.org/archive/debian-security/$DEBIAN_SECURITY_SNAPSHOT \1|" /etc/apt/sources.list \ + && grep -q snapshot.debian.org /etc/apt/sources.list \ + && apt-get update \ + && apt-get install --assume-yes --no-install-recommends \ + apt-transport-https \ + ca-certificates \ + openssl \ + && install-php-extensions \ + pdo_mysql \ + pdo_pgsql \ + intl \ + pcntl \ + gd \ + bcmath \ + zip \ + soap \ + xsl \ + sockets \ + "event-$PHP_EVENT_VERSION" \ + "igbinary-$PHP_IGBINARY_VERSION" \ + "redis-$PHP_REDIS_VERSION" \ + "amqp-$PHP_AMQP_VERSION" \ + && cp "$PHP_INI_DIR/php.ini-production" "$PHP_INI_DIR/php.ini" \ + && mkdir -p \ + $XDG_CONFIG_HOME \ + $XDG_DATA_HOME \ + $XDG_CACHE_HOME \ + && rm -rf /var/www/* \ + # Cleanup + && apt-get autoremove --assume-yes \ + && apt-get clean --assume-yes \ + && rm -rf /var/lib/apt/lists/* \ + && rm -rf /tmp/* + +COPY files/general / + +FROM {{ getenv "COMPOSER_IMAGE" }} AS composer + +FROM runtime AS builder + +ARG TARGETARCH +ARG DEBIAN_FRONTEND=noninteractive + +# Latest version of Xdebug: https://pecl.php.net/package/xdebug +ARG XDEBUG_VERSION=3.1.6 +# Latest version of pcov: https://pecl.php.net/package/pcov +ARG PCOV_VERSION=1.0.12 + +RUN --mount=type=bind,from=php_extension_installer,source=/usr/bin/install-php-extensions,target=/usr/local/bin/install-php-extensions \ + apt-get update \ + && apt-get install --assume-yes --no-install-recommends \ + vim \ + git \ + sqlite3 \ + wait-for-it \ + p7zip-full \ + unzip \ + curl \ + # Download Composer keys + && mkdir -p "$XDG_CONFIG_HOME/composer" \ + && curl -fsSLo "$XDG_CONFIG_HOME/composer/keys.dev.pub" https://composer.github.io/snapshots.pub \ + && curl -fsSLo "$XDG_CONFIG_HOME/composer/keys.tags.pub" https://composer.github.io/releases.pub \ + && chmod 644 "$XDG_CONFIG_HOME/composer/keys.dev.pub" "$XDG_CONFIG_HOME/composer/keys.tags.pub" \ + # Install Xdebug and pcov PHP extensions + && install-php-extensions \ + "xdebug-$XDEBUG_VERSION" \ + "pcov-$PCOV_VERSION" \ + && cp "$PHP_INI_DIR/php.ini-development" "$PHP_INI_DIR/php.ini" \ + # Cleanup + && apt-get autoremove --assume-yes \ + && apt-get clean --assume-yes \ + && rm -rf /var/lib/apt/lists/* \ + && rm -rf /tmp/* + +# Latest version of fixuid: https://github.com/boxboat/fixuid/releases/latest +ARG FIXUID_VERSION=0.6.0 + +ARG USER=code +ARG GROUP=code +ARG USER_UID=1000 +ARG USER_GID=1000 + +SHELL ["/bin/bash", "-o", "pipefail", "-c"] + +RUN curl -fsSLo /tmp/fixuid.tar.gz "https://github.com/boxboat/fixuid/releases/download/v$FIXUID_VERSION/fixuid-${FIXUID_VERSION}-linux-${TARGETARCH}.tar.gz" \ + && tar -xf /tmp/fixuid.tar.gz -C /usr/local/bin fixuid \ + && chown root:root /usr/local/bin/fixuid \ + && chmod 4755 /usr/local/bin/fixuid \ + && rm /tmp/fixuid.tar.gz \ + # Create user and group, and setup fixuid configuration + && existing_group="$(getent group "$USER_GID" | cut -d: -f1 || true)" \ + && if [ -z "$existing_group" ]; then \ + groupadd --gid "$USER_GID" "$GROUP"; \ + existing_group="$GROUP"; \ + fi \ + && useradd --uid "$USER_UID" --gid "$USER_GID" --create-home "$USER" --shell /bin/bash \ + && mkdir -p \ + /etc/fixuid \ + "/data" \ + "/config" \ + "/cache/npm" \ + "/cache/node" \ + && chown -R "$USER_UID":"$USER_GID" \ + "/data" \ + "/config" \ + "/cache" \ + && cat < /etc/fixuid/config.yml +user: $USER +group: $existing_group +paths: + - /var/www + - /home/$USER + - /data + - /config + - /cache + +EOF + +COPY --from=composer /composer /usr/bin/composer + +# Latest version of node: https://hub.docker.com/_/node/tags +FROM {{ getenv "NODE_IMAGE" }} AS node + +FROM builder AS builder_nodejs + +ARG DEBIAN_FRONTEND=noninteractive + +ENV COREPACK_ENABLE_DOWNLOAD_PROMPT=0 +ENV npm_config_cache="$XDG_CACHE_HOME/npm" + +COPY --from=node /usr/local/bin/node /usr/local/bin/node +COPY --from=node /usr/local/lib/node_modules /usr/local/lib/node_modules + +RUN apt-get update \ + && apt-get install --assume-yes --no-install-recommends \ + gcc \ + g++ \ + make \ + && ln -s ../lib/node_modules/corepack/dist/corepack.js /usr/local/bin/corepack \ + && corepack install --global npm@11.x yarn@4.x pnpm@10.x \ + && corepack enable npm yarn pnpm \ + # Cleanup + && apt-get autoremove --assume-yes \ + && apt-get clean --assume-yes \ + && rm -rf /var/lib/apt/lists/* \ + && rm -rf /tmp/* diff --git a/LICENSE b/LICENSE index 1132639..7559929 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ MIT License -Copyright (c) 2024 Ilyes Ahidar +Copyright (c) 2026 Ilyes Ahidar Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/README.md b/README.md index 147e314..e7b6d95 100644 --- a/README.md +++ b/README.md @@ -1,27 +1,28 @@ # php74 -[![Build Images](https://github.com/Ilyes512/php74/actions/workflows/main.yml/badge.svg)](https://github.com/Ilyes512/php74/actions/workflows/main.yml) +[![Build Images](https://github.com/specsnl/php74/actions/workflows/main.yml/badge.svg)](https://github.com/specsnl/php74/actions/workflows/main.yml) A PHP 7.4 (FPM and Apache) based Docker base image. ## Pulling the images ``` -docker pull ghcr.io/ilyes512/php74:runtime-latest -docker pull ghcr.io/ilyes512/php74:builder-latest -docker pull ghcr.io/ilyes512/php74:builder-nodejs-latest -docker pull ghcr.io/ilyes512/php74:vscode-latest - -docker pull ghcr.io/ilyes512/php74/apache:runtime-latest -docker pull ghcr.io/ilyes512/php74/apache:builder-latest -docker pull ghcr.io/ilyes512/php74/apache:builder-nodejs-latest -docker pull ghcr.io/ilyes512/php74/apache:vscode-latest +# FPM +docker pull ghcr.io/specsnl/php74:latest +docker pull ghcr.io/specsnl/php74/builder:latest +docker pull ghcr.io/specsnl/php74/builder_nodejs:latest + +# Apache +docker pull ghcr.io/specsnl/php74/apache:latest +docker pull ghcr.io/specsnl/php74/apache/builder:latest +docker pull ghcr.io/specsnl/php74/apache/builder_nodejs:latest ``` -The tag scheme: `{TARGET}-{VERSION}` +The image name scheme: `ghcr.io/specsnl/php74[/{VARIANT}][/{TARGET}]:{VERSION}` -- **{TARGET}**: `runtime`, `builder`, `builder_nodejs` or `vscode` -- **{VERSION}**: `latest` or tag i.e. `1.0.0` +- **{VARIANT}**: omitted for FPM, otherwise `apache` +- **{TARGET}**: omitted for `runtime`, otherwise `builder` or `builder_nodejs` (also published as `node`) +- **{VERSION}**: `latest`, a release tag (i.e. `0.5.5`), `main` or `pr-` ## Building the docker image(s) @@ -30,44 +31,70 @@ There are multiple targets: - **runtime**: this is for *production*. It does not contain any development tools like Composer and Xdebug. - **builder**: this is for *development*. This is based on the runtime-target and it adds Composer, Xdebug etc. - **builder_nodejs**: this is for *development*. This is based on the builder-target and it adds NodeJS. - - **vscode**: this is for *development* using - [VS Code Remote](https://code.visualstudio.com/docs/remote/remote-overview). This is based on the - `builder_nodejs`-target and adds some VS Code deps. Building `runtime`-target: ``` -docker build --tag ghcr.io/ilyes512/php74:runtime-latest --file fpm/Dockerfile --target runtime . +docker build --tag ghcr.io/specsnl/php74:latest --file fpm/Dockerfile --target runtime . ``` Building `builder`-target: ``` -docker build --tag ghcr.io/ilyes512/php74:builder-latest --file fpm/Dockerfile --target builder . +docker build --tag ghcr.io/specsnl/php74/builder:latest --file fpm/Dockerfile --target builder . ``` Building `builder_nodejs`-target: ``` -docker build --tag ghcr.io/ilyes512/php74:builder-nodejs-latest --file fpm/Dockerfile --target builder_nodejs . +docker build --tag ghcr.io/specsnl/php74/builder_nodejs:latest --file fpm/Dockerfile --target builder_nodejs . ``` -Building `vscode`-target: +## Debian bullseye is EOL (`DEBIAN_SECURITY_SNAPSHOT`) + +PHP 7.4 images are only published for Debian 11 (bullseye), which is past end-of-life. Its security +suite has stopped being maintained, and the mirrors have moved on in a way that breaks `apt-get`: + +- `deb.debian.org` still serves the `bullseye-security` package index, but the `.deb` pool behind it + has been purged — every package download returns a 404. +- `archive.debian.org`, where EOL suites normally end up, does not have `bullseye-security` yet. As + of this writing it only goes up to `buster`. +- The final `Release` file (published 2026-08-31) carries a 7-day `Valid-Until` that has long since + lapsed, so `apt` rejects the repository as expired even where it is reachable. + +To still get the last published security updates, the runtime stage rewrites the `bullseye-security` +entry in `/etc/apt/sources.list` to point at [snapshot.debian.org](https://snapshot.debian.org), +which keeps every historical mirror state permanently. The build arg pins which state is used: ``` -docker build --tag ghcr.io/ilyes512/php74:vscode-latest --file fpm/Dockerfile --target vscode . +ARG DEBIAN_SECURITY_SNAPSHOT=20260901T000000Z ``` +That timestamp sits just after the final security publish, so the image gets the complete, final set +of bullseye security updates. Because the snapshot is immutable, this does not break when Debian +finishes moving bullseye to `archive.debian.org`. The rewrite also disables `apt`'s freshness check +for that one repository — signatures are still verified, only the "is this recent?" assertion is +skipped, which is unavoidable for a deliberately frozen suite. + +A `grep` guard follows the rewrite so the build fails loudly if the base image ever changes its +`sources.list` format, rather than silently falling back to building without security updates. + +Do not remove this in a cleanup: without it, `apt-get install` fails outright. + ## Task commands Available [Task](https://taskfile.dev/#/) commands: ``` -* build: Build all PHP Docker image targets of both the FPM and Apache variants +* build: Build all PHP Docker image targets of the FPM and Apache +* generate: Generate all Dockerfiles from Dockerfile.tmpl +* lint: Apply a Dockerfile linter to all Dockerfiles * build:apache: Build all PHP Docker image targets of the Apache variant * build:fpm: Build all PHP Docker image targets of the FPM variant +* install:hooks: Install git hooks (pre-commit regenerates and stages Dockerfiles from template) * lint:apache: Apply a Dockerfile linter (https://github.com/hadolint/hadolint) * lint:fpm: Apply a Dockerfile linter (https://github.com/hadolint/hadolint) +* remove:hooks: Remove installed git hooks * shell:apache: Interactive shell * shell:fpm: Interactive shell ``` diff --git a/Taskfile.dist.yml b/Taskfile.dist.yml index 615e873..9df1f1d 100644 --- a/Taskfile.dist.yml +++ b/Taskfile.dist.yml @@ -1,21 +1,32 @@ version: "3" -silent: true - vars: DOCKER_REPO: ghcr.io - DOCKER_OWNER: ilyes512 + DOCKER_OWNER: specsnl # Latatest version of Hadolint: https://hub.docker.com/r/hadolint/hadolint/tags or https://github.com/hadolint/hadolint/releases - HADOLINT_TAG_VERSION: v2.12.0 + HADOLINT_TAG_VERSION: v2.14.0 + # Latest version of gomplate: https://hub.docker.com/r/hairyhenderson/gomplate/tags or https://github.com/hairyhenderson/gomplate/releases + GOMPLATE_TAG_VERSION: v5.1.0 + +# env: +# BUILDKIT_PROGRESS: plain + +silent: true tasks: build: - desc: Build all PHP Docker image targets of both the FPM and Apache variants + desc: Build all PHP Docker image targets of the FPM and Apache cmds: - task: build:fpm - task: build:apache + lint: + desc: Apply a Dockerfile linter to all Dockerfiles + cmds: + - task: lint:fpm + - task: lint:apache + build:fpm: desc: Build all PHP Docker image targets of the FPM variant deps: [lint:fpm] @@ -38,11 +49,6 @@ tasks: TARGET: builder_nodejs DOCKER_IMAGE_NAME: '{{.DOCKER_IMAGE_NAME}}' DOCKER_FILE_PATH: '{{.DOCKER_FILE_PATH}}' - - task: build:target - vars: - TARGET: vscode - DOCKER_IMAGE_NAME: '{{.DOCKER_IMAGE_NAME}}' - DOCKER_FILE_PATH: '{{.DOCKER_FILE_PATH}}' build:apache: desc: Build all PHP Docker image targets of the Apache variant @@ -66,11 +72,6 @@ tasks: TARGET: builder_nodejs DOCKER_IMAGE_NAME: '{{.DOCKER_IMAGE_NAME}}' DOCKER_FILE_PATH: '{{.DOCKER_FILE_PATH}}' - - task: build:target - vars: - TARGET: vscode - DOCKER_IMAGE_NAME: '{{.DOCKER_IMAGE_NAME}}' - DOCKER_FILE_PATH: '{{.DOCKER_FILE_PATH}}' build:target: preconditions: @@ -78,32 +79,78 @@ tasks: test '{{.TARGET}}' = 'runtime' -o '{{.TARGET}}' = 'builder' -o '{{.TARGET}}' = 'builder_nodejs' - -o '{{.TARGET}}' = 'vscode' - msg: TARGET needs to contain the Docker TARGET [runtime, builder, builder_nodejs, vscode] + msg: TARGET needs to contain the Docker TARGET [runtime, builder, builder_nodejs] vars: VERSION: '{{.VERSION | default "latest"}}' + TARGET_PATH: '{{if ne .TARGET "runtime"}}/{{.TARGET}}{{end}}' cmds: - docker build --target {{.TARGET}} - --tag {{.DOCKER_REPO}}/{{.DOCKER_OWNER}}/{{.DOCKER_IMAGE_NAME}}:{{.TARGET}}-{{.VERSION}} + --tag {{.DOCKER_REPO}}/{{.DOCKER_OWNER}}/{{.DOCKER_IMAGE_NAME}}{{.TARGET_PATH}}:{{.VERSION}} --file {{.DOCKER_FILE_PATH}} . + requires: + vars: [DOCKER_IMAGE_NAME, TARGET, DOCKER_FILE_PATH] lint:fpm: desc: Apply a Dockerfile linter (https://github.com/hadolint/hadolint) cmds: - - task: lint + - task: do:lint vars: { DOCKERFILE_PATH: fpm/Dockerfile } lint:apache: desc: Apply a Dockerfile linter (https://github.com/hadolint/hadolint) cmds: - - task: lint + - task: do:lint vars: { DOCKERFILE_PATH: apache/Dockerfile } - lint: + generate: + desc: Generate all Dockerfiles from Dockerfile.tmpl + cmds: + - task: generate:variant + vars: { VARIANT: fpm } + - task: generate:variant + vars: { VARIANT: apache } + + generate:variant: + internal: true vars: - DOCKERFILE_PATH: '{{.DOCKERFILE_PATH}}' + BASE_IMAGE: + sh: awk '/^FROM .* AS runtime$/ { print $2; exit }' {{.VARIANT}}/Dockerfile + PHP_EXTENSION_INSTALLER_IMAGE: + sh: awk '/^FROM .* AS php_extension_installer$/ { print $2; exit }' {{.VARIANT}}/Dockerfile + COMPOSER_IMAGE: + sh: awk '/^FROM .* AS composer$/ { print $2; exit }' {{.VARIANT}}/Dockerfile + NODE_IMAGE: + sh: awk '/^FROM .* AS node$/ { print $2; exit }' {{.VARIANT}}/Dockerfile + cmds: + - docker run + --rm + --volume $(pwd)/Dockerfile.tmpl:/input/Dockerfile.tmpl:ro + --volume $(pwd)/variants/{{.VARIANT}}.yaml:/input/variant.yaml:ro + --env "BASE_IMAGE={{.BASE_IMAGE}}" + --env "PHP_EXTENSION_INSTALLER_IMAGE={{.PHP_EXTENSION_INSTALLER_IMAGE}}" + --env "COMPOSER_IMAGE={{.COMPOSER_IMAGE}}" + --env "NODE_IMAGE={{.NODE_IMAGE}}" + hairyhenderson/gomplate:{{.GOMPLATE_TAG_VERSION}} + --context .=file:///input/variant.yaml + --file /input/Dockerfile.tmpl + > {{.VARIANT}}/Dockerfile + requires: + vars: [VARIANT] + + install:hooks: + desc: Install git hooks (pre-commit regenerates and stages Dockerfiles from template) + cmds: + - cp scripts/pre-commit .git/hooks/pre-commit + + remove:hooks: + desc: Remove installed git hooks + cmds: + - rm -f .git/hooks/pre-commit + + do:lint: + internal: true cmds: - docker run --interactive @@ -113,6 +160,8 @@ tasks: hadolint - < {{.DOCKERFILE_PATH}} + requires: + vars: [DOCKERFILE_PATH] shell:fpm: desc: Interactive shell @@ -124,7 +173,7 @@ tasks: --interactive --tty --rm - {{.DOCKER_REPO}}/{{.DOCKER_OWNER}}/{{.DOCKER_IMAGE_NAME}}:builder_nodejs-{{.VERSION | default "latest" }} + {{.DOCKER_REPO}}/{{.DOCKER_OWNER}}/{{.DOCKER_IMAGE_NAME}}/builder_nodejs:{{.VERSION | default "latest" }} bash shell:apache: @@ -137,5 +186,5 @@ tasks: --interactive --tty --rm - {{.DOCKER_REPO}}/{{.DOCKER_OWNER}}/{{.DOCKER_IMAGE_NAME}}:builder_nodejs-{{.VERSION | default "latest" }} + {{.DOCKER_REPO}}/{{.DOCKER_OWNER}}/{{.DOCKER_IMAGE_NAME}}/builder_nodejs:{{.VERSION | default "latest" }} bash diff --git a/apache/Dockerfile b/apache/Dockerfile index e3655f4..5b5c4c1 100644 --- a/apache/Dockerfile +++ b/apache/Dockerfile @@ -1,216 +1,181 @@ -# Latest version of PHP base image: https://hub.docker.com/_/php?tab=tags +# syntax=docker/dockerfile:1 +# check=error=true + +# Latest version of php-extension-installer: https://hub.docker.com/r/mlocati/php-extension-installer/tags +FROM mlocati/php-extension-installer:2.11.12 AS php_extension_installer + +# Latest version of PHP base image: https://hub.docker.com/_/php/tags FROM php:7.4.33-apache-bullseye AS runtime -ARG UNIQUE_ID_FOR_CACHEFROM=runtime +ARG DEBIAN_FRONTEND=noninteractive + +ARG XDG_CONFIG_HOME=/config +ENV XDG_CONFIG_HOME=$XDG_CONFIG_HOME + +ARG XDG_DATA_HOME=/data +ENV XDG_DATA_HOME=$XDG_DATA_HOME + +ARG XDG_CACHE_HOME=/cache +ENV XDG_CACHE_HOME=$XDG_CACHE_HOME # Latest version of event-extension: https://pecl.php.net/package/event -ARG PHP_EVENT_VERSION=3.1.3 +ARG PHP_EVENT_VERSION=3.1.6 # Latest version of igbinary-extension: https://pecl.php.net/package/igbinary -ARG PHP_IGBINARY_VERSION=3.2.15 +ARG PHP_IGBINARY_VERSION=3.2.17RC1 # Latest version of redis-extension: https://pecl.php.net/package/redis -ARG PHP_REDIS_VERSION=6.0.2 +ARG PHP_REDIS_VERSION=6.3.0 # Latest version of amqp-extension: https://pecl.php.net/package/amqp -ARG PHP_AMQP_VERSION=2.1.2 +ARG PHP_AMQP_VERSION=2.2.0 -ENV SMTPHOST mail -ENV SMTPEHLO localhost +ARG DEBIAN_SECURITY_SNAPSHOT=20260901T000000Z WORKDIR /var/www -RUN apt-get update \ +RUN --mount=type=bind,from=php_extension_installer,source=/usr/bin/install-php-extensions,target=/usr/local/bin/install-php-extensions \ + # Bullseye is EOL: + sed -i -E "s|^deb http://deb.debian.org/debian-security (.*)|deb [check-valid-until=no] http://snapshot.debian.org/archive/debian-security/$DEBIAN_SECURITY_SNAPSHOT \1|" /etc/apt/sources.list \ + && grep -q snapshot.debian.org /etc/apt/sources.list \ + && apt-get update \ && apt-get install --assume-yes --no-install-recommends \ + apt-transport-https \ ca-certificates \ openssl \ - curl \ - msmtp-mta \ - # Dependency of the PHP intl-extension - libicu67 \ - # Dependency of the PHP gd-extension - libpng16-16 \ - libwebp6 \ - libjpeg62-turbo \ - libfreetype6 \ - # Dependency of PHP zip-extension - libzip4 \ - # Dependency of PHP event-extension - libevent-2.1-7 \ - libevent-openssl-2.1-7 \ - libevent-extra-2.1-7 \ - # Dependency of PHP pdo_pgsql-extension - libpq5 \ - # Dependency of PHP amqp-extension - librabbitmq4 \ - # Dependency of PHP xsl-extension - libxslt1.1 \ - # Install packages that are needed for building PHP extensions - && apt-get install --assume-yes --no-install-recommends \ - $PHPIZE_DEPS \ - # Dependency of the PHP intl-extension - libicu-dev \ - # Dependencies of PHP gd-extension - libpng-dev \ - libwebp-dev \ - libjpeg62-turbo-dev \ - libfreetype6-dev \ - # Dependency of PHP zip-extension - libzip-dev \ - # Dependency of PHP event-extension - libevent-dev \ - libssl-dev \ - # Dependency of PHP soap-extension - libxml2-dev \ - # Dependency of PHP pdo_pgsql-extension - libpq-dev \ - # Dependency of PHP amqp-extension - librabbitmq-dev \ - # Dependency of PHP xsl-extension - libxslt1-dev \ - # Configure PHP gd-extension - && docker-php-ext-configure gd \ - --enable-gd \ - --with-jpeg \ - --with-freetype \ - --with-webp \ - # Install PHP extensions - && docker-php-ext-install -j "$(nproc --all)" \ + && install-php-extensions \ pdo_mysql \ pdo_pgsql \ intl \ - opcache \ pcntl \ gd \ bcmath \ zip \ soap \ xsl \ - # Dependency of PHP event-extension sockets \ - && pecl install "event-$PHP_EVENT_VERSION" \ - # Optional dependency of PHP redis-extension - && pecl install "igbinary-$PHP_IGBINARY_VERSION" \ - && pecl install --configureoptions 'enable-redis-igbinary="yes"' "redis-$PHP_REDIS_VERSION" \ - && pecl install "amqp-$PHP_AMQP_VERSION" \ - && docker-php-ext-enable --ini-name docker-php-ext-zz-custom.ini \ - event \ - igbinary \ - redis \ - amqp \ + "event-$PHP_EVENT_VERSION" \ + "igbinary-$PHP_IGBINARY_VERSION" \ + "redis-$PHP_REDIS_VERSION" \ + "amqp-$PHP_AMQP_VERSION" \ && cp "$PHP_INI_DIR/php.ini-production" "$PHP_INI_DIR/php.ini" \ - # Purge packages that where only needed for building php extensions - && apt-get purge --assume-yes \ - $PHPIZE_DEPS \ - libicu-dev \ - libpng-dev \ - libwebp-dev \ - libjpeg62-turbo-dev \ - libfreetype6-dev \ - libzip-dev \ - libevent-dev \ - libssl-dev \ - libxml2-dev \ - libpq-dev \ - librabbitmq-dev \ - # Cleanup + && mkdir -p \ + $XDG_CONFIG_HOME \ + $XDG_DATA_HOME \ + $XDG_CACHE_HOME \ && rm -rf /var/www/* \ + # Cleanup && apt-get autoremove --assume-yes \ && apt-get clean --assume-yes \ && rm -rf /var/lib/apt/lists/* \ && rm -rf /tmp/* -COPY files / +COPY files/general / + +FROM composer/composer:2.10.2-bin AS composer FROM runtime AS builder -ARG UNIQUE_ID_FOR_CACHEFROM=builder +ARG TARGETARCH +ARG DEBIAN_FRONTEND=noninteractive -# Latest version of Phive: https://api.github.com/repos/phar-io/phive/releases/latest -ARG PHIVE_VERSION=0.15.2 -# Latest version of Composer: https://getcomposer.org/download -ARG COMPOSER_VERSION=2.7.1 -# Note that XDEBUG >3.2.0 is not compatible with PHP 7.4 +# Latest version of Xdebug: https://pecl.php.net/package/xdebug ARG XDEBUG_VERSION=3.1.6 -# Latest version of pcov: https://github.com/krakjoe/pcov/tags or https://pecl.php.net/package/pcov -ARG PCOV_VERSION=1.0.11 +# Latest version of pcov: https://pecl.php.net/package/pcov +ARG PCOV_VERSION=1.0.12 -RUN apt-get update \ +RUN --mount=type=bind,from=php_extension_installer,source=/usr/bin/install-php-extensions,target=/usr/local/bin/install-php-extensions \ + apt-get update \ && apt-get install --assume-yes --no-install-recommends \ - # Needed for xdebug extension configuration - $PHPIZE_DEPS \ vim \ git \ - unzip \ sqlite3 \ wait-for-it \ - # Needed for phive: - gnupg \ - # Install Phive - && curl -fsSLo /usr/local/bin/phive "https://github.com/phar-io/phive/releases/download/$PHIVE_VERSION/phive-$PHIVE_VERSION.phar" \ - && curl -fsSLo /tmp/phive.phar.asc "https://github.com/phar-io/phive/releases/download/$PHIVE_VERSION/phive-$PHIVE_VERSION.phar.asc" \ - && gpg --keyserver keys.openpgp.org --recv-keys 0x9D8A98B29B2D5D79 \ - && gpg --verify /tmp/phive.phar.asc /usr/local/bin/phive \ - && chmod +x /usr/local/bin/phive \ - && phive update-repository-list \ - # Install Composer using Phive - && phive install --global composer:$COMPOSER_VERSION --trust-gpg-keys CBB3D576F2A0946F \ - && rm -rf /root/.phive \ - # Install Xdebug PHP extension - && pecl install "xdebug-$XDEBUG_VERSION" \ - && docker-php-ext-enable xdebug \ - # Install pcov PHP extension - && pecl install "pcov-$PCOV_VERSION" \ - && docker-php-ext-enable pcov \ + p7zip-full \ + unzip \ + curl \ + # Download Composer keys + && mkdir -p "$XDG_CONFIG_HOME/composer" \ + && curl -fsSLo "$XDG_CONFIG_HOME/composer/keys.dev.pub" https://composer.github.io/snapshots.pub \ + && curl -fsSLo "$XDG_CONFIG_HOME/composer/keys.tags.pub" https://composer.github.io/releases.pub \ + && chmod 644 "$XDG_CONFIG_HOME/composer/keys.dev.pub" "$XDG_CONFIG_HOME/composer/keys.tags.pub" \ + # Install Xdebug and pcov PHP extensions + && install-php-extensions \ + "xdebug-$XDEBUG_VERSION" \ + "pcov-$PCOV_VERSION" \ && cp "$PHP_INI_DIR/php.ini-development" "$PHP_INI_DIR/php.ini" \ # Cleanup - && apt-get purge --assume-yes $PHPIZE_DEPS \ && apt-get autoremove --assume-yes \ && apt-get clean --assume-yes \ && rm -rf /var/lib/apt/lists/* \ && rm -rf /tmp/* -FROM builder AS builder_nodejs +# Latest version of fixuid: https://github.com/boxboat/fixuid/releases/latest +ARG FIXUID_VERSION=0.6.0 + +ARG USER=code +ARG GROUP=code +ARG USER_UID=1000 +ARG USER_GID=1000 SHELL ["/bin/bash", "-o", "pipefail", "-c"] -ARG UNIQUE_ID_FOR_CACHEFROM=builder_nodejs +RUN curl -fsSLo /tmp/fixuid.tar.gz "https://github.com/boxboat/fixuid/releases/download/v$FIXUID_VERSION/fixuid-${FIXUID_VERSION}-linux-${TARGETARCH}.tar.gz" \ + && tar -xf /tmp/fixuid.tar.gz -C /usr/local/bin fixuid \ + && chown root:root /usr/local/bin/fixuid \ + && chmod 4755 /usr/local/bin/fixuid \ + && rm /tmp/fixuid.tar.gz \ + # Create user and group, and setup fixuid configuration + && existing_group="$(getent group "$USER_GID" | cut -d: -f1 || true)" \ + && if [ -z "$existing_group" ]; then \ + groupadd --gid "$USER_GID" "$GROUP"; \ + existing_group="$GROUP"; \ + fi \ + && useradd --uid "$USER_UID" --gid "$USER_GID" --create-home "$USER" --shell /bin/bash \ + && mkdir -p \ + /etc/fixuid \ + "/data" \ + "/config" \ + "/cache/npm" \ + "/cache/node" \ + && chown -R "$USER_UID":"$USER_GID" \ + "/data" \ + "/config" \ + "/cache" \ + && cat < /etc/fixuid/config.yml +user: $USER +group: $existing_group +paths: + - /var/www + - /home/$USER + - /data + - /config + - /cache + +EOF + +COPY --from=composer /composer /usr/bin/composer + +# Latest version of node: https://hub.docker.com/_/node/tags +FROM node:24.19.0-trixie-slim AS node + +FROM builder AS builder_nodejs + +ARG DEBIAN_FRONTEND=noninteractive + +ENV COREPACK_ENABLE_DOWNLOAD_PROMPT=0 +ENV npm_config_cache="$XDG_CACHE_HOME/npm" -# Latest version of Node.js: https://nodejs.org -ARG NODE_MAJOR=20 +COPY --from=node /usr/local/bin/node /usr/local/bin/node +COPY --from=node /usr/local/lib/node_modules /usr/local/lib/node_modules RUN apt-get update \ && apt-get install --assume-yes --no-install-recommends \ gcc \ g++ \ make \ - && mkdir -p /etc/apt/keyrings \ - && curl -fsSL https://deb.nodesource.com/gpgkey/nodesource-repo.gpg.key | gpg --dearmor -o /etc/apt/keyrings/nodesource.gpg \ - && echo "deb [signed-by=/etc/apt/keyrings/nodesource.gpg] https://deb.nodesource.com/node_$NODE_MAJOR.x nodistro main" | tee /etc/apt/sources.list.d/nodesource.list \ - && apt-get update \ - && apt-get install --assume-yes --no-install-recommends \ - nodejs \ - && npm uninstall --global npm \ - && corepack install --global --all \ + && ln -s ../lib/node_modules/corepack/dist/corepack.js /usr/local/bin/corepack \ + && corepack install --global npm@11.x yarn@4.x pnpm@10.x \ && corepack enable npm yarn pnpm \ + # Cleanup && apt-get autoremove --assume-yes \ && apt-get clean --assume-yes \ && rm -rf /var/lib/apt/lists/* \ && rm -rf /tmp/* - -FROM builder_nodejs AS vscode - -ARG UNIQUE_ID_FOR_CACHEFROM=vscode - -RUN apt-get update \ - && apt-get install --assume-yes --no-install-recommends \ - openssh-client \ - sudo \ - # VSCode Live Share Extension dependencies - libicu67 \ - libkrb5-3 \ - zlib1g \ - gnome-keyring \ - libsecret-1-0 \ - desktop-file-utils \ - x11-utils \ - && apt-get autoremove --assume-yes \ - && apt-get clean --assume-yes \ - && rm -rf /var/lib/apt/lists/* diff --git a/files/usr/local/etc/php/conf.d/010-default.ini b/files/general/usr/local/etc/php/conf.d/010-default.ini similarity index 100% rename from files/usr/local/etc/php/conf.d/010-default.ini rename to files/general/usr/local/etc/php/conf.d/010-default.ini diff --git a/fpm/Dockerfile b/fpm/Dockerfile index 78c8b25..a20fa68 100644 --- a/fpm/Dockerfile +++ b/fpm/Dockerfile @@ -1,216 +1,181 @@ -# Latest version of PHP base image: https://hub.docker.com/_/php?tab=tags +# syntax=docker/dockerfile:1 +# check=error=true + +# Latest version of php-extension-installer: https://hub.docker.com/r/mlocati/php-extension-installer/tags +FROM mlocati/php-extension-installer:2.11.12 AS php_extension_installer + +# Latest version of PHP base image: https://hub.docker.com/_/php/tags FROM php:7.4.33-fpm-bullseye AS runtime -ARG UNIQUE_ID_FOR_CACHEFROM=runtime +ARG DEBIAN_FRONTEND=noninteractive + +ARG XDG_CONFIG_HOME=/config +ENV XDG_CONFIG_HOME=$XDG_CONFIG_HOME + +ARG XDG_DATA_HOME=/data +ENV XDG_DATA_HOME=$XDG_DATA_HOME + +ARG XDG_CACHE_HOME=/cache +ENV XDG_CACHE_HOME=$XDG_CACHE_HOME # Latest version of event-extension: https://pecl.php.net/package/event -ARG PHP_EVENT_VERSION=3.1.3 +ARG PHP_EVENT_VERSION=3.1.6 # Latest version of igbinary-extension: https://pecl.php.net/package/igbinary -ARG PHP_IGBINARY_VERSION=3.2.15 +ARG PHP_IGBINARY_VERSION=3.2.17RC1 # Latest version of redis-extension: https://pecl.php.net/package/redis -ARG PHP_REDIS_VERSION=6.0.2 +ARG PHP_REDIS_VERSION=6.3.0 # Latest version of amqp-extension: https://pecl.php.net/package/amqp -ARG PHP_AMQP_VERSION=2.1.2 +ARG PHP_AMQP_VERSION=2.2.0 -ENV SMTPHOST mail -ENV SMTPEHLO localhost +ARG DEBIAN_SECURITY_SNAPSHOT=20260901T000000Z WORKDIR /var/www -RUN apt-get update \ +RUN --mount=type=bind,from=php_extension_installer,source=/usr/bin/install-php-extensions,target=/usr/local/bin/install-php-extensions \ + # Bullseye is EOL: + sed -i -E "s|^deb http://deb.debian.org/debian-security (.*)|deb [check-valid-until=no] http://snapshot.debian.org/archive/debian-security/$DEBIAN_SECURITY_SNAPSHOT \1|" /etc/apt/sources.list \ + && grep -q snapshot.debian.org /etc/apt/sources.list \ + && apt-get update \ && apt-get install --assume-yes --no-install-recommends \ + apt-transport-https \ ca-certificates \ openssl \ - curl \ - msmtp-mta \ - # Dependency of the PHP intl-extension - libicu67 \ - # Dependency of the PHP gd-extension - libpng16-16 \ - libwebp6 \ - libjpeg62-turbo \ - libfreetype6 \ - # Dependency of PHP zip-extension - libzip4 \ - # Dependency of PHP event-extension - libevent-2.1-7 \ - libevent-openssl-2.1-7 \ - libevent-extra-2.1-7 \ - # Dependency of PHP pdo_pgsql-extension - libpq5 \ - # Dependency of PHP amqp-extension - librabbitmq4 \ - # Dependency of PHP xsl-extension - libxslt1.1 \ - # Install packages that are needed for building PHP extensions - && apt-get install --assume-yes --no-install-recommends \ - $PHPIZE_DEPS \ - # Dependency of the PHP intl-extension - libicu-dev \ - # Dependencies of PHP gd-extension - libpng-dev \ - libwebp-dev \ - libjpeg62-turbo-dev \ - libfreetype6-dev \ - # Dependency of PHP zip-extension - libzip-dev \ - # Dependency of PHP event-extension - libevent-dev \ - libssl-dev \ - # Dependency of PHP soap-extension - libxml2-dev \ - # Dependency of PHP pdo_pgsql-extension - libpq-dev \ - # Dependency of PHP amqp-extension - librabbitmq-dev \ - # Dependency of PHP xsl-extension - libxslt1-dev \ - # Configure PHP gd-extension - && docker-php-ext-configure gd \ - --enable-gd \ - --with-jpeg \ - --with-freetype \ - --with-webp \ - # Install PHP extensions - && docker-php-ext-install -j "$(nproc --all)" \ + && install-php-extensions \ pdo_mysql \ pdo_pgsql \ intl \ - opcache \ pcntl \ gd \ bcmath \ zip \ soap \ xsl \ - # Dependency of PHP event-extension sockets \ - && pecl install "event-$PHP_EVENT_VERSION" \ - # Optional dependency of PHP redis-extension - && pecl install "igbinary-$PHP_IGBINARY_VERSION" \ - && pecl install --configureoptions 'enable-redis-igbinary="yes"' "redis-$PHP_REDIS_VERSION" \ - && pecl install "amqp-$PHP_AMQP_VERSION" \ - && docker-php-ext-enable --ini-name docker-php-ext-zz-custom.ini \ - event \ - igbinary \ - redis \ - amqp \ + "event-$PHP_EVENT_VERSION" \ + "igbinary-$PHP_IGBINARY_VERSION" \ + "redis-$PHP_REDIS_VERSION" \ + "amqp-$PHP_AMQP_VERSION" \ && cp "$PHP_INI_DIR/php.ini-production" "$PHP_INI_DIR/php.ini" \ - # Purge packages that where only needed for building php extensions - && apt-get purge --assume-yes \ - $PHPIZE_DEPS \ - libicu-dev \ - libpng-dev \ - libwebp-dev \ - libjpeg62-turbo-dev \ - libfreetype6-dev \ - libzip-dev \ - libevent-dev \ - libssl-dev \ - libxml2-dev \ - libpq-dev \ - librabbitmq-dev \ - # Cleanup + && mkdir -p \ + $XDG_CONFIG_HOME \ + $XDG_DATA_HOME \ + $XDG_CACHE_HOME \ && rm -rf /var/www/* \ + # Cleanup && apt-get autoremove --assume-yes \ && apt-get clean --assume-yes \ && rm -rf /var/lib/apt/lists/* \ && rm -rf /tmp/* -COPY files / +COPY files/general / + +FROM composer/composer:2.10.2-bin AS composer FROM runtime AS builder -ARG UNIQUE_ID_FOR_CACHEFROM=builder +ARG TARGETARCH +ARG DEBIAN_FRONTEND=noninteractive -# Latest version of Phive: https://api.github.com/repos/phar-io/phive/releases/latest -ARG PHIVE_VERSION=0.15.2 -# Latest version of Composer: https://getcomposer.org/download -ARG COMPOSER_VERSION=2.7.1 -# Note that XDEBUG >3.2.0 is not compatible with PHP 7.4 +# Latest version of Xdebug: https://pecl.php.net/package/xdebug ARG XDEBUG_VERSION=3.1.6 -# Latest version of pcov: https://github.com/krakjoe/pcov/tags or https://pecl.php.net/package/pcov -ARG PCOV_VERSION=1.0.11 +# Latest version of pcov: https://pecl.php.net/package/pcov +ARG PCOV_VERSION=1.0.12 -RUN apt-get update \ +RUN --mount=type=bind,from=php_extension_installer,source=/usr/bin/install-php-extensions,target=/usr/local/bin/install-php-extensions \ + apt-get update \ && apt-get install --assume-yes --no-install-recommends \ - # Needed for xdebug extension configuration - $PHPIZE_DEPS \ vim \ git \ - unzip \ sqlite3 \ wait-for-it \ - # Needed for phive: - gnupg \ - # Install Phive - && curl -fsSLo /usr/local/bin/phive "https://github.com/phar-io/phive/releases/download/$PHIVE_VERSION/phive-$PHIVE_VERSION.phar" \ - && curl -fsSLo /tmp/phive.phar.asc "https://github.com/phar-io/phive/releases/download/$PHIVE_VERSION/phive-$PHIVE_VERSION.phar.asc" \ - && gpg --keyserver keys.openpgp.org --recv-keys 0x9D8A98B29B2D5D79 \ - && gpg --verify /tmp/phive.phar.asc /usr/local/bin/phive \ - && chmod +x /usr/local/bin/phive \ - && phive update-repository-list \ - # Install Composer using Phive - && phive install --global composer:$COMPOSER_VERSION --trust-gpg-keys CBB3D576F2A0946F \ - && rm -rf /root/.phive \ - # Install Xdebug PHP extension - && pecl install "xdebug-$XDEBUG_VERSION" \ - && docker-php-ext-enable xdebug \ - # Install pcov PHP extension - && pecl install "pcov-$PCOV_VERSION" \ - && docker-php-ext-enable pcov \ + p7zip-full \ + unzip \ + curl \ + # Download Composer keys + && mkdir -p "$XDG_CONFIG_HOME/composer" \ + && curl -fsSLo "$XDG_CONFIG_HOME/composer/keys.dev.pub" https://composer.github.io/snapshots.pub \ + && curl -fsSLo "$XDG_CONFIG_HOME/composer/keys.tags.pub" https://composer.github.io/releases.pub \ + && chmod 644 "$XDG_CONFIG_HOME/composer/keys.dev.pub" "$XDG_CONFIG_HOME/composer/keys.tags.pub" \ + # Install Xdebug and pcov PHP extensions + && install-php-extensions \ + "xdebug-$XDEBUG_VERSION" \ + "pcov-$PCOV_VERSION" \ && cp "$PHP_INI_DIR/php.ini-development" "$PHP_INI_DIR/php.ini" \ # Cleanup - && apt-get purge --assume-yes $PHPIZE_DEPS \ && apt-get autoremove --assume-yes \ && apt-get clean --assume-yes \ && rm -rf /var/lib/apt/lists/* \ && rm -rf /tmp/* -FROM builder AS builder_nodejs +# Latest version of fixuid: https://github.com/boxboat/fixuid/releases/latest +ARG FIXUID_VERSION=0.6.0 + +ARG USER=code +ARG GROUP=code +ARG USER_UID=1000 +ARG USER_GID=1000 SHELL ["/bin/bash", "-o", "pipefail", "-c"] -ARG UNIQUE_ID_FOR_CACHEFROM=builder_nodejs +RUN curl -fsSLo /tmp/fixuid.tar.gz "https://github.com/boxboat/fixuid/releases/download/v$FIXUID_VERSION/fixuid-${FIXUID_VERSION}-linux-${TARGETARCH}.tar.gz" \ + && tar -xf /tmp/fixuid.tar.gz -C /usr/local/bin fixuid \ + && chown root:root /usr/local/bin/fixuid \ + && chmod 4755 /usr/local/bin/fixuid \ + && rm /tmp/fixuid.tar.gz \ + # Create user and group, and setup fixuid configuration + && existing_group="$(getent group "$USER_GID" | cut -d: -f1 || true)" \ + && if [ -z "$existing_group" ]; then \ + groupadd --gid "$USER_GID" "$GROUP"; \ + existing_group="$GROUP"; \ + fi \ + && useradd --uid "$USER_UID" --gid "$USER_GID" --create-home "$USER" --shell /bin/bash \ + && mkdir -p \ + /etc/fixuid \ + "/data" \ + "/config" \ + "/cache/npm" \ + "/cache/node" \ + && chown -R "$USER_UID":"$USER_GID" \ + "/data" \ + "/config" \ + "/cache" \ + && cat < /etc/fixuid/config.yml +user: $USER +group: $existing_group +paths: + - /var/www + - /home/$USER + - /data + - /config + - /cache + +EOF + +COPY --from=composer /composer /usr/bin/composer + +# Latest version of node: https://hub.docker.com/_/node/tags +FROM node:24.19.0-trixie-slim AS node + +FROM builder AS builder_nodejs + +ARG DEBIAN_FRONTEND=noninteractive + +ENV COREPACK_ENABLE_DOWNLOAD_PROMPT=0 +ENV npm_config_cache="$XDG_CACHE_HOME/npm" -# Latest version of Node.js: https://nodejs.org -ARG NODE_MAJOR=20 +COPY --from=node /usr/local/bin/node /usr/local/bin/node +COPY --from=node /usr/local/lib/node_modules /usr/local/lib/node_modules RUN apt-get update \ && apt-get install --assume-yes --no-install-recommends \ gcc \ g++ \ make \ - && mkdir -p /etc/apt/keyrings \ - && curl -fsSL https://deb.nodesource.com/gpgkey/nodesource-repo.gpg.key | gpg --dearmor -o /etc/apt/keyrings/nodesource.gpg \ - && echo "deb [signed-by=/etc/apt/keyrings/nodesource.gpg] https://deb.nodesource.com/node_$NODE_MAJOR.x nodistro main" | tee /etc/apt/sources.list.d/nodesource.list \ - && apt-get update \ - && apt-get install --assume-yes --no-install-recommends \ - nodejs \ - && npm uninstall --global npm \ - && corepack install --global --all \ + && ln -s ../lib/node_modules/corepack/dist/corepack.js /usr/local/bin/corepack \ + && corepack install --global npm@11.x yarn@4.x pnpm@10.x \ && corepack enable npm yarn pnpm \ + # Cleanup && apt-get autoremove --assume-yes \ && apt-get clean --assume-yes \ && rm -rf /var/lib/apt/lists/* \ && rm -rf /tmp/* - -FROM builder_nodejs AS vscode - -ARG UNIQUE_ID_FOR_CACHEFROM=vscode - -RUN apt-get update \ - && apt-get install --assume-yes --no-install-recommends \ - openssh-client \ - sudo \ - # VSCode Live Share Extension dependencies - libicu67 \ - libkrb5-3 \ - zlib1g \ - gnome-keyring \ - libsecret-1-0 \ - desktop-file-utils \ - x11-utils \ - && apt-get autoremove --assume-yes \ - && apt-get clean --assume-yes \ - && rm -rf /var/lib/apt/lists/* diff --git a/scripts/pre-commit b/scripts/pre-commit new file mode 100755 index 0000000..b35aa28 --- /dev/null +++ b/scripts/pre-commit @@ -0,0 +1,4 @@ +#!/usr/bin/env sh +set -e +task generate +git add fpm/Dockerfile apache/Dockerfile diff --git a/variants/apache.yaml b/variants/apache.yaml new file mode 100644 index 0000000..5ff5955 --- /dev/null +++ b/variants/apache.yaml @@ -0,0 +1,2 @@ +image_label: PHP base image +image_url: https://hub.docker.com/_/php/tags diff --git a/variants/fpm.yaml b/variants/fpm.yaml new file mode 100644 index 0000000..5ff5955 --- /dev/null +++ b/variants/fpm.yaml @@ -0,0 +1,2 @@ +image_label: PHP base image +image_url: https://hub.docker.com/_/php/tags