diff --git a/.forgejo/workflows/build.yaml b/.forgejo/workflows/build.yaml index 725334a7..adefc2f8 100644 --- a/.forgejo/workflows/build.yaml +++ b/.forgejo/workflows/build.yaml @@ -1,9 +1,10 @@ -name: Build +name: Build and Deploy on: push: branches: - main + - production env: DOCKER_BUILDKIT: 1 @@ -14,7 +15,30 @@ concurrency: cancel-in-progress: true jobs: - build: + deploy-staging: + name: Deploy to Dokku Staging + if: github.ref == 'refs/heads/main' + runs-on: ubuntu-22.04 + steps: + - name: Checkout code + uses: actions/checkout@v4 + with: + fetch-depth: 0 # Full history needed for Dokku + + - name: Deploy to Dokku + env: + SSH_PRIVATE_KEY: ${{ secrets.DOKKU_SSH_KEY }} + run: | + mkdir -p ~/.ssh + echo "$SSH_PRIVATE_KEY" > ~/.ssh/id_ed25519 + chmod 600 ~/.ssh/id_ed25519 + ssh-keyscan -H 204.110.191.231 >> ~/.ssh/known_hosts + git remote add dokku dokku@204.110.191.231:towerops || true + git push dokku main:main --force + + build-production: + name: Build and Deploy to Production + if: github.ref == 'refs/heads/production' runs-on: ubuntu-22.04 steps: - name: Checkout code @@ -41,7 +65,7 @@ jobs: SHORT_SHA=$(echo "${{ github.sha }}" | cut -c1-7) IMAGE=${{ secrets.REGISTRY_URL }}/${{ github.repository }} echo "image=${IMAGE}" >> $GITHUB_OUTPUT - echo "tag=${IMAGE}:main-${TIMESTAMP}-${SHORT_SHA}" >> $GITHUB_OUTPUT + echo "tag=${IMAGE}:production-${TIMESTAMP}-${SHORT_SHA}" >> $GITHUB_OUTPUT echo "latest_tag=${IMAGE}:latest" >> $GITHUB_OUTPUT echo "cache_tag=${IMAGE}:buildcache" >> $GITHUB_OUTPUT @@ -49,6 +73,7 @@ jobs: uses: docker/build-push-action@v6 with: context: . + file: k8s/Dockerfile push: true tags: | ${{ steps.meta.outputs.tag }} @@ -65,6 +90,6 @@ jobs: if ! git diff --cached --quiet; then git commit -m "chore: update towerops-web image to ${{ steps.meta.outputs.tag }} [skip ci]" # Pull with rebase to handle concurrent pushes - git pull --rebase origin main - git push origin HEAD:main + git pull --rebase origin production + git push origin HEAD:production fi diff --git a/DEPLOYMENT.md b/DEPLOYMENT.md new file mode 100644 index 00000000..99950752 --- /dev/null +++ b/DEPLOYMENT.md @@ -0,0 +1,128 @@ +# Deployment Guide + +## Overview + +Towerops uses a branch-based deployment strategy: +- **`main` branch** → Dokku staging environment (automatic) +- **`production` branch** → Kubernetes production cluster (automatic) + +## Staging Deployment (Dokku) + +### Automatic +Push or merge to `main` branch automatically deploys to Dokku staging: + +```bash +git push origin main +``` + +The Forgejo Actions workflow pushes to the Dokku remote: `dokku@204.110.191.231:towerops` + +### Manual +You can also deploy manually: + +```bash +git push dokku main +``` + +## Production Deployment (Kubernetes) + +### Process +To deploy to production: + +1. **Merge `main` into `production` branch:** + ```bash + git checkout production + git merge main + git push origin production + ``` + +2. **Forgejo Actions will automatically:** + - Build Docker image with tag `production--` + - Push image to container registry (`git.mcintire.me`) + - Update `k8s/deployment.yaml` with new image tag + - Commit and push the update back to `production` branch + - Kubernetes (via FluxCD) picks up the change and deploys + +3. **Monitor the deployment:** + ```bash + kubectl get pods -n towerops -w + ``` + +### Rollback +To rollback to a previous version: + +```bash +# Find the commit with the working version +git log k8s/deployment.yaml + +# Reset to that commit +git checkout production +git reset --hard +git push origin production --force +``` + +Or manually update the image tag in `k8s/deployment.yaml` and push. + +## Required Secrets + +### Forgejo Actions Secrets +Configure these in your Forgejo repository settings: + +- `DOKKU_SSH_KEY` - SSH private key for Dokku deployments +- `REGISTRY_URL` - Container registry URL (e.g., `git.mcintire.me`) +- `REGISTRY_USER` - Registry username +- `REGISTRY_PASSWORD` - Registry password/token + +### Kubernetes Secrets +These must exist in the `towerops` namespace: + +- `forgejo-registry` - Docker registry credentials +- `towerops-secrets` - Application secrets (RELEASE_COOKIE, SECRET_KEY_BASE, CLOAK_KEY) +- `towerops-db` - Database connection +- `towerops-aws` - AWS credentials +- `towerops-billing` - Stripe API keys (optional) +- `towerops-redis` - Redis/Valkey connection + +## Branch Protection + +Recommended branch protection rules: + +### `main` branch +- Require pull request reviews +- Require status checks to pass +- Auto-deploys to staging on merge + +### `production` branch +- Require pull request reviews +- Require status checks to pass +- **Only merge from `main`** +- Auto-deploys to production on merge + +## Troubleshooting + +### Staging deployment fails +Check Forgejo Actions logs and Dokku logs: +```bash +ssh dokku@204.110.191.231 logs towerops +``` + +### Production deployment fails +1. Check Forgejo Actions logs for build errors +2. Check if image was pushed to registry +3. Check Kubernetes pod status: + ```bash + kubectl get pods -n towerops + kubectl logs -n towerops deployment/towerops + ``` + +### Image not updating in Kubernetes +1. Verify `k8s/deployment.yaml` has the new image tag +2. Check FluxCD reconciliation: + ```bash + kubectl get gitrepositories -n flux-system + kubectl get kustomizations -n flux-system + ``` +3. Manual rollout restart if needed: + ```bash + kubectl rollout restart deployment/towerops -n towerops + ```