Skip to content

Commit

Permalink
feat: add support for php 8.0
Browse files Browse the repository at this point in the history
  • Loading branch information
carlalexander committed Sep 10, 2021
1 parent 88d726b commit e2e2625
Show file tree
Hide file tree
Showing 6 changed files with 272 additions and 2 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ jobs:
strategy:
fail-fast: false
matrix:
php-versions: ['7.2', '7.3', '7.4']
php-versions: ['7.2', '7.3', '7.4', '8.0']
steps:
- name: Checkout code
uses: actions/checkout@v2
Expand Down
3 changes: 2 additions & 1 deletion runtime/Makefile
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
SHELL := /bin/bash
.PHONY: build build-images publish

build: build-php-72.zip build-php-73.zip build-php-74.zip
build: build-php-72.zip build-php-73.zip build-php-74.zip build-php-80.zip

build-php%.zip: build-images
PHP_VERSION=$$(echo $@ | cut -d'.' -f 1 | cut -d'-' -f 2,3); \
Expand All @@ -15,6 +15,7 @@ build-images:
cd php-72 ; docker build -t ymir/runtime/php-72 .
cd php-73 ; docker build -t ymir/runtime/php-73 .
cd php-74 ; docker build -t ymir/runtime/php-74 .
cd php-80 ; docker build -t ymir/runtime/php-80 .

publish-images: publish-php-72 publish-php-73 publish-php-74

Expand Down
156 changes: 156 additions & 0 deletions runtime/php-80/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,156 @@
FROM ymir/runtime/base as php-build


###############################################################################
# Oniguruma
# This library is not packaged in PHP since PHP 7.4.
# See https://github.com/php/php-src/blob/43dc7da8e3719d3e89bd8ec15ebb13f997bbbaa9/UPGRADING#L578-L581
# We do not install the system version because I didn't manage to make it work...
# Ideally we shouldn't compile it ourselves.
# https://github.com/kkos/oniguruma/releases
# Needed by:
# - php mbstring
ENV VERSION_ONIG=6.9.6
ENV ONIG_BUILD_DIR=${BUILD_DIR}/oniguruma
RUN set -xe; \
mkdir -p ${ONIG_BUILD_DIR}; \
curl -Ls https://github.com/kkos/oniguruma/releases/download/v${VERSION_ONIG}/onig-${VERSION_ONIG}.tar.gz \
| tar xzC ${ONIG_BUILD_DIR} --strip-components=1
WORKDIR ${ONIG_BUILD_DIR}/
RUN set -xe; \
./configure --prefix=${INSTALL_DIR}; \
make -j $(nproc); \
make install


ENV PHP_BUILD_DIR=${BUILD_DIR}/php
RUN set -xe; \
mkdir -p ${PHP_BUILD_DIR}; \
# Download and upack the source code
curl -Ls https://github.com/php/php-src/archive/php-8.0.10.tar.gz \
| tar xzC ${PHP_BUILD_DIR} --strip-components=1
# Move into the unpackaged code directory
WORKDIR ${PHP_BUILD_DIR}/

# Configure the build
# -fstack-protector-strong : Be paranoid about stack overflows
# -fpic : Make PHP's main executable position-independent (improves ASLR security mechanism, and has no performance impact on x86_64)
# -fpie : Support Address Space Layout Randomization (see -fpic)
# -O3 : Optimize for fastest binaries possible.
# -I : Add the path to the list of directories to be searched for header files during preprocessing.
# --enable-option-checking=fatal: make sure invalid --configure-flags are fatal errors instead of just warnings
# --enable-ftp: because ftp_ssl_connect() needs ftp to be compiled statically (see https://github.com/docker-library/php/issues/236)
# --enable-mbstring: because otherwise there's no way to get pecl to use it properly (see https://github.com/docker-library/php/issues/195)
# --enable-maintainer-zts: build PHP as ZTS (Zend Thread Safe) to be able to use pthreads
# --with-zlib and --with-zlib-dir: See https://stackoverflow.com/a/42978649/245552
# --with-pear: necessary for `pecl` to work (to install PHP extensions)
#
RUN set -xe \
&& ./buildconf --force \
&& CFLAGS="-fstack-protector-strong -fpic -fpie -O3 -I${INSTALL_DIR}/include -I/usr/include -ffunction-sections -fdata-sections" \
CPPFLAGS="-fstack-protector-strong -fpic -fpie -O3 -I${INSTALL_DIR}/include -I/usr/include -ffunction-sections -fdata-sections" \
LDFLAGS="-L${INSTALL_DIR}/lib64 -L${INSTALL_DIR}/lib -Wl,-O1 -Wl,--strip-all -Wl,--hash-style=both -pie" \
./configure \
--build=x86_64-pc-linux-gnu \
--prefix=${INSTALL_DIR} \
--enable-option-checking=fatal \
--enable-sockets \
--with-config-file-path=${INSTALL_DIR}/etc/php \
--with-config-file-scan-dir=${INSTALL_DIR}/etc/php/conf.d:/var/task/php/conf.d \
--enable-fpm \
--disable-cgi \
--enable-cli \
--disable-phpdbg \
--disable-phpdbg-webhelper \
--with-sodium \
--with-readline \
--with-openssl \
--with-zlib=${INSTALL_DIR} \
--with-zlib-dir=${INSTALL_DIR} \
--with-curl \
--enable-exif \
--enable-ftp \
--with-gettext \
--enable-mbstring \
--with-pdo-mysql=shared,mysqlnd \
--with-mysqli \
--enable-pcntl \
--with-zip \
--enable-bcmath \
--enable-intl=shared \
--enable-soap \
--with-xsl=${INSTALL_DIR} \
--with-pear
RUN make -j $(nproc)
# Run `make install` and override PEAR's PHAR URL because pear.php.net is down
RUN set -xe; \
make install PEAR_INSTALLER_URL='https://github.com/pear/pearweb_phars/raw/master/install-pear-nozlib.phar'; \
{ find ${INSTALL_DIR}/bin ${INSTALL_DIR}/sbin -type f -perm +0111 -exec strip --strip-all '{}' + || true; }; \
make clean; \
cp php.ini-production ${INSTALL_DIR}/etc/php/php.ini

