Skip to content

build .rpm and .deb packages to automatically install and configure frankenphp #1497

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 79 commits into from
May 14, 2025

Conversation

henderkes
Copy link
Contributor

see #1459

requires fpm but it works perfectly well to automatically configure frankenphp

we could let this script run in the centos 7 container on deployment.

@henderkes henderkes marked this pull request as draft April 13, 2025 17:39
@henderkes henderkes marked this pull request as ready for review April 13, 2025 18:37
@henderkes
Copy link
Contributor Author

henderkes commented Apr 13, 2025

even better, once crazywhalecc/static-php-cli#673 is merged, we can --build-shared=xdebug in the glibc command and automatically release frankenphp-xdebug-$(FRANKENPHP_VERSION) and frankenphp-ffi-$(FRANKENPHP_VERSION).

Still need to think about how to appropriately handle this in CI though, I'm not sure if FRANKENPHP_VERSION is automatically set as an environment variable, or if the build-static script sets it.

Could change the build-static script to export the version and call ./build-packages.sh after and modify the dockerfile to install ruby, fpm and rpm-build.

@henderkes henderkes changed the title build .rpm and .deb packages to automatically install and configure frankenphp [WIP] build .rpm and .deb packages to automatically install and configure frankenphp Apr 14, 2025
@henderkes
Copy link
Contributor Author

now I'm getting a weird bug where the worker keeps counting $i up twice instead of once. Other than that, it's working well I think.

@henderkes henderkes requested a review from dunglas April 14, 2025 16:01
@henderkes henderkes changed the title [WIP] build .rpm and .deb packages to automatically install and configure frankenphp build .rpm and .deb packages to automatically install and configure frankenphp Apr 15, 2025
@henderkes
Copy link
Contributor Author

success! to get them from the container after building we can run

docker run --rm static-builder-gnu sh -c "ls /go/src/app/dist | grep '^frankenphp'" | xargs -I {} sh -c 'docker cp $(docker create static-builder-gnu):/go/src/app/dist/{} ./{}'

@henderkes
Copy link
Contributor Author

henderkes commented Apr 15, 2025

@dunglas I'm happy with this now. Prepared things for when we merge shared extension support into static-php-cli as well.

The reason I haven't added a .apk is that alpine doesn't even ship with an init system by default (OpenRC is only included in the full blown desktop version), so I felt it made no sense to write a package that adds no real benefits to a simple binary download.

Copy link
Member

@dunglas dunglas left a comment

Choose a reason for hiding this comment

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

This is AWESOME.

I left some minor comments. I also think we should ensure that the experience is as similar as possible between the Docker images, the Brew package and the Linux packages (demo files, php.ini, Caddyfile etc) to simply the maintenance and support.

@@ -0,0 +1,53 @@
# The Caddyfile is an easy way to configure your Caddy web server.
Copy link
Member

Choose a reason for hiding this comment

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

That would be nice to use the same Caddyfile in every distributions, with the same features enabled.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I don't think it makes sense to enable a worker by default in the docker Caddyfile. There's no example project (and it makes no sense to ship one either).

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I've removed the worker mode from the default Caddyfile. However, I still don't think it really makes sense to use the same Caddyfiles for docker and system packages. They just inherently incur different conventions.

@@ -0,0 +1,140 @@
<?php
Copy link
Member

Choose a reason for hiding this comment

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

Could we reduce or remove the provided demo files?
Could we also share them between the Docker images and the packages?

@ginifizz will take a look to the graphic design part.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I've reduced the demo files to one index.php and the two images. I've changed the frankenphp image to use this svg but with the white swapped to the purple from the other images.

@henderkes
Copy link
Contributor Author

I had to switch to a frankenphp user, uninstalling frankenphp or caddy would automatically remove the other's user otherwise.

fi
fi

HOME=~frankenphp frankenphp trust
Copy link
Contributor Author

Choose a reason for hiding this comment

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

I don't have the faintest idea how caddy works around not having to do this. Or maybe they do and I simply cannot find it in the install scripts.

@henderkes
Copy link
Contributor Author

henderkes commented Apr 20, 2025

We've merged dynamic extension support into static-php-cli, by the way. Should I put that into this PR and also build a frankenphp-xdebug package that depends on the frankenphp package?

For that, I actually have a question - is it possible to load php with and without xdebug and route the request depending on whether a XDEBUG_SESSION header is set?

