fix: deploy.py --initial als einzelner docker-compose Stack + docker-compose.yaml rename
This commit is contained in:
+123
-110
@@ -401,7 +401,8 @@ def ssh_run(cmd: str, timeout: int = 60) -> tuple[int, str]:
|
||||
|
||||
|
||||
def deploy_api(client: CoolifyClient, app_uuid: str, skip_build: bool = False) -> StepResult:
|
||||
"""Deploy or restart the API application via Coolify API."""
|
||||
"""Deploy or restart the application via Coolify API.
|
||||
Uses /api/v1/deploy which works for both dockerfile and dockercompose build packs."""
|
||||
# Set FQDN via PATCH
|
||||
if APP_DOMAIN:
|
||||
print(f" Setting FQDN to {APP_DOMAIN}...")
|
||||
@@ -410,26 +411,24 @@ def deploy_api(client: CoolifyClient, app_uuid: str, skip_build: bool = False) -
|
||||
except Exception as e:
|
||||
print(f" Warning: could not set FQDN: {e}")
|
||||
|
||||
if skip_build:
|
||||
print(" Skip-build mode: restarting application via Coolify API...")
|
||||
print(" Triggering Coolify deploy via /api/v1/deploy...")
|
||||
try:
|
||||
result = client.deploy_application(app_uuid)
|
||||
deploy_uuid = _extract_deploy_uuid(result)
|
||||
resp = httpx.post(
|
||||
f"{client.base_url}/api/v1/deploy",
|
||||
headers=client.headers,
|
||||
json={"uuid": app_uuid},
|
||||
timeout=30,
|
||||
)
|
||||
if resp.status_code == 200:
|
||||
deployments = resp.json().get("deployments", [])
|
||||
if deployments:
|
||||
deploy_uuid = deployments[0].get("deployment_uuid", "")
|
||||
if deploy_uuid:
|
||||
print(f" Deploy queued: {deploy_uuid[:12]}")
|
||||
return _wait_deployment(client, deploy_uuid, timeout=300)
|
||||
return _wait_deployment(client, deploy_uuid, timeout=600)
|
||||
return StepResult(True, "Deploy triggered (no UUID returned)")
|
||||
except Exception as e:
|
||||
return StepResult(False, f"Deploy trigger failed: {e}")
|
||||
|
||||
print(" Triggering Coolify build & deploy for API...")
|
||||
try:
|
||||
result = client.deploy_application(app_uuid)
|
||||
deploy_uuid = _extract_deploy_uuid(result)
|
||||
if not deploy_uuid:
|
||||
return StepResult(False, "No deployment UUID returned from Coolify")
|
||||
print(f" Deploy queued: {deploy_uuid[:12]}")
|
||||
return _wait_deployment(client, deploy_uuid, timeout=300)
|
||||
else:
|
||||
return StepResult(False, f"Deploy failed: {resp.status_code} {resp.text[:200]}")
|
||||
except Exception as e:
|
||||
return StepResult(False, f"Deploy trigger failed: {e}")
|
||||
|
||||
@@ -883,6 +882,7 @@ POSTGRES_COMPOSE = (
|
||||
"services:\n"
|
||||
" postgres:\n"
|
||||
" image: pgvector/pgvector:pg16\n"
|
||||
" container_name: crm-postgres\n"
|
||||
" restart: unless-stopped\n"
|
||||
" environment:\n"
|
||||
" POSTGRES_USER: ${DB_USER}\n"
|
||||
@@ -906,6 +906,7 @@ REDIS_COMPOSE = (
|
||||
"services:\n"
|
||||
" redis:\n"
|
||||
" image: redis:7-alpine\n"
|
||||
" container_name: crm-redis\n"
|
||||
" restart: unless-stopped\n"
|
||||
" command: redis-server --requirepass ${REDIS_PASSWORD}\n"
|
||||
" volumes:\n"
|
||||
@@ -1084,119 +1085,131 @@ def deploy_initial() -> int:
|
||||
environment_name = os.environ.get("COOLIFY_ENVIRONMENT", "production")
|
||||
server_uuid = os.environ.get("COOLIFY_SERVER_UUID", "")
|
||||
|
||||
# Step 1: Create PostgreSQL service
|
||||
print("\n[1/7] Creating PostgreSQL service...")
|
||||
pg_uuid = create_service(client, project_uuid, environment_name, server_uuid,
|
||||
POSTGRES_COMPOSE, "crm-postgres")
|
||||
if pg_uuid:
|
||||
print(f" PostgreSQL service created: {pg_uuid[:12]}")
|
||||
set_service_envs(client, pg_uuid, get_postgres_envs())
|
||||
client.deploy_application(pg_uuid)
|
||||
time.sleep(10)
|
||||
steps.append(("PostgreSQL service", StepResult(True, f"Created: {pg_uuid[:12]}")))
|
||||
else:
|
||||
steps.append(("PostgreSQL service", StepResult(False, "Failed to create")))
|
||||
print_summary(steps)
|
||||
return 1
|
||||
_print_result(steps[-1][1])
|
||||
# ─── Single docker-compose application (like the original working app) ──
|
||||
# All 4 containers (postgres, redis, crm-app, crm-worker) in one stack.
|
||||
# Coolify reads docker-compose.yaml from the Git repo, builds images, all
|
||||
# containers share one network. Service names work as DNS names. No manual
|
||||
# network configuration needed. No cryptic container names.
|
||||
|
||||
# Step 2: Create Redis service
|
||||
print("\n[2/7] Creating Redis service...")
|
||||
redis_uuid = create_service(client, project_uuid, environment_name, server_uuid,
|
||||
REDIS_COMPOSE, "crm-redis")
|
||||
if redis_uuid:
|
||||
print(f" Redis service created: {redis_uuid[:12]}")
|
||||
set_service_envs(client, redis_uuid, get_redis_envs())
|
||||
client.deploy_application(redis_uuid)
|
||||
time.sleep(10)
|
||||
steps.append(("Redis service", StepResult(True, f"Created: {redis_uuid[:12]}")))
|
||||
else:
|
||||
steps.append(("Redis service", StepResult(False, "Failed to create")))
|
||||
print_summary(steps)
|
||||
return 1
|
||||
_print_result(steps[-1][1])
|
||||
|
||||
# Step 3: Create API application
|
||||
print("\n[3/7] Creating API application...")
|
||||
api_uuid = create_api_application(client, project_uuid, environment_name, server_uuid)
|
||||
if api_uuid:
|
||||
print(f" API application created: {api_uuid[:12]}")
|
||||
set_application_envs(client, api_uuid, get_api_envs())
|
||||
# Set FQDN
|
||||
if APP_DOMAIN:
|
||||
client.update_application(api_uuid, domains=APP_DOMAIN)
|
||||
steps.append(("API application", StepResult(True, f"Created: {api_uuid[:12]}")))
|
||||
else:
|
||||
steps.append(("API application", StepResult(False, "Failed to create")))
|
||||
print_summary(steps)
|
||||
return 1
|
||||
_print_result(steps[-1][1])
|
||||
|
||||
# Step 4: Create Worker service (with API image reference)
|
||||
print("\n[4/7] Creating Worker service...")
|
||||
worker_compose = generate_worker_compose(api_uuid, "PLACEHOLDER")
|
||||
# For initial creation, use a temporary compose — Coolify will assign UUID
|
||||
# We'll update it after creation with the real UUID
|
||||
worker_uuid = create_service(client, project_uuid, environment_name, server_uuid,
|
||||
worker_compose, WORKER_NAME)
|
||||
if worker_uuid:
|
||||
print(f" Worker service created: {worker_uuid[:12]}")
|
||||
# Update compose with real worker UUID
|
||||
real_compose = generate_worker_compose(api_uuid, worker_uuid)
|
||||
client.update_service(worker_uuid, real_compose)
|
||||
# Set connect_to_docker_network
|
||||
httpx.patch(
|
||||
f"{client.base_url}/api/v1/services/{worker_uuid}",
|
||||
# Step 1: Create application via private-deploy-key (with Git repo)
|
||||
print("\n[1/4] Creating docker-compose application...")
|
||||
try:
|
||||
resp = httpx.post(
|
||||
f"{client.base_url}/api/v1/applications/private-deploy-key",
|
||||
headers=client.headers,
|
||||
json={"connect_to_docker_network": True},
|
||||
json={
|
||||
"project_uuid": project_uuid,
|
||||
"environment_name": environment_name,
|
||||
"server_uuid": server_uuid,
|
||||
"name": APP_NAME,
|
||||
"git_repository": API_GIT_REPO,
|
||||
"git_branch": API_GIT_BRANCH,
|
||||
"private_key_uuid": os.environ.get("COOLIFY_PRIVATE_KEY_UUID", ""),
|
||||
"build_pack": "dockerfile",
|
||||
"ports_exposes": "8000",
|
||||
},
|
||||
timeout=30,
|
||||
)
|
||||
set_service_envs(client, worker_uuid, get_worker_envs())
|
||||
steps.append(("Worker service", StepResult(True, f"Created: {worker_uuid[:12]}")))
|
||||
if resp.status_code == 201:
|
||||
app_uuid = resp.json().get("uuid")
|
||||
print(f" Application created: {app_uuid[:12]}")
|
||||
steps.append(("Create application", StepResult(True, f"Created: {app_uuid[:12]}")))
|
||||
else:
|
||||
steps.append(("Worker service", StepResult(False, "Failed to create")))
|
||||
steps.append(("Create application", StepResult(False, f"{resp.status_code}: {resp.text[:200]}")))
|
||||
print_summary(steps)
|
||||
return 1
|
||||
except Exception as e:
|
||||
steps.append(("Create application", StepResult(False, str(e))))
|
||||
print_summary(steps)
|
||||
return 1
|
||||
_print_result(steps[-1][1])
|
||||
|
||||
# Step 5: Deploy API (builds image + runs migrations via prestart.sh)
|
||||
print("\n[5/7] Deploying API (build + migrations)...")
|
||||
# Step 2: PATCH to dockercompose build_pack (Coolify reads docker-compose.yaml from Git)
|
||||
print("\n[2/4] Configuring docker-compose build pack...")
|
||||
try:
|
||||
result = client.deploy_application(api_uuid)
|
||||
deploy_uuid = _extract_deploy_uuid(result)
|
||||
if deploy_uuid:
|
||||
resp = httpx.patch(
|
||||
f"{client.base_url}/api/v1/applications/{app_uuid}",
|
||||
headers=client.headers,
|
||||
json={"build_pack": "dockercompose"},
|
||||
timeout=30,
|
||||
)
|
||||
if resp.status_code == 200:
|
||||
print(" Build pack set to dockercompose")
|
||||
steps.append(("Configure compose", StepResult(True, "dockercompose build pack set")))
|
||||
else:
|
||||
steps.append(("Configure compose", StepResult(False, f"{resp.status_code}: {resp.text[:200]}")))
|
||||
print_summary(steps)
|
||||
return 1
|
||||
except Exception as e:
|
||||
steps.append(("Configure compose", StepResult(False, str(e))))
|
||||
print_summary(steps)
|
||||
return 1
|
||||
_print_result(steps[-1][1])
|
||||
|
||||
# Step 3: Set environment variables (domain, admin credentials, secrets)
|
||||
print("\n[3/4] Setting environment variables...")
|
||||
envs = [
|
||||
{"key": "POSTGRES_USER", "value": os.environ.get("DB_USER", "crm_user")},
|
||||
{"key": "POSTGRES_DB", "value": DB_NAME},
|
||||
{"key": "DB_PASSWORD", "value": DB_PASSWORD},
|
||||
{"key": "REDIS_PASSWORD", "value": REDIS_PASSWORD},
|
||||
{"key": "SECRET_KEY", "value": SECRET_KEY},
|
||||
{"key": "ENVIRONMENT", "value": os.environ.get("ENVIRONMENT", "production")},
|
||||
{"key": "LOG_LEVEL", "value": os.environ.get("LOG_LEVEL", "INFO")},
|
||||
{"key": "SESSION_COOKIE_SECURE", "value": "true"},
|
||||
{"key": "STORAGE_PATH", "value": os.environ.get("STORAGE_PATH", "/data/storage")},
|
||||
{"key": "CORS_ORIGINS", "value": APP_DOMAIN},
|
||||
{"key": "FRONTEND_URL", "value": APP_DOMAIN},
|
||||
{"key": "ADMIN_EMAIL", "value": os.environ.get("ADMIN_EMAIL", "admin@media-on.de")},
|
||||
{"key": "ADMIN_PASSWORD", "value": os.environ.get("ADMIN_PASSWORD", "Admin123!")},
|
||||
]
|
||||
try:
|
||||
resp = httpx.patch(
|
||||
f"{client.base_url}/api/v1/applications/{app_uuid}/envs/bulk",
|
||||
headers=client.headers,
|
||||
json={"data": envs},
|
||||
timeout=30,
|
||||
)
|
||||
if resp.status_code in (200, 201):
|
||||
print(f" {len(envs)} environment variables set")
|
||||
steps.append(("Set envs", StepResult(True, f"{len(envs)} envs set")))
|
||||
else:
|
||||
steps.append(("Set envs", StepResult(False, f"{resp.status_code}: {resp.text[:200]}")))
|
||||
except Exception as e:
|
||||
steps.append(("Set envs", StepResult(False, str(e))))
|
||||
_print_result(steps[-1][1])
|
||||
|
||||
# Step 4: Deploy via /api/v1/deploy (works for dockercompose build_pack)
|
||||
print("\n[4/4] Deploying docker-compose stack...")
|
||||
try:
|
||||
resp = httpx.post(
|
||||
f"{client.base_url}/api/v1/deploy",
|
||||
headers=client.headers,
|
||||
json={"uuid": app_uuid},
|
||||
timeout=30,
|
||||
)
|
||||
if resp.status_code == 200:
|
||||
deploy_data = resp.json()
|
||||
deployments = deploy_data.get("deployments", [])
|
||||
if deployments:
|
||||
deploy_uuid = deployments[0].get("deployment_uuid", "")
|
||||
print(f" Deploy queued: {deploy_uuid[:12]}")
|
||||
r = _wait_deployment(client, deploy_uuid, timeout=300)
|
||||
r = _wait_deployment(client, deploy_uuid, timeout=600)
|
||||
else:
|
||||
r = StepResult(True, "Deploy triggered (no UUID)")
|
||||
else:
|
||||
r = StepResult(False, f"{resp.status_code}: {resp.text[:200]}")
|
||||
except Exception as e:
|
||||
r = StepResult(False, f"Deploy failed: {e}")
|
||||
steps.append(("API deploy", r))
|
||||
steps.append(("Deploy", r))
|
||||
_print_result(r)
|
||||
if not r.success:
|
||||
print_summary(steps)
|
||||
return 1
|
||||
|
||||
# Step 6: Deploy Worker
|
||||
print("\n[6/7] Deploying Worker...")
|
||||
tag_code, tag_output = ssh_run(
|
||||
f'docker images --format "{{{{.Repository}}}}:{{{{.Tag}}}}" | '
|
||||
f'grep "^{api_uuid}:" | grep -v latest | head -1 | '
|
||||
f'xargs -I{{}} docker tag {{}} {api_uuid}:latest'
|
||||
)
|
||||
result = client.deploy_application(worker_uuid)
|
||||
deploy_uuid = _extract_deploy_uuid(result)
|
||||
if deploy_uuid:
|
||||
dep_result = _wait_deployment(client, deploy_uuid, timeout=120)
|
||||
steps.append(("Worker deploy", dep_result))
|
||||
else:
|
||||
wr = _wait_service_healthy(client, worker_uuid, timeout=120)
|
||||
steps.append(("Worker deploy", wr))
|
||||
_print_result(steps[-1][1])
|
||||
|
||||
# Step 7: Verification
|
||||
print("\n[7/7] Running verification...")
|
||||
verify_results = run_verification(client, worker_uuid=worker_uuid)
|
||||
# Verification
|
||||
print("\n[5/5] Running verification...")
|
||||
verify_results = run_verification(client, worker_uuid=None)
|
||||
steps.extend(verify_results)
|
||||
|
||||
all_ok = print_summary(steps)
|
||||
|
||||
Reference in New Issue
Block a user