Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
130 changes: 61 additions & 69 deletions .github/workflows/docker-ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -30,76 +30,75 @@ concurrency:
cancel-in-progress: true

jobs:
setup:
runs-on: ubuntu-latest
outputs:
matrix: ${{ steps.matrix.outputs.matrix }}
s6_version: ${{ steps.s6.outputs.version }}
steps:
- name: Compute build matrix
id: matrix
run: |
if [ "${{ github.event_name }}" = "pull_request" ]; then
PHP_VERSIONS='["8.4","8.2"]'
echo "::notice::PR detected — testing PHP 8.4 + 8.2 only (skipping 8.3)"
else
PHP_VERSIONS='["8.4","8.3","8.2"]'
fi

# Build trixie include list for v2 based on selected PHP versions
INCLUDES="[]"
for ver in $(echo "$PHP_VERSIONS" | jq -r '.[]'); do
for type in fpm cli apache; do
INCLUDES=$(echo "$INCLUDES" | jq -c ". + [{\"variant\":\"v2\",\"php-version\":\"$ver\",\"php-type\":\"$type\",\"php-base\":\"trixie\"}]")
done
done

MATRIX=$(jq -n -c \
--argjson versions "$PHP_VERSIONS" \
--argjson includes "$INCLUDES" \
'{
"variant": ["v1","v2"],
"php-version": $versions,
"php-type": ["fpm","cli","apache"],
"php-base": ["alpine","bookworm"],
"exclude": [
{"php-type":"apache","php-base":"alpine"},
{"variant":"v2","php-base":"bookworm"}
],
"include": $includes
}')

echo "matrix=$MATRIX" >> $GITHUB_OUTPUT

- name: Get latest s6-overlay version
id: s6
run: |
set -euo pipefail
RESPONSE="$(curl -fSLs \
-H "Authorization: Bearer ${{ github.token }}" \
https://api.github.com/repos/just-containers/s6-overlay/releases/latest)"
S6_OVERLAY_VERSION="$(echo "$RESPONSE" | jq -r .tag_name)"
if [ -z "$S6_OVERLAY_VERSION" ] || [ "$S6_OVERLAY_VERSION" = "null" ]; then
echo "::error::Failed to determine s6-overlay version"
exit 1
fi
echo "version=${S6_OVERLAY_VERSION}" >> $GITHUB_OUTPUT
echo "✅ Latest s6-overlay version: ${S6_OVERLAY_VERSION}"

build-and-test:
needs: setup
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
variant: [v1, v2]
php-version: ['8.4', '8.3', '8.2']
php-type: [fpm, cli, apache]
php-base: [alpine, bookworm]
exclude:
- php-type: apache
php-base: alpine
- variant: v2
php-base: bookworm
include:
- variant: v2
php-version: '8.4'
php-type: fpm
php-base: trixie
- variant: v2
php-version: '8.4'
php-type: cli
php-base: trixie
- variant: v2
php-version: '8.4'
php-type: apache
php-base: trixie
- variant: v2
php-version: '8.3'
php-type: fpm
php-base: trixie
- variant: v2
php-version: '8.3'
php-type: cli
php-base: trixie
- variant: v2
php-version: '8.3'
php-type: apache
php-base: trixie
- variant: v2
php-version: '8.2'
php-type: fpm
php-base: trixie
- variant: v2
php-version: '8.2'
php-type: cli
php-base: trixie
- variant: v2
php-version: '8.2'
php-type: apache
php-base: trixie
matrix: ${{ fromJson(needs.setup.outputs.matrix) }}

name: ${{ matrix.variant }}-${{ matrix.php-version }}-${{ matrix.php-type }}-${{ matrix.php-base }}

steps:
- name: Checkout
uses: actions/checkout@v4

- name: Get latest s6-overlay version
id: s6-version
run: |
S6_OVERLAY_VERSION="$(curl -s https://api.github.com/repos/just-containers/s6-overlay/releases/latest | jq -r .tag_name)"
echo "version=${S6_OVERLAY_VERSION}" >> $GITHUB_OUTPUT
echo "✅ Latest s6-overlay version: ${S6_OVERLAY_VERSION}"

