Getting a Core Dump in PHP Docker container
Tags: php, docker, gdb, coredump
Published: 2023-09-25 16:50:37

## PHP is failing with SIGSEGV
It could be not a common situation, but sometimes you start your PHP container and at some point PHP-FPM is failing showing an error log like:
```
NOTICE: fpm is running, pid 1
NOTICE: ready to handle connections
WARNING: [pool www] child 7 exited on signal 11 (SIGSEGV - core dumped) after 245.799183 seconds from start
```
It is a [Segmentation Fault](https://en.wikipedia.org/wiki/Segmentation_fault). There could be a various reasons for that. The cause of that could be an incompatibility of some PHP Extensions, or even a PHP code executing in some specific edge cases.

## Core Dump
To understand the real root cause of SIGSEGV is to backtrace the core dump with [GDB](https://en.wikipedia.org/wiki/GNU_Debugger) and/or [Valgrind](https://en.wikipedia.org/wiki/Valgrind).

> Just to note, this article is not about how to use GDB/Valgrind to find why segfault happens, but how to prepare for it.

## Problem #1
In my case, there was no core dump, nowhere. Probably, you may have the same case.
To check where core dump should be saved you could runt he command:
```
cat /proc/sys/kernel/core_pattern
```
In my case the output was:
```
|/usr/share/apport/apport -p%p -s%s -c%c -d%d -P%P -u%u -g%g -- %E
```
So it means that core dump is piped to `apport`, but for some reason it's not resulted in a core dump saved to a file.

I am using `php8.2-fpm-alpine3.18` (now) and `php8.0-alpine3.12` (before) Docker images. But it seems majority (if not all) Alpine images has the same problem.

## Solution #1
You need to do a few changes to let Docker image properly save the core dump.

1. In your Docker entry point file, please add the following lines before the last `exec` statement:
    ```
    ulimit -c unlimited
    echo '/tmp/core' > /proc/sys/kernel/core_pattern
    echo 1 > /proc/sys/fs/suid_dumpable
    ```
2. In the `docker-compose.yml` find your PHP service and update the file so it will look like this (of course, omit >>> and <<<):
    ```
    services:
      php-app:
        ...
    >>>
        privileged: true
        ulimits:
          core: 99999999999
    <<<
        ...
    ```
3. Rebuild the image.
4. Now, when segfault will happen you should be able to find it in `/tmp` directory. A core dump file will be named like `/tmp/core.7`, where the number corresponds to the number of a PHP-FPM worker failed.

## Problem #2
Great! Now we have core dump and could debug it.

But why we have a problem #2?
The problem is in PHP binaries that have no debug symbols. It's absolutely normal to strip these symbols after compilation, as this saves a memory and improves performance. No one wants to have a fat and slow PHP binaries in production environment!

However, debugging without debug symbols is a total disaster.

## Solution #2
Well, long story short - you need to recompile PHP and do not strip debug symbols. Here are the steps:
1. Checkout Git repository of Docker PHP images:
    ```sh
    git clone https://github.com/docker-library/php
    cd php
    ```
2. Go into directory where relevant `Dockerfile` is located. If you are using PHP 8.2 under Alpine Linux, the path should be:
    ```
    cd 8.2/alpine3.18/fpm
    ```
3. Now open `Dockerfile` and find following lines:
    ```
	find \
		/usr/local \
		-type f \
		-perm '/0111' \
		-exec sh -euxc ' \
			strip --strip-all "$@" || : \
		' -- '{}' + \
	; \
    ```
4. Completely delete these lines out of `Dockerfile` and save it.
5. Build the image and tag it:
    ```
    docker build -t php-fpm-debug .
    ```
6. Now you have an image with PHP compiled with debug symbols. What's next? Yes, build your app image from this one!
7. In `Dockerfile` of your app replace `FROM ...` with `FROM php-fpm-debug:latest`.
8. Build it! But be aware to not use `--pull` argument, so docker will search local repository for the specified image.

## Result
Now, if segfault will happen you will be able to find core dump in `/tmp` directory and it will contain debug symbols for easier debugging process.

P.S. If you know a good article or tutorial on how to use GDB or Valgrind to debug PHP core dumps, please leave in a comment below. Much appreciated!