Replacing Flask with Gunicorn
You can replace Flask with Gunicorn as an alternative HTTP server. Create a simple Hello World app to learn how.
Prerequisites
- QRadar app SDK version 2
- Python 3
- pip
Create the app
Create a new folder for your app:
mkdir GunicornApp && cd GunicornApp
Use the QRadar app SDK to initialise the app code:
qapp create
Add the Gunicorn pip Dependency
Create a new folder called container/pip
for storing the Gunicorn pip dependencies that are installed.
mkdir container/pip
Download the Gunicorn pip and any of its dependencies by using pip download
:
pip download \
--only-binary=:all: \
--platform linux_x86_64 \
--dest container/pip \
gunicorn
This code downloads the Gunicorn pip and any of its dependencies into the container/pip
folder.
Add the Supervisord configuration
Create a new folder called container/conf/supervisord.d
to hold supervisord configuration files:
mkdir -p container/conf/supervisord.d
This container/conf/supervisord.d
folder holds all Supervisord configurations, which are copied into /etc/supervisord.d
on startup.
Create a Gunicorn configuration file container/conf/supervisord.d/gunicorn.conf
for your app:
[program:gunicorn]
directory=/opt/app-root
command=/usr/local/bin/gunicorn -b 0.0.0.0:5000 --timeout 120 --access-logfile - --workers=4 --preload "app:create_app()"
autostart=true
autorestart=unexpected
stdout_logfile=/opt/app-root/store/log/gunicorn.log
stderr_logfile=/opt/app-root/store/log/gunicorn.log
This configuration file defines how Supervisord should run Gunicorn as part of this app, with log files defined, automatic restarts and the command to start Gunicorn (with all of its command line parameters) stated.
Write the manifest
Edit the manifest.json
file to edit some values to make it more relevant to the app.
Example:
{
"name": "Gunicorn App",
"description": "Custom supervisord configuration which starts gunicorn as a replacement for flask and exposes port 5000 as the webserver port",
"version": "1.0.0",
"image": "qradar-app-base:2.0.0",
"load_flask": "false",
"areas": [
{
"id": "GunicornSupervisordTab",
"text": "Gunicorn supervisord",
"description": "Dummy tab that displays text from the flask app",
"url": "index",
"required_capabilities": []
}
],
"services": [
{
"name": "gunicorn",
"port": 5000,
"version": "1.0"
}
],
"uuid": "<your unique app UUID>"
}
This manifest code overrides the Flask webserver and informs QRadar that it should not be loaded:
"load_flask": "false",
The manifest then defines an area
in the QRadar UI to display the app, called GunicornSupervisordTab
that is populated by calling the /index
endpoint:
"areas": [
{
"id": "GunicornSupervisordTab",
"text": "Gunicorn supervisord",
"description": "Dummy tab that displays text from the flask app",
"url": "index",
"required_capabilities": []
}
],
Finally, the manifest describes and defines a named service that will run the Supervisord gunicorn
program that you configured previously, along with the port it serves on, exposing the path /index
:
"services": [
{
"name": "gunicorn",
"port": 5000,
"version": "1.0"
}
],
Because this named service is running on port 5000, the area does not need to include a reference to the named service that it is querying; it can be accessed directly. This is only the case if the named service is running on port 5000.
Run and package the app
Use the following command to run the app locally from the project root:
qapp run
Use the following commands to package and deploy the app
qapp package -p <app zip name>
qapp deploy -p <app zip name> -q <qradar console> -u <qradar user>