Tons of Stuff
This commit is contained in:
147
deploy/README.md
Normal file
147
deploy/README.md
Normal file
@@ -0,0 +1,147 @@
|
||||
# Deployment Guide
|
||||
|
||||
Multiple deployment methods for rmtPocketWatcher backend.
|
||||
|
||||
## Method 1: Portainer with Git Repository
|
||||
|
||||
**Best for:** Teams using Portainer for container management
|
||||
|
||||
### Setup in Portainer UI:
|
||||
|
||||
1. Go to Stacks → Add Stack → Git Repository
|
||||
2. Configure:
|
||||
- **Name**: rmtpocketwatcher
|
||||
- **Repository URL**: Your Git repo URL
|
||||
- **Reference**: refs/heads/main
|
||||
- **Compose path**: deploy/portainer-stack.yml
|
||||
3. Add environment variables:
|
||||
- `POSTGRES_PASSWORD`: your_secure_password
|
||||
- `IMAGE_TAG`: latest
|
||||
4. Deploy
|
||||
|
||||
### Update via Webhook:
|
||||
|
||||
1. In Portainer, enable webhook for the stack
|
||||
2. Add webhook URL to Gitea secrets: `PORTAINER_WEBHOOK_URL`
|
||||
3. Push to main branch triggers auto-deploy
|
||||
|
||||
### Update via API Script:
|
||||
|
||||
```bash
|
||||
export PORTAINER_URL="http://your-portainer:9000"
|
||||
export PORTAINER_API_KEY="your_api_key"
|
||||
export POSTGRES_PASSWORD="your_password"
|
||||
export GIT_REPO_URL="https://your-git-repo.git"
|
||||
|
||||
chmod +x deploy/portainer-deploy.sh
|
||||
./deploy/portainer-deploy.sh
|
||||
```
|
||||
|
||||
## Method 2: Direct Docker via SSH
|
||||
|
||||
**Best for:** Simple deployments to a single Docker host
|
||||
|
||||
```bash
|
||||
export DOCKER_HOST="your-server.com"
|
||||
export DOCKER_USER="deploy"
|
||||
export GIT_REPO="https://your-git-repo.git"
|
||||
|
||||
chmod +x deploy/docker-deploy.sh
|
||||
./deploy/docker-deploy.sh
|
||||
```
|
||||
|
||||
For local deployment:
|
||||
```bash
|
||||
export DOCKER_HOST="localhost"
|
||||
export GIT_REPO="https://your-git-repo.git"
|
||||
./deploy/docker-deploy.sh
|
||||
```
|
||||
|
||||
## Method 3: Gitea Actions (Automated)
|
||||
|
||||
**Best for:** CI/CD pipeline automation
|
||||
|
||||
### Setup:
|
||||
|
||||
1. Add secrets to your Gitea repository:
|
||||
- `DOCKER_HOST`: your-server.com
|
||||
- `DOCKER_USER`: deploy
|
||||
- `DOCKER_SSH_KEY`: Your SSH private key
|
||||
|
||||
2. Push to main branch or modify backend files
|
||||
3. Workflow automatically builds and deploys
|
||||
|
||||
### Manual trigger:
|
||||
- Go to Actions → Deploy Backend to Docker → Run workflow
|
||||
|
||||
## Method 4: Portainer API via Gitea Actions
|
||||
|
||||
**Best for:** Portainer users with CI/CD
|
||||
|
||||
### Setup:
|
||||
|
||||
1. Get Portainer API key:
|
||||
- Portainer → User Settings → Access tokens → Add access token
|
||||
|
||||
2. Add secrets to Gitea:
|
||||
- `PORTAINER_URL`: http://your-portainer:9000
|
||||
- `PORTAINER_API_KEY`: your_api_key
|
||||
- `PORTAINER_STACK_ID`: stack_id (from Portainer URL)
|
||||
- `PORTAINER_WEBHOOK_URL`: webhook URL (optional)
|
||||
|
||||
3. Manually trigger workflow or use webhook
|
||||
|
||||
## Environment Variables
|
||||
|
||||
Required for all methods:
|
||||
- `POSTGRES_PASSWORD`: Database password
|
||||
|
||||
Optional:
|
||||
- `POSTGRES_USER`: Database user (default: rmtpw)
|
||||
- `POSTGRES_DB`: Database name (default: rmtpocketwatcher)
|
||||
- `BACKEND_PORT`: Backend port (default: 3000)
|
||||
- `SCRAPE_INTERVAL`: Minutes between scrapes (default: 5)
|
||||
- `SCRAPER_TIMEOUT`: Scraper timeout in ms (default: 30000)
|
||||
- `SCRAPER_MAX_RETRIES`: Max retry attempts (default: 3)
|
||||
|
||||
## Monitoring
|
||||
|
||||
Check deployment status:
|
||||
```bash
|
||||
docker-compose ps
|
||||
docker-compose logs -f backend
|
||||
```
|
||||
|
||||
Via Portainer:
|
||||
- Stacks → rmtpocketwatcher → Container logs
|
||||
|
||||
## Rollback
|
||||
|
||||
### Portainer:
|
||||
1. Go to Stack → Editor
|
||||
2. Change `IMAGE_TAG` to previous version
|
||||
3. Update stack
|
||||
|
||||
### Direct Docker:
|
||||
```bash
|
||||
cd /opt/rmtpocketwatcher
|
||||
git checkout <previous-commit>
|
||||
docker-compose up -d --build backend
|
||||
```
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
**Stack won't start:**
|
||||
- Check environment variables are set
|
||||
- Verify database connection
|
||||
- Check logs: `docker-compose logs backend`
|
||||
|
||||
**Portainer API fails:**
|
||||
- Verify API key is valid
|
||||
- Check endpoint ID matches your environment
|
||||
- Ensure Portainer version supports Git deployment
|
||||
|
||||
**SSH deployment fails:**
|
||||
- Verify SSH key has correct permissions (600)
|
||||
- Check user has Docker permissions
|
||||
- Ensure Git is installed on remote host
|
||||
75
deploy/docker-deploy.sh
Normal file
75
deploy/docker-deploy.sh
Normal file
@@ -0,0 +1,75 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Direct Docker Deployment Script
|
||||
# This script deploys rmtPocketWatcher directly to a Docker host via SSH
|
||||
|
||||
set -e
|
||||
|
||||
# Configuration
|
||||
DOCKER_HOST="${DOCKER_HOST:-localhost}"
|
||||
DOCKER_USER="${DOCKER_USER:-root}"
|
||||
DEPLOY_PATH="${DEPLOY_PATH:-/opt/rmtpocketwatcher}"
|
||||
GIT_REPO="${GIT_REPO}"
|
||||
GIT_BRANCH="${GIT_BRANCH:-main}"
|
||||
|
||||
# Colors
|
||||
RED='\033[0;31m'
|
||||
GREEN='\033[0;32m'
|
||||
YELLOW='\033[1;33m'
|
||||
NC='\033[0m'
|
||||
|
||||
echo -e "${GREEN}Deploying rmtPocketWatcher to Docker host...${NC}"
|
||||
|
||||
# Check if we're deploying locally or remotely
|
||||
if [ "$DOCKER_HOST" = "localhost" ]; then
|
||||
echo -e "${YELLOW}Deploying locally...${NC}"
|
||||
|
||||
# Pull latest code
|
||||
if [ -d "$DEPLOY_PATH" ]; then
|
||||
cd "$DEPLOY_PATH"
|
||||
git pull origin "$GIT_BRANCH"
|
||||
else
|
||||
git clone -b "$GIT_BRANCH" "$GIT_REPO" "$DEPLOY_PATH"
|
||||
cd "$DEPLOY_PATH"
|
||||
fi
|
||||
|
||||
# Build and deploy
|
||||
docker-compose down
|
||||
docker-compose build backend
|
||||
docker-compose up -d
|
||||
|
||||
echo -e "${GREEN}Local deployment complete!${NC}"
|
||||
else
|
||||
echo -e "${YELLOW}Deploying to remote host: ${DOCKER_HOST}${NC}"
|
||||
|
||||
# Deploy via SSH
|
||||
ssh ${DOCKER_USER}@${DOCKER_HOST} << EOF
|
||||
set -e
|
||||
|
||||
# Pull or clone repository
|
||||
if [ -d "${DEPLOY_PATH}" ]; then
|
||||
cd "${DEPLOY_PATH}"
|
||||
git pull origin ${GIT_BRANCH}
|
||||
else
|
||||
git clone -b ${GIT_BRANCH} ${GIT_REPO} ${DEPLOY_PATH}
|
||||
cd "${DEPLOY_PATH}"
|
||||
fi
|
||||
|
||||
# Build and deploy
|
||||
docker-compose down
|
||||
docker-compose build backend
|
||||
docker-compose up -d
|
||||
|
||||
echo "Deployment complete!"
|
||||
EOF
|
||||
|
||||
echo -e "${GREEN}Remote deployment complete!${NC}"
|
||||
fi
|
||||
|
||||
# Show status
|
||||
echo -e "${YELLOW}Checking service status...${NC}"
|
||||
if [ "$DOCKER_HOST" = "localhost" ]; then
|
||||
docker-compose ps
|
||||
else
|
||||
ssh ${DOCKER_USER}@${DOCKER_HOST} "cd ${DEPLOY_PATH} && docker-compose ps"
|
||||
fi
|
||||
76
deploy/portainer-deploy.sh
Normal file
76
deploy/portainer-deploy.sh
Normal file
@@ -0,0 +1,76 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Portainer Deployment Script
|
||||
# This script deploys or updates the rmtPocketWatcher stack via Portainer API
|
||||
|
||||
set -e
|
||||
|
||||
# Configuration
|
||||
PORTAINER_URL="${PORTAINER_URL:-http://localhost:9000}"
|
||||
PORTAINER_API_KEY="${PORTAINER_API_KEY}"
|
||||
STACK_NAME="${STACK_NAME:-rmtpocketwatcher}"
|
||||
ENDPOINT_ID="${ENDPOINT_ID:-1}"
|
||||
|
||||
# Colors
|
||||
RED='\033[0;31m'
|
||||
GREEN='\033[0;32m'
|
||||
YELLOW='\033[1;33m'
|
||||
NC='\033[0m'
|
||||
|
||||
# Check required variables
|
||||
if [ -z "$PORTAINER_API_KEY" ]; then
|
||||
echo -e "${RED}Error: PORTAINER_API_KEY is not set${NC}"
|
||||
echo "Usage: PORTAINER_API_KEY=your_key ./portainer-deploy.sh"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo -e "${GREEN}Deploying rmtPocketWatcher to Portainer...${NC}"
|
||||
|
||||
# Check if stack exists
|
||||
STACK_ID=$(curl -s -X GET \
|
||||
"${PORTAINER_URL}/api/stacks" \
|
||||
-H "X-API-Key: ${PORTAINER_API_KEY}" \
|
||||
| jq -r ".[] | select(.Name==\"${STACK_NAME}\") | .Id")
|
||||
|
||||
if [ -z "$STACK_ID" ] || [ "$STACK_ID" = "null" ]; then
|
||||
echo -e "${YELLOW}Stack not found. Creating new stack...${NC}"
|
||||
|
||||
# Create new stack from Git repository
|
||||
curl -X POST \
|
||||
"${PORTAINER_URL}/api/stacks/create/standalone/repository" \
|
||||
-H "X-API-Key: ${PORTAINER_API_KEY}" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d @- << EOF
|
||||
{
|
||||
"name": "${STACK_NAME}",
|
||||
"endpointId": ${ENDPOINT_ID},
|
||||
"repositoryURL": "${GIT_REPO_URL}",
|
||||
"repositoryReferenceName": "refs/heads/main",
|
||||
"composeFile": "deploy/portainer-stack.yml",
|
||||
"repositoryAuthentication": false,
|
||||
"env": [
|
||||
{"name": "POSTGRES_PASSWORD", "value": "${POSTGRES_PASSWORD}"},
|
||||
{"name": "IMAGE_TAG", "value": "latest"}
|
||||
]
|
||||
}
|
||||
EOF
|
||||
|
||||
echo -e "${GREEN}Stack created successfully!${NC}"
|
||||
else
|
||||
echo -e "${YELLOW}Stack found (ID: ${STACK_ID}). Updating...${NC}"
|
||||
|
||||
# Update existing stack via Git pull
|
||||
curl -X PUT \
|
||||
"${PORTAINER_URL}/api/stacks/${STACK_ID}/git/redeploy" \
|
||||
-H "X-API-Key: ${PORTAINER_API_KEY}" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{
|
||||
"pullImage": true,
|
||||
"prune": true
|
||||
}'
|
||||
|
||||
echo -e "${GREEN}Stack updated successfully!${NC}"
|
||||
fi
|
||||
|
||||
echo -e "${GREEN}Deployment complete!${NC}"
|
||||
echo -e "Access your backend at: ${PORTAINER_URL%:*}:3000"
|
||||
52
deploy/portainer-stack.yml
Normal file
52
deploy/portainer-stack.yml
Normal file
@@ -0,0 +1,52 @@
|
||||
version: '3.8'
|
||||
|
||||
# Portainer Stack Configuration
|
||||
# This file is used when deploying via Portainer's Git repository feature
|
||||
|
||||
services:
|
||||
postgres:
|
||||
image: postgres:16-alpine
|
||||
restart: unless-stopped
|
||||
environment:
|
||||
POSTGRES_USER: ${POSTGRES_USER:-rmtpw}
|
||||
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
|
||||
POSTGRES_DB: ${POSTGRES_DB:-rmtpocketwatcher}
|
||||
volumes:
|
||||
- postgres_data:/var/lib/postgresql/data
|
||||
networks:
|
||||
- rmtpw-network
|
||||
healthcheck:
|
||||
test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER:-rmtpw} -d ${POSTGRES_DB:-rmtpocketwatcher}"]
|
||||
interval: 10s
|
||||
timeout: 5s
|
||||
retries: 5
|
||||
|
||||
backend:
|
||||
image: ${DOCKER_REGISTRY:-ghcr.io}/${DOCKER_IMAGE:-lambdabanking/rmtpocketwatcher-backend}:${IMAGE_TAG:-latest}
|
||||
restart: unless-stopped
|
||||
depends_on:
|
||||
postgres:
|
||||
condition: service_healthy
|
||||
environment:
|
||||
DATABASE_URL: postgresql://${POSTGRES_USER:-rmtpw}:${POSTGRES_PASSWORD}@postgres:5432/${POSTGRES_DB:-rmtpocketwatcher}?schema=public
|
||||
PORT: ${BACKEND_PORT:-3000}
|
||||
HOST: 0.0.0.0
|
||||
NODE_ENV: production
|
||||
SCRAPE_INTERVAL_MINUTES: ${SCRAPE_INTERVAL:-5}
|
||||
SCRAPER_HEADLESS: "true"
|
||||
SCRAPER_TIMEOUT: ${SCRAPER_TIMEOUT:-30000}
|
||||
SCRAPER_MAX_RETRIES: ${SCRAPER_MAX_RETRIES:-3}
|
||||
ports:
|
||||
- "${BACKEND_PORT:-3000}:3000"
|
||||
networks:
|
||||
- rmtpw-network
|
||||
labels:
|
||||
- "com.centurylinklabs.watchtower.enable=true"
|
||||
|
||||
volumes:
|
||||
postgres_data:
|
||||
driver: local
|
||||
|
||||
networks:
|
||||
rmtpw-network:
|
||||
driver: bridge
|
||||
Reference in New Issue
Block a user