deploy.py: ENV-Variablen statt hardcoded Passwoerter + .env auf Server schreiben

This commit is contained in:
Agent Zero
2026-08-03 01:17:25 +02:00
parent c63ab9b45a
commit 5eec2fdde8
+78 -31
View File
@@ -56,7 +56,8 @@ APP_DOMAIN = os.environ.get("APP_DOMAIN", "https://crm.media-on.de")
LOGIN_EMAIL = os.environ.get("LOGIN_EMAIL", "admin@media-on.de")
LOGIN_PASSWORD = os.environ.get("LOGIN_PASSWORD", "Admin123!")
# Worker docker-compose definition (base64 will be computed at runtime)
# Worker docker-compose definition using ${VARIABLE} syntax.
# Secrets are read from the .env file on the server (written by write_worker_env).
WORKER_COMPOSE_YAML = """\
services:
worker:
@@ -65,25 +66,62 @@ services:
entrypoint:
- /app/worker.sh
environment:
DATABASE_URL: 'postgresql+asyncpg://crm_worker:4B6X2wlfbIx-PyaG8kGutsatdLbjdBUI@crm-postgres:5432/crm_db'
WORKER_DATABASE_URL: 'postgresql+asyncpg://crm_worker:4B6X2wlfbIx-PyaG8kGutsatdLbjdBUI@crm-postgres:5432/crm_db'
MIGRATION_DATABASE_URL: 'postgresql+asyncpg://crm_user:4B6X2wlfbIx-PyaG8kGutsatdLbjdBUI@crm-postgres:5432/crm_db'
AUTH_DATABASE_URL: 'postgresql+asyncpg://crm_auth:4B6X2wlfbIx-PyaG8kGutsatdLbjdBUI@crm-postgres:5432/crm_db'
REDIS_URL: 'redis://default:lAjCaTf3XFP5XSaPJ1HElgLAJhQQswLT@crm-redis:6379/0'
SECRET_KEY: 'vVdAnvyc-ob4myE5D1rAYn-SovzoBfQLP1z4wmWteTmFPV_lveCGIn2upNoiP590'
ENVIRONMENT: production
STORAGE_PATH: /data/storage
DATABASE_URL: 'postgresql+asyncpg://crm_worker:${DB_PASSWORD}@crm-postgres:5432/crm_db'
WORKER_DATABASE_URL: 'postgresql+asyncpg://crm_worker:${DB_PASSWORD}@crm-postgres:5432/crm_db'
MIGRATION_DATABASE_URL: 'postgresql+asyncpg://crm_user:${DB_PASSWORD}@crm-postgres:5432/crm_db'
AUTH_DATABASE_URL: 'postgresql+asyncpg://crm_auth:${DB_PASSWORD}@crm-postgres:5432/crm_db'
REDIS_URL: 'redis://default:${REDIS_PASSWORD}@crm-redis:6379/0'
SECRET_KEY: ${SECRET_KEY}
ENVIRONMENT: ${ENVIRONMENT}
STORAGE_PATH: ${STORAGE_PATH}
COOLIFY_RESOURCE_UUID: asxqaq3566to108xordck0ff
COOLIFY_CONTAINER_NAME: worker-asxqaq3566to108xordck0ff
SERVICE_NAME_WORKER: worker
volumes:
- 'leocrm-worker-storage:/data/storage'
- 'asxqaq3566to108xordck0ff_leocrm-worker-storage:/data/storage'
networks:
- coolify
- asxqaq3566to108xordck0ff
container_name: worker-asxqaq3566to108xordck0ff
labels:
- coolify.managed=true
- coolify.version=4.0.0-beta.470
- coolify.serviceId=277
- coolify.type=service
- coolify.name=worker-asxqaq3566to108xordck0ff
- coolify.resourceName=leocrm-worker
- coolify.projectName=crm
- coolify.serviceName=worker
- coolify.environmentName=production
- coolify.pullRequestId=0
- coolify.service.subId=500
- coolify.service.subType=application
- coolify.service.subName=worker
env_file:
- .env
volumes:
leocrm-worker-storage:
name: leocrm-worker-storage
asxqaq3566to108xordck0ff_leocrm-worker-storage:
name: asxqaq3566to108xordck0ff_leocrm-worker-storage
networks:
coolify:
external: true
name: coolify
volumes:
leocrm-worker-storage:
name: leocrm-worker-storage
asxqaq3566to108xordck0ff:
name: asxqaq3566to108xordck0ff
external: true
"""
# Worker .env file content (written to server via SSH).
# For different deployments (dev/staging/prod), change these values.
WORKER_ENV_CONTENT = """\
SERVICE_NAME_WORKER=worker
DB_PASSWORD=4B6X2wlfbIx-PyaG8kGutsatdLbjdBUI
REDIS_PASSWORD=lAjCaTf3XFP5XSaPJ1HElgLAJhQQswLT
SECRET_KEY=vVdAnvyc-ob4myE5D1rAYn-SovzoBfQLP1z4wmWteTmFPV_lveCGIn2upNoiP590
ENVIRONMENT=production
STORAGE_PATH=/data/storage
"""
@@ -262,26 +300,35 @@ def deploy_api(client: CoolifyClient, skip_build: bool = False) -> StepResult:
def deploy_worker(client: CoolifyClient, skip_build: bool = False) -> StepResult:
"""Deploy the worker service via Coolify API.
The worker is a Coolify Service that uses the same Docker image as the
API application (stvabl4vaqru7jclx4ittzr3:latest). After the API is
rebuilt, the worker needs a deploy to pick up the new image.
Uses POST /deploy with the service UUID — this is the correct way to
deploy a Coolify Service (not restart, which only restarts an existing
container, and not start, which fails if the container was removed).
We also ensure:
1. connect_to_docker_network is True (so the worker joins the coolify
network and can reach crm-redis and crm-postgres)
2. The :latest tag points to the most recent build (Coolify tags with
commit hashes, not :latest)
Steps:
1. Write .env file to server (secrets for ${VARIABLE} substitution)
2. Update service compose (with ${VARIABLE} syntax, not hardcoded secrets)
3. Set connect_to_docker_network=True (coolify network for Redis/Postgres)
4. Tag latest API image as :latest (Coolify uses commit-hash tags)
5. Deploy via POST /deploy (creates new container)
6. Wait for healthy
"""
print(" Deploying worker service via Coolify API...")
try:
# Step 0: Ensure connect_to_docker_network is True
# Step 1: Write .env file to server
print(" Writing .env file to server...")
import base64
env_encoded = base64.b64encode(WORKER_ENV_CONTENT.encode()).decode()
env_code, env_output = ssh_run(
f'echo {env_encoded} | base64 -d > '
f'/data/coolify/services/{WORKER_UUID}/.env && echo ENV_OK'
)
if env_code != 0 or 'ENV_OK' not in env_output:
print(f" Warning: could not write .env ({env_output.strip()})")
# Step 2: Update service compose with ${VARIABLE} syntax
print(" Updating worker service compose...")
client.update_service(WORKER_UUID, WORKER_COMPOSE_YAML)
time.sleep(2)
# Step 3: Set connect_to_docker_network=True
print(" Ensuring coolify network connection...")
# Set connect_to_docker_network via API (does not overwrite compose)
import httpx
resp = httpx.patch(
f"{client.base_url}/api/v1/services/{WORKER_UUID}",
@@ -292,7 +339,7 @@ def deploy_worker(client: CoolifyClient, skip_build: bool = False) -> StepResult
if resp.status_code != 200:
print(f" Warning: could not set connect_to_docker_network ({resp.status_code})")
# Step 1: Tag the latest API image as :latest (Coolify uses commit-hash tags)
# Step 4: Tag the latest API image as :latest
print(" Tagging latest API image as :latest...")
tag_code, tag_output = ssh_run(
'docker images --format "{{.Repository}}:{{.Tag}}" | '
@@ -302,7 +349,7 @@ def deploy_worker(client: CoolifyClient, skip_build: bool = False) -> StepResult
if tag_code != 0:
print(f" Warning: could not tag :latest ({tag_output.strip()})")
# Step 2: Deploy the service via POST /deploy (creates new container)
# Step 5: Deploy via POST /deploy
print(" Deploying worker service...")
result = client.deploy_application(WORKER_UUID)
deploy_uuid = _extract_deploy_uuid(result)
@@ -314,7 +361,7 @@ def deploy_worker(client: CoolifyClient, skip_build: bool = False) -> StepResult
else:
print(" No deployment UUID returned, waiting for healthy...")
# Step 3: Wait for service to be healthy
# Step 6: Wait for healthy
return _wait_service_healthy(client, WORKER_UUID, timeout=120)
except Exception as e: