# Automatic Updates Setup ## Overview The Towerops agent now supports **automatic updates** using **Watchtower**, eliminating the need for manual updates or self-update code in the agent. ## How It Works ``` ┌─────────────────┐ │ Push to main │ └────────┬────────┘ │ ↓ ┌─────────────────┐ │ GitLab CI/CD │ ← Builds Docker image │ builds image │ Tags: main, latest, timestamp └────────┬────────┘ │ ↓ ┌─────────────────┐ │ Docker Hub │ ← New image published │ gmcintire/ │ Tag: main (updated) │ towerops-agent │ └────────┬────────┘ │ ↓ ┌─────────────────┐ │ Watchtower │ ← Polls every 5 minutes │ (on customer │ Detects new 'main' tag │ network) │ Pulls new image └────────┬────────┘ Restarts container │ ↓ ┌─────────────────┐ │ Agent updated │ ← Zero downtime │ automatically │ New version running └─────────────────┘ ``` ## Versioning Strategy ### Git-Based Versioning The agent version is **automatically generated** from git: | Scenario | Version Format | Example | |----------|----------------|---------| | Exact tag | `X.Y.Z` | `0.2.0` | | After tag | `X.Y.Z.N.hash` | `0.2.0.5.831588e` | | No tags | `X.Y.Z.hash` | `0.1.0.831588e` | | Dirty tree | `X.Y.Z-modified` | `0.2.0-modified` | **Generated by**: `git describe --tags --always --dirty=-modified` ### Docker Image Tags Every push to `main` creates **multiple tags**: | Tag | Purpose | Updated On | |-----|---------|------------| | `main` | **Auto-update tracking** | Every push | | `latest` | Stable/production | Every push | | `0.1.0.5.831588e` | Specific version | Every push | | `main-831588e` | Commit reference | Every push | | `main-20260116-143022` | Timestamp | Every push | ### Release Tags Git tags trigger **multi-arch releases**: ```bash git tag v0.2.0 git push --tags # CI builds: linux/amd64, linux/arm64 # Tags: 0.2.0, v0.2.0, latest ``` ## Setup Instructions ### 1. Docker Compose (Recommended) Copy `docker-compose.example.yml` to `docker-compose.yml`: ```yaml services: towerops-agent: image: gmcintire/towerops-agent:main # ← Track main for auto-updates # ... environment vars ... labels: - "com.centurylinklabs.watchtower.enable=true" watchtower: image: containrrr/watchtower:latest environment: - WATCHTOWER_POLL_INTERVAL=300 # Check every 5 minutes - WATCHTOWER_LABEL_ENABLE=true - WATCHTOWER_CLEANUP=true volumes: - /var/run/docker.sock:/var/run/docker.sock ``` Start services: ```bash docker-compose up -d ``` ### 2. Docker Run (Manual) **Agent**: ```bash docker run -d \ --name towerops-agent \ --restart unless-stopped \ --label com.centurylinklabs.watchtower.enable=true \ -e TOWEROPS_API_URL=https://app.towerops.com \ -e TOWEROPS_AGENT_TOKEN=your-token \ -v $(pwd)/data:/data \ gmcintire/towerops-agent:main ``` **Watchtower**: ```bash docker run -d \ --name watchtower \ --restart unless-stopped \ -e WATCHTOWER_POLL_INTERVAL=300 \ -e WATCHTOWER_LABEL_ENABLE=true \ -e WATCHTOWER_CLEANUP=true \ -v /var/run/docker.sock:/var/run/docker.sock \ containrrr/watchtower ``` ### 3. Kubernetes Use a Kubernetes CronJob with a Docker image updater like: - **Keel** (https://keel.sh/) - **Flux** (https://fluxcd.io/) - **ArgoCD Image Updater** (https://argocd-image-updater.readthedocs.io/) Example with Keel: ```yaml apiVersion: apps/v1 kind: Deployment metadata: name: towerops-agent labels: keel.sh/policy: force keel.sh/trigger: poll spec: template: spec: containers: - name: agent image: gmcintire/towerops-agent:main ``` ## Watchtower Configuration ### Update Frequency **Default**: Every 5 minutes (`WATCHTOWER_POLL_INTERVAL=300`) **Recommended settings**: - **Aggressive**: 300s (5 min) - Get updates quickly - **Balanced**: 1800s (30 min) - Reduce Docker Hub API calls - **Conservative**: 3600s (1 hour) - Minimize load ### Notifications Get notified when updates happen: #### Slack ```yaml environment: - WATCHTOWER_NOTIFICATIONS=slack - WATCHTOWER_NOTIFICATION_SLACK_HOOK_URL=https://hooks.slack.com/services/YOUR/WEBHOOK/URL - WATCHTOWER_NOTIFICATION_SLACK_IDENTIFIER=Towerops Agent ``` #### Email ```yaml environment: - WATCHTOWER_NOTIFICATIONS=email - WATCHTOWER_NOTIFICATION_EMAIL_FROM=watchtower@yourdomain.com - WATCHTOWER_NOTIFICATION_EMAIL_TO=alerts@yourdomain.com - WATCHTOWER_NOTIFICATION_EMAIL_SERVER=smtp.gmail.com - WATCHTOWER_NOTIFICATION_EMAIL_SERVER_PORT=587 - WATCHTOWER_NOTIFICATION_EMAIL_SERVER_USER=your-email@gmail.com - WATCHTOWER_NOTIFICATION_EMAIL_SERVER_PASSWORD=your-app-password ``` #### Discord, Telegram, etc. See: https://containrrr.dev/watchtower/notifications/ ### Update Scheduling Run updates at specific times (cron format): ```yaml environment: # Daily at 4am - WATCHTOWER_SCHEDULE=0 0 4 * * * # Every Sunday at 2am - WATCHTOWER_SCHEDULE=0 0 2 * * 0 ``` ### Rolling Updates Update only specific containers: ```yaml environment: - WATCHTOWER_SCOPE=towerops # Only update containers with this scope label # On agent: labels: - "com.centurylinklabs.watchtower.scope=towerops" ``` ## Tag Selection Strategy ### Production (Stable) Use **`latest`** tag for stable releases only: ```yaml image: gmcintire/towerops-agent:latest ``` - Updated only on git tags (`v0.2.0`, `v0.3.0`, etc.) - Tested releases - Manual version control ### Auto-Updates (Continuous) Use **`main`** tag for automatic updates: ```yaml image: gmcintire/towerops-agent:main ``` - Updated on every push to main branch - Latest features and bug fixes - Automated deployment - **Recommended for most users** ### Pinned Version Use **specific version** to prevent updates: ```yaml image: gmcintire/towerops-agent:0.2.0.5.831588e ``` - Never updates automatically - Full control over upgrades - Use when stability is critical ## Monitoring Updates ### Check Watchtower Logs ```bash # Docker Compose docker-compose logs -f watchtower # Docker docker logs -f watchtower ``` ### Check Agent Version ```bash # View agent logs for version on startup docker logs towerops-agent | grep "Current version" # Output: Current version: 0.2.0.5.831588e ``` ### Manual Update Check Force Watchtower to check immediately: ```bash # Send SIGUSR1 to Watchtower docker kill --signal=SIGUSR1 watchtower ``` ## Rollback ### To Previous Version Find previous image: ```bash # List available tags docker image ls gmcintire/towerops-agent # Use timestamp tag for specific build docker pull gmcintire/towerops-agent:main-20260116-143022 ``` Update docker-compose.yml: ```yaml image: gmcintire/towerops-agent:main-20260116-143022 ``` Restart: ```bash docker-compose up -d --force-recreate towerops-agent ``` ### Disable Auto-Updates Remove or comment out Watchtower: ```yaml # watchtower: # image: containrrr/watchtower:latest # ... ``` Or disable for specific container: ```yaml labels: - "com.centurylinklabs.watchtower.enable=false" ``` ## Comparison: Self-Update vs Watchtower | Feature | Self-Update (Old) | Watchtower (New) | |---------|-------------------|------------------| | **Complexity** | Agent pulls images | External service | | **Docker socket** | Required in agent | Only in Watchtower | | **Update trigger** | Agent checks hourly | Watchtower polls | | **Rollback** | Exit code 0 | Standard Docker | | **Notifications** | None | Slack, email, etc. | | **Multi-container** | One agent only | All containers | | **Scheduling** | Fixed interval | Cron expressions | | **Security** | Agent has Docker access | Isolated service | **Winner**: Watchtower - More flexible, secure, and featureful ## Security Considerations ### Docker Socket Access Watchtower needs access to Docker socket (`/var/run/docker.sock`). This gives it full Docker API access. **Mitigation**: - Run Watchtower in separate namespace - Use label filtering to limit scope - Monitor Watchtower logs - Use official Watchtower image only ### Image Verification Watchtower pulls images without signature verification by default. **Options**: - Use Docker Content Trust: `export DOCKER_CONTENT_TRUST=1` - Verify image checksums manually - Use private registry with access controls ### Update Testing Test updates in staging before production: 1. **Staging**: Use `main` tag, auto-update 2. **Production**: Use `latest` tag, manual update after staging validation ## Troubleshooting ### Watchtower Not Updating **Check**: 1. Watchtower is running: `docker ps | grep watchtower` 2. Labels are correct: `docker inspect towerops-agent | grep watchtower` 3. Network access: `docker exec watchtower ping -c 1 docker.io` 4. Logs for errors: `docker logs watchtower` ### Update Loop If agent keeps restarting after update: 1. Check agent logs: `docker logs towerops-agent` 2. Pin to previous version (see Rollback) 3. Report issue on GitHub ### High Resource Usage Watchtower using too much memory: ```yaml deploy: resources: limits: memory: 64M # Reduce from 128M ``` ## CI/CD Pipeline ### Automatic Builds **On every push to main**: 1. GitLab CI builds Docker image 2. Tags with multiple identifiers 3. Pushes to Docker Hub 4. Watchtower detects within 5 minutes 5. Agent updates automatically **View pipeline**: https://gitlab.com/towerops/towerops-agent/-/pipelines ### Build Time - **Main branch** (amd64 only): ~5 minutes - **Git tags** (multi-arch): ~20 minutes ## Best Practices 1. **Use `main` tag** for automatic updates 2. **Enable notifications** to track updates 3. **Set reasonable poll interval** (300-1800s) 4. **Monitor Watchtower logs** regularly 5. **Test in staging** before production 6. **Keep Watchtower updated** (`docker pull containrrr/watchtower:latest`) 7. **Use Docker Compose** for easier management ## Resources - **Watchtower Docs**: https://containrrr.dev/watchtower/ - **Docker Hub**: https://hub.docker.com/r/gmcintire/towerops-agent - **GitLab CI**: https://gitlab.com/towerops/towerops-agent/-/blob/main/.gitlab-ci.yml - **Issue Tracker**: https://github.com/towerops/towerops-agent/issues --- **Status**: ✅ Complete **Date**: January 16, 2026 **Impact**: Fully automated zero-touch updates for all deployments