- name: Setup QEMU
uses: docker/setup-qemu-action@v3
with:
platforms: amd64,arm64,arm

- name: Setup Docker Buildx
uses: docker/setup-buildx-action@v3

Expand Down Expand Up @@ -138,7 +137,7 @@ jobs:
VERSION=${{ steps.vars.outputs.VERSION }}
PHPVERSION=${{ matrix.php-version }}
BASEOS=${{ matrix.php-base }}
S6_OVERLAY_VERSION=${{ steps.s6-version.outputs.version }}
S6_OVERLAY_VERSION=${{ needs.setup.outputs.s6_version }}
BUILD_DATE=${{ steps.vars.outputs.BUILD_DATE }}
VCS_REF=${{ github.sha }}
tags: test-${{ steps.vars.outputs.TAG }}
Expand Down Expand Up @@ -295,7 +294,7 @@ jobs:
echo "::notice::✅ Build and tests passed for ${{ matrix.variant }} - ${{ steps.vars.outputs.TAG }}"

publish:
needs: build-and-test
needs: [setup, build-and-test]
if: github.ref == 'refs/heads/main' && (github.event_name == 'push' || github.event_name == 'schedule')
runs-on: ubuntu-latest
strategy:
Expand Down Expand Up @@ -356,13 +355,6 @@ jobs:
- name: Checkout
uses: actions/checkout@v4

- name: Get latest s6-overlay version
id: s6-version
run: |
S6_OVERLAY_VERSION="$(curl -s https://api.github.com/repos/just-containers/s6-overlay/releases/latest | jq -r .tag_name)"
echo "version=${S6_OVERLAY_VERSION}" >> $GITHUB_OUTPUT
echo "✅ Latest s6-overlay version: ${S6_OVERLAY_VERSION}"

- name: Setup QEMU
uses: docker/setup-qemu-action@v3
with:
Expand Down Expand Up @@ -429,7 +421,7 @@ jobs:
VERSION=${{ steps.vars.outputs.VERSION }}
PHPVERSION=${{ matrix.php-version }}
BASEOS=${{ matrix.php-base }}
S6_OVERLAY_VERSION=${{ steps.s6-version.outputs.version }}
S6_OVERLAY_VERSION=${{ needs.setup.outputs.s6_version }}
BUILD_DATE=${{ steps.vars.outputs.BUILD_DATE }}
VCS_REF=${{ github.sha }}
tags: |
Expand Down
54 changes: 13 additions & 41 deletions Dockerfile.v1
Original file line number Diff line number Diff line change
Expand Up @@ -6,57 +6,29 @@ ARG BASEOS
# Set environment variables
ENV DEBIAN_FRONTEND=noninteractive

COPY extras/retry.sh /usr/local/bin/retry
RUN chmod +x /usr/local/bin/retry