Right now I check for (pseudocode, can't check atm)

route {
    @xdebug header *XDEBUG_SESSION*
    php_fastcgi @xdebug /path/to/www.sock
    php
}

where php_fpm has xdebug loaded and frankenphp doesn't.

Edit: I think frankenphp-xdebug would be a thing for another PR. Let's get regular frankenphp packages merged first.

@henderkes henderkes requested a review from dunglas April 20, 2025 12:19
Copy link
Member

@dunglas dunglas left a comment

Choose a reason for hiding this comment

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

This looks almost good to me, but I'm far from being a specialist of packaging.

We'll have to setup package repositories after that, right?

@@ -0,0 +1,14 @@
<?php
Copy link
Member

Choose a reason for hiding this comment

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

Same here

@@ -115,12 +117,27 @@ ENV SPC_LIBC='glibc'
ENV SPC_CMD_VAR_PHP_MAKE_EXTRA_LDFLAGS_PROGRAM='-Wl,-O3 -pie'
ENV SPC_CMD_VAR_PHP_MAKE_EXTRA_LIBS='-ldl -lpthread -lm -lresolv -lutil -lrt'
ENV SPC_OPT_DOWNLOAD_ARGS='--ignore-cache-sources=php-src'
ENV SPC_OPT_BUILD_ARGS=''
ENV SPC_OPT_BUILD_ARGS='--with-config-file-path=/etc/frankenphp/php.ini --with-config-file-scan-dir=/etc/frankenphp/php.d'
Copy link
Member

Choose a reason for hiding this comment

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

Do we really need to change the defaults? If so, we'll have to update the docs too

Copy link
Contributor Author

@henderkes henderkes Apr 24, 2025

Choose a reason for hiding this comment

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

The default for php is /etc/php.ini and /etc/php.d or /etc/php/conf.d depending on the distro. I doubt we wish to use those directories as we'd couple our frankenphp changes to those of the system php package. There are too many reasons why this is a terrible idea.

When compiling php without --with-config-file-path it chooses /usr/local/etc/php/php.ini and a different additional path depending on the system it was compiled on. That default is not in line with any system installation you would expect from a rpm/deb package. My only other idea for this was /etc/frankenphp.ini and /etc/frankenphp.d, but that would suggest frankenphp is something different than php, which it isn't.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

To expand on this, /usr/local/etc/ is the folder for user, not system installations of self-compiled software. FrankenPHP installed from a package should definitely not reside there - what if the user compiles and installs php themselves? Suddenly our frankenphp package is broken.

@henderkes
Copy link
Contributor Author

henderkes commented May 8, 2025

After thinking about it for a while, I've simplified the example project to just a php file without worker stuff. Also got rid of the environment variables to be more in line with other system installed packages (like caddy).

image

frankenphp
}

http://, https:// {
Copy link
Contributor Author

Choose a reason for hiding this comment

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

http://, https;// or localhost? I prefer the latter, but the official packages all use http://

Copy link
Member

Choose a reason for hiding this comment

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

Let's do as the official packages.

Copy link
Contributor Author

@henderkes henderkes May 9, 2025

Choose a reason for hiding this comment

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

Okay, I've removed https to follow Caddy's standards. I'm happy with the PR the way it's implemented then, for now. Next project would be to look into automating a package repository for .deb and .rpm packages and offer each php extension individually. We've merged dynamic extension building into static-php-cli now so it's technically possible to build frankenphp with only core php and compile all extensions as shared libraries at the same time.

@henderkes
Copy link
Contributor Author

henderkes commented May 12, 2025

I'm thinking about spinning up a static php package repository with static-php instead. Then we could build a shared libphp embed frankenphp and have the packages reply on php-zts instead. Not much would change about the PR, except that the php.ini would be dropped from here.

@dunglas
Copy link
Member

dunglas commented May 13, 2025

@henderkes should we wait for this or can we merge this PR now? I plan to draft a new release of FrankenPHP very soon. If it's ready for prime time, could you rebase against main, please?

@henderkes
Copy link
Contributor Author

henderkes commented May 13, 2025

It's ready for release. It will take a significant amount of work to build repositories the way I envision it, so we're looking at a timeline of at least a month if I had to guess. Then we can look into coordinating shared frankenphp and static-php builds in the same repository.

