CFTunnels/portainer-automation/PORTAINER_STACK.md
hitanshu310 8f4af5e322 Hithomelabs/CFTunnels#99: Deploy portainer-automation service
- Add Dockerfile for portainer-automation (multi-stage build)
- Add standalone docker-compose.yaml for PA service
- Add application-prod.properties (prod Portainer :9443)
- Add application-ci.properties (CI test endpoints)
- Add .env.example with documented env vars for PA
- Add PORTAINER_STACK.md with deployment guide, env var tables, architecture diagram
- Add CI workflow (portainer_automation_build_push.yml) for image build/push
- Update root docker-compose.yaml to include PA service
2026-07-07 02:51:58 +05:30

8.5 KiB

Portainer Automation Service — Portainer Stack Guide

Overview

The Portainer Automation service exposes a single endpoint (POST /api/deploy/{stackId}) that triggers a redeploy of a Portainer stack. CI workflows call this endpoint after pushing new container images.

The service is deployed as a separate Portainer stack (Option B) — independent from the CFTunnels stacks — so it can be reused by other projects.


Architecture Diagram

┌─────────────────┐     push tag     ┌──────────────────┐
│  Gitea Runner   │ ──────────────►  │  Docker Registry  │
│ (CI workflow)   │                  │  :8928            │
└────────┬────────┘                  └──────────────────┘
         │
         │ POST /api/deploy/{stackId}
         │ X-API-Key: <service-api-key>
         ▼
┌─────────────────────────────────────┐
│  Portainer Automation Service      │
│  (portainer-automation_${ENV})     │
│  port: 8081                         │
└──────────┬──────────────────────────┘
           │ PUT /api/stacks/{id}/git/redeploy
           │ X-API-Key: <portainer-api-key>
           ▼
┌─────────────────────────────────────┐
│  Portainer CE                       │
│  Dev: :9442 / Prod: :9443          │
└──────────┬──────────────────────────┘
           │ git pull + stack redeploy
           ▼
┌─────────────────────────────────────┐
│  Target Stack (e.g. CFTunnels)     │
│  Docker Compose from Git           │
└─────────────────────────────────────┘

Portainer Stack Configuration

Create a New Stack in Portainer

  1. Navigate: Portainer UI → Stacks → Add stack
  2. Name: portainer-automation-{env} (e.g. portainer-automation-dev)
  3. Build method: Git repository
  4. Repository URL: https://gitea.hithomelabs.com/Hithomelabs/CFTunnels.git
  5. Repository reference: refs/heads/test (dev) or refs/heads/main (prod)
  6. Compose path: portainer-automation/docker-compose.yaml
  7. Environment variables: See table below

Environment Variables — Dev

Variable Value Description
ENV dev Environment label
HOST_PORT 8081 Host port mapping
SPRING_PROFILES_ACTIVE local Spring profile (uses devdocker.hithomelabs.com)
PORTAINER_API_KEY ptk_xxxx_dev_xxxx Portainer Dev API access token
PORTAINER_SERVICE_API_KEY (generate a random key) CI → Service auth key

Portainer Dev endpoint: https://devdocker.hithomelabs.com (port 9442 behind Cloudflare Tunnel)

Environment Variables — Prod

Variable Value Description
ENV prod Environment label
HOST_PORT 8082 Host port mapping
SPRING_PROFILES_ACTIVE prod Spring profile (uses 192.168.0.100:9443)
PORTAINER_API_KEY ptk_xxxx_prod_xxxx Portainer Prod API access token
PORTAINER_SERVICE_API_KEY (generate a different random key) CI → Service auth key

Portainer Prod endpoint: https://192.168.0.100:9443 (internal network)


Deployment Steps

Prerequisites

  1. Portainer Automation Docker image is built and pushed (see CI workflow)
  2. Portainer API access tokens created (Portainer UI → My access tokens)
  3. Gitea secrets configured:
    • PORTAINER_SERVICE_API_KEY — shared secret for dev
    • PORTAINER_SERVICE_API_KEY_PROD — shared secret for prod

Step 1: Build and Push Image

The CI workflow .gitea/workflows/portainer_automation_build_push.yml handles this automatically on push to the test branch.

To build manually:

./gradlew :portainer-automation:bootBuildImage \
  --imageName=192.168.0.100:8928/hithomelabs/portainer-automation:<version>

