Skip to content
Draft
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
22 changes: 22 additions & 0 deletions packages/aloft/composer.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
{
"name": "tempest/aloft",
"description": "Development and Production webserver Dockerfiles and utilities for TempestPHP.",
"require": {
"php": "^8.5",
"tempest/core": "3.x-dev",
"tempest/support": "3.x-dev"
},
"require-dev": {},
"autoload": {
"psr-4": {
"Tempest\\Aloft\\": "src"
}
},
"autoload-dev": {
"psr-4": {
"Tempest\\Aloft\\Tests\\": "tests"
}
},
"license": "MIT",
"minimum-stability": "dev"
}
66 changes: 66 additions & 0 deletions packages/aloft/docker/.dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
# -----------------------------------------------------------------------
# Git
# -----------------------------------------------------------------------
.git
.gitignore
.gitattributes

# -----------------------------------------------------------------------
# Docker build tooling (never needed inside the image)
# -----------------------------------------------------------------------
Dockerfile
docker-bake.hcl
.dockerignore

# -----------------------------------------------------------------------
# CI / tooling config
# -----------------------------------------------------------------------
.github
.gitlab-ci.yml
.travis.yml
.editorconfig
.env*
!.env.example

# -----------------------------------------------------------------------
# PHP tooling and dev dependencies
# -----------------------------------------------------------------------
/vendor
composer.lock

# -----------------------------------------------------------------------
# Node (if any frontend tooling is present)
# -----------------------------------------------------------------------
node_modules
npm-debug.log
yarn-error.log

# -----------------------------------------------------------------------
# Tests
# -----------------------------------------------------------------------
/tests
/test
phpunit.xml
phpunit.xml.dist
.phpunit.result.cache
.phpunit.cache

# -----------------------------------------------------------------------
# Static analysis and code style
# -----------------------------------------------------------------------
.php-cs-fixer.cache
.php-cs-fixer.php
phpstan.neon
phpstan.neon.dist
psalm.xml
psalm.xml.dist

# -----------------------------------------------------------------------
# IDE and OS noise
# -----------------------------------------------------------------------
.idea
.vscode
*.swp
*.swo
.DS_Store
Thumbs.db
56 changes: 56 additions & 0 deletions packages/aloft/docker/Caddyfile.noworker
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
# The Caddyfile is an easy way to configure FrankenPHP and the Caddy web server.
# This Caddyfile is provided by the TempestPHP Framework with some added options for convenience.
#
# https://github.com/tempestphp/tempest-framework
# https://frankenphp.dev/docs/config
# https://caddyserver.com/docs/caddyfile

{
skip_install_trust
{$CADDY_DEFAULT_BIND}
http_port {$CADDY_HTTP_PORT:8000}
https_port {$CADDY_HTTPS_PORT:8443}

{$CADDY_GLOBAL_OPTIONS}

frankenphp {
{$FRANKENPHP_CONFIG}
}
}

{$CADDY_EXTRA_CONFIG}

