Skip to content

Commit 227977e

Browse files
damienferna.stecherAlliBalliBaba
authored
docs(docker): add an example of building distroless image (#1900)
Related to #151, this PR adds an example about how building a distroless image for a Frankenphp project. FYI, on https://github.com/dunglas/symfony-docker, it only saves ~24MB in the image size. I think we could go even further by building our own distroless image with Bazel like they do [here](https://github.com/GoogleContainerTools/distroless) but for now, the doc is a good start. --------- Co-authored-by: a.stecher <a.stecher@sportradar.com> Co-authored-by: Alexander Stecher <45872305+AlliBalliBaba@users.noreply.github.com>
1 parent 3ed8723 commit 227977e

File tree

1 file changed

+73
-0
lines changed

1 file changed

+73
-0
lines changed

docs/docker.md

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -203,6 +203,79 @@ The Docker images are built:
203203
- when a new release is tagged
204204
- daily at 4 am UTC, if new versions of the official PHP images are available
205205

206+
## Hardening Images
207+
208+
To further reduce the attack surface and size of your FrankenPHP Docker images, it's also possible to build them on top of a
209+
[Google distroless](https://github.com/GoogleContainerTools/distroless) or
210+
[Docker hardened](https://www.docker.com/products/hardened-images) image.
211+
212+
> [!WARNING]
213+
> These minimal base images do not include a shell or package manager, which makes debugging more difficult.
214+
> They are therefore recommended only for production if security is a high priority.
215+
216+
When adding additional PHP extensions, you will need an intermediate build stage:
217+
218+
```dockerfile
219+
FROM dunglas/frankenphp AS builder
220+
221+
# Add additional PHP extensions here
222+
RUN install-php-extensions pdo_mysql pdo_pgsql #...
223+
224+
# Copy shared libs of frankenphp and all installed extensions to temporary location
225+
# You can also do this step manually by analyzing ldd output of frankenphp binary and each extension .so file
226+
RUN apt-get update && apt-get install -y libtree && \
227+
EXT_DIR="$(php -r 'echo ini_get("extension_dir");')" && \
228+
FRANKENPHP_BIN="$(which frankenphp)"; \
229+
LIBS_TMP_DIR="/tmp/libs"; \
230+
mkdir -p "$LIBS_TMP_DIR"; \
231+
for target in "$FRANKENPHP_BIN" $(find "$EXT_DIR" -maxdepth 2 -type f -name "*.so"); do \
232+
libtree -pv "$target" | sed 's/.*── \(.*\) \[.*/\1/' | grep -v "^$target" | while IFS= read -r lib; do \
233+
[ -z "$lib" ] && continue; \
234+
base=$(basename "$lib"); \
235+
destfile="$LIBS_TMP_DIR/$base"; \
236+
if [ ! -f "$destfile" ]; then \
237+
cp "$lib" "$destfile"; \
238+
fi; \
239+
done; \
240+
done
241+
242+
243+
# Distroless debian base image, make sure this is the same debian version as the base image
244+
FROM gcr.io/distroless/base-debian13
245+
# Docker hardened image alternative
246+
# FROM dhi.io/debian:13
247+
248+
# Location of your app and Caddyfile to be copied into the container
249+
ARG PATH_TO_APP="."
250+
ARG PATH_TO_CADDYFILE="./Caddyfile"
251+
252+
# Copy your app into /app
253+
# For further hardening make sure only writable paths are owned by the nonroot user
254+
COPY --chown=nonroot:nonroot "$PATH_TO_APP" /app
255+
COPY "$PATH_TO_CADDYFILE" /etc/caddy/Caddyfile
256+
257+
# Copy frankenphp and necessary libs
258+
COPY --from=builder /usr/local/bin/frankenphp /usr/local/bin/frankenphp
259+
COPY --from=builder --chown=nonroot:nonroot /usr/local/lib/php/extensions /usr/local/lib/php/extensions
260+
COPY --from=builder /tmp/libs /usr/lib
261+
262+
# Copy php.ini configuration files
263+
COPY --from=builder /usr/local/etc/php/conf.d /usr/local/etc/php/conf.d
264+
COPY --from=builder /usr/local/etc/php/php.ini-production /usr/local/etc/php/php.ini
265+
266+
# Create necessary caddy dirs
267+
# These dirs also need to be writable in case of a read-only root filesystem
268+
COPY --from=builder --chown=nonroot:nonroot /data/caddy /data/caddy
269+
COPY --from=builder --chown=nonroot:nonroot /config/caddy /config/caddy
270+
271+
USER nonroot
272+
273+
WORKDIR /app
274+
275+
# entrypoint to run frankenphp with the provided Caddyfile
276+
ENTRYPOINT ["/usr/local/bin/frankenphp", "run", "-c", "/etc/caddy/Caddyfile"]
277+
```
278+
206279
## Development Versions
207280

208281
Development versions are available in the [`dunglas/frankenphp-dev`](https://hub.docker.com/repository/docker/dunglas/frankenphp-dev) Docker repository.

0 commit comments

Comments
 (0)