Skip to content

Commit

Permalink
feat(php): add initcontainer build and bundle logic (#84)
Browse files Browse the repository at this point in the history
* feat(php): add initcontainer build and bundle logic

* fix: add download script

* chore: improve arg clarity

* Update src/php/php-agent-download.sh

Co-authored-by: Timothy Pansino <[email protected]>

* fix: narrow architecture matching

* chore: include invalid values in log output

* chore: double quotes to prevent globbing

* chore: address shellcheck feedback

* chore: double quote to prevent globbing

* chore: output libc on failure for debugging

* add vm composer ini

---------

Co-authored-by: Timothy Pansino <[email protected]>
  • Loading branch information
bduranleau-nr and TimPansino authored Oct 9, 2024
1 parent f624f08 commit 5c43ce2
Show file tree
Hide file tree
Showing 6 changed files with 255 additions and 6 deletions.
16 changes: 10 additions & 6 deletions src/php/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,17 @@
# - Download the newrelic php artefacts to `/instrumentation` directory. This is required as when instrumenting the pod,
# one init container will be created to copy the files to your app's container.
# - Grant the necessary access to the files in the `/instrumentation` directory.
FROM alpine:latest@sha256:77726ef6b57ddf65bb551896826ec38bc3e53f75cdde31354fbffb4f25238ebd as build
RUN apk update && apk add ca-certificates
ARG version
ARG architecture
ARG php
FROM alpine:latest@sha256:77726ef6b57ddf65bb551896826ec38bc3e53f75cdde31354fbffb4f25238ebd AS build
RUN apk update && apk add ca-certificates && apk add --no-cache bash
ARG AGENT_VERSION
ARG LIBC
WORKDIR /instrumentation
RUN wget -c "https://download.newrelic.com/php_agent/release/newrelic-${php}-${version}-${architecture}.tar.gz" -O - | tar -xz --strip-components 1
COPY php-agent-download.sh k8s-php-install.sh nr_env_to_ini.sh nrini.mapping ./
RUN chmod +x php-agent-download.sh k8s-php-install.sh nr_env_to_ini.sh
RUN ./php-agent-download.sh $LIBC $AGENT_VERSION
RUN rm php-agent-download.sh
RUN mkdir php-agent php-agent/bin php-agent/ext php-agent/ini php-agent/logs
COPY newrelic.ini ./php-agent/ini/

FROM busybox:latest@sha256:9ae97d36d26566ff84e8893c64a6dc4fe8ca6d1144bf5b87b2b85a32def253c7
COPY --from=build /instrumentation /instrumentation
Expand Down
78 changes: 78 additions & 0 deletions src/php/k8s-php-install.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
#!/bin/sh

ZEND_API_NO=$1 # zend representation of the PHP version number
AGENT_FILEPATH=/newrelic-instrumentation/agent
DAEMON_FILEPATH=/newrelic-instrumentation/daemon
INSTALL_LOG=/newrelic-instrumentation/newrelic-install.log

log() {
msg="$1"
timestamp=$(date +"%m-%d-%Y %T")
echo "${timestamp} : ${msg}" >>${INSTALL_LOG}
}

if [ -z "${ZEND_API_NO}" ]; then
log "Missing Zend api number. Exiting."
exit 1
fi

log "Installing New Relic PHP Agent for the K8S Agent Operator"

#
# Determine the architecture we are executing on.
#
arch=$( (uname -m) 2>/dev/null) || arch="unknown"
case "${arch}" in
aarch64 | arm64) arch=aarch64 ;;
x86_64 | amd64) arch=x64 ;;
esac

# exit if arch is unsupported
if [ "${arch}" != "x64" ] && [ "${arch}" != "aarch64" ]; then
msg=$(
cat <<EOF
An unsupported architecture detected: "${arch}"
Please visit:
https://docs.newrelic.com/docs/apm/agents/php-agent/getting-started/php-agent-compatibility-requirements/
to view compatibilty requirements for the the New Relic PHP agent.
EOF
)

log "${msg}"

log "The install will now exit."
exit 1
fi

# exit if invalid php x arch
if [ "${arch}" = "aarch64" ]; then
if [ "${ZEND_API_NO}" = "20170218" ] || [ "${ZEND_API_NO}" = "20180731" ] || [ "${ZEND_API_NO}" = "20190902" ]; then
log "Invalid arch x php detected. ARM64 is only supported for PHP 8.0+. The install will now exit."
exit 1
fi
fi

AGENT_SO=${AGENT_FILEPATH}/${arch}/newrelic-${ZEND_API_NO}.so

