|
| 1 | +# Production Hardening |
| 2 | + |
| 3 | +This checklist keeps the public Docker Compose files safe to publish while |
| 4 | +covering the failure mode observed on the Numbers mainnet explorer: long-running |
| 5 | +containers consumed nearly all VM memory, then the VM kept receiving packets but |
| 6 | +stopped returning responses. |
| 7 | + |
| 8 | +## Resource Guards |
| 9 | + |
| 10 | +The compose service files define non-secret defaults that can be overridden by |
| 11 | +the production environment: |
| 12 | + |
| 13 | +```sh |
| 14 | +BACKEND_MEM_LIMIT=4g |
| 15 | +BACKEND_MEMSWAP_LIMIT=4g |
| 16 | +DB_MEM_LIMIT=6g |
| 17 | +DB_MEMSWAP_LIMIT=6g |
| 18 | +STATS_MEM_LIMIT=1g |
| 19 | +STATS_MEMSWAP_LIMIT=1g |
| 20 | +STATS_DB_MEM_LIMIT=1g |
| 21 | +STATS_DB_MEMSWAP_LIMIT=1g |
| 22 | +REDIS_MEM_LIMIT=512m |
| 23 | +REDIS_MEMSWAP_LIMIT=512m |
| 24 | +``` |
| 25 | + |
| 26 | +Keep total container limits below host memory so the OS, nginx, Docker, and the |
| 27 | +monitoring agent have headroom. On a 16 GiB VM, reserve at least 3 GiB for the |
| 28 | +host. |
| 29 | + |
| 30 | +## Health Checks |
| 31 | + |
| 32 | +The backend container now exposes a Docker healthcheck against: |
| 33 | + |
| 34 | +```text |
| 35 | +http://localhost:$${PORT:-4000}/api/v2/main-page/indexing-status |
| 36 | +``` |
| 37 | + |
| 38 | +Production monitoring should also check the public endpoint: |
| 39 | + |
| 40 | +```sh |
| 41 | +curl -fsS --max-time 10 \ |
| 42 | + https://mainnet.num.network/api/v2/main-page/indexing-status |
| 43 | +``` |
| 44 | + |
| 45 | +Alert if this endpoint is non-200 or exceeds the expected latency for multiple |
| 46 | +consecutive checks. |
| 47 | + |
| 48 | +## Log Rotation |
| 49 | + |
| 50 | +Docker `json-file` log rotation is enabled for the high-volume services. The |
| 51 | +defaults are intentionally conservative and can be adjusted without changing the |
| 52 | +compose files: |
| 53 | + |
| 54 | +```sh |
| 55 | +BACKEND_LOG_MAX_SIZE=50m |
| 56 | +BACKEND_LOG_MAX_FILE=5 |
| 57 | +DB_LOG_MAX_SIZE=50m |
| 58 | +DB_LOG_MAX_FILE=5 |
| 59 | +STATS_LOG_MAX_SIZE=50m |
| 60 | +STATS_LOG_MAX_FILE=5 |
| 61 | +STATS_DB_LOG_MAX_SIZE=25m |
| 62 | +STATS_DB_LOG_MAX_FILE=5 |
| 63 | +REDIS_LOG_MAX_SIZE=25m |
| 64 | +REDIS_LOG_MAX_FILE=5 |
| 65 | +``` |
| 66 | + |
| 67 | +## Monitoring |
| 68 | + |
| 69 | +Required production alerts: |
| 70 | + |
| 71 | +- VM memory used > 85% for 10 minutes. |
| 72 | +- VM outbound bytes = 0 while inbound bytes > 0 for 5 minutes. |
| 73 | +- Public explorer health endpoint returns non-200 for 3 consecutive checks. |
| 74 | +- Docker container health is `unhealthy` for backend. |
| 75 | + |
| 76 | +Enable process-level memory metrics on the VM. Without process RSS history, an |
| 77 | +incident can prove memory exhaustion but cannot identify which process caused it. |
| 78 | +Do not exclude these Ops Agent metrics in production: |
| 79 | + |
| 80 | +```yaml |
| 81 | +agent.googleapis.com/processes/* |
| 82 | +agent.googleapis.com/swap/* |
| 83 | +``` |
0 commit comments