447 lines
10 KiB
Markdown
447 lines
10 KiB
Markdown
# 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
|