Skip to content

Commit 9a2b160

Browse files
KingPinKingPin
authored andcommitted
perf: optimize CI workflow and Dockerfiles for faster builds
- Remove QEMU setup from build-and-test (only builds amd64) - Add setup job: fetches s6-overlay version once and computes PR-aware matrix (skip PHP 8.3 on PRs, test 8.4 + 8.2 only) - Add BuildKit cache mounts for apt/apk in both Dockerfiles - Extract retry/backoff logic to shared extras/retry.sh script, replacing ~50 lines of duplicated inline retry loops - Enable BuildKit for v1 in test-build.sh (required for cache mounts)
1 parent 59fdc4e commit 9a2b160

5 files changed

Lines changed: 77 additions & 104 deletions

File tree

.github/workflows/docker-ci.yml

Lines changed: 28 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -30,13 +30,37 @@ concurrency:
3030
cancel-in-progress: true
3131

3232
jobs:
33+
setup:
34+
runs-on: ubuntu-latest
35+
outputs:
36+
php-versions: ${{ steps.matrix.outputs.php-versions }}
37+
s6-version: ${{ steps.s6.outputs.version }}
38+
steps:
39+
- name: Determine PHP versions to test
40+
id: matrix
41+
run: |
42+
if [ "${{ github.event_name }}" = "pull_request" ]; then
43+
echo 'php-versions=["8.4","8.2"]' >> $GITHUB_OUTPUT
44+
echo "::notice::PR detected — testing PHP 8.4 + 8.2 only (skipping 8.3)"
45+
else
46+
echo 'php-versions=["8.4","8.3","8.2"]' >> $GITHUB_OUTPUT
47+
fi
48+
49+
- name: Get latest s6-overlay version
50+
id: s6
51+
run: |
52+
S6_OVERLAY_VERSION="$(curl -s https://api.github.com/repos/just-containers/s6-overlay/releases/latest | jq -r .tag_name)"
53+
echo "version=${S6_OVERLAY_VERSION}" >> $GITHUB_OUTPUT
54+
echo "✅ Latest s6-overlay version: ${S6_OVERLAY_VERSION}"
55+
3356
build-and-test:
57+
needs: setup
3458
runs-on: ubuntu-latest
3559
strategy:
3660
fail-fast: false
3761
matrix:
3862
variant: [v1, v2]
39-
php-version: ['8.4', '8.3', '8.2']
63+
php-version: ${{ fromJson(needs.setup.outputs.php-versions) }}
4064
php-type: [fpm, cli, apache]
4165
php-base: [alpine, bookworm]
4266
exclude:
@@ -88,18 +112,6 @@ jobs:
88112
- name: Checkout
89113
uses: actions/checkout@v4
90114

91-
- name: Get latest s6-overlay version
92-
id: s6-version
93-
run: |
94-
S6_OVERLAY_VERSION="$(curl -s https://api.github.com/repos/just-containers/s6-overlay/releases/latest | jq -r .tag_name)"
95-
echo "version=${S6_OVERLAY_VERSION}" >> $GITHUB_OUTPUT
96-
echo "✅ Latest s6-overlay version: ${S6_OVERLAY_VERSION}"
97-
98-
- name: Setup QEMU
99-
uses: docker/setup-qemu-action@v3
100-
with:
101-
platforms: amd64,arm64,arm
102-
103115
- name: Setup Docker Buildx
104116
uses: docker/setup-buildx-action@v3
105117

@@ -138,7 +150,7 @@ jobs:
138150
VERSION=${{ steps.vars.outputs.VERSION }}
139151
PHPVERSION=${{ matrix.php-version }}
140152
BASEOS=${{ matrix.php-base }}
141-
S6_OVERLAY_VERSION=${{ steps.s6-version.outputs.version }}
153+
S6_OVERLAY_VERSION=${{ needs.setup.outputs.s6-version }}
142154
BUILD_DATE=${{ steps.vars.outputs.BUILD_DATE }}
143155
VCS_REF=${{ github.sha }}
144156
tags: test-${{ steps.vars.outputs.TAG }}
@@ -295,7 +307,7 @@ jobs:
295307
echo "::notice::✅ Build and tests passed for ${{ matrix.variant }} - ${{ steps.vars.outputs.TAG }}"
296308
297309
publish:
298-
needs: build-and-test
310+
needs: [setup, build-and-test]
299311
if: github.ref == 'refs/heads/main' && (github.event_name == 'push' || github.event_name == 'schedule')
300312
runs-on: ubuntu-latest
301313
strategy:
@@ -356,13 +368,6 @@ jobs:
356368
- name: Checkout
357369
uses: actions/checkout@v4
358370