# verify existence of agent .so
if [ ! -f "${AGENT_SO}" ]; then
log "Agent binary not found (${AGENT_SO}). Exiting."
exit 1
fi

# copy the .so to the expected location
cp "${AGENT_SO}" /newrelic-instrumentation/php-agent/ext/newrelic.so

DAEMON_BINARY=${DAEMON_FILEPATH}/newrelic-daemon.${arch}

# verify existence of the daemon binary
if [ ! -f "${DAEMON_BINARY}" ]; then
log "Daemon binary not found (${DAEMON_BINARY}). Exiting."
exit 1
fi

# copy the binary to the expected location
cp "${DAEMON_BINARY}" /newrelic-instrumentation/php-agent/bin/newrelic-daemon

log "Installation complete."
5 changes: 5 additions & 0 deletions src/php/newrelic.ini
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
extension = "/newrelic-instrumentation/php-agent/ext/newrelic.so"
[newrelic]
newrelic.daemon.location="/newrelic-instrumentation/php-agent/bin/newrelic-daemon"
newrelic.daemon.logfile="/newrelic-instrumentation/php-agent/logs/newrelic-daemon.log"
newrelic.logfile="/newrelic-instrumentation/php-agent/logs/php-agent.log"
14 changes: 14 additions & 0 deletions src/php/nr_env_to_ini.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
#!/bin/sh

map_file=/newrelic-instrumentation/nrini.mapping
output_file=/newrelic-instrumentation/php-agent/ini/newrelic.ini

if [ -n "${NEW_RELIC_LICENSE_KEY}" ]; then
echo "newrelic.license=${NEW_RELIC_LICENSE_KEY}" >>$output_file
fi

