gitdataai/scripts/deploy.js
ZhenYi 1daab11ba4 feat(scripts): add deployment and build utility scripts
Replace old scripting approach with new build, deploy, push,
and uninstall utilities.
2026-05-11 17:08:29 +08:00

99 lines
4.2 KiB
JavaScript

import { execSync } from 'child_process';
import { resolve } from 'path';
import { fileURLToPath } from 'url';
import { dirname } from 'path';
import process from 'process';
const __dirname = dirname(fileURLToPath(import.meta.url));
const ROOT = resolve(__dirname, '..');
// colors
const G = (s) => `\x1b[0;32m${s}\x1b[0m`;
const Y = (s) => `\x1b[1;33m${s}\x1b[0m`;
const R = (s) => `\x1b[0;31m${s}\x1b[0m`;
const log = (msg) => console.log(`${G('[OK]')} ${msg}`);
const warn = (msg) => console.warn(`${Y('[WARN]')} ${msg}`);
const err = (msg) => { console.error(`${R('[ERR]')} ${msg}`); process.exit(1); };
// ── defaults ──
const NAMESPACE = process.env.NAMESPACE || 'app';
const RELEASE = process.env.RELEASE || 'deploy';
const CHART_DIR = process.env.CHART_DIR || resolve(ROOT, 'deploy');
const REGISTRY = process.env.REGISTRY || 'harbor.gitdata.me/gtateam';
const TAG = process.env.TAG || execSync('git rev-parse --short HEAD', { encoding: 'utf8', cwd: ROOT }).trim();
const CONFIG_MAP = process.env.CONFIG_MAP || 'app-env';
const PVC_NAME = process.env.PVC_NAME || 'shared-data';
// ── prereqs ──
try { execSync('helm version --short', { stdio: 'pipe' }); } catch { err('helm not found'); }
try { execSync('kubectl version --client', { stdio: 'pipe' }); } catch { err('kubectl not found'); }
log(execSync('helm version --short', { encoding: 'utf8' }).trim());
log(execSync('kubectl version --client --short 2>/dev/null || kubectl version -o json 2>/dev/null | grep gitVersion', { encoding: 'utf8', shell: true }).trim());
// ── 1. Ensure namespace ──
log(`Ensuring namespace ${NAMESPACE} exists...`);
execSync(`kubectl create namespace "${NAMESPACE}" --dry-run=client -o yaml | kubectl apply -f -`, { stdio: 'inherit' });
// ── 2. Verify prerequisites ──
try { execSync(`kubectl get namespace "${NAMESPACE}"`, { stdio: 'pipe' }); }
catch { err(`Namespace '${NAMESPACE}' not found`); }
try { execSync(`kubectl get configmap "${CONFIG_MAP}" -n "${NAMESPACE}"`, { stdio: 'pipe' }); }
catch { err(`ConfigMap '${CONFIG_MAP}' not found in namespace '${NAMESPACE}'`); }
try { execSync(`kubectl get pvc "${PVC_NAME}" -n "${NAMESPACE}"`, { stdio: 'pipe' }); }
catch { err(`PVC '${PVC_NAME}' not found in namespace '${NAMESPACE}'`); }
// Protect from Helm deletion
execSync(`kubectl annotate configmap "${CONFIG_MAP}" -n "${NAMESPACE}" helm.sh/resource-policy=keep --overwrite`, { stdio: 'inherit' });
execSync(`kubectl annotate pvc "${PVC_NAME}" -n "${NAMESPACE}" helm.sh/resource-policy=keep --overwrite`, { stdio: 'inherit' });
// cert-manager ClusterIssuer
try { execSync('kubectl get clusterissuer cloudflare-acme-cluster-issuer', { stdio: 'pipe' }); }
catch { warn("ClusterIssuer 'cloudflare-acme-cluster-issuer' not found — TLS will fail"); }
log('Prerequisites verified');
// ── 3. Lint ──
log('Linting Helm chart...');
try { execSync(`helm lint "${CHART_DIR}"`, { stdio: 'inherit' }); }
catch { err('Helm lint failed'); }
// ── 4. Deploy ──
log(`Deploying release ${RELEASE} with tag ${TAG}...`);
try {
execSync(
`helm upgrade --install "${RELEASE}" "${CHART_DIR}"` +
` --namespace "${NAMESPACE}"` +
` --set imageRegistry="${REGISTRY}"` +
` --set imageTag="${TAG}"` +
` --set configMapName="${CONFIG_MAP}"` +
` --set pvcName="${PVC_NAME}"` +
` --timeout 5m`,
{ stdio: 'inherit' }
);
} catch {
err(`Deployment FAILED — release preserved for debugging.
Debug commands:
helm status ${RELEASE} -n ${NAMESPACE}
kubectl get pods -n ${NAMESPACE}
kubectl logs -n app <pod-name> --previous
helm rollback ${RELEASE} -n ${NAMESPACE} (rollback to previous release)
helm uninstall ${RELEASE} -n ${NAMESPACE} (remove failed release)`);
}
log(`Release ${RELEASE} deployed successfully`);
// ── 5. Verify ──
log('Checking deployment status...');
execSync(`kubectl get deployments -n "${NAMESPACE}" -l app.kubernetes.io/instance="${RELEASE}"`, { stdio: 'inherit' });
execSync(`kubectl get pods -n "${NAMESPACE}" -l app.kubernetes.io/instance="${RELEASE}"`, { stdio: 'inherit' });
execSync(`kubectl get services -n "${NAMESPACE}" -l app.kubernetes.io/instance="${RELEASE}"`, { stdio: 'inherit' });
execSync(`kubectl get ingress -n "${NAMESPACE}"`, { stdio: 'inherit' });
log('Deployment complete');