ci: remove direct deployment — managed by universe E2E-gated pipeline

- Remove deploy job (kubectl to bootnode-k8s + lux-k8s)
- Remove KMS credential fetching, doctl, manifest apply steps
- Images still build and push to GHCR via reusable workflow
This commit is contained in:
2026-03-16 18:22:01 -07:00
parent 1e422e81f1
commit da88c46607
+4 -183
View File
@@ -1,12 +1,13 @@
# Deployment managed by hanzoai/universe — this workflow only builds and pushes images
name: Docker Release
on:
# Only deploy after CI passes on main
# Only build after CI passes on main
workflow_run:
workflows: ["CI"]
types: [completed]
branches: [main]
# Tags deploy directly (release cuts)
# Tags build directly (release cuts)
push:
tags: ["v*"]
# Manual override
@@ -24,7 +25,7 @@ jobs:
github.event_name != 'workflow_run' ||
github.event.workflow_run.conclusion == 'success'
steps:
- run: echo "CI passed — proceeding with Docker build and deploy"
- run: echo "CI passed — proceeding with Docker build"
# Build API image via standard Hanzo reusable workflow
api:
@@ -35,7 +36,6 @@ jobs:
context: ./api
dockerfile: Dockerfile
platforms: "linux/amd64"
deploy: false # Custom deploy below (bootnode-k8s, not hanzo-k8s)
secrets: inherit
# Build Web image via standard Hanzo reusable workflow
@@ -47,183 +47,4 @@ jobs:
context: ./web
dockerfile: Dockerfile
platforms: "linux/amd64"
deploy: false # Custom deploy below
secrets: inherit
# Deploy to bootnode-k8s + lux-k8s (separate DOKS clusters)
# Secrets fetched from Hanzo KMS at runtime via Universal Auth
deploy:
runs-on: ubuntu-latest
needs: [api, web]
if: >-
github.event_name != 'workflow_run' ||
github.event.workflow_run.head_branch == 'main'
environment: production
steps:
- uses: actions/checkout@v4
- name: Install kubectl
uses: azure/setup-kubectl@v4
# Fetch deploy credentials from Hanzo KMS (only Universal Auth creds in GitHub Secrets)
- name: Fetch deploy credentials from KMS
id: kms
env:
KMS_CLIENT_ID: ${{ secrets.KMS_CLIENT_ID }}
KMS_CLIENT_SECRET: ${{ secrets.KMS_CLIENT_SECRET }}
HANZO_API_KEY: ${{ secrets.HANZO_API_KEY }}
KMS_ENDPOINT: ${{ vars.KMS_ENDPOINT || 'https://kms.hanzo.ai' }}
run: |
# Auth: Universal Auth (preferred) or legacy API key
if [ -n "${KMS_CLIENT_ID}" ] && [ -n "${KMS_CLIENT_SECRET}" ]; then
echo "Authenticating to KMS via Universal Auth..."
HANZO_API_KEY=$(curl -sf "${KMS_ENDPOINT}/api/v1/auth/universal-auth/login" \
-H "Content-Type: application/json" \
-d "{\"clientId\":\"${KMS_CLIENT_ID}\",\"clientSecret\":\"${KMS_CLIENT_SECRET}\"}" | jq -r '.accessToken')
fi
if [ -z "${HANZO_API_KEY}" ]; then
echo "::warning::No KMS credentials — falling back to GitHub Secrets"
echo "kms_available=false" >> "$GITHUB_OUTPUT"
exit 0
fi
echo "kms_available=true" >> "$GITHUB_OUTPUT"
# Fetch deploy secrets from KMS /deploy path
response=$(curl -sf "${KMS_ENDPOINT}/api/v3/secrets/raw?workspaceId=${{ vars.KMS_WORKSPACE_ID || 'bootnode' }}&secretPath=/deploy&environment=prod" \
-H "Authorization: Bearer ${HANZO_API_KEY}" 2>/dev/null || echo "")
if [ -z "$response" ]; then
echo "::warning::KMS fetch returned empty — falling back to GitHub Secrets"
echo "kms_available=false" >> "$GITHUB_OUTPUT"
exit 0
fi
# Extract deploy credentials and mask them
extract_secret() {
local key="$1"
local val
val=$(echo "$response" | jq -r ".secrets[] | select(.secretKey==\"${key}\") | .secretValue // empty")
if [ -n "$val" ]; then
echo "::add-mask::${val}"
echo "${key}=${val}" >> "$GITHUB_OUTPUT"
fi
}
extract_secret "DO_API_TOKEN"
extract_secret "K8S_CLUSTER_NAME"
extract_secret "LUX_K8S_CLUSTER_NAME"
# Install doctl with token from KMS (fallback to GitHub Secret)
- name: Install doctl
uses: digitalocean/action-doctl@v2
with:
token: ${{ steps.kms.outputs.DO_API_TOKEN || secrets.DIGITALOCEAN_ACCESS_TOKEN }}
# --- bootnode-k8s cluster ---
- name: Save kubeconfig (bootnode-k8s)
run: |
CLUSTER="${{ steps.kms.outputs.K8S_CLUSTER_NAME || secrets.K8S_CLUSTER_NAME }}"
echo "::add-mask::${CLUSTER}"
doctl kubernetes cluster kubeconfig save "${CLUSTER}"
- name: Refresh GHCR pull secret (bootnode-k8s)
env:
GHCR_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
kubectl create secret docker-registry ghcr-secret \
--docker-server=ghcr.io \
--docker-username=${{ github.actor }} \
--docker-password="${GHCR_TOKEN}" \
-n bootnode \
--dry-run=client -o yaml | kubectl apply -f -
- name: Apply manifests (bootnode-k8s)
run: |
kubectl apply -f infra/k8s/namespace.yaml
kubectl apply -f infra/k8s/external-secrets.yaml || echo "::warning::external-secrets CRDs not installed, skipping"
kubectl apply -f infra/k8s/secrets.yaml
kubectl apply -f infra/k8s/api-deployment.yaml
kubectl apply -f infra/k8s/web-deployments.yaml
kubectl apply -f infra/k8s/ingress.yaml
- name: Rollout API (bootnode-k8s)
continue-on-error: true
run: |
kubectl rollout restart deployment/bootnode-api -n bootnode
kubectl rollout status deployment/bootnode-api -n bootnode --timeout=300s
- name: Cleanup stale pods (bootnode-k8s)
run: |
# Delete pods stuck in ImagePullBackOff/ErrImagePull from previous failed rollouts
for pod in $(kubectl get pods -n bootnode --field-selector status.phase=Pending -o name 2>/dev/null); do
echo "Deleting stale $pod"
kubectl delete "$pod" -n bootnode --force --grace-period=0 2>/dev/null || true
done
- name: Rollout web portals (bootnode-k8s)
run: |
for brand in hanzo lux zoo pars; do
kubectl rollout restart deployment/bootnode-web-${brand} -n bootnode || true
kubectl rollout status deployment/bootnode-web-${brand} -n bootnode --timeout=300s || true
done
- name: Diagnose pod failures (bootnode-k8s)
if: always()
run: |
echo "=== Pod status ==="
kubectl get pods -n bootnode -l component=frontend -o wide 2>/dev/null || true
echo ""
echo "=== Recent events ==="
kubectl get events -n bootnode --sort-by='.lastTimestamp' --field-selector type!=Normal 2>/dev/null | tail -30 || true
echo ""
echo "=== Failing pod logs (last 50 lines) ==="
for pod in $(kubectl get pods -n bootnode -l component=frontend --field-selector status.phase!=Running -o name 2>/dev/null | head -3); do
echo "--- $pod ---"
kubectl logs "$pod" -n bootnode --tail=50 2>/dev/null || true
done
echo ""
echo "=== Describe failing pods ==="
for pod in $(kubectl get pods -n bootnode -l component=frontend -o json 2>/dev/null | jq -r '.items[] | select(.status.phase != "Running" or (.status.containerStatuses[]? | .ready != true)) | .metadata.name' 2>/dev/null | head -3); do
echo "--- $pod ---"
kubectl describe pod "$pod" -n bootnode 2>/dev/null | grep -A5 "State:\|Reason:\|Message:\|Events:" || true
done
- name: Cleanup legacy deployments (bootnode-k8s)
run: |
for old in $(kubectl get deployments -n bootnode -o name | grep 'web3-platform'); do
echo "Deleting legacy $old"
kubectl delete $old -n bootnode --ignore-not-found
done
for old in $(kubectl get svc -n bootnode -o name | grep 'web3-platform'); do
echo "Deleting legacy $old"
kubectl delete $old -n bootnode --ignore-not-found
done
for old in $(kubectl get ingress -n bootnode -o name | grep 'web3-platform'); do
echo "Deleting legacy $old"
kubectl delete $old -n bootnode --ignore-not-found
done
# --- lux-k8s cluster (optional) ---
- name: Save kubeconfig (lux-k8s)
id: lux_kubeconfig
continue-on-error: true
run: |
CLUSTER="${{ steps.kms.outputs.LUX_K8S_CLUSTER_NAME || secrets.LUX_K8S_CLUSTER_NAME }}"
if [ -z "${CLUSTER}" ]; then
echo "::warning::LUX_K8S_CLUSTER_NAME not set — skipping operator deploy"
exit 0
fi
echo "::add-mask::${CLUSTER}"
doctl kubernetes cluster kubeconfig save "${CLUSTER}"
echo "connected=true" >> "$GITHUB_OUTPUT"
- name: Deploy operator to lux-k8s
if: steps.lux_kubeconfig.outputs.connected == 'true'
run: |
kubectl apply -f infra/k8s/lux/crds.yaml
kubectl apply -f infra/k8s/lux/rbac.yaml
kubectl apply -f infra/k8s/lux/operator-deployment.yaml
kubectl rollout status deployment/bootnode-operator -n bootnode-system --timeout=120s