while IFS=':' read -r envvar inivar; do
if [ -n "$(printenv "$envvar")" ]; then
echo "$inivar=$(printenv "$envvar")" >>$output_file
fi
done <"$map_file"
121 changes: 121 additions & 0 deletions src/php/nrini.mapping
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
NEW_RELIC_ENABLED:newrelic.enabled
NEW_RELIC_LICENSE:newrelic.license
NEW_RELIC_LOGFILE:newrelic.logfile
NEW_RELIC_LOGLEVEL:newrelic.loglevel
NEW_RELIC_HIGH_SECURITY:newrelic.high_security
NEW_RELIC_APPNAME:newrelic.appname
NEW_RELIC_PROCESS_HOST_DISPLAY_NAME:newrelic.process_host.display_name
NEW_RELIC_DAEMON_LOGFILE:newrelic.daemon.logfile
NEW_RELIC_DAEMON_LOGLEVEL:newrelic.daemon.loglevel
NEW_RELIC_DAEMON_ADDRESS:newrelic.daemon.address
NEW_RELIC_DAEMON_SSL_CA_BUNDLE:newrelic.daemon.ssl_ca_bundle
NEW_RELIC_DAEMON_SSL_CA_PATH:newrelic.daemon.ssl_ca_path
NEW_RELIC_DAEMON_PROXY:newrelic.daemon.proxy
NEW_RELIC_DAEMON_PIDFILE:newrelic.daemon.pidfile
NEW_RELIC_DAEMON_LOCATION:newrelic.daemon.location
NEW_RELIC_DAEMON_COLLECTOR_HOST:newrelic.daemon.collector_host
NEW_RELIC_DAEMON_DONT_LAUNCH:newrelic.daemon.dont_launch
NEW_RELIC_DAEMON_UTILIZATION_DETECT_AWS:newrelic.daemon.utilization.detect_aws
NEW_RELIC_DAEMON_UTILIZATION_DETECT_AZURE:newrelic.daemon.utilization.detect_azure
NEW_RELIC_DAEMON_UTILIZATION_DETECT_GCP:newrelic.daemon.utilization.detect_gcp
NEW_RELIC_DAEMON_UTILIZATION_DETECT_PCF:newrelic.daemon.utilization.detect_pcf
NEW_RELIC_DAEMON_UTILIZATION_DETECT_DOCKER:newrelic.daemon.utilization.detect_docker
NEW_RELIC_DAEMON_UTILIZATION_DETECT_KUBERNETES:newrelic.daemon.utilization.detect_kubernetes
NEW_RELIC_DAEMON_APP_TIMEOUT:newrelic.daemon.app_timeout
NEW_RELIC_DAEMON_APP_CONNECT_TIMEOUT:newrelic.daemon.app_connect_timeout
NEW_RELIC_DAEMON_START_TIMEOUT:newrelic.daemon.start_timeout
NEW_RELIC_ERROR_COLLECTOR_ENABLED:newrelic.error_collector.enabled
NEW_RELIC_ERROR_COLLECTOR_IGNORE_USER_EXCEPTION_HANDLER:newrelic.error_collector.ignore_user_exception_handler
NEW_RELIC_ERROR_COLLECTOR_IGNORE_EXCEPTIONS:newrelic.error_collector.ignore_exceptions
NEW_RELIC_ERROR_COLLECTOR_IGNORE_ERRORS:newrelic.error_collector.ignore_errors
NEW_RELIC_ERROR_COLLECTOR_RECORD_DATABASE_ERRORS:newrelic.error_collector.record_database_errors
NEW_RELIC_ERROR_COLLECTOR_PRIORITIZE_API_ERRORS:newrelic.error_collector.prioritize_api_errors
NEW_RELIC_BROWSER_MONITORING_AUTO_INSTRUMENT:newrelic.browser_monitoring.auto_instrument
NEW_RELIC_TRANSACTION_TRACER_ENABLED:newrelic.transaction_tracer.enabled
NEW_RELIC_TRANSACTION_TRACER_THRESHOLD:newrelic.transaction_tracer.threshold
NEW_RELIC_TRANSACTION_TRACER_DETAIL:newrelic.transaction_tracer.detail
NEW_RELIC_TRANSACTION_TRACER_SLOW_SQL:newrelic.transaction_tracer.slow_sql
NEW_RELIC_TRANSACTION_TRACER_STACK_TRACE_THRESHOLD:newrelic.transaction_tracer.stack_trace_threshold
NEW_RELIC_TRANSACTION_TRACER_EXPLAIN_ENABLED:newrelic.transaction_tracer.explain_enabled
NEW_RELIC_TRANSACTION_TRACER_EXPLAIN_THRESHOLD:newrelic.transaction_tracer.explain_threshold
NEW_RELIC_TRANSACTION_TRACER_RECORD_SQL:newrelic.transaction_tracer.record_sql
NEW_RELIC_TRANSACTION_TRACER_CUSTOM:newrelic.transaction_tracer.custom
NEW_RELIC_TRANSACTION_TRACER_INTERNAL_FUNCTIONS_ENABLED:newrelic.transaction_tracer.internal_functions_enabled
NEW_RELIC_FRAMEWORK:newrelic.framework
NEW_RELIC_WEBTRANSACTION_NAME_REMOVE_TRAILING_PATH:newrelic.webtransaction.name.remove_trailing_path
NEW_RELIC_WEBTRANSACTION_NAME_FUNCTIONS:newrelic.webtransaction.name.functions
NEW_RELIC_WEBTRANSACTION_NAME_FILES:newrelic.webtransaction.name.files
NEW_RELIC_DAEMON_AUDITLOG:newrelic.daemon.auditlog
NEW_RELIC_TRANSACTION_EVENTS_ENABLED:newrelic.transaction_events.enabled
NEW_RELIC_ATTRIBUTES_ENABLED:newrelic.attributes.enabled
NEW_RELIC_TRANSACTION_EVENTS_ATTRIBUTES_ENABLED:newrelic.transaction_events.attributes.enabled
NEW_RELIC_TRANSACTION_TRACER_ATTRIBUTES_ENABLED:newrelic.transaction_tracer.attributes.enabled
NEW_RELIC_ERROR_COLLECTOR_ATTRIBUTES_ENABLED:newrelic.error_collector.attributes.enabled
NEW_RELIC_BROWSER_MONITORING_ATTRIBUTES_ENABLED:newrelic.browser_monitoring.attributes.enabled
NEW_RELIC_SPAN_EVENTS_ATTRIBUTES_ENABLED:newrelic.span_events.attributes.enabled
NEW_RELIC_ATTRIBUTES_INCLUDE:newrelic.attributes.include
NEW_RELIC_ATTRIBUTES_EXCLUDE:newrelic.attributes.exclude
NEW_RELIC_TRANSACTION_EVENTS_ATTRIBUTES_INCLUDE:newrelic.transaction_events.attributes.include
NEW_RELIC_TRANSACTION_EVENTS_ATTRIBUTES_EXCLUDE:newrelic.transaction_events.attributes.exclude
NEW_RELIC_TRANSACTION_TRACER_ATTRIBUTES_INCLUDE:newrelic.transaction_tracer.attributes.include
NEW_RELIC_TRANSACTION_TRACER_ATTRIBUTES_EXCLUDE:newrelic.transaction_tracer.attributes.exclude
NEW_RELIC_ERROR_COLLECTOR_ATTRIBUTES_INCLUDE:newrelic.error_collector.attributes.include
NEW_RELIC_ERROR_COLLECTOR_ATTRIBUTES_EXCLUDE:newrelic.error_collector.attributes.exclude
NEW_RELIC_BROWSER_MONITORING_ATTRIBUTES_INCLUDE:newrelic.browser_monitoring.attributes.include
NEW_RELIC_BROWSER_MONITORING_ATTRIBUTES_EXCLUDE:newrelic.browser_monitoring.attributes.exclude
NEW_RELIC_SPAN_EVENTS_ATTRIBUTES_INCLUDE:newrelic.span_events.attributes.include
NEW_RELIC_SPAN_EVENTS_ATTRIBUTES_EXCLUDE:newrelic.span_events.attributes.exclude
NEW_RELIC_FEATURE_FLAG:newrelic.feature_flag
NEW_RELIC_CUSTOM_INSIGHTS_EVENTS_ENABLED:newrelic.custom_insights_events.enabled
NEW_RELIC_CUSTOM_INSIGHTS_EVENTS_MAX_SAMPLES_STORED:newrelic.custom_events.max_samples_stored
NEW_RELIC_LABELS:newrelic.labels
NEW_RELIC_SYNTHETICS_ENABLED:newrelic.synthetics.enabled
NEW_RELIC_CROSS_APPLICATION_TRACER_ENABLED:newrelic.cross_application_tracer.enabled
NEW_RELIC_DISTRIBUTED_TRACING_ENABLED:newrelic.distributed_tracing_enabled
NEW_RELIC_DISTRIBUTED_TRACING_EXCLUDE_NEWRELIC_HEADER:newrelic.distributed_tracing_exclude_newrelic_header
NEW_RELIC_SPAN_EVENTS_ENABLED:newrelic.span_events_enabled
NEW_RELIC_SPAN_EVENTS_MAX_SAMPLES_STORED:newrelic.span_events.max_samples_stored
NEW_RELIC_INFINITE_TRACING_TRACE_OBSERVER_HOST:newrelic.infinite_tracing.trace_observer.host
NEW_RELIC_INFINITE_TRACING_TRACE_OBSERVER_PORT:newrelic.infinite_tracing.trace_observer.port
NEW_RELIC_INFINITE_TRACING_SPAN_EVENTS_QUEUE_SIZE:newrelic.infinite_tracing.span_events.queue_size
NEW_RELIC_TRANSACTION_TRACER_GATHER_INPUT_QUERIES:newrelic.transaction_tracer.gather_input_queries
NEW_RELIC_ERROR_COLLECTOR_CAPTURE_EVENTS:newrelic.error_collector.capture_events
NEW_RELIC_GUZZLE_ENABLED:newrelic.guzzle.enabled
NEW_RELIC_PHPUNIT_EVENTS_ENABLED:newrelic.phpunit_events.enabled
NEW_RELIC_DATASTORE_TRACER_INSTANCE_REPORTING_ENABLED:newrelic.datastore_tracer.instance_reporting.enabled
NEW_RELIC_DATASTORE_TRACER_DATABASE_NAME_REPORTING_ENABLED:newrelic.datastore_tracer.database_name_reporting.enabled
NEW_RELIC_SECURITY_POLICIES_TOKEN:newrelic.security_policies_token
NEW_RELIC_PRELOAD_FRAMEWORK_LIBRARY_DETECTION:newrelic.preload_framework_library_detection
NEW_RELIC_TRANSACTION_TRACER_MAX_SEGMENTS_WEB:newrelic.transaction_tracer.max_segments_web
NEW_RELIC_TRANSACTION_TRACER_MAX_SEGMENTS_CLI:newrelic.transaction_tracer.max_segments_cli
NEW_RELIC_FRAMEWORK_DRUPAL_MODULES:newrelic.framework.drupal.modules
NEW_RELIC_FRAMEWORK_WORDPRESS_HOOKS:newrelic.framework.wordpress.hooks
NEW_RELIC_FRAMEWORK_WORDPRESS_HOOKS_OPTIONS:newrelic.framework.wordpress.hooks.options
NEW_RELIC_FRAMEWORK_WORDPRESS_HOOKS_THRESHOLD:newrelic.framework.wordpress.hooks.threshold
NEW_RELIC_APPLICATION_LOGGING_ENABLED:newrelic.application_logging.enabled
NEW_RELIC_APPLICATION_LOGGING_FORWARDING_ENABLED:newrelic.application_logging.forwarding.enabled
NEW_RELIC_APPLICATION_LOGGING_FORWARDING_MAX_SAMPLES_STORED:newrelic.application_logging.forwarding.max_samples_stored
NEW_RELIC_APPLICATION_LOGGING_FORWARDING_LOG_LEVEL:newrelic.application_logging.forwarding.log_level
NEW_RELIC_APPLICATION_LOGGING_LOCAL_DECORATING_ENABLED:newrelic.application_logging.local_decorating.enabled
NEW_RELIC_APPLICATION_LOGGING_METRICS_ENABLED:newrelic.application_logging.metrics.enabled
NEW_RELIC_APPLICATION_LOGGING_FORWARDING_CONTEXT_DATA_ENABLED:newrelic.application_logging.forwarding.context_data.enabled
NEW_RELIC_APPLICATION_LOGGING_FORWARDING_CONTEXT_DATA_INCLUDE:newrelic.application_logging.forwarding.context_data.include
NEW_RELIC_APPLICATION_LOGGING_FORWARDING_CONTEXT_DATA_EXCLUDE:newrelic.application_logging.forwarding.context_data.exclude
NEW_RELIC_CODE_LEVEL_METRICS_ENABLED:newrelic.code_level_metrics.enabled
NEW_RELIC_VULNERABILITY_MANAGEMENT_PACKAGE_DETECTION_ENABLED:newrelic.vulnerability_management.package_detection.enabled
NEW_RELIC_VULNERABILITY_MANAGEMENT_COMPOSER_API_ENABLED:newrelic.vulnerability_management.composer_api.enabled
NEW_RELIC_FEATURE_FLAG:newrelic.feature_flag
NEW_RELIC_SPECIAL:newrelic.special
NEW_RELIC_SPECIAL_APPINFO_TIMEOUT:newrelic.special.appinfo_timeout
NEW_RELIC_DAEMON_SPECIAL_CURL_VERBOSE:newrelic.daemon.special.curl_verbose
NEW_RELIC_DAEMON_SPECIAL_INTEGRATION:newrelic.daemon.special.integration
NEW_RELIC_SPECIAL_DISABLE_INSTRUMENTATION:newrelic.special.disable_instrumentation
NEW_RELIC_SPECIAL_EXPENSIVE_NODE_MIN:newrelic.special.expensive_node_min
NEW_RELIC_SPECIAL_MAX_NESTING_LEVEL:newrelic.special.max_nesting_level
NEW_RELIC_SPECIAL_ENABLE_EXTENSION_INSTRUMENTATION:newrelic.special.enable_extension_instrumentation
NEW_RELIC_BROWSER_MONITORING_DEBUG:newrelic.browser_monitoring.debug
NEW_RELIC_BROWSER_MONITORING_LOADER:newrelic.browser_monitoring.loader
NEW_RELIC_INFINITE_TRACING_SPAN_EVENTS_AGENT_QUEUE_SIZE:newrelic.infinite_tracing.span_events.agent_queue.size
NEW_RELIC_INFINITE_TRACING_SPAN_EVENTS_AGENT_QUEUE_TIMEOUT:newrelic.infinite_tracing.span_events.agent_queue.timeout
NEW_RELIC_FRAMEWORK_WORDPRESS_HOOKS_SKIP_FILENAME:newrelic.framework.wordpress.hooks_skip_filename
NEW_RELIC_DISTRIBUTED_TRACING_PAD_TRACE_ID:newrelic.distributed_tracing.pad_trace_id
27 changes: 27 additions & 0 deletions src/php/php-agent-download.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
#!/bin/bash

libc=$1
version=$2

if [ -z "$libc" ]; then
echo "'libc' argument not supplied. Defaulting to 'gnu'"
libc="gnu"
elif [[ ! $libc =~ ^(musl|gnu)$ ]]; then
echo "error: invalid 'libc' argument provided: ${libc}. Exiting."
exit 1
fi

if [ -z "$version" ]; then
latest=$(wget -c https://download.newrelic.com/php_agent/release/ -O - | grep newrelic-php5 | cut -d '-' -f 3 | head -n 1)
url="https://download.newrelic.com/php_agent/release/newrelic-php5-${latest}-linux"
else
url="https://download.newrelic.com/php_agent/archive/${version}/newrelic-php5-${version}-linux"
fi

if [ "$libc" = 'musl' ]; then
url+="-musl.tar.gz"
else
url+=".tar.gz"
fi

wget -c "${url}" -O - | tar -xz --strip-components 1

0 comments on commit 5c43ce2

Please sign in to comment.