
Using NewRelic with Bref on AWS Lambda
Running serverless is great. When migrating our applications to use Bref we realized that we need a non-standard php-extension. With "non-standard" I mean that the extension is not included by default by Bref. With some help I manage to make every thing work as I wanted it to. Here is what I did:
I cloned the Bref repository to be able to build my own image. Then I added the NewRelic extension and config to php.Dockerfile
in the /runtime/php directory.
## Install NewRelic
RUN \
curl -L https://download.newrelic.com/php_agent/release/newrelic-php5-8.7.0.242-linux.tar.gz | tar -C /tmp -zx && \
export NR_INSTALL_USE_CP_NOT_LN=1 && \
export NR_INSTALL_DAEMONPATH=${INSTALL_DIR}/sbin/newrelic-daemon && \
export NR_INSTALL_SILENT=1 && \
/tmp/newrelic-php5-*/newrelic-install install && \
rm -rf /tmp/newrelic-php5-* /tmp/nrinstall*
RUN echo $' \n\
extension = "newrelic.so" \n\
newrelic.appname = "BrefLambda" \n\
newrelic.license = "0123456789" \n\
newrelic.logfile = "/dev/null" \n\
newrelic.loglevel = "error" \n\
' >> ${INSTALL_DIR}/etc/php/php.ini
RUN mkdir -p ${INSTALL_DIR}/etc/newrelic && \
echo "loglevel=error" > ${INSTALL_DIR}/etc/newrelic/newrelic.cfg && \
echo "logfile=/dev/null" >> ${INSTALL_DIR}/etc/newrelic/newrelic.cfg
I disable logging since I run this on a read-only environment.
This is great and it should have been working on a normal server. However, NewRelic is configured to automatically start with the PHP-FPM server. Since Bref has it custom implementation of PHP-FPM that will not work. We need to start the the newrelic-daemon manually every time we load our Lambda function.
Let's start with the function
layer:
# runtime/php/layers/function/bootstrap
# Start NewRelic daemon
/opt/bref/sbin/newrelic-daemon -c /opt/bref/etc/newrelic/newrelic.cfg
Finally done, but let's move on to the website
layer. First I rename the boostrap
file to bootstrap-php
. Then I create
a new bootstrap
file with the following contents:
#!/bin/sh
# Start NewRelic daemon
/opt/bref/sbin/newrelic-daemon -c /opt/bref/etc/newrelic/newrelic.cfg
# Start PHP-FPM
/opt/bootstrap-php
Now I add a line in bootstrap-php
to make sure NewRelic is not considering my requests as background jobs:
// bootstrap-php
// ...
ini_set('display_errors', '1');
error_reporting(E_ALL);
// Tell NewRelic that this is not a background job
newrelic_background_job(false);
// ...
Last thing to do is to make sure the new bootstrap-php
is part of the runtime zip file.
# export.sh
# ...
# Create the PHP FPM layer
# Add files specific to this layer
cp /layers/fpm/bootstrap bootstrap
cp /layers/fpm/bootstrap-php bootstrap-php # <---- New line
chmod 755 bootstrap bootstrap-php # <---- Modified line
cp /layers/fpm/php.ini bref/etc/php/conf.d/bref.ini
cp /layers/fpm/php-fpm.conf bref/etc/php-fpm.conf
# Zip the layer
zip --quiet --recurse-paths /export/php-${PHP_SHORT_VERSION}-fpm.zip . --exclude "*php-cgi"
# Cleanup the files specific to this layer
rm bootstrap bootstrap-php # <---- Modified line
rm bref/etc/php/conf.d/bref.ini
rm bref/etc/php-fpm.conf
Now we are finally done. Just rebuild your php docker, package your zip files and publish them on AWS.
cd runtime/php
make build
make distribution
aws lambda publish-layer-version --layer-name bref-php-73 --profile default --zip-file fileb://../export/php-73.zip
aws lambda publish-layer-version --layer-name bref-php-73-fpm --profile default --zip-file fileb://../export/php-73-fpm.zip
In the response to the aws lambda publish-layer-version
you will see the new ARN to use.
Resources:
Website:
Type: AWS::Serverless::Function
Properties:
FunctionName: 'my website'
Runtime: provided
Layers:
- 'arn:aws:lambda:eu-central-1:123456789:layer:bref-php-73-fpm:1'
When everything is deployed, you need to make sure that your lambda function can reach internet. The NewRelic
daemon must be able to send data to NewRelic's servers. You should also add newrelic_start_transaction
and
newrelic_end_of_transaction
on appropriate places in your application. Or else NewRelic will log really
long response times. If you are using Symfony and EkinoNewRelic bundle, you should configure it as you were
using Symfony HTTP Cache.
To accomplish this setup took me way more hours then I want to admit. So I hope this small post could help someone to be a little faster than I was.