# Install extensions using pecl
RUN pecl install APCu
RUN pecl install igbinary
RUN pecl install zstd

# Build extensions
WORKDIR ${IMAGICK_BUILD_DIR}
RUN set -xe; \
pecl download imagick-${VERSION_IMAGICK_EXTENSION}; \
tar xzf imagick-${VERSION_IMAGICK_EXTENSION}.tgz
WORKDIR ${IMAGICK_BUILD_DIR}/imagick-${VERSION_IMAGICK_EXTENSION}
RUN set -xe; \
phpize; \
./configure --with-imagick=${INSTALL_DIR}; \
make -j $(nproc); \
make install;

WORKDIR ${REDIS_BUILD_DIR}
RUN set -xe; \
pecl download redis-${VERSION_REDIS_EXTENSION}; \
tar xzf redis-${VERSION_REDIS_EXTENSION}.tgz
WORKDIR ${REDIS_BUILD_DIR}/redis-${VERSION_REDIS_EXTENSION}
RUN set -xe; \
phpize; \
./configure --enable-redis-igbinary --enable-redis-zstd; \
make && make install;

# Install Composer
RUN curl -sS https://getcomposer.org/installer | ${INSTALL_DIR}/bin/php -- --install-dir=${INSTALL_DIR}/bin/ --filename=composer

