Skip to content

Commit

Permalink
Merge pull request #678 from brefphp/php8
Browse files Browse the repository at this point in the history
PHP 8 runtimes
  • Loading branch information
mnapoli authored Jul 14, 2020
2 parents c139ed6 + 4648884 commit 740e59f
Show file tree
Hide file tree
Showing 8 changed files with 206 additions and 21 deletions.
2 changes: 2 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,11 @@ publish-docker-images: docker-images
"bref/php-72" "bref/php-72-fpm" "bref/php-72-fpm-dev" \
"bref/php-73" "bref/php-73-fpm" "bref/php-73-fpm-dev" \
"bref/php-74" "bref/php-74-fpm" "bref/php-74-fpm-dev" \
"bref/php-80" "bref/php-80-fpm" "bref/php-80-fpm-dev" \
"bref/build-php-72" \
"bref/build-php-73" \
"bref/build-php-74" \
"bref/build-php-80" \
"bref/fpm-dev-gateway"; \
do \
docker tag $$image:latest $$image:${DOCKER_TAG} ; \
Expand Down
4 changes: 3 additions & 1 deletion docs/runtimes/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -69,8 +69,10 @@ The `${...}` notation is the [syntax to use variables](https://serverless.com/fr
- `${bref:layer.php-73-fpm}`
- `${bref:layer.php-72-fpm}`
- `${bref:layer.console}`
- `${bref:layer.php-80}`
- `${bref:layer.php-80-fpm}`

Bref currently provides runtimes for PHP 7.2, 7.3 and 7.4.
Bref currently provides runtimes for PHP 7.2, 7.3 and 7.4. It also provides **experimental** runtimes for PHP 8.0.

> `php-74` means PHP 7.4.\*. It is not possible to require a specific "patch" version.

Expand Down
7 changes: 6 additions & 1 deletion runtime/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ publish: layers
cd layers ; php publish.php

# Build the layers
layers: export/console.zip export/php-72.zip export/php-73.zip export/php-74.zip export/php-72-fpm.zip export/php-73-fpm.zip export/php-74-fpm.zip
layers: export/console.zip export/php-72.zip export/php-73.zip export/php-74.zip export/php-80.zip export/php-72-fpm.zip export/php-73-fpm.zip export/php-74-fpm.zip export/php-80-fpm.zip

# The PHP runtimes
export/php%.zip: docker-images
Expand All @@ -30,22 +30,27 @@ docker-images:
cd base ; docker build --file php-72.Dockerfile -t bref/build-php-72 --target build-environment .
cd base ; docker build --file php-73.Dockerfile -t bref/build-php-73 --target build-environment .
cd base ; docker build --file php-74.Dockerfile -t bref/build-php-74 --target build-environment .
cd base ; docker build --file php-80.Dockerfile -t bref/build-php-80 --target build-environment .
# Build the whole Dockerfile to generate the cleaned images that will be used in the next step
cd base ; docker build --file php-72.Dockerfile -t bref/tmp/cleaned-build-php-72 .
cd base ; docker build --file php-73.Dockerfile -t bref/tmp/cleaned-build-php-73 .
cd base ; docker build --file php-74.Dockerfile -t bref/tmp/cleaned-build-php-74 .
cd base ; docker build --file php-80.Dockerfile -t bref/tmp/cleaned-build-php-80 .
# - function
cd layers/function ; docker build -t bref/php-72 --build-arg PHP_VERSION=72 .
cd layers/function ; docker build -t bref/php-73 --build-arg PHP_VERSION=73 .
cd layers/function ; docker build -t bref/php-74 --build-arg PHP_VERSION=74 .
cd layers/function ; docker build -t bref/php-80 --build-arg PHP_VERSION=80 .
# - fpm
cd layers/fpm ; docker build -t bref/php-72-fpm --build-arg PHP_VERSION=72 .
cd layers/fpm ; docker build -t bref/php-73-fpm --build-arg PHP_VERSION=73 .
cd layers/fpm ; docker build -t bref/php-74-fpm --build-arg PHP_VERSION=74 .
cd layers/fpm ; docker build -t bref/php-80-fpm --build-arg PHP_VERSION=80 .
# Other Docker images
cd layers/fpm-dev ; docker build -t bref/php-72-fpm-dev --build-arg PHP_VERSION=72 .
cd layers/fpm-dev ; docker build -t bref/php-73-fpm-dev --build-arg PHP_VERSION=73 .
cd layers/fpm-dev ; docker build -t bref/php-74-fpm-dev --build-arg PHP_VERSION=74 .
cd layers/fpm-dev ; docker build -t bref/php-80-fpm-dev --build-arg PHP_VERSION=80 .
cd layers/web; docker build -t bref/fpm-dev-gateway .
# Run tests
php layers/tests.php
146 changes: 146 additions & 0 deletions runtime/base/php-80.Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,146 @@
# The container we build here contains everything needed to compile PHP + PHP.
#
# It can be used as a base to compile extra extensions.

# PHP Build
# https://github.com/php/php-src/releases
# Needs:
# - zlib
# - libxml2
# - openssl
# - readline
# - sodium

FROM bref/tmp/step-1/build-environment as build-environment


###############################################################################
# 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.3
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 VERSION_PHP=8.0.0alpha2


ENV PHP_BUILD_DIR=${BUILD_DIR}/php
RUN set -xe; \
mkdir -p ${PHP_BUILD_DIR}; \
# Download and upack the source code
# --location will follow redirects
# --silent will hide the progress, but also the errors: we restore error messages with --show-error
# --fail makes sure that curl returns an error instead of fetching the 404 page
curl --location --silent --show-error --fail https://downloads.php.net/~carusogabriel/php-${VERSION_PHP}.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 \
--with-pdo-pgsql=shared,${INSTALL_DIR} \
--enable-intl=shared \
--enable-soap \
--with-xsl=${INSTALL_DIR} \
--enable-gd \
--with-jpeg=${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

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

# Install extensions
# We can install extensions manually or using `pecl`
#RUN pecl install mongodb
#RUN pecl install redis
RUN pecl install APCu
#RUN pecl install imagick


# Run the next step in the previous environment because the `clean.sh` script needs `find`,
# which isn't installed by default
FROM build-environment as build-environment-cleaned
# Remove extra files to make the layers as slim as possible
COPY clean.sh /tmp/clean.sh
RUN /tmp/clean.sh && rm /tmp/clean.sh


# 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 amazonlinux:2018.03
ENV PATH="/opt/bin:${PATH}" \
LD_LIBRARY_PATH="/opt/bref/lib64:/opt/bref/lib"

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

# Set the workdir to the same directory as in AWS Lambda
WORKDIR /var/task
33 changes: 25 additions & 8 deletions runtime/layers/fpm-dev/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,16 +1,33 @@
ARG PHP_VERSION
FROM bref/build-php-$PHP_VERSION as build_extensions
# We need that variable so we re-import it again (args are cleared after each FROM)
ARG PHP_VERSION

RUN pecl install xdebug
RUN if [ "$PHP_VERSION" = "80" ] ; \
then \
echo "Installing xdebug from master to support PHP 8.0" \
&& git clone git://github.com/xdebug/xdebug.git \
&& cd xdebug \
&& phpize \
&& ./configure --enable-xdebug \
&& make \
&& make install \
&& cd .. \
&& rm -rf xdebug ; \
else \
pecl install xdebug ; \
fi
RUN cp $(php -r "echo ini_get('extension_dir');")/xdebug.so /tmp

ENV current_os=linux
RUN version=$(php -r "echo PHP_MAJOR_VERSION.PHP_MINOR_VERSION;")-zts \
&& curl -A "Docker" -o /tmp/blackfire-probe.tar.gz -D - -L -s https://blackfire.io/api/v1/releases/probe/php/$current_os/amd64/$version \
&& mkdir -p /tmp/blackfire \
&& tar zxpf /tmp/blackfire-probe.tar.gz -C /tmp/blackfire \
&& cp /tmp/blackfire/blackfire-*.so /tmp/blackfire.so \
&& rm -rf /tmp/blackfire /tmp/blackfire-probe.tar.gz
RUN if [ "$PHP_VERSION" != "80" ] ; \
then \
version=$(php -r "echo PHP_MAJOR_VERSION.PHP_MINOR_VERSION;")-zts \
&& curl -A "Docker" -o /tmp/blackfire-probe.tar.gz -D - -L -s https://blackfire.io/api/v1/releases/probe/php/linux/amd64/$version \
&& mkdir -p /tmp/blackfire \
&& tar zxpf /tmp/blackfire-probe.tar.gz -C /tmp/blackfire \
&& cp /tmp/blackfire/blackfire-*.so /tmp/blackfire.so \
&& rm -rf /tmp/blackfire /tmp/blackfire-probe.tar.gz ; \
fi

FROM bref/php-${PHP_VERSION}-fpm as build_dev

Expand Down
5 changes: 3 additions & 2 deletions runtime/layers/layer-list.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,13 @@
*/

use AsyncAws\Lambda\LambdaClient;
use AsyncAws\Lambda\Result\LayerVersionsListItem;
use AsyncAws\Lambda\ValueObject\LayerVersionsListItem;

require_once __DIR__ . '/../../vendor/autoload.php';

const LAYER_NAMES = [
'php-80',
'php-80-fpm',
'php-74',
'php-74-fpm',
'php-73',
Expand Down Expand Up @@ -64,4 +66,3 @@ function listLayers(string $selectedRegion): array

return $layers;
}

2 changes: 2 additions & 0 deletions runtime/layers/publish.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@
require_once __DIR__ . '/../../vendor/autoload.php';

$layers = [
'php-80' => 'PHP 8.0 for PHP functions',
'php-80-fpm' => 'PHP-FPM 8.0 for HTTP applications',
'php-74' => 'PHP 7.4 for PHP functions',
'php-74-fpm' => 'PHP-FPM 7.4 for HTTP applications',
'php-73' => 'PHP 7.3 for PHP functions',
Expand Down
28 changes: 19 additions & 9 deletions runtime/layers/tests.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,15 @@
'bref/php-72',
'bref/php-73',
'bref/php-74',
'bref/php-80',
'bref/php-72-fpm',
'bref/php-73-fpm',
'bref/php-74-fpm',
'bref/php-80-fpm',
'bref/php-72-fpm-dev',
'bref/php-73-fpm-dev',
'bref/php-74-fpm-dev',
'bref/php-80-fpm-dev',
];
foreach ($allLayers as $layer) {
// Working directory
Expand All @@ -25,36 +28,43 @@

// PHP runs correctly
$phpVersion = trim(`docker run --rm --entrypoint php $layer -v`);
assertContains('PHP 7.', $phpVersion);
assertMatchesRegex('/PHP (7|8)\.\d+\.\d+/', $phpVersion);
echo '.';

exec("docker run --rm -v \${PWD}/helpers:/var/task/ --entrypoint /var/task/extensions-test.sh $layer", $output, $exitCode);
if ($exitCode !== 0) {
throw new Exception(implode(PHP_EOL, $output), $exitCode);
// Test extensions load correctly
// Skip this for PHP 8.0 until all extensions are supported
if (strpos($layer, 'php-80') === false) {
exec("docker run --rm -v \${PWD}/helpers:/var/task/ --entrypoint /var/task/extensions-test.sh $layer", $output, $exitCode);
if ($exitCode !== 0) {
throw new Exception(implode(PHP_EOL, $output), $exitCode);
}
echo '.';
}
echo '.';
}

// FPM layers
$fpmLayers = [
'bref/php-72-fpm',
'bref/php-73-fpm',
'bref/php-74-fpm',
'bref/php-80-fpm',
'bref/php-72-fpm-dev',
'bref/php-73-fpm-dev',
'bref/php-74-fpm-dev',
'bref/php-80-fpm-dev',
];
foreach ($fpmLayers as $layer) {
// PHP-FPM is installed
$phpVersion = trim(`docker run --rm --entrypoint php-fpm $layer -v`);
assertContains('PHP 7.', $phpVersion);
assertMatchesRegex('/PHP (7|8)\.\d+\.\d+/', $phpVersion);
echo '.';
}

// dev layers
$devLayers = [
'bref/php-72-fpm-dev',
'bref/php-73-fpm-dev',
'bref/php-80-fpm-dev',
];
$devExtensions = [
'xdebug',
Expand All @@ -79,9 +89,9 @@ function assertEquals($expected, $actual)
}
}

function assertContains(string $expected, string $actual)
function assertMatchesRegex(string $expected, string $actual)
{
if (strpos($actual, $expected) === false) {
throw new Exception("$actual does not contain $expected");
if (preg_match($expected, $actual) === false) {
throw new Exception("$actual does not match regex $expected");
}
}

0 comments on commit 740e59f

Please sign in to comment.