# Install dependencies based on the base OS
RUN if [ "$BASEOS" = "bookworm" ]; then \
RUN --mount=type=cache,target=/var/cache/apt,sharing=locked,id=apt-$BASEOS \
--mount=type=cache,target=/var/lib/apt/lists,sharing=locked,id=aptlists-$BASEOS \
if [ "$BASEOS" = "bookworm" ]; then \
echo 'deb http://deb.debian.org/debian bookworm main' > /etc/apt/sources.list && \
apt-get update && \
apt-get -y upgrade && \
apt-get install -y --no-install-recommends curl git zip unzip ghostscript imagemagick optipng gifsicle pngcrush jpegoptim libjpeg-turbo-progs pngquant webp && \
rm -rf /var/lib/apt/lists/*; \
apt-get install -y --no-install-recommends curl git zip unzip ghostscript imagemagick optipng gifsicle pngcrush jpegoptim libjpeg-turbo-progs pngquant webp; \
elif [ "$BASEOS" = "alpine" ]; then \
apk update && \
apk add --no-cache curl git zip unzip ghostscript imagemagick optipng gifsicle pngcrush jpegoptim libjpeg-turbo libjpeg-turbo-utils pngquant libwebp-tools; \
fi

# Add all needed PHP extensions with retry logic for transient network failures
RUN for ATTEMPT in 1 2 3; do \
if curl -sSLf -o /usr/local/bin/install-php-extensions \
https://github.com/mlocati/docker-php-extension-installer/releases/latest/download/install-php-extensions; then \
break; \
else \
if [ $ATTEMPT -lt 3 ]; then \
case $ATTEMPT in \
1) SLEEP_TIME=5 ;; \
2) SLEEP_TIME=10 ;; \
esac; \
echo "Download attempt $ATTEMPT failed, retrying in ${SLEEP_TIME}s..."; \
sleep $SLEEP_TIME; \
rm -f /usr/local/bin/install-php-extensions; \
else \
echo "Failed to download install-php-extensions after 3 attempts"; \
exit 1; \
fi; \
fi; \
done && \
# Download and install PHP extensions with retry for transient failures
RUN retry 3 curl -sSLf -o /usr/local/bin/install-php-extensions \
https://github.com/mlocati/docker-php-extension-installer/releases/latest/download/install-php-extensions && \
chmod +x /usr/local/bin/install-php-extensions && \
for ATTEMPT in 1 2 3; do \
if install-php-extensions amqp bcmath bz2 calendar ctype exif intl imagick imap json mbstring ldap mcrypt memcached mongodb \
mysqli opcache pdo_mysql pdo_pgsql pgsql redis snmp soap sockets tidy timezonedb uuid vips xsl yaml zip zstd @composer; then \
break; \
else \
if [ $ATTEMPT -lt 3 ]; then \
case $ATTEMPT in \
1) SLEEP_TIME=5 ;; \
2) SLEEP_TIME=10 ;; \
esac; \
echo "Extension installation attempt $ATTEMPT failed, retrying in ${SLEEP_TIME}s..."; \
sleep $SLEEP_TIME; \
else \
echo "Failed to install PHP extensions after 3 attempts"; \
exit 1; \
fi; \
fi; \
done
retry 3 install-php-extensions \
amqp bcmath bz2 calendar ctype exif intl imagick imap json mbstring ldap mcrypt memcached mongodb \
mysqli opcache pdo_mysql pdo_pgsql pgsql redis snmp soap sockets tidy timezonedb uuid vips xsl yaml zip zstd @composer

# Enable Apache rewrite mod, if applicable
RUN if command -v a2enmod; then a2enmod rewrite; fi
Expand Down
51 changes: 12 additions & 39 deletions Dockerfile.v2
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,9 @@ ARG VERSION
# Set environment variables
ENV DEBIAN_FRONTEND=noninteractive

COPY extras/retry.sh /usr/local/bin/retry
RUN chmod +x /usr/local/bin/retry

# OCI standard labels
LABEL org.opencontainers.image.title="php-docker" \
org.opencontainers.image.description="PHP runtime with s6-overlay and curated extensions" \
Expand All @@ -26,7 +29,9 @@ LABEL org.opencontainers.image.title="php-docker" \

# Install build dependencies, PHP extensions, runtime libraries, and s6-overlay
# Then clean up build-only packages in a single layer to minimize image size
RUN if [ "$BASEOS" = "trixie" ] || [ "$BASEOS" = "bookworm" ]; then \
RUN --mount=type=cache,target=/var/cache/apt,sharing=locked,id=apt-$BASEOS \
--mount=type=cache,target=/var/lib/apt/lists,sharing=locked,id=aptlists-$BASEOS \
if [ "$BASEOS" = "trixie" ] || [ "$BASEOS" = "bookworm" ]; then \
apt-get update && \
apt-get -y upgrade && \
# Install build tools, dev packages, and runtime libraries together
Expand Down Expand Up @@ -129,25 +134,8 @@ RUN if [ "$BASEOS" = "trixie" ] || [ "$BASEOS" = "bookworm" ]; then \
libxpm libxpm-dev; \
fi && \
# Download PHP extension installer with retry
for ATTEMPT in 1 2 3; do \
if curl -sSLf -o /usr/local/bin/install-php-extensions \
https://github.com/mlocati/docker-php-extension-installer/releases/latest/download/install-php-extensions; then \
break; \
else \
if [ $ATTEMPT -lt 3 ]; then \
case $ATTEMPT in \
1) SLEEP_TIME=5 ;; \
2) SLEEP_TIME=10 ;; \
esac; \
echo "Download attempt $ATTEMPT failed, retrying in ${SLEEP_TIME}s..."; \
sleep $SLEEP_TIME; \
rm -f /usr/local/bin/install-php-extensions; \
else \
echo "Failed to download install-php-extensions after 3 attempts"; \
exit 1; \
fi; \
fi; \
done && \
retry 3 curl -sSLf -o /usr/local/bin/install-php-extensions \
https://github.com/mlocati/docker-php-extension-installer/releases/latest/download/install-php-extensions && \
chmod +x /usr/local/bin/install-php-extensions && \
# Install PHP extensions
install-php-extensions \
Expand All @@ -173,25 +161,10 @@ RUN if [ "$BASEOS" = "trixie" ] || [ "$BASEOS" = "bookworm" ]; then \
*) S6_ARCH="x86_64" ;; \
esac && \
echo "Downloading s6-overlay ${S6_OVERLAY_VERSION} for ${S6_ARCH}" && \
for ATTEMPT in 1 2 3; do \
if wget -O /tmp/s6-overlay-noarch.tar.xz https://github.com/just-containers/s6-overlay/releases/download/${S6_OVERLAY_VERSION}/s6-overlay-noarch.tar.xz && \
wget -O /tmp/s6-overlay-${S6_ARCH}.tar.xz https://github.com/just-containers/s6-overlay/releases/download/${S6_OVERLAY_VERSION}/s6-overlay-${S6_ARCH}.tar.xz; then \
break; \
else \
if [ $ATTEMPT -lt 3 ]; then \
case $ATTEMPT in \
1) SLEEP_TIME=5 ;; \
2) SLEEP_TIME=10 ;; \
esac; \
echo "Download attempt $ATTEMPT failed, retrying in ${SLEEP_TIME}s..."; \
sleep $SLEEP_TIME; \
rm -f /tmp/s6-overlay-*.tar.xz; \
else \
echo "Failed to download s6-overlay after 3 attempts"; \
exit 1; \
fi; \
fi; \
done && \
retry 3 wget -O /tmp/s6-overlay-noarch.tar.xz \
https://github.com/just-containers/s6-overlay/releases/download/${S6_OVERLAY_VERSION}/s6-overlay-noarch.tar.xz && \
retry 3 wget -O /tmp/s6-overlay-${S6_ARCH}.tar.xz \
https://github.com/just-containers/s6-overlay/releases/download/${S6_OVERLAY_VERSION}/s6-overlay-${S6_ARCH}.tar.xz && \
tar -C / -Jxpf /tmp/s6-overlay-noarch.tar.xz && \
tar -C / -Jxpf /tmp/s6-overlay-${S6_ARCH}.tar.xz && \
rm /tmp/s6-overlay-noarch.tar.xz /tmp/s6-overlay-${S6_ARCH}.tar.xz && \
Expand Down
21 changes: 21 additions & 0 deletions extras/retry.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
#!/bin/sh
# Retry a command with linear backoff
# Usage: retry <max_attempts> <command...>
# Example: retry 3 curl -sSLf -o /tmp/file https://example.com/file

MAX=$1
shift

for ATTEMPT in $(seq 1 "$MAX"); do
if "$@"; then
exit 0
fi
if [ "$ATTEMPT" -lt "$MAX" ]; then
SLEEP_TIME=$((5 * ATTEMPT))
echo "Attempt $ATTEMPT/$MAX failed, retrying in ${SLEEP_TIME}s..."
sleep "$SLEEP_TIME"
fi
done

echo "Failed after $MAX attempts: $*"
exit 1
2 changes: 1 addition & 1 deletion extras/test-build.sh
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ build_v1() {
echo "Building v1: ${IMAGE_NAME}:${tag}"
echo " VERSION=${version}, PHPVERSION=${phpversion}, BASEOS=${baseos}"

docker build -f Dockerfile.v1 \
DOCKER_BUILDKIT=1 docker build -f Dockerfile.v1 \
--build-arg VERSION="${version}" \
--build-arg PHPVERSION="${phpversion}" \
--build-arg BASEOS="${baseos}" \
Expand Down
Loading