359-
- name: Get latest s6-overlay version
360-
id: s6-version
361-
run: |
362-
S6_OVERLAY_VERSION="$(curl -s https://api.github.com/repos/just-containers/s6-overlay/releases/latest | jq -r .tag_name)"
363-
echo "version=${S6_OVERLAY_VERSION}" >> $GITHUB_OUTPUT
364-
echo "✅ Latest s6-overlay version: ${S6_OVERLAY_VERSION}"
365-
366371
- name: Setup QEMU
367372
uses: docker/setup-qemu-action@v3
368373
with:
@@ -429,7 +434,7 @@ jobs:
429434
VERSION=${{ steps.vars.outputs.VERSION }}
430435
PHPVERSION=${{ matrix.php-version }}
431436
BASEOS=${{ matrix.php-base }}
432-
S6_OVERLAY_VERSION=${{ steps.s6-version.outputs.version }}
437+
S6_OVERLAY_VERSION=${{ needs.setup.outputs.s6-version }}
433438
BUILD_DATE=${{ steps.vars.outputs.BUILD_DATE }}
434439
VCS_REF=${{ github.sha }}
435440
tags: |

Dockerfile.v1

Lines changed: 14 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -6,57 +6,30 @@ ARG BASEOS
66
# Set environment variables
77
ENV DEBIAN_FRONTEND=noninteractive
88

