visit
FROM your-registry.com:5555/your_base_image:latest
USER root
WORKDIR /app
RUN apt update && apt install -y supervisor
# Cleanup
RUN rm -rf /var/lib/apt/lists/* && apt clean
COPY ./pre_stop.sh /pre_stop.sh
COPY ./supervisord_githubeventconsumer.conf /etc/supervisord.conf
COPY ./supervisord_githubeventconsumer.sh /supervisord_githubeventconsumer.sh
CMD supervisord -c /etc/supervisord.conf
[supervisord]
nodaemon=true
user=root
[program:consume-github-events]
command=bash /supervisord_githubeventconsumer.sh
directory=/app
autostart=true
# Restart on unexpected exit codes
autorestart=unexpected
# Expect 37 exit code, returned when stop file exists
exitcodes=37
startretries=99999
startsecs=0
# Your user
user=www-data
killasgroup=true
stopasgroup=true
# Number of consumers to run. We use a high number because we are bound by network IO
numprocs=70
process_name=%(program_name)s_%(process_num)02d
stdout_logfile=/dev/stdout
stdout_logfile_maxbytes=0
stderr_logfile=/dev/stderr
stderr_logfile_maxbytes=0
if [ -f "/tmp/debricked-stop-work.txt" ]; then
rm -rf /tmp/debricked-stop-work.txt
exit 37
else
php bin/console messenger:consume -m 100 --time-limit=3600 --memory-limit=150M githubevents --env=prod
fi
In the previous section in the Dockerfile you might have noticed that we copied a file called `pre_stop.sh` to our image. That file looks as the following:
# Script to execute when pod is about to be terminated
touch /tmp/debricked-stop-work.txt
chown www-data:www-data /tmp/debricked-stop-work.txt
# Tell workers to stop
php bin/console messenger:stop-workers --env=prod
# Wait until file has been deleted
until [ ! -f /tmp/debricked-stop-work.txt ]
do
echo "Stop file still exists"
sleep 5
done
echo "Stop file found, exiting"
When executed, this bash script will create a `/tmp/debricked-stop-work.txt` file. Because the script also calls `
php /app/bin/console messenger:stop-workers
`, it will gracefully stop the current workers/consumers, causing the `supervisord_githubeventconsumer.sh` to be restarted by Supervisord. When the script it restarted it will now immediately exit with status code 37 because the `/tmp/debricked-stop-work.txt` exists. In turn causing Supervisor to exit, because 37 is our expected exit code.As soon as Supervisor exits, so will our Docker image as Supervisor is our CMD and the `pre_script.sh` will also terminate because `supervisord_githubeventconsumer.sh` deletes the `/tmp/debricked-stop-work.txt` before exiting with 37. We have achieved a graceful shutdown!
But when is `pre_script.sh` executed? You might be asking yourself. We will execute it on Kubernetes container’s `PreStop` .
This event occurs whenever a container is about to be terminated, such as when being terminated by the auto scaler. It is a blocking event, meaning that the container will not be deleted before this script is complete, just what we want.To configure the lifecycle event we just need to a few lines of code to our deployment config, like in the example below:---
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: gheventconsumer
namespace: default
labels:
app: gheventconsumer
tier: backend
spec:
replicas: 1
selector:
matchLabels:
app: gheventconsumer
template:
metadata:
labels:
app: gheventconsumer
spec:
terminationGracePeriodSeconds: 240 # Consuming might be slow, allow for 4 minutes graceful shutdown
containers:
- name: gheventconsumer
image: your-registry.com:5555/your_base_image:latest
imagePullPolicy: Always
Lifecycle: # ← this let’s shut down gracefully
preStop:
exec:
command: ["bash", "/pre_stop.sh"]
resources:
requests:
cpu: 0.490m
memory: 6500Mi
---
apiVersion: autoscaling/v2beta1
kind: HorizontalPodAutoscaler
metadata:
name: gheventconsumer-hpa
namespace: default
labels:
app: gheventconsumer
tier: backend
spec:
scaleTargetRef:
kind: Deployment
name: gheventconsumer
apiVersion: apps/v1
minReplicas: 1
maxReplicas: 5
metrics:
- type: Resource
resource:
name: cpu
targetAverageUtilization: 60