{$CADDY_SERVER_NAME:localhost}:{$CADDY_HTTP_PORT:8000}, {$CADDY_SERVER_NAME:localhost}:{$CADDY_HTTPS_PORT:8443} {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think you can leave off ports here because they are already defined globally above.

#log {
# # Redact the authorization query parameter that can be set by Mercure
# format filter {
# request>uri query {
# replace authorization REDACTED
# }
# }
#}

root {$CADDY_SERVER_ROOT:public/}
encode zstd br gzip

# Uncomment the following lines to enable Mercure and Vulcain modules
#mercure {
# # Publisher JWT key
# publisher_jwt {env.MERCURE_PUBLISHER_JWT_KEY} {env.MERCURE_PUBLISHER_JWT_ALG}
# # Subscriber JWT key
# subscriber_jwt {env.MERCURE_SUBSCRIBER_JWT_KEY} {env.MERCURE_SUBSCRIBER_JWT_ALG}
# # Allow anonymous subscribers (double-check that it's what you want)
# anonymous
# # Enable the subscription API (double-check that it's what you want)
# subscriptions
# # Extra directives
# {$MERCURE_EXTRA_DIRECTIVES}
#}
#vulcain

{$CADDY_SERVER_EXTRA_DIRECTIVES}

php_server {
#worker /path/to/your/worker.php
}
}
82 changes: 82 additions & 0 deletions packages/aloft/docker/Dockerfile
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm going back and forth on the distroless. I really like the idea in concept, but I have a few concerns:

  1. I think the ideal world is that these are stubs we are publishing into the project for someone to use/customize. These would be a lot of stubs to publish and I'm guessing the average user is going to get overwhelmed and/or not understand what is going on here.
  2. The resulting image is still pretty large. Knowing the issues with MUSL, I'd be curious if we could get the same/less size using RedHat UBI or something.
  3. I am just imagining a situation where someone submits a bug report about something with the Docker image and we want logs or something.

Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
# Build-time arguments — set by bake.hcl, can be overridden individually
ARG FRANKENPHP_VERSION=1.11.2
ARG PHP_VERSION=8.5.3
ARG BASE_IMAGE=dunglas/frankenphp:${FRANKENPHP_VERSION}-php${PHP_VERSION}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd be half tempted to pin the version and reduce flexibility here.

# Controls which distroless variant is used as the runner base.
# Valid values mirror gcr.io/distroless/cc-debian13 tags: nonroot | debug-nonroot
ARG DISTROLESS_VARIANT=nonroot

FROM ${BASE_IMAGE} AS frankenphp

RUN curl -sSLf \
-o /usr/local/bin/install-php-extensions \
https://github.com/mlocati/docker-php-extension-installer/releases/latest/download/install-php-extensions && \
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I concur with previous comments about latest. We should probably pin things like this and verify the hash.

chmod +x /usr/local/bin/install-php-extensions

# Install additional extensions here and they are carried forward into the final image
RUN install-php-extensions \
gd \
intl \
mysqli \
pcntl \
pdo_mysql \
pdo_pgsql \
pdo_sqlite \
redis \
zip

