Redbull namespace on 84.8.102.119: forensic report
1. Question
On Nov 9 the redbull Helm install failed: pods stayed Pending with "insufficient memory / cpu". On Nov 10 redbull is running on the same VM. What changed?
2. The machine did not change
- Last reboot: Wed Nov 4 14:57. Resizing an OCI VM shape needs a reboot, so nothing was resized between Nov 9 and Nov 10.
- Node capacity: 8 CPU / ~17.1 GiB RAM, no swap. The hostname still says "4ocpu-12ram" because it was resized before Nov 4.
- The same six app namespaces exist: cyber-mode-v4, cyber-mode, ndf, cybermode-v5, raya, redbull. cyber-mode, cyber-mode-v4, ndf and cybermode-v5 still have their full default sizing.
3. Helm history: what was changed and when
redbull
| Rev | Time (UTC) | Result | back | svc pods | mongodb |
|---|---|---|---|---|---|
| 1 | Nov 9 12:13 | failed (timeout) | 500m / 768Mi | 100–250m / 256–512Mi | 250m / 512Mi |
| 2 | Nov 10 14:37 | failed | 100m / 200Mi | 100m / 200Mi | 250m / 512Mi |
| 3 | Nov 10 14:57 | ok | 10m / 20Mi | 10m / 20Mi | 250m / 512Mi |
| 4 | Nov 10 15:00 | ok | 10m / 20Mi, L 512Mi | 10m / 20Mi, L 512Mi | 250m / 512Mi |
| 5–6 | Nov 10 15:02–15:03 | ok | same | same | 250m / 250Mi, L 1Gi |
| 7 | Nov 10 15:04 | ok | same | same | 250m / 100Mi, L 1Gi |
| 8 | Nov 10 15:14 | deployed | same | same | same + image pull secret enabled |
frontend (50m/64Mi) and redis (50m/128Mi) were never changed. Seven upgrades in 37 minutes, stepping requests down until the scheduler accepted the pods.
raya (another client)
| Rev | Time (UTC) | back | mongodb |
|---|---|---|---|
| 1–2 | Nov 5 | 500m / 768Mi, L 1536Mi | 250m / 512Mi, L 1536Mi |
| 3 | Nov 10 15:08 | 500m / 768Mi, L 1024Mi | 250m / 250Mi, L 1024Mi |
| 4 | Nov 10 15:10 | 250m / 768Mi, L 1024Mi | 250m / 250Mi, L 1024Mi |
raya's back and mongodb pods restarted at about 15:10 as a result.
4. Who and how
SSH key used
The SSH log (journalctl -u sshd) shows the sessions that made the changes logged in with key
SHA256:hc4I1eapt0GUsS3vwwFMp4MXmV8Enkr9lKIeuK8n5rY, which is this entry in /home/opc/.ssh/authorized_keys:
256 SHA256:hc4I1eapt0GUsS3vwwFMp4MXmV8Enkr9lKIeuK8n5rY m.saleh@pksaudi.com (ED25519)
| Login | From IP | Note |
|---|---|---|
| Nov 9 14:02 | 156.216.125.103 | ~2 h after the failed rev 1 |
| Nov 10 09:02 | 156.213.42.88 | |
| Nov 10 14:27 | 156.213.97.123 | session that made the changes (until 15:22) |
| Nov 10 14:37 | 156.213.97.123 | second terminal, same window |
The IP changes (probably a home or mobile connection), but the key stays the same. Other logins in the window: key ahmedelshenawy@pksaudi.com once at Nov 10 13:00 for 9 seconds; key adnan@gmail.com from our own VM 159.69.185.31.
Files and commands
/home/opc/redbull/profile-testing.yamlcreated 15:04 ·/home/opc/raya/profile-testing.yaml15:10/home/opc/redbull/custom-values.yaml15:15: only domain, URL and email edits compared with the raya-based backupmongodump.zip+mongo-restore.shcopied into~/redbullas root at 15:18, thenbash mongo-restore.shran (seeded the redbull DB)
/home/opc/.bash_history shows the loop:
vim profile-testing.yaml helm upgrade --install redbull ./cybermode -n redbull -f custom-values.yaml -f profile-testing.yaml (repeated several times, then the same for raya)
The override file's own header says:
TESTING resource profile (VMs / POCs / Demos) ... ~20 concurrent users ... NOT for production ... a heavy Excel/PDF export can ... OOM-restart the pod. Acceptable for functional testing; do NOT use this profile under real load.
In the redbull copy, requests were edited even lower (10m / 20Mi) than the totals the file states.
5. The math: why Nov 9 failed and Nov 10 fits
| CPU reserved | Memory reserved | |
|---|---|---|
| Everything except redbull (raya at original size) | 7,620m | 17,286Mi |
| + redbull original (rev 1) | +1,500m | +3,008Mi |
| Needed on Nov 9 | 9,120m | 20,294Mi |
| Everything except redbull (raya trimmed: −250m, −262Mi) | 7,370m | 17,024Mi |
| + redbull trimmed (rev 8) | +400m | +392Mi |
| Reserved now | 7,770m (97%) | 17,416Mi (99%) |
Trimming raya alone would not have been enough. Cutting redbull did most of the work (−1,100m CPU, −2,616Mi memory).
Reserved vs real usage (kubectl top, 16:42)
| redbull pod | Reserved | Actually using | Ratio |
|---|---|---|---|
| back | 20Mi | 158Mi | 7.9× |
| user-service | 20Mi | 122Mi | 6.1× |
| notification | 20Mi | 102Mi | 5.1× |
| regulator | 20Mi | 102Mi | 5.1× |
| reverb | 20Mi | 36Mi | 1.8× |
| mongodb | 100Mi | 185Mi | 1.9× |
Whole node: 10,896Mi used of ~17.1GiB (62%), ~5GiB available, CPU 4%. The memory limits of all pods add up to 46,250Mi = 264% of RAM.
6. Risk of the resizing done to run redbull
- The scheduler now has a false picture. It believes the six redbull app pods need 392Mi in total, but they use ~700Mi idle. Kubernetes uses requests to decide what fits, so the node looks 99% full on paper while the real margin depends on luck.
- Nothing else can be scheduled. Any new pod, any Helm upgrade that raises requests, or any extra pod (a job, a debug pod, a second replica) will go Pending. Changing raya or redbull back to normal sizing will also fail.
- Redbull is first in line to be killed. When memory runs low, the kubelet evicts pods whose usage is furthest above their request. Redbull pods use 5–8× their request, so they are evicted first. When memory runs out faster than eviction, the Linux OOM killer can hit any of the 66 pods, including other clients.
- Limits are overcommitted 264%, with no swap. Every pod is allowed to grow past its reservation. If several tenants grow at once (exports, imports, backups), the sum can pass 17GiB and the kernel starts killing processes across all six namespaces.
- Redbull back is capped at 512Mi with 4 PHP workers. PHP's
memory_limitis 1024M per worker. One heavy Excel/PDF export, or four busy workers at ~120Mi each, can exceed 512Mi and OOM-restart the pod. The other 4.1.3 tenants have 1536Mi. - Redbull MongoDB reserves 100Mi (limit 1Gi, WiredTiger cache ~256Mi). It's fine for a demo, but slow and OOM-prone with real data.
- Another client's environment was changed. raya's back CPU and mongodb memory/limits were lowered and its pods restarted. raya is now smaller than the other 4.1.3 tenants, and the server shows no separate record of approval.
- It is a testing profile. The file says it is not for production. If redbull is a real client environment, it is running on testing-grade sizing.
7. Why live notifications on redbull may not work
The frontend setting that tells the browser where to open the live-notification WebSocket has a typo, and it has been there since rev 1 (Nov 9):
VUE_APP_NOTIFICATION_REVERB_HOST: "cyber-rebull.advancedcontrols.tech" <- missing "d" expected: "cyber-redbull.advancedcontrols.tech"
How live notifications work: the browser opens a WebSocket wss://<REVERB_HOST>:443/app/<key> to the reverb pod and waits for pushed events. With the wrong host, the browser connects to cyber-rebull..., and one of these happens:
- No DNS record exists for that name, so the connection fails immediately.
- A wildcard DNS record sends it to a server, but the TLS certificate is for
cyber-redbull..., so the browser rejects the connection (certificate name mismatch). - Even with a valid TLS connection, the ingress has no rule for
cyber-rebull..., so it returns 404 from the default backend instead of reaching reverb.
The rest of the app works because API calls use the correct cyber-redbull... URLs. Users see pages and data, but bell notifications and real-time updates don't arrive until the page is refreshed. The browser console shows repeated WebSocket connection errors.
The backend side (REVERB_HOST, REVERB_ALLOWED_ORIGINS, notification → reverb) uses the correct name, so the typo in the frontend value is the only suspect found.
8. How many users each deployment can handle
How to read it: each PHP service handles one request per worker at a time (phpFpm.maxChildren). Every click in the app sends requests to back and to user-service, which checks auth for every request. With 4 back workers, 4 user-service workers and ~0.3 s per request, one tenant serves ~10–13 requests per second. An active user sends a few requests every few seconds, so that comes to roughly 20–30 users working at the same time before requests start queueing. Logged-in but idle users cost almost nothing.
| Namespace | Version | back workers / mem limit | Concurrent active users (est.) | What breaks first |
|---|---|---|---|---|
| cyber-mode | 4.1.3 | 4 / 1536Mi | ~20–30 | request queueing (slow pages) |
| cyber-mode-v4 | 4.1.3 | 4 / 1536Mi | ~20–30 | request queueing |
| ndf | 4.1.3 | 4 / 1536Mi | ~20–30 | request queueing |
| raya | 4.1.3 | 4 / 1024Mi (trimmed) | ~20 | back OOM on a heavy export |
| redbull | 4.1.3 | 4 / 512Mi (testing) | ~10–20 | back OOM-restart; first to be evicted |
| cybermode-v5 | 5.0.0 | microservices, 1Gi limits | ~20–30 (least certain) | unknown: worker counts not in values |
Across the whole VM, the binding limit is RAM, not CPU (CPU is at 4%). There is ~5GiB of real headroom. A busy tenant grows by roughly 0.5–1.5GiB (PHP workers up to their limits, MongoDB cache warming). So the VM can absorb about 2–4 tenants being busy at the same time, not all six. Past that, the kernel starts killing pods.
9. If every deployment gets one user at the same time
Expected result: everything keeps working. One user per tenant is light load.
- Each tenant wakes 1–2 PHP workers in back, user-service and regulator/notification, and MongoDB loads that user's data into cache. Estimated growth: ~100–300Mi per tenant, so ~0.6–1.8GiB in total.
- Node memory goes from ~10.9GiB to roughly 11.5–12.7GiB of 17.1GiB, still with several GiB free. CPU stays low.
- No new pods are created, so the 99% reservation doesn't matter here. Existing pods simply use more of the memory they are already allowed to use.
Where one user per tenant can still go wrong:
- If several of those single users start a heavy action at the same moment (Excel/PDF export, regulator framework import, big report), each PHP worker can take up to 1GiB. Four or five of these together use up the ~5GiB headroom. Redbull back (512Mi limit) is the most likely to OOM-restart, even when it's the only heavy job on the box.
- A redbull or raya user might see live notifications fail (redbull, section 7) or short 502 errors while a pod restarts after OOM.
- If the node runs low on memory for another reason at that moment (a MongoDB backup, image pulls, page cache pressure), redbull pods get evicted first because their reservations are far below real use.
10. What to tell your manager
11. How to reproduce these findings
ssh -i ~/.ssh/id_ed25519_mf opc@84.8.102.119 sudo /usr/local/bin/helm history redbull -n redbull sudo /usr/local/bin/helm get values redbull -n redbull --revision 1 # vs --revision 8 sudo /usr/local/bin/helm history raya -n raya sudo /usr/local/bin/k3s kubectl describe node | sed -n '/Allocated/,/Events/p' sudo /usr/local/bin/k3s kubectl top pod -n redbull last -F | head ; last -x reboot | head -2 sudo journalctl -u sshd --since 2026-11-09 | grep Accepted ssh-keygen -lf /home/opc/.ssh/authorized_keys cat ~/redbull/profile-testing.yaml ; tail -90 ~/.bash_history