Step 2: Create Stack in Portainer (Dev)

  1. Log in to Portainer Dev (https://devdocker.hithomelabs.com)
  2. Stacks → Add stack
  3. Name: portainer-automation-dev
  4. Build method: Git repository
  5. Repository: https://gitea.hithomelabs.com/Hithomelabs/CFTunnels.git
  6. Reference: refs/heads/test
  7. Compose path: portainer-automation/docker-compose.yaml
  8. Add env vars from the Dev table above
  9. Click Deploy the stack

Step 3: Verify Dev Deployment

# Redeploy a stack via the automation service
curl -X POST \
  -H "X-API-Key: <service-api-key>" \
  http://portainer-automation-dev:8081/api/deploy/<stack-id>

# Expected: "Deployment initiated for stack <stack-id>"

Step 4: Create Stack in Portainer (Prod)

  1. Log in to Portainer Prod (https://192.168.0.100:9443)
  2. Follow the same steps as Step 2, with:
    • Name: portainer-automation-prod
    • Reference: refs/heads/main
    • Env vars from the Prod table above

Step 5: Wire CI Triggers

Ensure CI workflows call the automation endpoint:

Dev (in test_image_build_push.yml):

- name: Trigger Portainer Redeploy (Dev)
  if: success()
  env:
    PORTAINER_AUTOMATION_URL: "http://portainer-automation-dev:8081"
    STACK_ID: ${{ vars.PORTAINER_AUTOMATION_DEV_STACK_ID }}
    API_KEY: ${{ secrets.PORTAINER_SERVICE_API_KEY }}
  run: |
    wget -q --no-check-certificate --timeout=30 \
      --header="X-API-Key: $API_KEY" \
      -O - \
      "$PORTAINER_AUTOMATION_URL/api/deploy/$STACK_ID" 2>&1 \
      || echo "Deploy trigger failed (non-fatal)"    

Prod (in prod_image_tag_promote.yaml):

- name: Trigger Portainer Redeploy (Prod)
  if: success()
  env:
    PORTAINER_AUTOMATION_URL: "http://portainer-automation-prod:8082"
    STACK_ID: ${{ vars.PORTAINER_AUTOMATION_PROD_STACK_ID }}
    API_KEY: ${{ secrets.PORTAINER_SERVICE_API_KEY_PROD }}
  run: |
    wget -q --no-check-certificate --timeout=30 \
      --header="X-API-Key: $API_KEY" \
      -O - \
      "$PORTAINER_AUTOMATION_URL/api/deploy/$STACK_ID" 2>&1 \
      || echo "Deploy trigger failed (non-fatal)"    

Configuration Reference

Profile Resolution Order

The service resolves configuration in this order (later overrides earlier):

  1. application.properties — default: https://192.168.0.100:9442
  2. application-{profile}.properties — profile-specific overrides
  3. Environment variables — highest priority

Profile Purposes

Profile File Portainer Target Use Case
default application.properties 192.168.0.100:9442 (Dev) CI/CD, Docker compose
local application-local.properties devdocker.hithomelabs.com Local dev via Cloudflare Tunnel
ci application-ci.properties portainer-test:9000 CI pipeline testing
prod application-prod.properties 192.168.0.100:9443 (Prod) Production deployment

Environment Variable Reference

Variable Required Default Description
SPRING_PROFILES_ACTIVE No (none) Active Spring profile
PORTAINER_API_KEY Yes Portainer API access token
PORTAINER_SERVICE_API_KEY Yes Shared secret for CI → service auth
ENV No test Deployment environment label
HOST_PORT No 8081 External port mapping

Health Checks

The service exposes no dedicated health endpoint yet. Verify availability by:

# Check that the service responds (expects 401 Unauthorized without API key)
curl -X POST http://portainer-automation-dev:8081/api/deploy/1
# Expected: {"timestamp":"...","status":401,"error":"Unauthorized",...}
# A 401 response means the service is running.

Troubleshooting

Symptom Likely Cause Fix
Connection refused Service not running Check stack status in Portainer
Invalid API key Wrong PORTAINER_SERVICE_API_KEY Verify env var matches CI secret
Portainer error: Unauthorized Wrong PORTAINER_API_KEY Regenerate token in Portainer UI
Stack not found Wrong stack ID Verify stack ID in Portainer URL