Why writing this?

New Relic is a great tool for monitoring your app’s performance. It also can be tricky to install, and the php script provided in the manual installation documentation does not work very well. Here’s how I installed quite manually:

Know your PHP

Let’s implement it on the dockerized project of this previous article. This means we will use the same directory structure. If you don’t feel like reading it, at least look at the Dockerfile.

First, you will need information about the php installation of the platform your app will be running. In this case, will be the container of the docker image. Build it and access the container by running

docker exec -it <container name> bash

Now, let’s get the information we need:

PHP Extension

php -i|grep "PHP Extension"

The value you need should be a number like 20160303

Architecture

file $(which php)

This should get you x86 or x64

Extension dir

php -i|grep extension_dir

You’ll need the directory. For example: /usr/lib/php/20160303

Thread Safety

See if it’s enabled or disabled:

php -i|grep "Thread Safety"

Updating your Dockerfile

We’ll implement this in a Dockerfile, but you can always run manually the commands. This is up to your implementation.

First, we’ll write our New Relic’s configuration file, so it’s easy to modify. Put it in build/newrelic.ini.

extension = "newrelic.so"
[newrelic]
newrelic.license = "PUT HERE YOUR LICENSE"

; Logging. Adjust to your needs.
newrelic.logfile = "/var/log/newrelic-php_agent.log"
newrelic.daemon.logfile = "/var/log/newrelic-daemon.log"

; Application name. Leave it like this, it will change later.
newrelic.appname = "PHP Application"

For more information, check New Relic’s documentation on configuration.

# Update your Dockerfile. Put this before the WORKDIR instruction

# Go into the build directory. This is where the newrelic.ini file is.
RUN cd /var/www/html/build && \

# Download the New Relic's latest release
wget -r -l1 -nd -A"linux.tar.gz" https://download.newrelic.com/php_agent/release/  && \

# Unzip it and enter it
gzip -dc newrelic*.tar.gz | tar xf -  && \
cd newrelic-php5*  && \

# Delete any previous New Relic extension
rm -f <Your extension dir>/newrelic.so  && \

# Copy the downloaded extension to your php's extension directory
# If is ZTS is compiled in, the file name should have "-zts" appended. See examples below.
cp ./agent/<x64 or x86>/newrelic-<Extension number>.so <Extension directory>/newrelic.so && \
#Examples:
# cp ./agent/x64/newrelic-20160303.so /usr/lib/php/20160303/newrelic.so && \
# cp ./agent/x64/newrelic-20160303-zts.so /usr/lib/php/20160303/newrelic.so && \

# Install New Relic's daemon
cp ./daemon/newrelic-daemon.<x64 or x86> /usr/bin/newrelic-daemon && \

# Copy your newrelic.ini custom file to your php conf.d dir. Make sure your php reads .ini files from this directory.
cp ../newrelic.ini /etc/php/7.1/fpm/conf.d/20-newrelic.ini && \
cp ../newrelic.ini /etc/php/7.1/cli/conf.d/20-newrelic.ini

Naming your application instances

It is true that New Relic identifies your application by the newrelic.appname configuration. If you hard code your configuration in the build/newrelic.ini file, then if you run multiple instances of it, you won’t be able to know which application is which. If you are ok with this, feel free to hard code it. If not, keep reading.

In our newrelic.ini file, we have the default name New Relic provides. We will leave it like this and change it according to an environment variable that lives inside the docker container, so you can change it depending on which environment you deploy. You will have, for example, this names on New Relic applications list:

  • Application prod
  • Application test
  • Application dev

Currently, our Dockerfile runs this at the bottom:

# (...)

WORKDIR /var/www/html

# Run supervisor
CMD ["supervisord", "-n"]

In the Dockerfile we don’t have access to the container’s environment variables, but we can create an entrypoint.sh file that our Dockerfile can run, where we do have access to them. Put it in your build folder.

#!/bin/sh

# build/entrypoint.sh

# Replace PHP Application with our custom name. Remember to edit both lines.
sed -i -e "s/PHP Application/My $APP_ENV application/g" /etc/php/7.1/fpm/conf.d/20-newrelic.ini && \
sed -i -e "s/PHP Application/My $APP_ENV application/g" /etc/php/7.1/cli/conf.d/20-newrelic.ini

/usr/bin/newrelic-daemon start

supervisord -n

In your Dockerfile, copy the build/entrypoint.sh file to the root directory and add execution permissions:

# Dockerfile
COPY ./build/entrypoint.sh /entrypoint.sh
RUN chmod +x /entrypoint.sh

Now you can edit your Dockerfile, remove the CMD ["supervisord", "-n"] line and add the following:

#(...)

ENTRYPOINT ["/entrypoint.sh"]

This should allow you to deploy different instances of your application and New Relic will be able to differentiate them like this:

  • My prod application
  • My test application
  • My dev application

Remember that this article is written assuming you followed this previous article.

Now, your Dockerfile should look like this:

Don’t forget to replace the New Relic’s installation part with your custom code.

# Dockerfile
FROM phusion/baseimage
ENV DEBIAN_FRONTEND noninteractive

# Install PHP
RUN add-apt-repository -y ppa:ondrej/php && apt-get update
RUN apt-get install -y \
# Only install the php extensions you need.
php7.1-fpm \
php7.1-mcrypt \
php7.1-intl \
php7.1-mbstring \
php7.1-xml \
php7.1-dom \
php7.1-zip \
php7.1-curl

# Create socket directory
RUN mkdir -p /var/run/php

# Don't clear env variables
# This is very important since it will allow us to read environment variables from the container.
RUN sed -e 's/;clear_env = no/clear_env = no/' -i /etc/php/7.1/fpm/pool.d/www.conf

# Install nginx
RUN apt-get install -y nginx

COPY ./build/site.conf /etc/nginx/conf.d/default.conf
COPY ./build/entrypoint.sh /entrypoint.sh
RUN chmod +x /entrypoint.sh

# Install supervisor
RUN apt-get install -y supervisor

ADD ./build/supervisor.conf /etc/supervisor/conf.d/my-app.conf

# Copy application files
COPY . /var/www/html

# Install and run composer
RUN apt-get install -y wget git zip
RUN cd /var/www/html && chmod +x ./build/composer.sh && ./build/composer.sh
RUN cd /var/www/html && php composer.phar install --no-scripts && rm composer.phar

# Allow php to write cache and logs. Note that the cache and data are outside the application directory because we don't want this data to be immutable.
# You can add the directories you want to store data to persist through deployments.
RUN mkdir -p /data/cache
RUN mkdir -p /data/logs
# Remember to allow php-fpm to write on those.
RUN chown -R www-data:www-data /data/cache
RUN chown -R www-data:www-data /data/logs
RUN chown -R www-data:www-data /var/www/html

# Install New Relic
# This part is a demonstration only. Replace with your code. Read above.
RUN cd /var/www/html/build && \
wget -r -l1 -nd -A"linux.tar.gz" https://download.newrelic.com/php_agent/release/  && \
gzip -dc newrelic*.tar.gz | tar xf -  && \
cd newrelic-php5*  && \
rm -f /usr/lib/php/20160303/newrelic.so  && \
cp ./agent/x64/newrelic-20160303.so /usr/lib/php/20160303/newrelic.so && \
cp ./daemon/newrelic-daemon.x64 /usr/bin/newrelic-daemon && \
cp ../newrelic.ini /etc/php/7.1/fpm/conf.d/20-newrelic.ini && \
cp ../newrelic.ini /etc/php/7.1/cli/conf.d/20-newrelic.ini

WORKDIR /var/www/html

ENTRYPOINT ["/entrypoint.sh"]