Installation Guide
Welcome to the Installation Guide! This page will help you set up and configure the system using Docker, Podman, Quadlet, or Kubernetes.
If you are upgrading from a previous version of Monitor, please refer to the Migration Guides before proceeding with the installation. These guides contain important steps to ensure a smooth upgrade process.
Installation Methods:
- Docker Setup: Quick and easy containerized installation.
- Podman Setup: Docker-compatible, rootless containers.
- Quadlet Setup: systemd-native Podman, no compose required.
- Kubernetes Setup: For scalable, production-grade deployments.
- Docker Setup
- Podman Setup
- Quadlet Setup
- Kubernetes Setup
To install using Docker:
- Download the provided
docker-compose.ymlfile below. - Pull the container image from the registry:
docker pull registry.frafos.net/abc/mon:<tag> - Update your
docker-compose.ymlto use the registry image:image: registry.frafos.net/abc/mon:<tag> - Run:
docker-compose up -d - Access the dashboard at
http://localhost:445
Fresh installations use plain HTTP only, as nginx and self-signed certificates are not included by default.
Container images are available at: Frafos Container Registry
Possible CAPs to be used during runtime
CAP_NET_BIND_SERVICE: Needed to give the container access to open a port for receiving syslog messages.
Show example docker-compose.yml
⬇️ Download docker-compose.yml
# Example Docker Compose file for Frafos monitoring stack
# Each service below represents a containerized application.
services:
ccm:
# Call Control Manager (CCM) service
image: registry.frafos.net/abc/ccm:5.6
container_name: ccm
ports:
- "443-444:443-444" # Expose ports 443 and 444
networks:
- monitoring # Connect to monitoring network
- signaling # Connect to signaling network
restart: always # Always restart on failure
volumes:
- ccm-data:/data # Persist data in named volume
cap_add:
- AUDIT_CONTROL # Add audit control capability
- AUDIT_WRITE # Add audit write capability
- CAP_NET_BIND_SERVICE # Allow binding to low-numbered ports
elastic:
# Elasticsearch service for log and metric storage
image: docker.elastic.co/elasticsearch/elasticsearch:9.1.5
container_name: elastic
ports:
- "9200:9200" # HTTP API
- "9300:9300" # Transport protocol
environment:
- discovery.type=single-node # Run as single node
- xpack.ml.enabled=false # Disable ML features
- network.host=_local_,_site_ # Bind to local and site interfaces
- path.repo=/usr/share/elasticsearch/snapshots # Path for snapshots
#- thread_pool.search.queue_size=10000 # (optional) Increase search queue size
#- http.max_initial_line_length=16kb # (optional) Increase max HTTP header size
#- cluster.max_shards_per_node=166 # (optional) Increase max shards
#- indices.lifecycle.history_index_enabled=false # (optional) Disable ILM history
# 1. FOR PLAIN HTTP USE THE FOLLOWING VARIABLES -----
- xpack.security.enabled=false # Disable security
- xpack.security.http.ssl.enabled=false # Disable HTTP SSL
# 1.2 OR ENABLE SECURITY --- (default user = elastic) ---
# - xpack.security.enabled=true
# - ELASTIC_PASSWORD=Test1234 # curl -u elastic:Test1234 http://localhost:9200/
# 2. FOR SSL USE THE FOLOWING VARIABLES -------------
# - xpack.security.enabled=true
# - xpack.security.http.ssl.enabled=true
# - xpack.security.http.ssl.certificate=certs/server.crt
# - xpack.security.http.ssl.key=certs/server.key
# - xpack.security.transport.ssl.enabled=true
# - xpack.security.transport.ssl.certificate=certs/server.crt
# - xpack.security.transport.ssl.key=certs/server.key
# - xpack.security.transport.ssl.verification_mode=certificate
# - xpack.security.transport.ssl.certificate_authorities=certs/ca.crt
# 2.2 --- ANONYMOUS AUTH --- (not recommended for production, but can be useful for development and testing purposes)
# - xpack.security.authc.anonymous.username=anonymous
# - xpack.security.authc.anonymous.roles=superuser
# - xpack.security.authc.anonymous.authz_exception=false
# 2.3 --- OR ---
# - ELASTIC_PASSWORD=Test1234 # curl --cacert ./path/to/certs/ca.crt -u elastic:Test1234 https://localhost:9200/
networks:
- monitoring
restart: always
ulimits:
nofile:
soft: 65536
hard: 65536
memlock:
soft: -1
hard: -1
deploy:
resources:
limits:
memory: 4g
healthcheck:
test: ["CMD-SHELL", "curl -fsS http://localhost:9200/ || exit 1"]
interval: 15s
timeout: 5s
retries: 20
start_period: 30s
volumes:
- es-data:/usr/share/elasticsearch/data # Data volume
- es-snapshots:/usr/share/elasticsearch/snapshots # Snapshots volume
#- ./elasticsearch.yml:/usr/share/elasticsearch/config/elasticsearch.yml:ro # (optional) Custom config
# - ./path/to/certs:/usr/share/elasticsearch/config/certs:ro
chrome:
# Headless Chrome for PDF generation or browser automation
image: zenika/alpine-chrome:124
#image: registry.frafos.net/contrib/alpine-chrome:latest # (alternative image)
container_name: chrome
#shm_size: "1gb" (optional) not required - zenika/alpine-chrome uses --disable-dev-shm-usage by default.
networks:
- monitoring
expose:
- "9222" # Expose remote debugging port
command:
- "--no-sandbox"
- "--remote-debugging-address=::"
- "--remote-debugging-port=9222"
restart: always
depends_on:
monitor:
condition: service_healthy
healthcheck:
test:
["CMD", "wget", "-q", "--spider", "http://localhost:9222/json/version"]
interval: 30s
timeout: 10s
retries: 3
monitor:
# Monitoring service (MONITOR)
image: registry.frafos.net/abc/mon:10.2
container_name: monitor
restart: always
ports:
- "445:445" # SERVER_PORT (445 on host, 445 in container)
- "514:514/udp" # VECTOR_SYSLOG_PORT (default VECTOR_SYSLOG_TRANSPORT_PROTOCOL is UDP)
- "514:514/tcp" # VECTOR_SYSLOG_PORT (when VECTOR_SYSLOG_TRANSPORT_PROTOCOL is TCP)
- "5044:5044" # VECTOR_SOCKET_PORT
- "5045:5045" # VECTOR_SOCKET_TLS_PORT
- "3042:3042" # UPLOAD_API_PORT
- "873:873" # UPLOAD_API_RSYNC_PORT
environment:
- BROWSER_URL=http://chrome:9222/
- PDF_RENDER_URL=http://monitor:445
#- CCM=ccm # (optional) CCM service name
#- ES=http://elastic:9200 # (optional) ES endpoint
#- REPORT_URL=http://localhost:445/report # (optional) Report URL (use localhost or bracketed IPv6 like http://[::1]:445/report)
#- ES_USERNAME=monitor # (optional) ES user
#- ES_PASSWORD=password # (optional) ES password
#- ADVANCED_ALERTS=true # (optional) Enable Advanced Alerts
#- ADVANCED_ALERTS_URL=http://alerts:80 # (optional) Advanced Alerts URL
volumes:
- monitor-data:/data:U # Persist MONITOR data
# (optional) needed by the bundled SQLite I/O collector below, to
# attribute disk I/O to the sqlite db file itself instead of the
# whole disk. Both mounts are required on Docker too, not just
# Podman: this bpftrace version looks for tracefs at
# /sys/kernel/tracing specifically, not /sys/kernel/debug/tracing -
# mounting only /sys/kernel/debug leaves it unable to find
# kprobe_events at all, regardless of container engine.
- /sys/kernel/debug:/sys/kernel/debug:rw
- /sys/kernel/tracing:/sys/kernel/tracing:rw
networks:
- monitoring
mem_limit: 1.5G
cpus: 1.0
cap_add:
- CAP_NET_BIND_SERVICE
- CAP_SYS_ADMIN # (optional) lets the bundled SQLite I/O collector attribute disk I/O to the db file itself instead of the whole disk
security_opt:
# (optional, paired with CAP_SYS_ADMIN above) Docker's default
# seccomp profile blocks perf_event_open, which bpftrace's
# kprobes need to attach - without this, bpftrace starts but
# immediately fails with "perf_event_open: Function not
# implemented" / "ERROR: Failed to open perf buffer", confirmed on
# Docker (not just Podman, where the same profile issue exists but
# is documented separately in the Quadlet setup notes).
- seccomp:unconfined
deploy:
resources:
limits:
memory: 1.5G
cpus: "1.0"
healthcheck:
test: ["CMD-SHELL", "node -e \"fetch('http://localhost:445/').then(r=>{process.exit(r.ok?0:1)}).catch(()=>process.exit(1))\""]
interval: 15s
timeout: 5s
retries: 20
start_period: 30s
tty: true # Enable TTY
stdin_open: true # Keep STDIN open
node-exporter:
image: prom/node-exporter:v1.11.1
container_name: node-exporter
ports:
- "9100:9100"
privileged: true
command: ["--path.rootfs=/hostfs"]
restart: always
volumes:
- /:/hostfs:ro,rslave
networks:
- monitoring
profiles:
- monitoring
- serverClientPrometheus
alerts:
image: registry.frafos.net/fril/alerts:10.2
container_name: alerts
restart: always
environment:
REDIS_HOST: "redis"
elasticConfigUrl: "http://elastic:9200/"
cap_add:
- AUDIT_CONTROL
- NET_RAW
- AUDIT_WRITE
ports:
- "80:80"
networks:
- monitoring
depends_on:
elastic:
condition: service_healthy
redis:
condition: service_healthy
healthcheck:
test:
[
"CMD-SHELL",
"curl -fsS 'http://localhost:80/api/alertapi/help' || exit 1",
]
interval: 15s
timeout: 5s
retries: 20
start_period: 15s
redis:
image: registry.frafos.net/fril/redis-stack-server:latest
container_name: redis
restart: always
expose: ["6379"]
security_opt: ["no-new-privileges:true"]
cap_drop: [MKNOD, NET_RAW, AUDIT_WRITE]
networks:
- monitoring
healthcheck:
test: ["CMD", "redis-cli", "ping"]
interval: 10s
timeout: 5s
retries: 20
start_period: 10s
rq2rest:
image: registry.frafos.net/fril/rq2rest:latest
container_name: rq2rest
command:
[
"-c",
"/etc/rq2rest.ini",
"-d",
"5",
"--redis_url=redis:6379",
"--http_url=http://alerts:80/ingestion/http/00000000-0000-0000-0000-000000000000",
]
restart: always
tty: true
networks:
- monitoring
depends_on:
redis:
condition: service_healthy
alerts:
condition: service_healthy
volumes:
es-data:
es-snapshots:
monitor-data:
ccm-data:
networks:
monitoring:
driver: bridge
enable_ipv6: true
signaling:
driver: bridge
enable_ipv6: true
Docker is the recommended way for quick setup and easy updates.
To install using Podman:
- Download the provided
docker-compose.ymlfile below. - Pull the container image from the registry:
podman pull registry.frafos.net/abc/mon:<tag> - Run the container:
podman run -d -p 445:5000 registry.frafos.net/abc/mon:<tag> - Or use Compose:
podman-compose up -d - Access the dashboard at
http://localhost:445
Fresh installations use plain HTTP only, as nginx and self-signed certificates are not included by default.
Container images are available at: Frafos Container Registry
Possible CAPs to be used during runtime
CAP_NET_BIND_SERVICE: Needed to give the container access to open a port for receiving syslog messages.CAP_SYS_ADMIN(optional): Lets the bundled SQLite I/O collector attribute disk I/O to the SQLite db file itself instead of the whole disk. See the Quadlet Setup tab for the extra requirements this has on Podman specifically.
Show example docker-compose.yml
⬇️ Download docker-compose.yml
# Example Docker Compose file for Frafos monitoring stack
# Each service below represents a containerized application.
services:
ccm:
# Call Control Manager (CCM) service
image: registry.frafos.net/abc/ccm:5.6
container_name: ccm
ports:
- "443-444:443-444" # Expose ports 443 and 444
networks:
- monitoring # Connect to monitoring network
- signaling # Connect to signaling network
restart: always # Always restart on failure
volumes:
- ccm-data:/data # Persist data in named volume
cap_add:
- AUDIT_CONTROL # Add audit control capability
- AUDIT_WRITE # Add audit write capability
- CAP_NET_BIND_SERVICE # Allow binding to low-numbered ports
elastic:
# Elasticsearch service for log and metric storage
image: docker.elastic.co/elasticsearch/elasticsearch:9.1.5
container_name: elastic
ports:
- "9200:9200" # HTTP API
- "9300:9300" # Transport protocol
environment:
- discovery.type=single-node # Run as single node
- xpack.ml.enabled=false # Disable ML features
- network.host=_local_,_site_ # Bind to local and site interfaces
- path.repo=/usr/share/elasticsearch/snapshots # Path for snapshots
#- thread_pool.search.queue_size=10000 # (optional) Increase search queue size
#- http.max_initial_line_length=16kb # (optional) Increase max HTTP header size
#- cluster.max_shards_per_node=166 # (optional) Increase max shards
#- indices.lifecycle.history_index_enabled=false # (optional) Disable ILM history
# 1. FOR PLAIN HTTP USE THE FOLLOWING VARIABLES -----
- xpack.security.enabled=false # Disable security
- xpack.security.http.ssl.enabled=false # Disable HTTP SSL
# 1.2 OR ENABLE SECURITY --- (default user = elastic) ---
# - xpack.security.enabled=true
# - ELASTIC_PASSWORD=Test1234 # curl -u elastic:Test1234 http://localhost:9200/
# 2. FOR SSL USE THE FOLOWING VARIABLES -------------
# - xpack.security.enabled=true
# - xpack.security.http.ssl.enabled=true
# - xpack.security.http.ssl.certificate=certs/server.crt
# - xpack.security.http.ssl.key=certs/server.key
# - xpack.security.transport.ssl.enabled=true
# - xpack.security.transport.ssl.certificate=certs/server.crt
# - xpack.security.transport.ssl.key=certs/server.key
# - xpack.security.transport.ssl.verification_mode=certificate
# - xpack.security.transport.ssl.certificate_authorities=certs/ca.crt
# 2.2 --- ANONYMOUS AUTH --- (not recommended for production, but can be useful for development and testing purposes)
# - xpack.security.authc.anonymous.username=anonymous
# - xpack.security.authc.anonymous.roles=superuser
# - xpack.security.authc.anonymous.authz_exception=false
# 2.3 --- OR ---
# - ELASTIC_PASSWORD=Test1234 # curl --cacert ./path/to/certs/ca.crt -u elastic:Test1234 https://localhost:9200/
networks:
- monitoring
restart: always
ulimits:
nofile:
soft: 65536
hard: 65536
memlock:
soft: -1
hard: -1
deploy:
resources:
limits:
memory: 4g
healthcheck:
test: ["CMD-SHELL", "curl -fsS http://localhost:9200/ || exit 1"]
interval: 15s
timeout: 5s
retries: 20
start_period: 30s
volumes:
- es-data:/usr/share/elasticsearch/data # Data volume
- es-snapshots:/usr/share/elasticsearch/snapshots # Snapshots volume
#- ./elasticsearch.yml:/usr/share/elasticsearch/config/elasticsearch.yml:ro # (optional) Custom config
# - ./path/to/certs:/usr/share/elasticsearch/config/certs:ro
chrome:
# Headless Chrome for PDF generation or browser automation
image: zenika/alpine-chrome:124
#image: registry.frafos.net/contrib/alpine-chrome:latest # (alternative image)
container_name: chrome
#shm_size: "1gb" (optional) not required - zenika/alpine-chrome uses --disable-dev-shm-usage by default.
networks:
- monitoring
expose:
- "9222" # Expose remote debugging port
command:
- "--no-sandbox"
- "--remote-debugging-address=::"
- "--remote-debugging-port=9222"
restart: always
depends_on:
monitor:
condition: service_healthy
healthcheck:
test:
["CMD", "wget", "-q", "--spider", "http://localhost:9222/json/version"]
interval: 30s
timeout: 10s
retries: 3
monitor:
# Monitoring service (MONITOR)
image: registry.frafos.net/abc/mon:10.2
container_name: monitor
restart: always
ports:
- "445:445" # SERVER_PORT (445 on host, 445 in container)
- "514:514/udp" # VECTOR_SYSLOG_PORT (default VECTOR_SYSLOG_TRANSPORT_PROTOCOL is UDP)
- "514:514/tcp" # VECTOR_SYSLOG_PORT (when VECTOR_SYSLOG_TRANSPORT_PROTOCOL is TCP)
- "5044:5044" # VECTOR_SOCKET_PORT
- "5045:5045" # VECTOR_SOCKET_TLS_PORT
- "3042:3042" # UPLOAD_API_PORT
- "873:873" # UPLOAD_API_RSYNC_PORT
environment:
- BROWSER_URL=http://chrome:9222/
- PDF_RENDER_URL=http://monitor:445
#- CCM=ccm # (optional) CCM service name
#- ES=http://elastic:9200 # (optional) ES endpoint
#- REPORT_URL=http://localhost:445/report # (optional) Report URL (use localhost or bracketed IPv6 like http://[::1]:445/report)
#- ES_USERNAME=monitor # (optional) ES user
#- ES_PASSWORD=password # (optional) ES password
#- ADVANCED_ALERTS=true # (optional) Enable Advanced Alerts
#- ADVANCED_ALERTS_URL=http://alerts:80 # (optional) Advanced Alerts URL
volumes:
- monitor-data:/data:U # Persist MONITOR data
# (optional) needed by the bundled SQLite I/O collector below, to
# attribute disk I/O to the sqlite db file itself instead of the
# whole disk. Both mounts are required on Docker too, not just
# Podman: this bpftrace version looks for tracefs at
# /sys/kernel/tracing specifically, not /sys/kernel/debug/tracing -
# mounting only /sys/kernel/debug leaves it unable to find
# kprobe_events at all, regardless of container engine.
- /sys/kernel/debug:/sys/kernel/debug:rw
- /sys/kernel/tracing:/sys/kernel/tracing:rw
networks:
- monitoring
mem_limit: 1.5G
cpus: 1.0
cap_add:
- CAP_NET_BIND_SERVICE
- CAP_SYS_ADMIN # (optional) lets the bundled SQLite I/O collector attribute disk I/O to the db file itself instead of the whole disk
security_opt:
# (optional, paired with CAP_SYS_ADMIN above) Docker's default
# seccomp profile blocks perf_event_open, which bpftrace's
# kprobes need to attach - without this, bpftrace starts but
# immediately fails with "perf_event_open: Function not
# implemented" / "ERROR: Failed to open perf buffer", confirmed on
# Docker (not just Podman, where the same profile issue exists but
# is documented separately in the Quadlet setup notes).
- seccomp:unconfined
deploy:
resources:
limits:
memory: 1.5G
cpus: "1.0"
healthcheck:
test: ["CMD-SHELL", "node -e \"fetch('http://localhost:445/').then(r=>{process.exit(r.ok?0:1)}).catch(()=>process.exit(1))\""]
interval: 15s
timeout: 5s
retries: 20
start_period: 30s
tty: true # Enable TTY
stdin_open: true # Keep STDIN open
node-exporter:
image: prom/node-exporter:v1.11.1
container_name: node-exporter
ports:
- "9100:9100"
privileged: true
command: ["--path.rootfs=/hostfs"]
restart: always
volumes:
- /:/hostfs:ro,rslave
networks:
- monitoring
profiles:
- monitoring
- serverClientPrometheus
alerts:
image: registry.frafos.net/fril/alerts:10.2
container_name: alerts
restart: always
environment:
REDIS_HOST: "redis"
elasticConfigUrl: "http://elastic:9200/"
cap_add:
- AUDIT_CONTROL
- NET_RAW
- AUDIT_WRITE
ports:
- "80:80"
networks:
- monitoring
depends_on:
elastic:
condition: service_healthy
redis:
condition: service_healthy
healthcheck:
test:
[
"CMD-SHELL",
"curl -fsS 'http://localhost:80/api/alertapi/help' || exit 1",
]
interval: 15s
timeout: 5s
retries: 20
start_period: 15s
redis:
image: registry.frafos.net/fril/redis-stack-server:latest
container_name: redis
restart: always
expose: ["6379"]
security_opt: ["no-new-privileges:true"]
cap_drop: [MKNOD, NET_RAW, AUDIT_WRITE]
networks:
- monitoring
healthcheck:
test: ["CMD", "redis-cli", "ping"]
interval: 10s
timeout: 5s
retries: 20
start_period: 10s
rq2rest:
image: registry.frafos.net/fril/rq2rest:latest
container_name: rq2rest
command:
[
"-c",
"/etc/rq2rest.ini",
"-d",
"5",
"--redis_url=redis:6379",
"--http_url=http://alerts:80/ingestion/http/00000000-0000-0000-0000-000000000000",
]
restart: always
tty: true
networks:
- monitoring
depends_on:
redis:
condition: service_healthy
alerts:
condition: service_healthy
volumes:
es-data:
es-snapshots:
monitor-data:
ccm-data:
networks:
monitoring:
driver: bridge
enable_ipv6: true
signaling:
driver: bridge
enable_ipv6: true
Podman is Docker-compatible and supports rootless containers. You can use podman-compose for multi-container setups.
Quadlet lets systemd manage Podman containers directly, without compose. To install using a Quadlet unit:
- Download the
mon.containerfile below. - Place it at
/etc/containers/systemd/mon.container(rootful) or~/.config/containers/systemd/mon.container(rootless). - Run
systemctl daemon-reload(orsystemctl --user daemon-reload), thensystemctl start mon.
The per-file SQLite I/O tracer's capability/mount block in the example is commented out by default and is opt-in only: it requires CAP_SYS_ADMIN plus an unconfined seccomp and AppArmor profile, which is close to root-equivalent on the host. The SQLite metrics collector runs fine without it, falling back to whole-disk I/O counters. See the comments in the file for why Podman needs more than just CAP_SYS_ADMIN and a /sys/kernel/debug mount here (unlike Docker) — on AppArmor-enabled hosts (Debian/Ubuntu by default), Podman's default AppArmor profile blocks tracefs access independently of seccomp, and unconfining seccomp alone leaves it failing with Permission denied.
Show example mon.container
# Example Podman Quadlet unit for the MONITOR service.
#
# Quadlet is systemd-native Podman: this file does NOT use docker-compose
# or podman-compose. Install it as (for a rootful/system-wide service):
# /etc/containers/systemd/mon.container
# then:
# systemctl daemon-reload
# systemctl start mon
#
# This covers only the `monitor` container itself - see
# docker-compose.example.yml for the full multi-service stack (CCM,
# Elasticsearch, Chrome, Alerts, Redis) if you need those too; each would
# need its own .container unit following the same pattern.
[Unit]
Description=Frafos Monitor
After=network-online.target
Wants=network-online.target
[Container]
Image=registry.frafos.net/abc/mon:10.2
ContainerName=monitor
PublishPort=445:445
# VECTOR_SYSLOG_PORT (default VECTOR_SYSLOG_TRANSPORT_PROTOCOL is UDP)
PublishPort=514:514/udp
# VECTOR_SYSLOG_PORT (when VECTOR_SYSLOG_TRANSPORT_PROTOCOL is TCP)
PublishPort=514:514/tcp
PublishPort=5044:5044
PublishPort=5045:5045
PublishPort=3042:3042
PublishPort=873:873
Environment=BROWSER_URL=http://chrome:9222/
Environment=PDF_RENDER_URL=http://monitor:445
Volume=monitor-data:/data:U
AddCapability=CAP_NET_BIND_SERVICE
# ---------------------------------------------------------------------
# (optional) Per-file SQLite I/O tracer (bpftrace) - attributes disk I/O
# to the sqlite db file itself instead of the whole disk. Commented out
# by default: needs CAP_SYS_ADMIN + unconfined seccomp/AppArmor, close to
# root-equivalent on the host. Without it, the collector still runs, just
# falling back to whole-disk I/O counters.
#
# Podman (unlike Docker) needs more than CAP_SYS_ADMIN + /sys/kernel/debug:
# - seccomp: default profile blocks perf_event_open.
# - AppArmor (on by default on Debian/Ubuntu): default profile blocks
# /sys/kernel/tracing/kprobe_events too -> "Permission denied".
# - tracefs: this bpftrace needs /sys/kernel/tracing specifically, not
# /sys/kernel/debug/tracing - mount both, or kprobes silently never
# attach and gauges report 0 forever instead of erroring.
#
# AddCapability=SYS_ADMIN
# PodmanArgs=--security-opt seccomp=unconfined
# PodmanArgs=--security-opt apparmor=unconfined
# Volume=/sys/kernel/debug:/sys/kernel/debug:rw
# Volume=/sys/kernel/tracing:/sys/kernel/tracing:rw
# ---------------------------------------------------------------------
HealthCmd=node -e "fetch('http://localhost:445/').then(r=>{process.exit(r.ok?0:1)}).catch(()=>process.exit(1))"
HealthInterval=15s
HealthTimeout=5s
HealthRetries=20
HealthStartPeriod=30s
[Service]
Restart=always
[Install]
WantedBy=multi-user.target default.target
To install using Kubernetes:
- Download the provided manifest file below.
- Make sure your manifest uses the registry image:
image: registry.frafos.net/abc/mon:<tag> - Apply the Kubernetes manifests:
kubectl apply -f manifest.example.yaml - Monitor pods and services:
kubectl get pods,kubectl get svc - Access the dashboard via the exposed service (see your cluster's configuration)
Container images are available at: Frafos Container Registry
Show example manifest (manifest.yaml)
# --------------------------
# Persistent Volume Claims
# --------------------------
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: ccm-data
spec:
accessModes: ["ReadWriteOnce"]
resources:
requests:
storage: 5Gi
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: es-data
spec:
accessModes: ["ReadWriteOnce"]
resources:
requests:
storage: 20Gi
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: es-snapshots
spec:
accessModes: ["ReadWriteOnce"]
resources:
requests:
storage: 10Gi
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: monitor-data
spec:
accessModes: ["ReadWriteOnce"]
resources:
requests:
storage: 5Gi
# --------------------------
# CCM
# --------------------------
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: ccm
spec:
replicas: 1
selector:
matchLabels:
app: ccm
template:
metadata:
labels:
app: ccm
spec:
containers:
- name: ccm
image: registry.frafos.net/abc/ccm:5.6
ports:
- containerPort: 443
- containerPort: 444
resources:
limits:
memory: "512Mi"
cpu: "500m"
requests:
memory: "256Mi"
cpu: "250m"
volumeMounts:
- name: ccm-storage
mountPath: /data
securityContext:
capabilities:
add: ["AUDIT_CONTROL", "AUDIT_WRITE"]
privileged: true
restartPolicy: Always
volumes:
- name: ccm-storage
persistentVolumeClaim:
claimName: ccm-data
---
apiVersion: v1
kind: Service
metadata:
name: ccm
spec:
selector:
app: ccm
ports:
- name: https
port: 443
targetPort: 443
- name: https2
port: 444
targetPort: 444
type: ClusterIP
# --------------------------
# Elasticsearch
# --------------------------
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: elastic
spec:
replicas: 1
selector:
matchLabels:
app: elastic
template:
metadata:
labels:
app: elastic
spec:
containers:
- name: elastic
image: docker.elastic.co/elasticsearch/elasticsearch:9.1.5
ports:
- containerPort: 9200
- containerPort: 9300
env:
- name: discovery.type
value: "single-node"
- name: network.host
value: "_local_,_site_"
- name: path.repo
value: "/usr/share/elasticsearch/snapshots"
- name: xpack.ml.enabled
value: "false"
#- name: thread_pool.search.queue_size # (optional) Increase search queue size
# value: "10000"
#- name: http.max_initial_line_length # (optional) Increase max HTTP header size
# value: "16kb"
#- name: cluster.max_shards_per_node # (optional) Increase max shards
# value: "166"
#- name: indices.lifecycle.history_index_enabled # (optional) Disable ILM history
# value: "false"
# 1. FOR PLAIN HTTP USE THE FOLLOWING VARIABLES -----
- name: xpack.security.enabled
value: "false"
- name: xpack.security.http.ssl.enabled
value: "false"
# 1.2 OR ENABLE SECURITY --- (default user = elastic) ---
#- name: xpack.security.enabled
# value: "true"
#- name: ELASTIC_PASSWORD # curl -u elastic:Test1234 http://localhost:9200/
# value: "Test1234"
# 2. FOR SSL USE THE FOLLOWING VARIABLES -------------
#- name: xpack.security.enabled
# value: "true"
#- name: xpack.security.http.ssl.enabled
# value: "true"
#- name: xpack.security.http.ssl.certificate
# value: "certs/server.crt"
#- name: xpack.security.http.ssl.key
# value: "certs/server.key"
#- name: xpack.security.transport.ssl.enabled
# value: "true"
#- name: xpack.security.transport.ssl.certificate
# value: "certs/server.crt"
#- name: xpack.security.transport.ssl.key
# value: "certs/server.key"
#- name: xpack.security.transport.ssl.verification_mode
# value: "certificate"
#- name: xpack.security.transport.ssl.certificate_authorities
# value: "certs/ca.crt"
# 2.2 --- ANONYMOUS AUTH --- (not recommended for production)
#- name: xpack.security.authc.anonymous.username
# value: "anonymous"
#- name: xpack.security.authc.anonymous.roles
# value: "superuser"
#- name: xpack.security.authc.anonymous.authz_exception
# value: "false"
# 2.3 --- OR ---
#- name: ELASTIC_PASSWORD # curl --cacert ./path/to/certs/ca.crt -u elastic:Test1234 https://localhost:9200/
# value: "Test1234"
resources:
limits:
memory: "4Gi"
cpu: "1000m"
requests:
memory: "2Gi"
cpu: "500m"
volumeMounts:
- name: es-data
mountPath: /usr/share/elasticsearch/data
- name: es-snapshots
mountPath: /usr/share/elasticsearch/snapshots
#- name: es-certs # (optional) Mount certificates for SSL
# mountPath: /usr/share/elasticsearch/config/certs
# readOnly: true
volumes:
- name: es-data
persistentVolumeClaim:
claimName: es-data
- name: es-snapshots
persistentVolumeClaim:
claimName: es-snapshots
#- name: es-certs # (optional) Secret or ConfigMap containing certs
# secret:
# secretName: es-certs
restartPolicy: Always
---
apiVersion: v1
kind: Service
metadata:
name: elastic
spec:
selector:
app: elastic
ports:
- name: http
port: 9200
targetPort: 9200
- name: transport
port: 9300
targetPort: 9300
# --------------------------
# Chrome
# --------------------------
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: chrome
spec:
replicas: 1
selector:
matchLabels:
app: chrome
template:
metadata:
labels:
app: chrome
spec:
containers:
- name: chrome
image: zenika/alpine-chrome:124
args:
- "--no-sandbox"
- "--remote-debugging-address=::"
- "--remote-debugging-port=9222"
ports:
- containerPort: 9222
resources:
limits:
memory: "512Mi"
cpu: "500m"
requests:
memory: "128Mi"
cpu: "100m"
restartPolicy: Always
---
apiVersion: v1
kind: Service
metadata:
name: chrome
spec:
selector:
app: chrome
ports:
- name: debug
port: 9222
targetPort: 9222
# --------------------------
# MONITOR
# --------------------------
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: monitor
spec:
replicas: 1
selector:
matchLabels:
app: monitor
template:
metadata:
labels:
app: monitor
spec:
containers:
- name: monitor
image: registry.frafos.net/abc/mon:10.2
securityContext:
capabilities:
add: ["NET_BIND_SERVICE", "SYS_ADMIN"] # SYS_ADMIN is (optional) - lets the bundled SQLite I/O collector attribute disk I/O to the db file itself instead of the whole disk
ports:
- containerPort: 445
- containerPort: 514
- containerPort: 5045
- containerPort: 5044
- containerPort: 3042
- containerPort: 873
env:
- name: BROWSER_URL
value: "http://chrome:9222/"
- name: PDF_RENDER_URL
value: "http://monitor:445"
- name: SERVER_PORT
value: "445"
volumeMounts:
- name: monitor-storage
mountPath: /data
- name: debugfs # (optional) needed by the bundled SQLite I/O collector above
mountPath: /sys/kernel/debug
tty: true
stdin: true
resources:
limits:
memory: "1.5Gi"
cpu: "1"
requests:
memory: "250Mi"
cpu: "250m"
readinessProbe:
exec:
command:
- node
- -e
- "fetch('http://localhost:445/').then(r=>{process.exit(r.ok?0:1)}).catch(()=>process.exit(1))"
initialDelaySeconds: 30
periodSeconds: 15
timeoutSeconds: 5
failureThreshold: 20
livenessProbe:
exec:
command:
- node
- -e
- "fetch('http://localhost:445/').then(r=>{process.exit(r.ok?0:1)}).catch(()=>process.exit(1))"
initialDelaySeconds: 30
periodSeconds: 15
timeoutSeconds: 5
failureThreshold: 20
restartPolicy: Always
volumes:
- name: monitor-storage
persistentVolumeClaim:
claimName: monitor-data
- name: debugfs # (optional) needed by the bundled SQLite I/O collector
hostPath:
path: /sys/kernel/debug
type: Directory
---
apiVersion: v1
kind: Service
metadata:
name: monitor
spec:
selector:
app: monitor
ports:
- name: server
port: 445
targetPort: 445
- name: vector-syslog-port
port: 514
targetPort: 514
- name: vector-socket-port
port: 5044
targetPort: 5044
- name: vector-socket-tls-port
port: 5045
targetPort: 5045
- name: upload-api
port: 3042
targetPort: 3042
- name: upload-rsync
port: 873
targetPort: 873
# --------------------------
# Redis
# --------------------------
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: redis
spec:
replicas: 1
selector:
matchLabels:
app: redis
template:
metadata:
labels:
app: redis
spec:
containers:
- name: redis
image: registry.frafos.net/fril/redis-stack-server:latest
ports:
- containerPort: 6379
securityContext:
capabilities:
drop: ["MKNOD", "NET_RAW", "AUDIT_WRITE"]
livenessProbe:
exec:
command: ["redis-cli", "ping"]
initialDelaySeconds: 10
periodSeconds: 10
timeoutSeconds: 5
failureThreshold: 3
resources:
limits:
memory: "1Gi"
cpu: "500m"
requests:
memory: "512Mi"
cpu: "250m"
restartPolicy: Always
---
apiVersion: v1
kind: Service
metadata:
name: redis
spec:
selector:
app: redis
ports:
- name: redis
port: 6379
targetPort: 6379
# --------------------------
# Alerts
# --------------------------
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: alerts
spec:
replicas: 1
selector:
matchLabels:
app: alerts
template:
metadata:
labels:
app: alerts
spec:
containers:
- name: alerts
image: registry.frafos.net/fril/alerts:10.2
ports:
- containerPort: 80
env:
- name: REDIS_HOST
value: "redis"
- name: elasticConfigUrl
value: "http://elastic:9200/"
securityContext:
capabilities:
add: ["AUDIT_CONTROL", "NET_RAW", "AUDIT_WRITE"]
readinessProbe:
httpGet:
path: /api/alertapi/help
port: 80
initialDelaySeconds: 15
periodSeconds: 15
timeoutSeconds: 5
failureThreshold: 20
resources:
limits:
memory: "1Gi"
cpu: "500m"
requests:
memory: "512Mi"
cpu: "250m"
restartPolicy: Always
---
apiVersion: v1
kind: Service
metadata:
name: alerts
spec:
selector:
app: alerts
ports:
- name: http
port: 80
targetPort: 80
# --------------------------
# rq2rest
# --------------------------
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: rq2rest
spec:
replicas: 1
selector:
matchLabels:
app: rq2rest
template:
metadata:
labels:
app: rq2rest
spec:
containers:
- name: rq2rest
image: registry.frafos.net/fril/rq2rest:latest
command:
- "/bin/sh"
- "-c"
- >
rq2rest -c /etc/rq2rest.ini -d 5
--redis_url=redis:6379
--http_url=http://alerts:80/ingestion/http/00000000-0000-0000-0000-000000000000
tty: true
resources:
limits:
memory: "1Gi"
cpu: "500m"
requests:
memory: "512Mi"
cpu: "250m"
restartPolicy: Always
---
apiVersion: v1
kind: Service
metadata:
name: rq2rest
spec:
selector:
app: rq2rest
ports:
- name: rq
port: 8080
targetPort: 8080
# --------------------------
# Node Exporter
# --------------------------
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: node-exporter
spec:
replicas: 1
selector:
matchLabels:
app: node-exporter
template:
metadata:
labels:
app: node-exporter
spec:
hostNetwork: true
hostPID: true
containers:
- name: node-exporter
image: prom/node-exporter:v1.11.1
args: ["--path.rootfs=/hostfs"]
ports:
- containerPort: 9100
securityContext:
privileged: true
volumeMounts:
- name: hostfs
mountPath: /hostfs
readOnly: true
mountPropagation: "HostToContainer"
resources:
limits:
memory: "64Mi"
cpu: "100m"
requests:
memory: "16Mi"
cpu: "50m"
restartPolicy: Always
volumes:
- name: hostfs
hostPath:
path: /
Kubernetes setup is ideal for scalable, resilient, and production-grade deployments.
Chrome Service
The Chrome service provides headless browser capabilities for generating PDF reports in Auto Trigger. It is pre-configured and starts automatically with the stack.
Configuration:
| Variable | Default | Description |
|---|---|---|
BROWSER_URL | http://chrome:9222/ | Connection URL for Chrome service |
PDF_RENDER_URL | http://monitor:5000 | URL Chrome uses to render reports |
Update PDF_RENDER_URL if your monitor service uses a different name or port.
Troubleshooting:
# Verify Chrome is running and healthy
docker ps | grep chrome
# View logs
docker logs chrome
If Chrome crashes frequently, increase shared memory:
chrome:
shm_size: '2gb'
shm_size is not required when using zenika/alpine-chrome — the image already uses --disable-dev-shm-usage by default, which bypasses Docker's 64MB shared memory limit.