11  How to interact with the Virtual Machine (VM) that hosts PIP

Abstract
This guide explains how to connect to, inspect, and maintain the Linux Virtual Machines (VMs) hosting the PIP (Poverty & Inequality Platform) APIs. It covers user access, Docker container management, data storage, debugging, and safe cleanup procedures. This document is written for users with limited Linux/Docker experience who need to operate, inspect, or troubleshoot the PIP infrastructure safely.

11.1 Access and Session Management

11.1.1 Login to the VM

  1. Go to PrivX.

  2. Use SSO login (World Bank Authenticator App).

  3. In the Connections tab, select the VM you want:

    • Development: Linux-wzlxdpip01.worldbank.org
    • QA: Linux-wzlxqpip01.worldbank.org
    • Production: Linux-wzlxppip01.worldbank.org
  4. Once connected, switch to the srvpip user:

    sudo su - srvpip

11.1.2 Copy, Paste, and Keyboard Shortcuts

Shortcut Action Notes
Ctrl + C Stop the current running process e.g. stop an infinite loop or hanging R process
Ctrl + D Log out of the current shell Ends your session as srvpip
Shift + Ctrl + V Paste from clipboard Works in most PrivX terminals
Shift + Insert Paste (alternative) Often easier in remote shells

Notice that Ctrl + C does not copy text in terminal. You only need to highlight with your mouse the section you want to copy. Once you stopped highlighting, the text is copied to your clipboard automatically.


11.2 Understanding the Environment

11.2.1 Users and Permissions

  • Your account: initial login via PrivX (not root)
  • srvpip user: used to manage Docker containers
  • root user: required for system-level commands; use only with sudo

Common prefixes:

  • docker → run Docker as normal user (often fails without permissions)
  • sudo docker → correct way when managing containers
  • sudo su - srvpip → switch to service account context

11.2.2 Architecture Overview

+-------------------------------------------------------------+
|                      Linux VM (Host)                        |
|                                                             |
|  Persistent Data:                                           |
|    /Data/pip/files/data   <---+                             |
|                               | (bind mount)                |
|                               v                             |
|  ---------------------------------------------------------  |
|  |               Docker Container: povertyscoreapi       |  |
|  |                                                     |  |
|  |   - Mounts /Data/pip/files/data → /Data             |  |
|  |   - Runs: Rscript /app/main.R                       |  |
|  |   - Listens on port 8080 (internal)                 |  |
|  ---------------------------------------------------------  |
|                               ^                             |
|                               |                             |
|  Host Port 80  <--------------+  (mapped to container 8080) |
+-------------------------------------------------------------+

Legend: - Data written to /Data inside the container is actually stored on the host at /Data/pip/files/data. - The API runs inside the container on port 8080, but is accessible from outside the VM on port 80.


11.3 Essential Docker Commands (Cheat Sheet)

Task Command Notes
List all containers sudo docker ps -a Shows running & stopped
View logs sudo docker logs -f povertyscoreapi Add --tail 200 to see last lines
Enter container shell sudo docker exec -it povertyscoreapi /bin/bash For interactive debugging
Check mounted volumes sudo docker inspect povertyscoreapi | grep Mounts -A 5 See /Data source
Delete stopped containers sudo docker container prune Cleans unused ones
Delete old images sudo docker image prune -a Be cautious — removes all unused
Check Docker service status sudo systemctl status docker Confirms Docker is active

11.4 Managing Data

11.4.1 Data on the VM (Persistent)

  • Main data location:

    cd /Data/pip/files/data
  • Inspect space usage:

    df -h | grep Data
    du -h --max-depth=1 | sort -h
  • Preview files safely:

    ls -lah
  • View folder sizes:

    du -sh *

11.4.1.1 🔍 Find large or old files

find /Data/pip/files/data -type f -mtime +365 | head -n 20

11.4.2 Data Inside Containers (Ephemeral)

Check where containers mount volumes:

sudo docker inspect povertyscoreapi | grep Mounts -A 5

You’ll see:

"Mounts": [
  {
    "Type": "bind",
    "Source": "/Data/pip/files/data",
    "Destination": "/Data"
  }
]