9+
COPY extras/retry.sh /usr/local/bin/retry
10+
RUN chmod +x /usr/local/bin/retry
11+
912
# Install dependencies based on the base OS
10-
RUN if [ "$BASEOS" = "bookworm" ]; then \
13+
RUN --mount=type=cache,target=/var/cache/apt,sharing=locked,id=apt-$BASEOS \
14+
--mount=type=cache,target=/var/lib/apt/lists,sharing=locked,id=aptlists-$BASEOS \
15+
--mount=type=cache,target=/var/cache/apk,sharing=locked,id=apk-$BASEOS \
16+
if [ "$BASEOS" = "bookworm" ]; then \
1117
echo 'deb http://deb.debian.org/debian bookworm main' > /etc/apt/sources.list && \
1218
apt-get update && \
1319
apt-get -y upgrade && \
14-
apt-get install -y --no-install-recommends curl git zip unzip ghostscript imagemagick optipng gifsicle pngcrush jpegoptim libjpeg-turbo-progs pngquant webp && \
15-
rm -rf /var/lib/apt/lists/*; \
20+
apt-get install -y --no-install-recommends curl git zip unzip ghostscript imagemagick optipng gifsicle pngcrush jpegoptim libjpeg-turbo-progs pngquant webp; \
1621
elif [ "$BASEOS" = "alpine" ]; then \
1722
apk update && \
1823
apk add --no-cache curl git zip unzip ghostscript imagemagick optipng gifsicle pngcrush jpegoptim libjpeg-turbo libjpeg-turbo-utils pngquant libwebp-tools; \
1924
fi
2025

21-
# Add all needed PHP extensions with retry logic for transient network failures
22-
RUN for ATTEMPT in 1 2 3; do \
23-
if curl -sSLf -o /usr/local/bin/install-php-extensions \
24-
https://github.com/mlocati/docker-php-extension-installer/releases/latest/download/install-php-extensions; then \
25-
break; \
26-
else \
27-
if [ $ATTEMPT -lt 3 ]; then \
28-
case $ATTEMPT in \
29-
1) SLEEP_TIME=5 ;; \
30-
2) SLEEP_TIME=10 ;; \
31-
esac; \
32-
echo "Download attempt $ATTEMPT failed, retrying in ${SLEEP_TIME}s..."; \
33-
sleep $SLEEP_TIME; \
34-
rm -f /usr/local/bin/install-php-extensions; \
35-
else \
36-
echo "Failed to download install-php-extensions after 3 attempts"; \
37-
exit 1; \
38-
fi; \
39-
fi; \
40-
done && \
26+
# Download and install PHP extensions with retry for transient failures
27+
RUN retry 3 curl -sSLf -o /usr/local/bin/install-php-extensions \
28+
https://github.com/mlocati/docker-php-extension-installer/releases/latest/download/install-php-extensions && \
4129
chmod +x /usr/local/bin/install-php-extensions && \
42-
for ATTEMPT in 1 2 3; do \
43-
if install-php-extensions amqp bcmath bz2 calendar ctype exif intl imagick imap json mbstring ldap mcrypt memcached mongodb \
44-
mysqli opcache pdo_mysql pdo_pgsql pgsql redis snmp soap sockets tidy timezonedb uuid vips xsl yaml zip zstd @composer; then \
45-
break; \
46-
else \
47-
if [ $ATTEMPT -lt 3 ]; then \
48-
case $ATTEMPT in \
49-
1) SLEEP_TIME=5 ;; \
50-
2) SLEEP_TIME=10 ;; \
51-
esac; \
52-
echo "Extension installation attempt $ATTEMPT failed, retrying in ${SLEEP_TIME}s..."; \
53-
sleep $SLEEP_TIME; \
54-
else \
55-
echo "Failed to install PHP extensions after 3 attempts"; \
56-
exit 1; \
57-
fi; \
58-
fi; \
59-
done
30+
retry 3 install-php-extensions \
31+
amqp bcmath bz2 calendar ctype exif intl imagick imap json mbstring ldap mcrypt memcached mongodb \
32+
mysqli opcache pdo_mysql pdo_pgsql pgsql redis snmp soap sockets tidy timezonedb uuid vips xsl yaml zip zstd @composer
6033

6134
# Enable Apache rewrite mod, if applicable
6235
RUN if command -v a2enmod; then a2enmod rewrite; fi

Dockerfile.v2

Lines changed: 13 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,9 @@ ARG VERSION
1212
# Set environment variables
1313
ENV DEBIAN_FRONTEND=noninteractive
1414

15+
COPY extras/retry.sh /usr/local/bin/retry
16+
RUN chmod +x /usr/local/bin/retry
17+
1518
# OCI standard labels
1619
LABEL org.opencontainers.image.title="php-docker" \
1720
org.opencontainers.image.description="PHP runtime with s6-overlay and curated extensions" \
@@ -26,7 +29,10 @@ LABEL org.opencontainers.image.title="php-docker" \
2629

2730
# Install build dependencies, PHP extensions, runtime libraries, and s6-overlay
2831
# Then clean up build-only packages in a single layer to minimize image size
29-
RUN if [ "$BASEOS" = "trixie" ] || [ "$BASEOS" = "bookworm" ]; then \
32+
RUN --mount=type=cache,target=/var/cache/apt,sharing=locked,id=apt-$BASEOS \
33+
--mount=type=cache,target=/var/lib/apt/lists,sharing=locked,id=aptlists-$BASEOS \
34+
--mount=type=cache,target=/var/cache/apk,sharing=locked,id=apk-$BASEOS \
35+
if [ "$BASEOS" = "trixie" ] || [ "$BASEOS" = "bookworm" ]; then \
3036
apt-get update && \
3137
apt-get -y upgrade && \
3238
# Install build tools, dev packages, and runtime libraries together
@@ -129,25 +135,8 @@ RUN if [ "$BASEOS" = "trixie" ] || [ "$BASEOS" = "bookworm" ]; then \
129135
libxpm libxpm-dev; \
130136
fi && \
131137
# Download PHP extension installer with retry
132-
for ATTEMPT in 1 2 3; do \
133-
if curl -sSLf -o /usr/local/bin/install-php-extensions \
134-
https://github.com/mlocati/docker-php-extension-installer/releases/latest/download/install-php-extensions; then \
135-
break; \
136-
else \
137-
if [ $ATTEMPT -lt 3 ]; then \
138-
case $ATTEMPT in \
139-
1) SLEEP_TIME=5 ;; \
140-
2) SLEEP_TIME=10 ;; \
141-
esac; \
142-
echo "Download attempt $ATTEMPT failed, retrying in ${SLEEP_TIME}s..."; \
143-
sleep $SLEEP_TIME; \
144-
rm -f /usr/local/bin/install-php-extensions; \
145-
else \
146-
echo "Failed to download install-php-extensions after 3 attempts"; \
147-
exit 1; \
148-
fi; \
149-
fi; \
150-
done && \
138+
retry 3 curl -sSLf -o /usr/local/bin/install-php-extensions \
139+
https://github.com/mlocati/docker-php-extension-installer/releases/latest/download/install-php-extensions && \
151140
chmod +x /usr/local/bin/install-php-extensions && \
152141
# Install PHP extensions
153142
install-php-extensions \
@@ -173,25 +162,10 @@ RUN if [ "$BASEOS" = "trixie" ] || [ "$BASEOS" = "bookworm" ]; then \
173162
*) S6_ARCH="x86_64" ;; \
174163
esac && \
175164
echo "Downloading s6-overlay ${S6_OVERLAY_VERSION} for ${S6_ARCH}" && \
176-
for ATTEMPT in 1 2 3; do \
177-
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 && \
178-
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 \
179-
break; \
180-
else \
181-
if [ $ATTEMPT -lt 3 ]; then \
182-
case $ATTEMPT in \
183-
1) SLEEP_TIME=5 ;; \
184-
2) SLEEP_TIME=10 ;; \
185-
esac; \
186-
echo "Download attempt $ATTEMPT failed, retrying in ${SLEEP_TIME}s..."; \
187-
sleep $SLEEP_TIME; \
188-
rm -f /tmp/s6-overlay-*.tar.xz; \
189-
else \
190-
echo "Failed to download s6-overlay after 3 attempts"; \
191-
exit 1; \
192-
fi; \
193-
fi; \
194-
done && \
165+
retry 3 wget -O /tmp/s6-overlay-noarch.tar.xz \
166+
https://github.com/just-containers/s6-overlay/releases/download/${S6_OVERLAY_VERSION}/s6-overlay-noarch.tar.xz && \
167+
retry 3 wget -O /tmp/s6-overlay-${S6_ARCH}.tar.xz \
168+
https://github.com/just-containers/s6-overlay/releases/download/${S6_OVERLAY_VERSION}/s6-overlay-${S6_ARCH}.tar.xz && \
195169
tar -C / -Jxpf /tmp/s6-overlay-noarch.tar.xz && \
196170
tar -C / -Jxpf /tmp/s6-overlay-${S6_ARCH}.tar.xz && \
197171
rm /tmp/s6-overlay-noarch.tar.xz /tmp/s6-overlay-${S6_ARCH}.tar.xz && \

extras/retry.sh

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
#!/bin/sh
2+
# Retry a command with exponential backoff
3+
# Usage: retry <max_attempts> <command...>
4+
# Example: retry 3 curl -sSLf -o /tmp/file https://example.com/file
5+
6+
MAX=$1
7+
shift
8+
9+
for ATTEMPT in $(seq 1 "$MAX"); do
10+
if "$@"; then
11+
exit 0
12+
fi
13+
if [ "$ATTEMPT" -lt "$MAX" ]; then
14+
SLEEP_TIME=$((5 * ATTEMPT))
15+
echo "Attempt $ATTEMPT/$MAX failed, retrying in ${SLEEP_TIME}s..."
16+
sleep "$SLEEP_TIME"
17+
fi
18+
done
19+
20+
echo "Failed after $MAX attempts: $*"
21+
exit 1

extras/test-build.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ build_v1() {
5151
echo "Building v1: ${IMAGE_NAME}:${tag}"
5252
echo " VERSION=${version}, PHPVERSION=${phpversion}, BASEOS=${baseos}"
5353

54-
docker build -f Dockerfile.v1 \
54+
DOCKER_BUILDKIT=1 docker build -f Dockerfile.v1 \
5555
--build-arg VERSION="${version}" \
5656
--build-arg PHPVERSION="${phpversion}" \
5757
--build-arg BASEOS="${baseos}" \

0 commit comments

Comments
 (0)