# Install pax-utils for lddtree
RUN apt-get update && apt-get install -y --no-install-recommends pax-utils && rm -rf /var/lib/apt/lists/*

# Copy and run the staging script which collects all runtime files into
# /tmp/staging with full paths preserved
COPY stage-files.sh /tmp/stage-files.sh
RUN chmod +x /tmp/stage-files.sh && /tmp/stage-files.sh

# Re-declare so it is in scope for this stage (ARGs declared before the first
# FROM are not automatically visible inside stages)
ARG DISTROLESS_VARIANT=nonroot

# Grab distroless image — variant is controlled by DISTROLESS_VARIANT ARG
FROM gcr.io/distroless/cc-debian13:${DISTROLESS_VARIANT} AS common

# See https://caddyserver.com/docs/conventions#file-locations for details
ENV XDG_CONFIG_HOME=/config
ENV XDG_DATA_HOME=/data

# Required from frankenphp
ENV GODEBUG=cgocheck=0

LABEL org.opencontainers.image.title=TempestPHP
LABEL org.opencontainers.image.description="The framework that gets out of your way"
LABEL org.opencontainers.image.url=https://tempestphp.com
LABEL org.opencontainers.image.source=https://github.com/tempestphp/tempest-framework/
LABEL org.opencontainers.image.licenses=MIT
LABEL org.opencontainers.image.vendor="Brent Roose and contributors"

# All libs, binaries and config collected by stage-files.sh into /tmp/staging.
# Everything is normalised to usr/ paths so this single COPY is safe against
# the distroless /lib -> usr/lib symlink.
COPY --from=frankenphp /tmp/staging/ /

# App directories need specific ownership — distroless has no chown so we
# use the COPY --chown flag. These overwrite the copies already in /tmp/staging.
# From the gcr container, the nonroot user is uid 1002, with gid 1000
COPY --from=frankenphp --chown=1002:1000 /app /app
COPY --from=frankenphp --chown=1002:1000 /config /config
COPY --from=frankenphp --chown=1002:1000 /data /data
COPY --from=frankenphp --chown=1002:1000 /etc/frankenphp /etc/frankenphp

COPY Caddyfile.noworker /etc/frankenphp/Caddyfile

WORKDIR /app

EXPOSE 8000
EXPOSE 8443
EXPOSE 8443/udp
EXPOSE 2019
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Any real reason to expose this?


USER nonroot

CMD ["frankenphp", "run", "--config", "/etc/frankenphp/Caddyfile", "--adapter", "caddyfile"]
HEALTHCHECK CMD curl -f http://localhost:2019/metrics || exit 1
97 changes: 97 additions & 0 deletions packages/aloft/docker/docker-bake.hcl
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My gut is that this adds a complexity that we're not after here and we either need to extract this out to a separate build process and publish to a registry or simplify.

Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
# -----------------------------------------------------------------------
# Variables — override via env vars or --set on the CLI
# e.g. FRANKENPHP_VERSION=1.12.0 docker buildx bake
# -----------------------------------------------------------------------

variable "FRANKENPHP_VERSION" {
description = "FrankenPHP release version"
default = "1.11.2"
}

variable "PHP_VERSION" {
description = "PHP release version"
default = "8.5.3"
}

variable "PUSH" {
default = "0"
}

variable "REGISTRY" {
default = ""
}

# Derived — prepends registry if set, otherwise just the image name
variable "IMAGE" {
default = REGISTRY != "" ? "${REGISTRY}/aloft" : "tempestphp/aloft"
}

# Derived values — not meant to be overridden directly
variable "BASE_IMAGE" {
default = "dunglas/frankenphp:${FRANKENPHP_VERSION}-php${PHP_VERSION}"
}

variable "VERSION_TAG" {
default = "${FRANKENPHP_VERSION}-${PHP_VERSION}"
}

# -----------------------------------------------------------------------
# Shared platform target — all runner targets inherit from this
# -----------------------------------------------------------------------

target "_common" {
dockerfile = "Dockerfile"
context = "."
platforms = PUSH == "1" ? ["linux/amd64", "linux/arm64"] : []
output = PUSH == "1" ? ["type=registry"] : ["type=docker"]
args = {
FRANKENPHP_VERSION = FRANKENPHP_VERSION
PHP_VERSION = PHP_VERSION
BASE_IMAGE = BASE_IMAGE
}
}

# -----------------------------------------------------------------------
# latest-nonroot — runner is gcr.io/distroless/cc-debian13:nonroot
# Tags: tempestphp/aloft:latest-nonroot
# tempestphp/aloft:1.11.2-8.5.3-nonroot
# -----------------------------------------------------------------------

target "latest-nonroot" {
inherits = ["_common"]
target = "common"
args = {
DISTROLESS_VARIANT = "nonroot"
}
tags = [
"${IMAGE}:latest-nonroot",
"${IMAGE}:${VERSION_TAG}-nonroot",
]
}

# -----------------------------------------------------------------------
# debug-nonroot — runner is gcr.io/distroless/cc-debian13:debug-nonroot
# Includes busybox shell for exec access while still running as nonroot.
# Tags: tempestphp/aloft:debug-nonroot
# tempestphp/aloft:1.11.2-8.5.3-debug-nonroot
# -----------------------------------------------------------------------

target "debug-nonroot" {
inherits = ["_common"]
target = "common"
args = {
DISTROLESS_VARIANT = "debug-nonroot"
}
tags = [
"${IMAGE}:debug-nonroot",
"${IMAGE}:${VERSION_TAG}-debug-nonroot",
]
}

# -----------------------------------------------------------------------
# Default group — builds both variants in parallel
# -----------------------------------------------------------------------

group "default" {
targets = ["latest-nonroot", "debug-nonroot"]
}
Loading