[Unit] Description={{.DisplayName}} Scanner (Vulnerability Scanning) After=network-online.target {{.HoldServiceName}}.service Wants=network-online.target [Service] Type=simple User={{.User}} Group={{.User}} ExecStart={{.BinaryPath}} serve --config {{.ConfigPath}} Restart=on-failure RestartSec=10 # Memory containment. The scanner sets a 512 MiB Go soft limit itself # (GOMEMLIMIT, see cmd/scanner/main.go), but that is soft: the runtime # collects harder to respect it and never fails an allocation to honour it, so # a large enough image walks straight through it. Without a cgroup cap the # kernel OOM killer chooses its own victim, and on a shared host the other # large process is the hold, meaning the scanner's overshoot kills the service # it reports to. These make the scanner the one that dies. # # MemoryHigh throttles and reclaims; MemoryMax kills. Sized from measurement: # one scan of a node:22-class image peaks at 561 MiB RSS with the Go limit in # force, so MemoryHigh sits above that and MemoryMax leaves headroom for the # hold and the OS on a 1 GiB host. Raise both together with scanner.workers. MemoryHigh=640M MemoryMax=768M # Scheduling priority. The scanner is the lowest-value process on a shared # host: a scan finishing a minute later costs nothing, a hold that cannot # answer a pull costs a user. Syft's extraction saturates CPU and writes # several times the compressed image size to disk, so left at the default # weight it competes evenly with the services that matter. # # Weights apply only under contention: the scanner still uses the whole box # when nothing else wants it, which is what makes this better than the fixed # inter-job sleep in worker.go (that yields on a timer whether or not anyone # needs the CPU, and yields nothing while a scan is actually running). # Everything else runs at the default weight of 100. # # IOWeight needs the io controller with a scheduler that honours it (BFQ, or # io.cost configured); where it is unsupported systemd ignores it silently and # CPUWeight still applies. CPUWeight=20 IOWeight=20 ReadWritePaths={{.DataDir}} ProtectSystem=strict ProtectHome=yes NoNewPrivileges=yes PrivateTmp=yes StandardOutput=journal StandardError=journal SyslogIdentifier={{.ServiceName}} [Install] WantedBy=multi-user.target