diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index b6590a3..a48d8b1 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -87,7 +87,7 @@ jobs: uses: docker/login-action@v4 with: registry: ${{ env.REGISTRY }} - username: admin + username: ${{ secrets.HARBOR_USERNAME }} password: ${{ secrets.HARBOR_PASSWORD }} - name: Set up Docker Buildx @@ -121,7 +121,7 @@ jobs: uses: docker/login-action@v4 with: registry: ${{ env.REGISTRY }} - username: admin + username: ${{ secrets.HARBOR_USERNAME }} password: ${{ secrets.HARBOR_PASSWORD }} - name: Set up Docker Buildx @@ -153,7 +153,7 @@ jobs: uses: docker/login-action@v4 with: registry: ${{ env.REGISTRY }} - username: admin + username: ${{ secrets.HARBOR_USERNAME }} password: ${{ secrets.HARBOR_PASSWORD }} - name: Set up Docker Buildx diff --git a/pipelines/harbor/deploy.sh b/pipelines/harbor/deploy.sh new file mode 100755 index 0000000..cfe50bc --- /dev/null +++ b/pipelines/harbor/deploy.sh @@ -0,0 +1,191 @@ +#!/usr/bin/env bash +set -euo pipefail + +# deploy.sh — Deploy Harbor container registry to Kubernetes +# Run from gremlin-1: bash ~/sources/kube/harbor/deploy.sh + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" + +echo "=== Harbor Container Registry Deploy ===" +echo "" + +# ------------------------------------------------------- +# 1. Create namespace +# ------------------------------------------------------- +echo "--- Step 1: Creating namespace ---" +kubectl create namespace harbor-service --dry-run=client -o yaml | kubectl apply -f - +echo " ✓ harbor-service namespace ready" +echo "" + +# ------------------------------------------------------- +# 2. Proxy CA cert (for Squid SSL bump) +# ------------------------------------------------------- +echo "--- Step 2: Proxy CA cert ---" +CA_CERT_PATH="/tmp/harbor-home.crt" +if curl -sf http://192.168.42.1/home.crt -o "$CA_CERT_PATH" 2>/dev/null; then + if ! kubectl get configmap proxy-ca-cert -n harbor-service > /dev/null 2>&1; then + kubectl create configmap proxy-ca-cert --from-file=ca.crt="$CA_CERT_PATH" -n harbor-service + echo " ✓ proxy-ca-cert created" + else + echo " ✓ proxy-ca-cert already exists" + fi +else + echo " ⚠ Could not fetch CA cert (non-fatal)" +fi +echo "" + +# ------------------------------------------------------- +# 3. Create NFS directories (requires root for mount) +# ------------------------------------------------------- +echo "--- Step 3: Ensuring NFS directories ---" +if [ "$(id -u)" -eq 0 ]; then + mkdir -p /tmp/harbor-nfs-init + mount -t nfs 192.168.42.8:/volume1/Kubernetes/harbor /tmp/harbor-nfs-init 2>/dev/null || true + mkdir -p /tmp/harbor-nfs-init/data/registry + mkdir -p /tmp/harbor-nfs-init/data/redis + mkdir -p /tmp/harbor-nfs-init/data/jobservice + mkdir -p /tmp/harbor-nfs-init/data/trivy + umount /tmp/harbor-nfs-init 2>/dev/null || true + rmdir /tmp/harbor-nfs-init 2>/dev/null || true + echo " ✓ NFS directories ready" +else + echo " ⚠ Not root — skipping NFS dir creation (dirs may already exist)" +fi +echo "" + +# ------------------------------------------------------- +# 4. Apply PVs and PVCs +# ------------------------------------------------------- +echo "--- Step 4: Applying PVs and PVCs ---" +kubectl apply -f "$SCRIPT_DIR/../pvs/harbor-pv.yaml" +kubectl apply -f "$SCRIPT_DIR/pvcs.yaml" +echo " ✓ PVs and PVCs applied" +echo "" + +# ------------------------------------------------------- +# 5. Remove old plain Docker Registry ingress +# ------------------------------------------------------- +echo "--- Step 5: Checking old registry ingress ---" +if kubectl get ingress registry-ingress -n git-server > /dev/null 2>&1; then + echo " Removing old registry ingress from git-server namespace..." + kubectl delete ingress registry-ingress -n git-server + echo " ✓ Old registry ingress removed" +else + echo " ✓ No old registry ingress found" +fi +echo "" + +# ------------------------------------------------------- +# 6. Install/upgrade Harbor via Helm +# ------------------------------------------------------- +echo "--- Step 6: Installing Harbor ---" +helm repo add harbor https://helm.goharbor.io 2>/dev/null || true +helm repo update harbor 2>/dev/null || true + +HARBOR_EXISTS=$(helm list -n harbor-service -q 2>/dev/null | grep -c harbor || true) +if [ "${HARBOR_EXISTS:-0}" -gt 0 ]; then + echo " Harbor already installed — upgrading..." +else + echo " Fresh Harbor install..." +fi + +helm upgrade --install harbor harbor/harbor \ + --namespace harbor-service \ + --values "$SCRIPT_DIR/values.yaml" \ + --timeout 10m \ + --wait + +echo "" +echo " Waiting for Harbor core to be ready..." +kubectl wait --for=condition=ready pod -l app=harbor,component=core -n harbor-service --timeout=180s || true +echo "" + +# ------------------------------------------------------- +# 7. Configure Harbor via API (idempotent) +# ------------------------------------------------------- +echo "--- Step 7: Configuring Harbor project and robot account ---" +HARBOR_API="https://registry.celestium.life/api/v2.0" +HARBOR_AUTH="admin:St0nks0racl3!" + +# Create stonks-oracle project if it doesn't exist +if curl -sf -u "$HARBOR_AUTH" "$HARBOR_API/projects?name=stonks-oracle" | python3 -c "import sys,json; sys.exit(0 if json.load(sys.stdin) else 1)" 2>/dev/null; then + echo " ✓ Project stonks-oracle already exists" +else + curl -sf -X POST -u "$HARBOR_AUTH" \ + -H "Content-Type: application/json" \ + "$HARBOR_API/projects" \ + -d '{"project_name":"stonks-oracle","public":true,"metadata":{"auto_scan":"true","severity":"high"},"storage_limit":-1}' + echo " ✓ Project stonks-oracle created (public, auto-scan enabled)" +fi + +# Create CI robot account if it doesn't exist +EXISTING_ROBOT=$(curl -sf -u "$HARBOR_AUTH" "$HARBOR_API/robots" 2>/dev/null | python3 -c " +import sys, json +robots = json.load(sys.stdin) +for r in robots: + if 'ci-push' in r.get('name', ''): + print(r['name']) + break +" 2>/dev/null || true) + +if [ -n "$EXISTING_ROBOT" ]; then + echo " ✓ Robot account already exists: $EXISTING_ROBOT" +else + ROBOT_RESP=$(curl -sf -X POST -u "$HARBOR_AUTH" \ + -H "Content-Type: application/json" \ + "$HARBOR_API/robots" \ + -d '{ + "name":"ci-push", + "description":"CI/CD pipeline push account", + "duration":-1, + "level":"project", + "permissions":[{ + "namespace":"stonks-oracle", + "kind":"project", + "access":[ + {"resource":"repository","action":"push"}, + {"resource":"repository","action":"pull"}, + {"resource":"tag","action":"create"}, + {"resource":"tag","action":"list"}, + {"resource":"artifact","action":"read"} + ] + }] + }') + ROBOT_NAME=$(echo "$ROBOT_RESP" | python3 -c "import sys,json; print(json.load(sys.stdin)['name'])") + ROBOT_SECRET=$(echo "$ROBOT_RESP" | python3 -c "import sys,json; print(json.load(sys.stdin)['secret'])") + echo " ✓ Robot account created" + echo " Username: $ROBOT_NAME" + echo " Secret: $ROBOT_SECRET" + echo " ⚠ Save these — add as HARBOR_USERNAME and HARBOR_PASSWORD in your CI secrets" +fi + +# Set tag retention policy (idempotent — check if one exists first) +PROJECT_ID=$(curl -sf -u "$HARBOR_AUTH" "$HARBOR_API/projects?name=stonks-oracle" | python3 -c "import sys,json; print(json.load(sys.stdin)[0]['project_id'])" 2>/dev/null || true) +if [ -n "$PROJECT_ID" ]; then + EXISTING_RETENTION=$(curl -sf -u "$HARBOR_AUTH" "$HARBOR_API/retentions" 2>/dev/null || true) + if echo "$EXISTING_RETENTION" | python3 -c "import sys,json; d=json.load(sys.stdin); sys.exit(0 if isinstance(d,list) and len(d)>0 else 1)" 2>/dev/null; then + echo " ✓ Tag retention policy already exists" + else + curl -sf -X POST -u "$HARBOR_AUTH" \ + -H "Content-Type: application/json" \ + "$HARBOR_API/retentions" \ + -d "{ + \"algorithm\":\"or\", + \"scope\":{\"level\":\"project\",\"ref\":$PROJECT_ID}, + \"trigger\":{\"kind\":\"Schedule\",\"settings\":{\"cron\":\"0 0 0 * * *\"}}, + \"rules\":[ + {\"disabled\":false,\"action\":\"retain\",\"scope_selectors\":{\"repository\":[{\"kind\":\"doublestar\",\"decoration\":\"repoMatches\",\"pattern\":\"**\"}]},\"tag_selectors\":[{\"kind\":\"doublestar\",\"decoration\":\"matches\",\"pattern\":\"latest\"}],\"params\":{}}, + {\"disabled\":false,\"action\":\"retain\",\"scope_selectors\":{\"repository\":[{\"kind\":\"doublestar\",\"decoration\":\"repoMatches\",\"pattern\":\"**\"}]},\"tag_selectors\":[{\"kind\":\"doublestar\",\"decoration\":\"matches\",\"pattern\":\"**\"}],\"params\":{\"latestPushedK\":10}} + ] + }" 2>/dev/null && echo " ✓ Tag retention policy created (keep latest + last 10 tags, daily)" || echo " ⚠ Could not create retention policy (non-fatal)" + fi +fi +echo "" + +echo "=== Harbor Deploy Complete ===" +echo "" +echo " URL: https://registry.celestium.life" +echo " Login: admin / St0nks0racl3!" +echo "" +echo " Pods:" +kubectl get pods -n harbor-service