It just means that I won't extend shared php extensions as part of the frankenphp release, but move it to the static-php side instead. I'll rebase tomorrow.

# Conflicts:
#	Dockerfile
#	alpine.Dockerfile
#	go.mod
#	static-builder-gnu.Dockerfile
#	static-builder-musl.Dockerfile
@dunglas dunglas merged commit bbbfdb3 into php:main May 14, 2025
43 checks passed
@dunglas
Copy link
Member

dunglas commented May 14, 2025

Thank you very much!! Great work.

@henderkes henderkes deleted the rpm branch May 14, 2025 09:47
@dunglas
Copy link
Member

dunglas commented May 20, 2025

@henderkes it looks like the packages aren't uploaded successfully to the releases: https://github.com/dunglas/frankenphp/releases/tag/v1.6.0

@henderkes
Copy link
Contributor Author

Hmm, indeed. I will look at the build logs to figure out what's going on.

@henderkes
Copy link
Contributor Author

Oh, it looks like the action doesn't trigger on tagging a release. It uses some other workflow?

@henderkes
Copy link
Contributor Author

Never mind, they are triggered, but not visible in the actions history.

Run # shellcheck disable=SC2034
# shellcheck disable=SC2034
  digest=$(jq -r '."static-builder-gnu"."containerimage.digest"' <<< "${METADATA}")
  container_id=$(docker create --platform=linux/arm6[4](https://github.com/dunglas/frankenphp/actions/runs/15063931639/job/42344465836#step:9:4) "${IMAGE_NAME}@${digest}")
  mkdir -p gh-output
  cd gh-output
  for file in $(docker run --rm "${IMAGE_NAME}@${digest}" sh -c "ls /go/src/app/dist | grep '^frankenphp'"); do
    docker cp "${container_id}:/go/src/app/dist/${file}" "./${file}"
  done
  docker rm "${container_id}"
  mv "${BINARY}" "${BINARY}-gnu"
  shell: /usr/bin/bash -e {0}
Unable to find image '***/frankenphp-dev@sha256:3062e7f6e0eb72962f18b17dd6643d456235a1952cd2ca10617b34bcf6c1d6b2' locally
Error response from daemon: toomanyrequests: You have reached your pull rate limit as '***': dckr_jti_RwLbnod8m96mttdDaz1YFCJDJ48=. You may increase the limit by upgrading. https://www.docker.com/increase-rate-limit
Error: Process completed with exit code 1.

@henderkes
Copy link
Contributor Author

henderkes commented May 20, 2025

@dunglas This unfortunately surpasses my docker knowledge a little. I'm not sure how to fix this without the possibility to trigger/test the workflow.

It seems like it's looking for the image locally instead of the docker registry, but the image should be available in the docker registry after the build step.

      "buildx.build.ref": "builder-3a2b0fd4-175c-493e-9dbd-0a7ca3fa6f0e/builder-3a2b0fd4-175c-493e-9dbd-0a7ca3fa6f0e0/hr0bmhjlm1azhgfbt0hapf157",
      "containerimage.descriptor": {
        "mediaType": "application/vnd.oci.image.index.v1+json",
        "digest": "sha256:3062e7f6e0eb72962f18b17dd6643d456235a1952cd2ca10617b34bcf6c1d6b2",
        "size": 856
      },
      "containerimage.digest": "sha256:3062e7f6e0eb72962f18b17dd6643d456235a1952cd2ca10617b34bcf6c1d6b2",
      "image.name": "***/frankenphp-dev"

Error:

Unable to find image '***/frankenphp-dev@sha256:3062e7f6e0eb72962f18b17dd6643d456235a1952cd2ca10617b34bcf6c1d6b2' locally
Error response from daemon: toomanyrequests: You have reached your pull rate limit as '***': dckr_jti_RwLbnod8m96mttdDaz1YFCJDJ48=. You may increase the limit by upgrading. https://www.docker.com/increase-rate-limit

I guess the solution would be to build the image and tag it locally, rather than into the docker registry? The same issue also occured for the musl workflows, so I'm thinking this might either have to be a one-time problem due to the rate limit.

@henderkes
Copy link
Contributor Author

https://github.com/mhpcc/frankenphp/blob/main/.github/workflows/create_custom_release.yaml#L46

This is how I work around it in my build with supervisor and cache, as I can't use the docker registry. I don't know if it would be intended to load them locally, though.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants