BBL API-Gateway Setup mit Prefect, Kong, EspoCRM und Gitea
Dieses Repository enthält die Flows für Prefect und dient als zentrale Dokumentation für das gesamte Setup. Das System integriert einen API-Gateway (Kong) für Prefect und EspoCRM, einen Git-Server (Gitea) für Code-Management und Docker für die Container-Orchestrierung. Traefik handhabt das externe Routing (einschließlich SSL), und Portainer/Watchtower managen Updates.
Einführung
Dieses Setup ermöglicht:
- Kong als API-Gateway: Routet Anfragen an Prefect (
api.bitbylaw.com:5000/prefect) und EspoCRM (api.bitbylaw.com:5000/espocrm). - Prefect für Workflows: Flows werden in diesem Repository erstellt, geändert, gepusht, deployed und über die API getriggert.
- Gitea als Git-Server: Zentrale Code-Speicherung für Prefect-Flows, integriert mit VS Code.
- EspoCRM: CRM-System, integriert mit Kong für API-Zugriff.
- Docker: Alle Komponenten laufen in Containern mit einem gemeinsamen Netzwerk (
bbl-shared-net) für interne Kommunikation. - Traefik: Manuelle Konfiguration für URLs wie
api.bitbylaw.com,ui.api.bitbylaw.com,git.bitbylaw.com,prefect.bitbylaw.com,espocrm.bitbylaw.com. - Sicherheit: Authentifizierung über Kong (z.B.
basic-authoderkey-auth), SSL via Traefik, SSH-Keys für Git.
Voraussetzungen
- VM/Host: Ubuntu/Debian mit Docker, Docker Compose, Portainer, Watchtower und Traefik installiert.
- Netzwerk: Externes Docker-Netzwerk
bbl-shared-net(docker network create bbl-shared-net). - Domains:
api.bitbylaw.com(Kong Proxy),ui.api.bitbylaw.com(Kong Manager),git.bitbylaw.com(Gitea),prefect.bitbylaw.com(Prefect UI),espocrm.bitbylaw.com(EspoCRM). - VS Code: Installiert auf der VM, mit Python-Extension und GitLens für Git-Integration.
- Python: 3.8+ in einer virtuellen Umgebung (
venvunter~/bbl-code). - Gitea-Credentials: Admin-User (
admin:strongpass). - Prefect-API: Ohne Auth (für Tests); für Produktion
basic-authaktivieren.
Docker-Konfiguration
Alle Container laufen in bbl-shared-net für interne Kommunikation. Watchtower-Labels für automatische Updates. Ports werden über Traefik geroutet.
Kong (API-Gateway)
docker-compose-kong.yml:
version: '3.8'
networks:
bbl-shared-net:
external: true
volumes:
kong_data: {}
services:
kong-database:
image: postgres:16
restart: always
networks:
- bbl-shared-net
environment:
POSTGRES_USER: kong
POSTGRES_PASSWORD: kong
POSTGRES_DB: kong
volumes:
- kong_data:/var/lib/postgresql/data
ports:
- "5432:5432"
healthcheck:
test: ["CMD", "pg_isready", "-U", "kong"]
interval: 5s
timeout: 5s
retries: 5
labels:
com.centurylinklabs.watchtower.enable: "true"
kong-migration:
image: kong:latest
command: "kong migrations bootstrap"
networks:
- bbl-shared-net
restart: on-failure
environment:
KONG_PG_HOST: kong-database
KONG_PG_USER: kong
KONG_PG_PASSWORD: kong
KONG_PG_DATABASE: kong
KONG_DATABASE: postgres
KONG_LOG_LEVEL: debug
depends_on:
kong-database:
condition: service_healthy
kong:
image: kong:latest
restart: always
networks:
- bbl-shared-net
environment:
KONG_PG_HOST: kong-database
KONG_PG_USER: kong
KONG_PG_PASSWORD: kong
KONG_PG_DATABASE: kong
KONG_DATABASE: postgres
KONG_PG_TIMEOUT: 10000
KONG_PROXY_LISTEN: 0.0.0.0:5000
KONG_ADMIN_LISTEN: 0.0.0.0:8001
KONG_ADMIN_GUI_LISTEN: 0.0.0.0:5001
KONG_PORTAL: on
KONG_ADMIN_GUI_AUTH: basic-auth
KONG_ADMIN_GUI_USERNAME: admin
KONG_ADMIN_GUI_PASSWORD: adminpass
KONG_LOG_LEVEL: debug
depends_on:
- kong-migration
- kong-database
healthcheck:
test: ["CMD", "kong", "health"]
interval: 5s
timeout: 5s
retries: 20
ports:
- "5000:5000"
- "8001:8001"
- "5001:5001"
labels:
com.centurylinklabs.watchtower.enable: "true"
- Konfiguration in Kong Manager: Services und Routes für Prefect (
prefect-service:http://prefect-server:4200/api, Route:/prefect) und EspoCRM (espocrm-service:http://espocrm:80, Route:/espocrm). - Authentifizierung:
basic-authoderkey-authauf Service-Ebene (z.B. fürprefect-service).
Prefect (Workflow-Management)
docker-compose-prefect.yml:
version: '3.8'
networks:
bbl-shared-net:
external: true
volumes:
postgres_data:
redis_data:
services:
postgres:
image: postgres:14
container_name: prefect-postgres
restart: unless-stopped
environment:
POSTGRES_USER: prefect
POSTGRES_PASSWORD: OujaoPhaiS5Eig7ohy3TeiKeecahhe
POSTGRES_DB: prefect
volumes:
- postgres_data:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U prefect"]
interval: 5s
timeout: 5s
retries: 5
networks:
- bbl-shared-net
labels:
com.centurylinklabs.watchtower.enable: "true"
redis:
image: redis:7
container_name: prefect-redis
restart: unless-stopped
volumes:
- redis_data:/data
healthcheck:
test: ["CMD-SHELL", "redis-cli ping"]
networks:
- bbl-shared-net
labels:
com.centurylinklabs.watchtower.enable: "true"
prefect-server:
image: prefecthq/prefect:3-latest
container_name: prefect-server
restart: unless-stopped
depends_on:
postgres:
condition: service_healthy
redis:
condition: service_healthy
environment:
PREFECT_API_DATABASE_CONNECTION_URL: postgresql+asyncpg://prefect:OujaoPhaiS5Eig7ohy3TeiKeecahhe@postgres:5432/prefect
PREFECT_SERVER_API_HOST: 0.0.0.0
PREFECT_SERVER_API_PORT: 4200
PREFECT_UI_API_URL: http://prefect-server:4200/api
PREFECT_SERVER_CSRF_PROTECTION_ENABLED: "true"
PREFECT_SERVER_AUTHENTICATION_ENABLED: "true"
PREFECT_MESSAGING_BROKER: prefect_redis.messaging
PREFECT_MESSAGING_CACHE: prefect_redis.messaging
PREFECT_REDIS_MESSAGING_HOST: redis
PREFECT_REDIS_MESSAGING_PORT: 6379
PREFECT_REDIS_MESSAGING_DB: 0
command: prefect server start --no-services
ports:
- "4200:4200"
networks:
- bbl-shared-net
labels:
com.centurylinklabs.watchtower.enable: "true"
prefect-services:
image: prefecthq/prefect:3-latest
container_name: prefect-services
restart: unless-stopped
depends_on:
postgres:
condition: service_healthy
redis:
condition: service_healthy
environment:
PREFECT_API_DATABASE_CONNECTION_URL: postgresql+asyncpg://prefect:OujaoPhaiS5Eig7ohy3TeiKeecahhe@postgres:5432/prefect
PREFECT_MESSAGING_BROKER: prefect_redis.messaging
PREFECT_MESSAGING_CACHE: prefect_redis.messaging
PREFECT_REDIS_MESSAGING_HOST: redis
PREFECT_REDIS_MESSAGING_PORT: 6379
PREFECT_REDIS_MESSAGING_DB: 0
command: prefect server services start
networks:
- bbl-shared-net
labels:
com.centurylinklabs.watchtower.enable: "true"
prefect-worker:
image: prefecthq/prefect:3-latest
container_name: prefect-worker
restart: unless-stopped
depends_on:
prefect-server:
condition: service_started
environment:
PREFECT_API_URL: http://prefect-server:4200/api
command: prefect worker start --pool local-pool
networks:
- bbl-shared-net
labels:
com.centurylinklabs.watchtower.enable: "true"
- Prefect UI:
https://prefect.bitbylaw.com. - API: Über Kong
https://api.bitbylaw.com/prefect.
Git-Server (Gitea)
docker-compose-gitea.yml:
version: '3.8'
networks:
bbl-shared-net:
external: true
volumes:
gitea-data: {}
services:
gitea:
image: gitea/gitea:latest
container_name: gitea
restart: always
environment:
- USER_UID=1000
- USER_GID=1000
- GITEA__server__ROOT_URL=http://git.bitbylaw.com:3000
- GITEA__database__DB_TYPE=sqlite3
- GITEA__server__SSH_DOMAIN=git.bitbylaw.com
volumes:
- gitea-data:/data
- /etc/timezone:/etc/timezone:ro
- /etc/localtime:/etc/localtime:ro
ports:
- "3000:3000"
- "2222:22"
networks:
- bbl-shared-net
labels:
com.centurylinklabs.watchtower.enable: "true"
- Web-UI:
https://git.bitbylaw.com. - SSH:
git@git.bitbylaw.com(Port 2222). - Integration: Flows werden in Repos wie
admin/prefect-flowsgepusht.
EspoCRM
docker-compose-espocrm.yml:
version: '3.8'
networks:
bbl-shared-net:
external: true
volumes:
espocrm-db:
espocrm:
services:
espocrm-db:
image: mariadb:latest
container_name: espocrm-db
environment:
MARIADB_ROOT_PASSWORD: root_password
MARIADB_DATABASE: espocrm
MARIADB_USER: espocrm
MARIADB_PASSWORD: database_password
volumes:
- espocrm-db:/var/lib/mysql
restart: always
healthcheck:
test: ["CMD", "healthcheck.sh", "--connect", "--innodb_initialized"]
interval: 20s
start_period: 10s
timeout: 10s
retries: 3
networks:
- bbl-shared-net
labels:
com.centurylinklabs.watchtower.enable: "true"
espocrm:
image: espocrm/espocrm:latest
container_name: espocrm
environment:
ESPOCRM_DATABASE_PLATFORM: Mysql
ESPOCRM_DATABASE_HOST: espocrm-db
ESPOCRM_DATABASE_USER: espocrm
ESPOCRM_DATABASE_PASSWORD: database_password
ESPOCRM_ADMIN_USERNAME: admin
ESPOCRM_ADMIN_PASSWORD: password
ESPOCRM_SITE_URL: "http://api.bitbylaw.com:5000/espocrm"
volumes:
- espocrm:/var/www/html
restart: always
depends_on:
espocrm-db:
condition: service_healthy
ports:
- "8080:80"
networks:
- bbl-shared-net
labels:
com.centurylinklabs.watchtower.enable: "true"
espocrm-daemon:
image: espocrm/espocrm:latest
container_name: espocrm-daemon
volumes:
- espocrm:/var/www/html
restart: always
entrypoint: docker-daemon.sh
networks:
- bbl-shared-net
labels:
com.centurylinklabs.watchtower.enable: "true"
espocrm-websocket:
image: espocrm/espocrm:latest
container_name: espocrm-websocket
environment:
ESPOCRM_CONFIG_USE_WEB_SOCKET: "true"
ESPOCRM_CONFIG_WEB_SOCKET_URL: "ws://api.bitbylaw.com:5000/espocrm/ws"
ESPOCRM_CONFIG_WEB_SOCKET_ZERO_M_Q_SUBSCRIBER_DSN: "tcp://*:7777"
ESPOCRM_CONFIG_WEB_SOCKET_ZERO_M_Q_SUBMISSION_DSN: "tcp://espocrm-websocket:7777"
volumes:
- espocrm:/var/www/html
restart: always
entrypoint: docker-websocket.sh
ports:
- "8081:8080"
networks:
- bbl-shared-net
labels:
com.centurylinklabs.watchtower.enable: "true"
- UI:
https://espocrm.bitbylaw.com. - Integration: Über Kong
https://api.bitbylaw.com/espocrm.
Flows erstellen, ändern und deployen
-
Flow erstellen:
- In VS Code: Öffne
~/bbl-code/prefect-flows. - Erstelle z.B.
flows/new_flow.py:from prefect import flow, task @task def say_hello(name: str) -> str: message = f"New Flow: Hello, {name}!" print(message) return message @flow(name="new-flow") def new_flow(name: str = "New World"): result = say_hello(name) return result if __name__ == "__main__": new_flow() - Teste lokal:
python3 flows/new_flow.py.
- In VS Code: Öffne
-
Flow ändern:
- Bearbeite
flows/hello_world.pyodernew_flow.pyin VS Code. - Speichere und teste lokal.
- Bearbeite
-
Commit und Push:
- In VS Code Source Control (Ctrl+Shift+G):
- Stage:
+neben Datei. - Commit: Nachricht eingeben (z.B.
Add new_flow.py) → Häkchen. - Push:
...→ Push.
- Stage:
- Alternativ Terminal:
git add flows/new_flow.py git commit -m "Add new_flow.py" git push origin main
- In VS Code Source Control (Ctrl+Shift+G):
-
Deploy den Flow:
- In VS Code Terminal:
cd ~/bbl-code/prefect-flows prefect deploy - Wähle das Deployment aus
prefect.yaml(z.B.new-flow-deployment). - Prefect pullt den Code aus Gitea in den Worker.
- In VS Code Terminal:
-
Trigger den Flow:
- Finde Deployment-ID:
curl -i https://api.bitbylaw.com/prefect/deployments - Trigger:
curl -i -X POST \ -H "Content-Type: application/json" \ -d '{ "name": "new-flow-run", "parameters": {"name": "New World"}, "state": {"type": "SCHEDULED"} }' \ https://api.bitbylaw.com/prefect/deployments/<deployment-id>/flow_runs - Prüfe:
curl -i https://api.bitbylaw.com/prefect/flow_runs/<flow-run-id>
- Finde Deployment-ID:
Sicherheit und Authentifizierung
- Kong:
basic-authoderkey-authauf Service-Ebene (z.B.prefect-service). - Gitea: SSH-Keys für passwortlosen Zugriff (siehe vorherige Anleitung).
- Traefik: SSL für alle URLs.
- Prefect: Aktiviere Authentifizierung in
PREFECT_SERVER_AUTHENTICATION_ENABLED.
Troubleshooting
- Git: Prüfe Logs in Gitea (
docker logs gitea). - Prefect Deployment: Worker-Logs (
docker logs prefect-worker). - Flow-Run: UI (
https://prefect.bitbylaw.com) oder API-Logs. - Traefik: Logs (
docker logs traefik).
Für Updates pushe Änderungen zu Gitea und deploye neu.