#cloud-config # WebArena Map Backend Server Boot-Init Script # Based on successful deployment from trajectory analysis # This script sets up tile server, geocoding server, and routing servers package_update: true package_upgrade: false package_reboot_if_required: false # Configure APT with retry logic and better error handling apt: conf: | APT::Acquire::Retries "3"; APT::Acquire::http::Timeout "30"; APT::Acquire::https::Timeout "30"; Dpkg::Options { "--force-confdef"; "--force-confold"; }; packages: - docker.io - curl - wget - htop - unzip # Create swap file to handle memory-intensive operations bootcmd: - | # Create 4GB swap file to handle large data extractions (reduced from 8GB to save space) if [ ! -f /swapfile ]; then fallocate -l 4G /swapfile chmod 600 /swapfile mkswap /swapfile swapon /swapfile echo '/swapfile none swap sw 0 0' >> /etc/fstab fi runcmd: # Wait for package locks to be released - while fuser /var/lib/dpkg/lock-frontend >/dev/null 2>&1; do echo "Waiting for dpkg lock..."; sleep 5; done - while fuser /var/lib/apt/lists/lock >/dev/null 2>&1; do echo "Waiting for apt lock..."; sleep 5; done # Enable and start Docker with retries - systemctl enable docker - systemctl start docker - sleep 10 # Add ubuntu user to docker group - usermod -aG docker ubuntu # Create necessary directories - mkdir -p /opt/osm_dump /opt/osrm /var/lib/docker/volumes - mkdir -p /root/logs # Install AWS CLI v2 (awscli package not available in Ubuntu 24.04) - curl "https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip" -o /tmp/awscliv2.zip - unzip /tmp/awscliv2.zip -d /tmp/ - /tmp/aws/install - rm -rf /tmp/awscliv2.zip /tmp/aws # Configure AWS CLI for S3 access (no credentials needed for public buckets) - mkdir -p /root/.aws - | cat > /root/.aws/config << 'EOF' [default] region = us-east-2 output = json EOF # Create a comprehensive bootstrap script that runs in background - | cat > /root/bootstrap.sh << 'EOF' #!/bin/bash set -euo pipefail exec > >(tee -a /var/log/webarena-map-bootstrap.log) 2>&1 echo "$(date): Starting WebArena map server bootstrap" echo "$(date): System info: $(uname -a)" echo "$(date): Available memory: $(free -h)" echo "$(date): Available disk space: $(df -h)" # Check if we have enough disk space (need at least 200GB free) AVAILABLE_GB=$(df / | awk 'NR==2 {print int($4/1024/1024)}') echo "$(date): Available disk space: ${AVAILABLE_GB}GB" if [ "$AVAILABLE_GB" -lt 200 ]; then echo "$(date): ERROR: Insufficient disk space. Need at least 200GB, have ${AVAILABLE_GB}GB" exit 1 fi # Function to retry commands with exponential backoff retry() { local n=1 local max=5 local delay=30 while true; do "$@" && break || { if [[ $n -lt $max ]]; then ((n++)) echo "$(date): Command failed. Attempt $n/$max. Waiting ${delay}s..." sleep $delay delay=$((delay * 2)) # Exponential backoff else echo "$(date): Command failed after $n attempts: $*" return 1 fi } done } # Function to monitor background processes monitor_extraction() { local pid=$1 local desc=$2 echo "$(date): Monitoring $desc (PID: $pid)" while kill -0 $pid 2>/dev/null; do echo "$(date): $desc still running..." sleep 60 done wait $pid local exit_code=$? if [ $exit_code -eq 0 ]; then echo "$(date): ✅ $desc completed successfully" else echo "$(date): ❌ $desc failed with exit code $exit_code" return $exit_code fi } # Download and extract data with retries and parallel processing where safe echo "$(date): Starting data downloads..." # Download all files first (can be done in parallel) echo "$(date): Downloading OSM tile server data..." retry aws s3 cp --no-sign-request s3://webarena-map-server-data/osm_tile_server.tar /root/osm_tile_server.tar & DOWNLOAD_TILE_PID=$! echo "$(date): Downloading Nominatim data..." retry aws s3 cp --no-sign-request s3://webarena-map-server-data/nominatim_volumes.tar /root/nominatim_volumes.tar & DOWNLOAD_NOM_PID=$! echo "$(date): Downloading OSM dump..." retry aws s3 cp --no-sign-request s3://webarena-map-server-data/osm_dump.tar /root/osm_dump.tar & DOWNLOAD_DUMP_PID=$! echo "$(date): Downloading OSRM routing data..." retry aws s3 cp --no-sign-request s3://webarena-map-server-data/osrm_routing.tar /root/osrm_routing.tar & DOWNLOAD_OSRM_PID=$! # Wait for all downloads to complete echo "$(date): Waiting for downloads to complete..." monitor_extraction $DOWNLOAD_TILE_PID "OSM tile server download" monitor_extraction $DOWNLOAD_NOM_PID "Nominatim download" monitor_extraction $DOWNLOAD_DUMP_PID "OSM dump download" monitor_extraction $DOWNLOAD_OSRM_PID "OSRM routing download" echo "$(date): All downloads completed. Starting extractions..." # Extract files sequentially to avoid memory issues and clean up immediately echo "$(date): Extracting OSM tile server data..." tar -C /var/lib/docker/volumes -xf /root/osm_tile_server.tar rm -f /root/osm_tile_server.tar # Clean up immediately to save space echo "$(date): ✅ OSM tile server data extracted and cleaned up" echo "$(date): Extracting Nominatim data..." tar -C /var/lib/docker/volumes -xf /root/nominatim_volumes.tar rm -f /root/nominatim_volumes.tar # Clean up immediately to save space echo "$(date): ✅ Nominatim data extracted and cleaned up" echo "$(date): Extracting OSM dump..." tar -C /opt/osm_dump -xf /root/osm_dump.tar rm -f /root/osm_dump.tar # Clean up immediately to save space echo "$(date): ✅ OSM dump extracted and cleaned up" echo "$(date): Extracting OSRM routing data..." tar -C /opt/osrm -xf /root/osrm_routing.tar rm -f /root/osrm_routing.tar # Clean up immediately to save space echo "$(date): ✅ OSRM routing data extracted and cleaned up" # Verify extracted data echo "$(date): Verifying extracted data..." ls -la /var/lib/docker/volumes/ | head -20 ls -la /opt/osm_dump/ | head -10 ls -la /opt/osrm/ | head -10 # Pull Docker images echo "$(date): Pulling Docker images..." docker pull overv/openstreetmap-tile-server docker pull mediagis/nominatim:4.2 docker pull ghcr.io/project-osrm/osrm-backend:v5.27.1 # Start containers with restart policies and proper resource limits echo "$(date): Starting tile server..." docker run --name tile --restart unless-stopped \ --memory=2g --memory-swap=4g \ --volume=osm-data:/data/database/ --volume=osm-tiles:/data/tiles/ \ -p 8080:80 -d overv/openstreetmap-tile-server run # Wait a bit for tile server to initialize sleep 30 echo "$(date): Starting Nominatim geocoding server..." docker run --name nominatim --restart unless-stopped \ --memory=4g --memory-swap=8g \ --env=IMPORT_STYLE=extratags \ --env=PBF_PATH=/nominatim/data/us-northeast-latest.osm.pbf \ --env=IMPORT_WIKIPEDIA=/nominatim/data/wikimedia-importance.sql.gz \ --volume=/opt/osm_dump:/nominatim/data \ --volume=nominatim-data:/var/lib/postgresql/14/main \ --volume=nominatim-flatnode:/nominatim/flatnode \ -p 8085:8080 -d mediagis/nominatim:4.2 /app/start.sh # Wait for Nominatim to initialize sleep 60 echo "$(date): Starting OSRM routing servers..." # Start OSRM car routing docker run --name osrm-car --restart unless-stopped \ --memory=1g --memory-swap=2g \ --volume=/opt/osrm/car:/data -p 5000:5000 -d \ ghcr.io/project-osrm/osrm-backend:v5.27.1 osrm-routed --algorithm mld /data/us-northeast-latest.osrm # Start OSRM bike routing docker run --name osrm-bike --restart unless-stopped \ --memory=1g --memory-swap=2g \ --volume=/opt/osrm/bike:/data -p 5001:5000 -d \ ghcr.io/project-osrm/osrm-backend:v5.27.1 osrm-routed --algorithm mld /data/us-northeast-latest.osrm # Start OSRM foot routing docker run --name osrm-foot --restart unless-stopped \ --memory=1g --memory-swap=2g \ --volume=/opt/osrm/foot:/data -p 5002:5000 -d \ ghcr.io/project-osrm/osrm-backend:v5.27.1 osrm-routed --algorithm mld /data/us-northeast-latest.osrm echo "$(date): All services started. Waiting for initialization..." sleep 120 echo "$(date): Verifying service health..." docker ps --format "table {{.Names}}\t{{.Image}}\t{{.Status}}\t{{.Ports}}" # Test service endpoints echo "$(date): Testing service endpoints..." # Test tile server if curl -f -s -o /dev/null "http://localhost:8080/tile/0/0/0.png"; then echo "$(date): ✅ Tile server is responding" else echo "$(date): ❌ Tile server is not responding" fi # Test Nominatim if curl -f -s -o /dev/null "http://localhost:8085/search?q=test&format=json&limit=1"; then echo "$(date): ✅ Nominatim is responding" else echo "$(date): ❌ Nominatim is not responding" fi # Test OSRM services for service in car bike foot; do port=$((5000 + $(echo "car bike foot" | tr ' ' '\n' | grep -n $service | cut -d: -f1) - 1)) if curl -f -s -o /dev/null "http://localhost:$port/route/v1/$service/-79.9959,40.4406;-79.9,40.45?overview=false"; then echo "$(date): ✅ OSRM $service routing is responding" else echo "$(date): ❌ OSRM $service routing is not responding" fi done # All tar files already cleaned up during extraction # Final status report echo "$(date): Bootstrap completed!" echo "$(date): Final service status:" docker ps echo "$(date): Available disk space after cleanup:" df -h echo "$(date): Memory usage:" free -h echo "$(date): Services are available at:" # 169.254.169.254 is the AWS Instance Metadata Service (IMDS) endpoint # It provides instance metadata including the public IP address echo " - Tile server: http://$(curl -s http://169.254.169.254/latest/meta-data/public-ipv4):8080/tile/{z}/{x}/{y}.png" echo " - Geocoding: http://$(curl -s http://169.254.169.254/latest/meta-data/public-ipv4):8085/" echo " - OSRM Car: http://$(curl -s http://169.254.169.254/latest/meta-data/public-ipv4):5000/" echo " - OSRM Bike: http://$(curl -s http://169.254.169.254/latest/meta-data/public-ipv4):5001/" echo " - OSRM Foot: http://$(curl -s http://169.254.169.254/latest/meta-data/public-ipv4):5002/" echo "$(date): Bootstrap script completed successfully!" EOF # Make bootstrap script executable and run it in background - chmod +x /root/bootstrap.sh - nohup /root/bootstrap.sh > /var/log/webarena-map-bootstrap.log 2>&1 & # Write completion marker write_files: - path: /root/cloud-init-completed content: | Cloud-init completed at $(date) Bootstrap script started in background Check /var/log/webarena-map-bootstrap.log for progress permissions: '0644' final_message: | WebArena map server cloud-init completed. Bootstrap script is running in background. Check /var/log/webarena-map-bootstrap.log for progress. Services will be available at: - Tiles: http://:8080/tile/{z}/{x}/{y}.png - Geocoding: http://:8085/ - Routing: http://:5000 (car), :5001 (bike), :5002 (foot)