Update CI/CD to build once and push to Harbor
Some checks failed
CI/CD Pipeline - Apartment API / Run Tests (push) Failing after 1s
CI/CD Pipeline - Apartment API / Build & Push Image (push) Has been skipped
CI/CD Pipeline - Apartment API / Deploy to Production (push) Has been skipped

- Add image variable substitution to docker-compose.yml
- Build image in CI, push to Harbor registry
- Deploy pulls from Harbor instead of rebuilding
- Supports both local dev (build) and prod (pull from registry)
This commit is contained in:
2026-01-22 14:46:57 -07:00
parent 94bbacb3a2
commit 0c387b1bcc
2 changed files with 60 additions and 11 deletions

View File

@ -9,10 +9,11 @@ on:
env:
NODE_VERSION: '20'
IMAGE_NAME: apartment-api
jobs:
# ============================================================
# Test Job - Runs first, blocks deployment if tests fail
# Test Job - Runs first, blocks everything if tests fail
# ============================================================
test:
name: Run Tests
@ -50,37 +51,84 @@ jobs:
NODE_ENV: test
# ============================================================
# Deploy Job - Only runs on main branch after tests pass
# Build & Push Job - Build image and push to Harbor
# ============================================================
deploy:
name: Deploy to Production
build:
name: Build & Push Image
runs-on: ubuntu-latest
needs: test
if: github.ref == 'refs/heads/main' && github.event_name != 'pull_request'
outputs:
image_tag: ${{ steps.meta.outputs.tags }}
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Log in to Harbor
uses: docker/login-action@v3
with:
registry: ${{ secrets.HARBOR_REGISTRY }}
username: ${{ secrets.HARBOR_USERNAME }}
password: ${{ secrets.HARBOR_PASSWORD }}
- name: Extract metadata for Docker
id: meta
uses: docker/metadata-action@v5
with:
images: ${{ secrets.HARBOR_REGISTRY }}/${{ secrets.HARBOR_PROJECT }}/${{ env.IMAGE_NAME }}
tags: |
type=sha,prefix=
type=raw,value=latest
- name: Build and push Docker image
uses: docker/build-push-action@v5
with:
context: .
push: true
tags: ${{ steps.meta.outputs.tags }}
cache-from: type=gha
cache-to: type=gha,mode=max
# ============================================================
# Deploy Job - Pull image and restart on production server
# ============================================================
deploy:
name: Deploy to Production
runs-on: ubuntu-latest
needs: build
if: github.ref == 'refs/heads/main' && github.event_name != 'pull_request'
steps:
- name: Deploy via SSH
uses: appleboy/ssh-action@v1.0.3
env:
HARBOR_REGISTRY: ${{ secrets.HARBOR_REGISTRY }}
HARBOR_PROJECT: ${{ secrets.HARBOR_PROJECT }}
with:
host: ${{ secrets.SSH_HOST }}
username: ${{ secrets.SSH_USER }}
key: ${{ secrets.SSH_PRIVATE_KEY }}
port: ${{ secrets.SSH_PORT || 22 }}
port: ${{ secrets.SSH_PORT }}
envs: HARBOR_REGISTRY,HARBOR_PROJECT
script: |
set -e
# Navigate to deployment directory
cd ${{ secrets.DEPLOY_PATH }}
# Pull latest code
git fetch origin main
git reset --hard origin/main
# Log in to Harbor
echo "${{ secrets.HARBOR_PASSWORD }}" | docker login ${{ secrets.HARBOR_REGISTRY }} -u ${{ secrets.HARBOR_USERNAME }} --password-stdin
# Rebuild and restart container
docker compose build --no-cache
# Set image to pull from Harbor and pull it
export IMAGE="${HARBOR_REGISTRY}/${HARBOR_PROJECT}/apartment-api:latest"
docker compose pull
# Restart with new image
docker compose up -d
# Clean up old images
@ -105,7 +153,7 @@ jobs:
host: ${{ secrets.SSH_HOST }}
username: ${{ secrets.SSH_USER }}
key: ${{ secrets.SSH_PRIVATE_KEY }}
port: ${{ secrets.SSH_PORT || 22 }}
port: ${{ secrets.SSH_PORT }}
script: |
# Test health endpoint via Traefik
HTTP_CODE=$(curl -s -o /dev/null -w "%{http_code}" https://apartments.maverickapplications.com/api/health || echo "000")