# Symlink all our binaries into /opt/bin so that Lambda sees them in the path.
RUN mkdir -p /opt/bin \
&& cd /opt/bin \
&& ln -s ../ymir/bin/* . \
&& ln -s ../ymir/sbin/* .

# Remove extra files to make the layers as slim as possible
COPY clean.sh /tmp
RUN /tmp/clean.sh && rm /tmp/clean.sh

# Copy config files
COPY php.ini ${INSTALL_DIR}/etc/php/conf.d
COPY php-fpm.conf ${INSTALL_DIR}/etc/php-fpm.d

# Build PHP runtime
RUN git clone https://github.com/ymirapp/php-runtime.git /tmp/runtime-build \
&& cd /tmp/runtime-build \
&& git checkout tags/v1.0.0 \
&& cd /opt \
&& cp -R /tmp/runtime-build/composer.json /tmp/runtime-build/composer.lock /tmp/runtime-build/runtime/bootstrap /tmp/runtime-build/runtime/runtime.php /tmp/runtime-build/src ./ \
&& chmod 0555 /opt/bootstrap /opt/runtime.php \
&& composer install --no-dev

# Now we start back from a clean image.
# We get rid of everything that is unnecessary (build tools, source code, and anything else
# that might have created intermediate layers for docker) by copying online the /opt directory.
FROM public.ecr.aws/lambda/provided:al2
ENV PATH="/opt/bin:${PATH}" \
LD_LIBRARY_PATH="/opt/ymir/lib64:/opt/ymir/lib"

# Copy everything we built above into the same dir on the base AmazonLinux container.
COPY --from=php-build /opt /opt

# Needed for building the layer
COPY --from=php-build /usr/lib64 /usr/lib64
45 changes: 45 additions & 0 deletions runtime/php-80/clean.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
# ------------------------------------------
# This script cleans extra files from /opt
# to keep the layers as small as possible.
# ------------------------------------------

# Stop on error
set -e
# Treat unset variables and parameters as an error.
set -u

# Strip all the unneeded symbols from shared libraries to reduce size.
find /opt/ymir -type f -name "*.so*" -exec strip --strip-unneeded {} \;
find /opt/ymir -type f -name "*.a"|xargs rm
find /opt/ymir -type f -name "*.la"|xargs rm
find /opt/ymir -type f -name "*.dist"|xargs rm
find /opt/ymir -type f -executable -exec sh -c "file -i '{}' | grep -q 'x-executable; charset=binary'" \; -print|xargs strip --strip-all

# Cleanup all the binaries we don't want.
find /opt/ymir/sbin -mindepth 1 -maxdepth 1 ! -name "composer" ! -name "php" ! -name "php-fpm" -exec rm {} \+
find /opt/ymir/bin -mindepth 1 -maxdepth 1 ! -name "composer" ! -name "php" ! -name "php-fpm" -exec rm {} \+
find /opt/bin -mindepth 1 -maxdepth 1 ! -name "composer" ! -name "php" ! -name "php-fpm" -exec rm {} \+

# Cleanup all the files we don't want either
# We do not support running pear functions in Lambda
rm -rf /opt/ymir/lib/php/PEAR
rm -rf /opt/ymir/share
rm -rf /opt/ymir/include
rm -rf /opt/ymir/{lib,lib64}/pkgconfig
rm -rf /opt/ymir/{lib,lib64}/cmake
rm -rf /opt/ymir/lib/xml2Conf.sh
find /opt/ymir/lib/php -mindepth 1 -maxdepth 1 -type d -a ! -name "extensions" -exec rm -rf {} \;
find /opt/ymir/lib/php -mindepth 1 -maxdepth 1 -type f -exec rm -rf {} \;
rm -rf /opt/ymir/lib/php/test
rm -rf /opt/ymir/lib/php/doc
rm -rf /opt/ymir/lib/php/docs
rm -rf /opt/ymir/tests
rm -rf /opt/ymir/doc
rm -rf /opt/ymir/docs
rm -rf /opt/ymir/man
rm -rf /opt/ymir/php
rm -rf /opt/ymir/www
rm -rf /opt/ymir/cfg
rm -rf /opt/ymir/libexec
rm -rf /opt/ymir/var
rm -rf /opt/ymir/data
21 changes: 21 additions & 0 deletions runtime/php-80/php-fpm.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
; Logging anywhere on disk doesn't make sense on lambda since instances are ephemeral
error_log = /dev/null
pid = /tmp/.ymir/php-fpm.pid
; Log above warning because PHP-FPM logs useless notices
; We must comment this flag else uncaught exceptions/fatal errors are not reported in the logs!
; TODO: report that to the PHP bug tracker
;log_level = 'warning'

[default]
pm = static
; We only need one child because a lambda can process only one request at a time
pm.max_children = 1
listen = /tmp/.ymir/php-fpm.sock
; Allows PHP processes to access the lambda's environment variables
clear_env = no
; Forward stderr of PHP processes to stderr of PHP-FPM (so that it can be sent to cloudwatch)
catch_workers_output = yes
; New PHP 7.3 option that disables a verbose log prefix
decorate_workers_output = no
; Limit the number of core dump logs to 1 to avoid filling up the /tmp disk
rlimit_core = 1
47 changes: 47 additions & 0 deletions runtime/php-80/php.ini
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
; Do not display errors in production because with PHP-FPM that means
; errors will be output in the HTTP response
display_errors=0

; Since PHP 7.4 the default value is E_ALL
; We override it to set the recommended configuration value for production.
; See https://github.com/php/php-src/blob/d91abf76e01a3c39424e8192ad049f473f900936/php.ini-production#L463
error_reporting = E_ALL & ~E_DEPRECATED & ~E_STRICT

memory_limit=3008M

opcache.enable=1
opcache.enable_cli=1

; Skip this check to save a bit
opcache.validate_permission=0

; The code is readonly on lambdas so it never changes
opcache.validate_timestamps=0

; Set sane values, modern PHP applications have higher needs than opcache's defaults
; See https://tideways.com/profiler/blog/fine-tune-your-opcache-configuration-to-avoid-caching-suprises
opcache.memory_consumption=128
opcache.max_accelerated_files=10000
opcache.max_wasted_percentage=10

extension=apcu.so
extension=igbinary.so
extension=imagick.so
extension=intl.so
extension=pdo_mysql.so
extension=redis.so
extension=zstd.so
zend_extension=opcache.so

; This directive determines which super global arrays are registered when PHP
; starts up. G,P,C,E & S are abbreviations for the following respective super
; globals: GET, POST, COOKIE, ENV and SERVER.
; We explicitly populate all variables else ENV is not populated by default.
variables_order="EGPCS"

; The lambda environment is not compatible with fastcgi_finish_request
disable_functions=fastcgi_finish_request

; API Gateway has a timeout of 29 seconds. Setting this to 28 will give PHP some
; time to properly finish up its resources and flush logs to CloudWatch.
max_execution_time=28

0 comments on commit e2e2625

Please sign in to comment.