🛠️ Lab 1 — Systemd-Managed GPU Inference Process on a Free-Tier Cloud VM (50 pts)

Goal: Stand up a free-tier cloud Linux server, wrap a long-running Python process in a systemd unit file so it survives crashes and reboots, cap its resource usage with systemd/cgroups, and monitor GPU (or simulated GPU) state throughout — using only free and local tools. Steps:

  1. Provision a free-tier VM. Sign up for either the Oracle Cloud "Always Free" tier (an Ampere A1 ARM VM) or a 12-month AWS/GCP free-tier instance. Launch an Ubuntu 22.04 or 24.04 LTS instance and SSH in as a regular (non-root) user.
  2. Confirm your baseline. Run lsb_release -a to confirm your Ubuntu version, df -h to check available disk space, and free -h to check available memory and swap. Record the output.
  3. (If you have GPU access) Install the NVIDIA driver following the Ubuntu Server 24.04 LTS + NVIDIA driver guide, then run nvidia-smi to confirm it reports GPU state. If your free-tier instance has no GPU (most Always Free tiers do not), install gpustat (pip install gpustat) anyway and simulate this step by documenting what output you would expect to see, referencing the CUDA Installation Guide for context on driver/CUDA version pairing.
  4. Write a simulated model-serving script. Create a small Python script (/opt/inference/server.py) that runs an infinite loop — e.g., sleeping and printing a heartbeat log line every few seconds — to stand in for a real inference server process.
  5. Write a systemd unit file. Create /etc/systemd/system/inference.service with [Unit], [Service], and [Install] sections. Set ExecStart= to the full absolute path of your Python interpreter and script (do not rely on PATH). Set Restart=on-failure. Do not mark the unit file executable — leave its permissions as standard config (typically 644).
  6. Cap resources with cgroups via systemd. Add CPUQuota= and MemoryMax= directives under [Service] to simulate capping a model-serving process to a fraction of the VM's CPU and memory (e.g., CPUQuota=50%, MemoryMax=512M).
  7. Enable and test. Run sudo systemctl daemon-reload, then sudo systemctl enable --now inference.service. Confirm it's running with systemctl status inference.service. Kill the process manually (sudo pkill -f server.py) and confirm systemd restarts it automatically.
  8. Monitor. Use systemctl status, journalctl -u inference.service, and (if available) nvidia-smi / gpustat to observe the service's state over a few minutes. Take screenshots of each.
  9. Tune swap (optional but recommended). Check current swap with swapon --show; if none exists, create a 1–2GB swapfile and enable it, documenting the commands used.
  10. Write up your results. In a short document, include: your unit file contents, command output from steps 2, 7, and 8, and 2–3 sentences reflecting on what would have gone wrong if you had skipped the absolute-path fix in Step 5 (tie this back to the PATH misconception from the lecture).

Deliverables: Submit your inference.service unit file, terminal/screenshot evidence of the service running and auto-restarting, your swap configuration notes, and your written reflection (upload as a PDF or text file, or paste directly into the submission text box).