mirror of
https://github.com/hanzoai/bootnode.git
synced 2026-10-25 02:31:30 +00:00
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:
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user