That means:

  • Inside container → /Data
  • On host → /Data/pip/files/data

11.4.2.1 Access via container shell:

sudo docker exec -it povertyscoreapi ls -lh /Data

11.4.3 Safe Deletion and Cleanup

Preview first:

ls -d /Data/pip/files/data/project_*

Delete specific folders:

rm -rf /Data/pip/files/data/folder1 /Data/pip/files/data/folder2

Delete all contents but keep parent folder:

rm -rf /Data/pip/files/data/*

Move to trash instead of deleting:

mkdir -p /Data/pip/files/trash
mv /Data/pip/files/data/folder1 /Data/pip/files/trash/

⚠️ Caution: rm -rf is irreversible — always check with ls first.


11.5 Diagnosing API or Container Issues

11.5.1 Check Container State

sudo docker ps -a

Get detailed exit info:

sudo docker inspect povertyscoreapi --format='ExitCode={{.State.ExitCode}} OOMKilled={{.State.OOMKilled}}'
  • ExitCode=0 → normal exit
  • ExitCode=137 → killed (likely out of memory)

11.5.2 View Logs

sudo docker logs povertyscoreapi | head -n 20   # startup logs
sudo docker logs --tail 200 povertyscoreapi     # recent logs

11.5.3 Reproduce Interactively

Start an interactive debug session:

sudo docker run --rm -it \
  --name povertyscoreapi-debug \
  -p 8080 \
  -v /Data/pip/files/data:/Data \
  itsesippscoreregistryprod.azurecr.io/povertyscoreapi:latest \
  /bin/bash

Inside:

Rscript /app/main.R

Press Ctrl + C to stop and exit to leave.


11.5.4 Restart or Rebuild Containers

sudo docker restart povertyscoreapi

Or rebuild completely:

sudo docker stop povertyscoreapi
sudo docker rm povertyscoreapi
sudo docker pull itsesippscoreregistryprod.azurecr.io/povertyscoreapi:latest
sudo docker run -d --name povertyscoreapi \
  -p 80:8080 \
  -v /Data/pip/files/data:/Data \
  itsesippscoreregistryprod.azurecr.io/povertyscoreapi:latest

11.6 Testing API Endpoints

11.6.1 From Inside the Container

curl http://localhost:80/api/v1/health-check

11.6.2 Loop through common endpoints

for ep in health-check pkgs-version data-signature gh-hash; do
  echo "---- Testing $ep ----"
  curl -s http://localhost:80/api/v1/$ep
  echo
done

11.6.3 From Outside (VM host or browser)

curl http://wzlxdpip01.worldbank.org/api/v1/health-check

11.7 Troubleshooting Common Errors

Symptom Likely Cause Fix
curl: (7) Failed connect Container not running or wrong port sudo docker ps -a
Exited (137) Out of memory (OOMKilled) Increase VM memory or limit API load
authentication required Not logged in to Azure Container Registry sudo az acr login --name itsesippscoreregistryprod
permission denied on /Data Wrong user ownership sudo chown -R srvpip /Data
No logs shown Container failed before startup Run sudo docker inspect povertyscoreapi
Port 8080 works but 80 doesn’t Port not mapped Run container with -p 80:8080

11.8 Understanding Ports (80 vs 8080)

  • Inside Docker, the API runs on 8080:

    pipapi::start_api(port = 8080, host = "0.0.0.0")
  • Outside Docker (host or browser), you can map any port using:

    -p 80:8080

    This means:

    host_port:container_port

    So users access:

    http://wzlxdpip01.worldbank.org/api/v1/...

    even though internally it listens on 8080.


11.9 Monitoring Resource Usage

Watch real-time CPU and memory:

sudo docker stats povertyscoreapi

Or globally:

top -u srvpip

11.10 Appendix

11.10.1 Check Disk Usage Quickly

df -h | grep Data

11.10.2 Check Docker Service Logs

sudo journalctl -u docker --since "2025-09-23 17:00"

11.10.3 Check R version inside container

sudo docker exec -it povertyscoreapi Rscript -e "R.version.string"