mirror of
https://github.com/ryankazokas/turbovault-app.git
synced 2026-04-16 21:02:52 +00:00
Deploy to production: GitHub Actions + ghcr.io + Kubernetes
- Switch from Gitea to GitHub Container Registry (ghcr.io) - Add GitHub Actions workflow with Tailscale connectivity - Update k8s manifests for cloud nodes and Traefik ingress - Configure for turbo.kazcloud.dev domain - Test deployment with home page text change
This commit is contained in:
@@ -14,9 +14,6 @@ jobs:
|
|||||||
- name: Checkout code
|
- name: Checkout code
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
- name: Set up Docker Buildx
|
|
||||||
uses: docker/setup-buildx-action@v3
|
|
||||||
|
|
||||||
- name: Extract version from tag
|
- name: Extract version from tag
|
||||||
id: version
|
id: version
|
||||||
run: |
|
run: |
|
||||||
@@ -28,12 +25,15 @@ jobs:
|
|||||||
echo "tag=latest" >> $GITHUB_OUTPUT
|
echo "tag=latest" >> $GITHUB_OUTPUT
|
||||||
fi
|
fi
|
||||||
|
|
||||||
- name: Log in to Gitea Container Registry
|
- name: Set up Docker Buildx
|
||||||
|
uses: docker/setup-buildx-action@v3
|
||||||
|
|
||||||
|
- name: Log in to GitHub Container Registry
|
||||||
uses: docker/login-action@v3
|
uses: docker/login-action@v3
|
||||||
with:
|
with:
|
||||||
registry: gitea.kazcloud.dev
|
registry: ghcr.io
|
||||||
username: ${{ github.actor }}
|
username: ${{ github.actor }}
|
||||||
password: ${{ secrets.GITEA_TOKEN }}
|
password: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
|
||||||
- name: Build and push Docker image
|
- name: Build and push Docker image
|
||||||
uses: docker/build-push-action@v5
|
uses: docker/build-push-action@v5
|
||||||
@@ -41,32 +41,43 @@ jobs:
|
|||||||
context: .
|
context: .
|
||||||
push: true
|
push: true
|
||||||
tags: |
|
tags: |
|
||||||
gitea.kazcloud.dev/ryankazokas/turbovault-app:${{ steps.version.outputs.tag }}
|
ghcr.io/ryankazokas/turbovault-app:${{ steps.version.outputs.tag }}
|
||||||
gitea.kazcloud.dev/ryankazokas/turbovault-app:latest
|
ghcr.io/ryankazokas/turbovault-app:latest
|
||||||
cache-from: type=gha
|
cache-from: type=gha
|
||||||
cache-to: type=gha,mode=max
|
cache-to: type=gha,mode=max
|
||||||
|
|
||||||
- name: Deploy to Kubernetes
|
- name: Connect to Tailscale
|
||||||
|
uses: tailscale/github-action@v2
|
||||||
|
with:
|
||||||
|
oauth-client-id: ${{ secrets.TAILSCALE_CLIENT_ID }}
|
||||||
|
oauth-secret: ${{ secrets.TAILSCALE_CLIENT_SECRET }}
|
||||||
|
tags: tag:ci
|
||||||
|
|
||||||
|
- name: Setup kubectl
|
||||||
|
uses: azure/setup-kubectl@v3
|
||||||
|
|
||||||
|
- name: Configure kubeconfig
|
||||||
env:
|
env:
|
||||||
KUBECONFIG_CONTENT: ${{ secrets.KUBECONFIG }}
|
KUBECONFIG_CONTENT: ${{ secrets.KUBECONFIG }}
|
||||||
run: |
|
run: |
|
||||||
# Setup kubectl
|
|
||||||
mkdir -p ~/.kube
|
mkdir -p ~/.kube
|
||||||
echo "$KUBECONFIG_CONTENT" | base64 -d > ~/.kube/config
|
echo "$KUBECONFIG_CONTENT" | base64 -d > ~/.kube/config
|
||||||
chmod 600 ~/.kube/config
|
chmod 600 ~/.kube/config
|
||||||
|
|
||||||
# Deploy
|
- name: Deploy to Kubernetes
|
||||||
|
run: |
|
||||||
echo "🚀 Deploying version ${{ steps.version.outputs.tag }} to Kubernetes..."
|
echo "🚀 Deploying version ${{ steps.version.outputs.tag }} to Kubernetes..."
|
||||||
|
|
||||||
kubectl set image deployment/turbovault \
|
kubectl set image deployment/turbovault \
|
||||||
turbovault=gitea.kazcloud.dev/ryankazokas/turbovault-app:${{ steps.version.outputs.tag }} \
|
turbovault=ghcr.io/ryankazokas/turbovault-app:${{ steps.version.outputs.tag }} \
|
||||||
-n turbovault
|
-n turbovault
|
||||||
|
|
||||||
# Wait for rollout
|
echo "⏳ Waiting for rollout to complete..."
|
||||||
kubectl rollout status deployment/turbovault -n turbovault --timeout=5m
|
kubectl rollout status deployment/turbovault -n turbovault --timeout=5m
|
||||||
|
|
||||||
echo "✅ Deployment complete!"
|
echo "✅ Deployment complete!"
|
||||||
|
echo ""
|
||||||
# Show current pods
|
echo "📊 Current pods:"
|
||||||
kubectl get pods -n turbovault -l app=turbovault
|
kubectl get pods -n turbovault -l app=turbovault
|
||||||
|
|
||||||
- name: Deployment summary
|
- name: Deployment summary
|
||||||
@@ -74,7 +85,7 @@ jobs:
|
|||||||
run: |
|
run: |
|
||||||
echo "✅ Build and deployment successful!"
|
echo "✅ Build and deployment successful!"
|
||||||
echo ""
|
echo ""
|
||||||
echo "📦 Image: gitea.kazcloud.dev/ryankazokas/turbovault-app:${{ steps.version.outputs.tag }}"
|
echo "📦 Image: ghcr.io/ryankazokas/turbovault-app:${{ steps.version.outputs.tag }}"
|
||||||
echo "🚀 Deployed to: turbovault namespace"
|
echo "🚀 Deployed to: turbovault namespace"
|
||||||
echo ""
|
echo ""
|
||||||
echo "View logs:"
|
echo "View logs:"
|
||||||
@@ -85,8 +96,8 @@ jobs:
|
|||||||
env:
|
env:
|
||||||
KUBECONFIG_CONTENT: ${{ secrets.KUBECONFIG }}
|
KUBECONFIG_CONTENT: ${{ secrets.KUBECONFIG }}
|
||||||
run: |
|
run: |
|
||||||
echo "❌ Deployment failed! Rolling back..."
|
echo "❌ Deployment failed! Attempting rollback..."
|
||||||
mkdir -p ~/.kube
|
mkdir -p ~/.kube
|
||||||
echo "$KUBECONFIG_CONTENT" | base64 -d > ~/.kube/config
|
echo "$KUBECONFIG_CONTENT" | base64 -d > ~/.kube/config
|
||||||
kubectl rollout undo deployment/turbovault -n turbovault || true
|
kubectl rollout undo deployment/turbovault -n turbovault || true
|
||||||
echo "⚠️ Attempted rollback. Check cluster status manually."
|
echo "⚠️ Rollback attempted. Check cluster status manually."
|
||||||
43
Dockerfile
43
Dockerfile
@@ -1,42 +1,62 @@
|
|||||||
# TurboVault Production Dockerfile
|
# TurboVault Production Dockerfile
|
||||||
# Multi-stage build for optimized image size
|
# Multi-stage build for optimized image size
|
||||||
|
|
||||||
# Stage 1: Build environment
|
# Stage 1: Builder - Full environment with all gems
|
||||||
FROM ruby:3.3-slim as builder
|
FROM ruby:3.3-slim AS builder
|
||||||
|
|
||||||
# Install build dependencies
|
# Install build dependencies
|
||||||
RUN apt-get update -qq && \
|
RUN apt-get update -qq && \
|
||||||
apt-get install -y --no-install-recommends \
|
apt-get install -y --no-install-recommends \
|
||||||
build-essential \
|
build-essential \
|
||||||
libpq-dev \
|
libpq-dev \
|
||||||
|
libyaml-dev \
|
||||||
nodejs \
|
nodejs \
|
||||||
npm \
|
npm \
|
||||||
git \
|
git \
|
||||||
curl && \
|
curl && \
|
||||||
rm -rf /var/lib/apt/lists/*
|
rm -rf /var/lib/apt/lists/*
|
||||||
|
|
||||||
# Set working directory
|
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
|
|
||||||
# Install gems
|
# Install ALL gems first (needed for asset compilation)
|
||||||
COPY Gemfile Gemfile.lock ./
|
COPY Gemfile Gemfile.lock ./
|
||||||
RUN bundle config set --local deployment 'true' && \
|
RUN bundle install --jobs 4 --retry 3
|
||||||
bundle config set --local without 'development test' && \
|
|
||||||
bundle install --jobs 4 --retry 3
|
|
||||||
|
|
||||||
# Copy application code
|
# Copy application code
|
||||||
COPY . .
|
COPY . .
|
||||||
|
|
||||||
# Precompile assets
|
# Precompile assets
|
||||||
|
ENV RAILS_ENV=production \
|
||||||
|
NODE_ENV=production \
|
||||||
|
SECRET_KEY_BASE=dummy
|
||||||
RUN bundle exec rails assets:precompile
|
RUN bundle exec rails assets:precompile
|
||||||
|
|
||||||
# Stage 2: Runtime environment
|
# Stage 2: Production gems only
|
||||||
|
FROM ruby:3.3-slim AS gems
|
||||||
|
|
||||||
|
# Install build dependencies (needed to install gems with native extensions)
|
||||||
|
RUN apt-get update -qq && \
|
||||||
|
apt-get install -y --no-install-recommends \
|
||||||
|
build-essential \
|
||||||
|
libpq-dev \
|
||||||
|
libyaml-dev && \
|
||||||
|
rm -rf /var/lib/apt/lists/*
|
||||||
|
|
||||||
|
WORKDIR /app
|
||||||
|
|
||||||
|
# Install ONLY production gems
|
||||||
|
COPY Gemfile Gemfile.lock ./
|
||||||
|
RUN bundle config set --local without 'development test' && \
|
||||||
|
bundle install --jobs 4 --retry 3
|
||||||
|
|
||||||
|
# Stage 3: Runtime - Minimal final image
|
||||||
FROM ruby:3.3-slim
|
FROM ruby:3.3-slim
|
||||||
|
|
||||||
# Install runtime dependencies
|
# Install ONLY runtime dependencies (no build tools!)
|
||||||
RUN apt-get update -qq && \
|
RUN apt-get update -qq && \
|
||||||
apt-get install -y --no-install-recommends \
|
apt-get install -y --no-install-recommends \
|
||||||
libpq5 \
|
libpq5 \
|
||||||
|
libyaml-0-2 \
|
||||||
curl \
|
curl \
|
||||||
ca-certificates && \
|
ca-certificates && \
|
||||||
rm -rf /var/lib/apt/lists/*
|
rm -rf /var/lib/apt/lists/*
|
||||||
@@ -44,11 +64,10 @@ RUN apt-get update -qq && \
|
|||||||
# Create app user
|
# Create app user
|
||||||
RUN groupadd -r app && useradd -r -g app app
|
RUN groupadd -r app && useradd -r -g app app
|
||||||
|
|
||||||
# Set working directory
|
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
|
|
||||||
# Copy gems from builder
|
# Copy production gems from gems stage
|
||||||
COPY --from=builder /usr/local/bundle /usr/local/bundle
|
COPY --from=gems /usr/local/bundle /usr/local/bundle
|
||||||
|
|
||||||
# Copy application code
|
# Copy application code
|
||||||
COPY --chown=app:app . .
|
COPY --chown=app:app . .
|
||||||
|
|||||||
320
INITIAL_DEPLOYMENT.md
Normal file
320
INITIAL_DEPLOYMENT.md
Normal file
@@ -0,0 +1,320 @@
|
|||||||
|
# Initial Deployment Guide
|
||||||
|
|
||||||
|
Follow these steps to deploy TurboVault to Kubernetes for the first time.
|
||||||
|
|
||||||
|
## Prerequisites
|
||||||
|
|
||||||
|
- ✅ Code pushed to GitHub
|
||||||
|
- ✅ PostgreSQL database ready (host, user, password)
|
||||||
|
- ✅ kubectl configured for k3s cluster (100.101.31.99:6443)
|
||||||
|
- ✅ Docker installed locally
|
||||||
|
- ✅ Gitea account at gitea.kazcloud.dev
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Step 1: Build and Push Initial Image
|
||||||
|
|
||||||
|
Since GitHub Actions hasn't run yet, build the first image manually:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Build image
|
||||||
|
docker build -t gitea.kazcloud.dev/ryan/turbovault-app:v1.0.0 .
|
||||||
|
|
||||||
|
# Login to Gitea registry
|
||||||
|
docker login gitea.kazcloud.dev
|
||||||
|
# Username: ryankazokas
|
||||||
|
# Password: <your-gitea-token>
|
||||||
|
|
||||||
|
# Push image
|
||||||
|
docker push gitea.kazcloud.dev/ryan/turbovault-app:v1.0.0
|
||||||
|
|
||||||
|
# Also tag as latest
|
||||||
|
docker tag gitea.kazcloud.dev/ryan/turbovault-app:v1.0.0 \
|
||||||
|
gitea.kazcloud.dev/ryan/turbovault-app:latest
|
||||||
|
docker push gitea.kazcloud.dev/ryan/turbovault-app:latest
|
||||||
|
```
|
||||||
|
|
||||||
|
✅ **Verify:** Check Gitea packages at `gitea.kazcloud.dev/ryankazokas/-/packages`
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Step 2: Configure Kubernetes Secrets
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Copy template
|
||||||
|
cp k8s/secrets.yaml.example k8s/secrets.yaml
|
||||||
|
|
||||||
|
# Generate Rails secret key
|
||||||
|
rails secret
|
||||||
|
# Copy the output
|
||||||
|
|
||||||
|
# Edit secrets file
|
||||||
|
nano k8s/secrets.yaml
|
||||||
|
```
|
||||||
|
|
||||||
|
**Add these values in `k8s/secrets.yaml`:**
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Secret
|
||||||
|
metadata:
|
||||||
|
name: turbovault-secrets
|
||||||
|
namespace: turbovault
|
||||||
|
type: Opaque
|
||||||
|
stringData:
|
||||||
|
SECRET_KEY_BASE: "<paste-output-from-rails-secret>"
|
||||||
|
DATABASE_PASSWORD: "your-postgres-password"
|
||||||
|
|
||||||
|
# Optional: IGDB integration
|
||||||
|
IGDB_CLIENT_ID: "your-igdb-client-id"
|
||||||
|
IGDB_CLIENT_SECRET: "your-igdb-client-secret"
|
||||||
|
|
||||||
|
# Optional: Email (for password resets)
|
||||||
|
SMTP_ADDRESS: "smtp.example.com"
|
||||||
|
SMTP_PORT: "587"
|
||||||
|
SMTP_USERNAME: "user@example.com"
|
||||||
|
SMTP_PASSWORD: "smtp-password"
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Step 3: Configure Database Connection
|
||||||
|
|
||||||
|
Edit `k8s/configmap.yaml`:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
apiVersion: v1
|
||||||
|
kind: ConfigMap
|
||||||
|
metadata:
|
||||||
|
name: turbovault-config
|
||||||
|
namespace: turbovault
|
||||||
|
data:
|
||||||
|
RAILS_ENV: "production"
|
||||||
|
DATABASE_HOST: "your-postgres-host"
|
||||||
|
DATABASE_NAME: "turbovault_production"
|
||||||
|
DATABASE_USERNAME: "turbovault"
|
||||||
|
RAILS_LOG_TO_STDOUT: "true"
|
||||||
|
RAILS_SERVE_STATIC_FILES: "true"
|
||||||
|
```
|
||||||
|
|
||||||
|
**Replace:**
|
||||||
|
- `your-postgres-host` - Your PostgreSQL server hostname/IP
|
||||||
|
- Database name and username if different
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Step 4: Deploy to Kubernetes
|
||||||
|
|
||||||
|
Run the automated deployment script:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
./scripts/deploy-k8s.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
**When prompted for registry credentials:**
|
||||||
|
- Registry: `gitea.kazcloud.dev`
|
||||||
|
- Username: `ryankazokas`
|
||||||
|
- Password: `<your-gitea-token>`
|
||||||
|
|
||||||
|
**The script will:**
|
||||||
|
1. Create namespace
|
||||||
|
2. Apply configmap
|
||||||
|
3. Apply secrets
|
||||||
|
4. Run database migration job
|
||||||
|
5. Deploy application
|
||||||
|
6. Create service
|
||||||
|
7. Create ingress
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Step 5: Verify Deployment
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Check all resources
|
||||||
|
kubectl get all -n turbovault
|
||||||
|
|
||||||
|
# Check pods are running
|
||||||
|
kubectl get pods -n turbovault
|
||||||
|
|
||||||
|
# View logs
|
||||||
|
kubectl logs -f -l app=turbovault -n turbovault
|
||||||
|
|
||||||
|
# Check migration job completed
|
||||||
|
kubectl logs job/turbovault-migrate -n turbovault
|
||||||
|
```
|
||||||
|
|
||||||
|
**Expected output:**
|
||||||
|
```
|
||||||
|
NAME READY STATUS RESTARTS AGE
|
||||||
|
pod/turbovault-xxxxxxxxxx-xxxxx 1/1 Running 0 2m
|
||||||
|
pod/turbovault-xxxxxxxxxx-xxxxx 1/1 Running 0 2m
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Step 6: Access Application
|
||||||
|
|
||||||
|
### Option A: Port Forward (Testing)
|
||||||
|
|
||||||
|
```bash
|
||||||
|
kubectl port-forward svc/turbovault-service 3000:80 -n turbovault
|
||||||
|
```
|
||||||
|
|
||||||
|
Visit: http://localhost:3000
|
||||||
|
|
||||||
|
### Option B: Ingress (Production)
|
||||||
|
|
||||||
|
Edit `k8s/ingress.yaml` with your domain and apply:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
kubectl apply -f k8s/ingress.yaml
|
||||||
|
```
|
||||||
|
|
||||||
|
Visit: https://your-domain.com
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Step 7: Configure GitHub Secrets
|
||||||
|
|
||||||
|
Now set up automated deployments for future updates.
|
||||||
|
|
||||||
|
See [docs/GITHUB_SECRETS.md](docs/GITHUB_SECRETS.md) for detailed instructions.
|
||||||
|
|
||||||
|
**Required secrets (add at https://github.com/ryankazokas/turbovault-app/settings/secrets/actions):**
|
||||||
|
|
||||||
|
1. `GITEA_USERNAME` - Your Gitea username
|
||||||
|
2. `GITEA_TOKEN` - Gitea access token (Settings → Applications)
|
||||||
|
3. `TAILSCALE_CLIENT_ID` - Tailscale OAuth client ID
|
||||||
|
4. `TAILSCALE_CLIENT_SECRET` - Tailscale OAuth client secret
|
||||||
|
5. `KUBECONFIG` - Base64-encoded kubeconfig (`cat ~/.kube/config | base64 -w 0`)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Step 8: Test Automated Deployment
|
||||||
|
|
||||||
|
After GitHub secrets are configured:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Create a test tag
|
||||||
|
git tag v1.0.1
|
||||||
|
git push origin v1.0.1
|
||||||
|
```
|
||||||
|
|
||||||
|
Watch at: https://github.com/ryankazokas/turbovault-app/actions
|
||||||
|
|
||||||
|
GitHub Actions will:
|
||||||
|
1. Build Docker image
|
||||||
|
2. Push to Gitea registry
|
||||||
|
3. Connect via Tailscale
|
||||||
|
4. Deploy to Kubernetes
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Troubleshooting
|
||||||
|
|
||||||
|
### Pods in CrashLoopBackOff
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# View logs
|
||||||
|
kubectl logs -l app=turbovault -n turbovault
|
||||||
|
|
||||||
|
# Common issues:
|
||||||
|
# - Database connection failed (check configmap/secrets)
|
||||||
|
# - Missing SECRET_KEY_BASE (check secrets)
|
||||||
|
# - Migration not run (check migration job logs)
|
||||||
|
```
|
||||||
|
|
||||||
|
### Migration Job Failed
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# View migration logs
|
||||||
|
kubectl logs job/turbovault-migrate -n turbovault
|
||||||
|
|
||||||
|
# Re-run migration
|
||||||
|
kubectl delete job turbovault-migrate -n turbovault
|
||||||
|
kubectl apply -f k8s/migrate-job.yaml
|
||||||
|
```
|
||||||
|
|
||||||
|
### Can't Pull Image
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Check image pull secret
|
||||||
|
kubectl get secrets -n turbovault
|
||||||
|
|
||||||
|
# Re-run deploy script to create secret
|
||||||
|
./scripts/deploy-k8s.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
### Database Connection Failed
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Test from pod
|
||||||
|
kubectl exec -it deployment/turbovault -n turbovault -- \
|
||||||
|
rails runner "puts ActiveRecord::Base.connection.execute('SELECT 1').first"
|
||||||
|
|
||||||
|
# Check environment variables
|
||||||
|
kubectl exec -it deployment/turbovault -n turbovault -- env | grep DATABASE
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Next Steps
|
||||||
|
|
||||||
|
After successful initial deployment:
|
||||||
|
|
||||||
|
1. ✅ Application is running in Kubernetes
|
||||||
|
2. ✅ GitHub Actions configured for automated deployments
|
||||||
|
3. 🚀 **Daily workflow:** Just push tags to deploy!
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Make changes
|
||||||
|
git add .
|
||||||
|
git commit -m "Feature: new functionality"
|
||||||
|
git push
|
||||||
|
|
||||||
|
# Deploy
|
||||||
|
git tag v1.0.2
|
||||||
|
git push origin v1.0.2
|
||||||
|
|
||||||
|
# GitHub Actions automatically builds and deploys! ✅
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Quick Reference
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# View status
|
||||||
|
kubectl get all -n turbovault
|
||||||
|
|
||||||
|
# View logs
|
||||||
|
kubectl logs -f -l app=turbovault -n turbovault
|
||||||
|
|
||||||
|
# Restart deployment
|
||||||
|
kubectl rollout restart deployment/turbovault -n turbovault
|
||||||
|
|
||||||
|
# Rollback deployment
|
||||||
|
kubectl rollout undo deployment/turbovault -n turbovault
|
||||||
|
|
||||||
|
# Delete everything (start over)
|
||||||
|
kubectl delete namespace turbovault
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Files You Modified
|
||||||
|
|
||||||
|
Keep these files safe (they're gitignored):
|
||||||
|
|
||||||
|
- `k8s/secrets.yaml` - Contains sensitive data (SECRET_KEY_BASE, passwords)
|
||||||
|
- `~/.kube/config` - Your Kubernetes access
|
||||||
|
|
||||||
|
**DO NOT** commit these to git!
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
**Need help?** Check logs first:
|
||||||
|
```bash
|
||||||
|
kubectl describe pod -l app=turbovault -n turbovault
|
||||||
|
kubectl logs -l app=turbovault -n turbovault
|
||||||
|
```
|
||||||
19
README.md
19
README.md
@@ -38,19 +38,14 @@ Visit http://localhost:3000
|
|||||||
|
|
||||||
### Deploy to Kubernetes
|
### Deploy to Kubernetes
|
||||||
|
|
||||||
```bash
|
See [INITIAL_DEPLOYMENT.md](INITIAL_DEPLOYMENT.md) for complete setup guide.
|
||||||
# 1. Build & push image
|
|
||||||
git tag v1.0.0 && git push origin v1.0.0
|
|
||||||
|
|
||||||
# 2. Configure secrets
|
**Quick steps:**
|
||||||
cp k8s/secrets.yaml.example k8s/secrets.yaml
|
1. Build and push first image to Gitea registry
|
||||||
# Edit with your values
|
2. Configure k8s secrets and configmap
|
||||||
|
3. Run `./scripts/deploy-k8s.sh`
|
||||||
# 3. Deploy
|
4. Configure GitHub Secrets for automation
|
||||||
./scripts/deploy-k8s.sh
|
5. Push tags to deploy: `git tag v1.0.1 && git push origin v1.0.1`
|
||||||
```
|
|
||||||
|
|
||||||
See [docs/QUICK_START.md](docs/QUICK_START.md) for details.
|
|
||||||
|
|
||||||
## Tech Stack
|
## Tech Stack
|
||||||
|
|
||||||
|
|||||||
130
TODO.md
Normal file
130
TODO.md
Normal file
@@ -0,0 +1,130 @@
|
|||||||
|
# TurboVault TODO
|
||||||
|
|
||||||
|
## Fix Gitea Ingress for Large Container Pushes
|
||||||
|
|
||||||
|
**Issue:** Docker push to Gitea registry times out on large layers (~250MB)
|
||||||
|
|
||||||
|
**Error:**
|
||||||
|
```
|
||||||
|
Package registry API internal error: 500 unexpected EOF
|
||||||
|
```
|
||||||
|
|
||||||
|
**Root Cause:** Ingress controller (nginx/traefik) in front of Gitea has timeout limits that prevent large uploads from completing.
|
||||||
|
|
||||||
|
**Symptoms:**
|
||||||
|
- Small layers push fine (already exists)
|
||||||
|
- Large gem layer (12f753f9ec10, ~250MB) times out after ~1 minute
|
||||||
|
- Gitea logs show: `PATCH /v2/ryan/turbovault-app/blobs/uploads/... elapsed 3275.4ms ... 500 unexpected EOF`
|
||||||
|
|
||||||
|
### Solution: Update Gitea Ingress
|
||||||
|
|
||||||
|
Find your Gitea ingress configuration and add these annotations:
|
||||||
|
|
||||||
|
**For NGINX Ingress Controller:**
|
||||||
|
```yaml
|
||||||
|
apiVersion: networking.k8s.io/v1
|
||||||
|
kind: Ingress
|
||||||
|
metadata:
|
||||||
|
name: gitea
|
||||||
|
namespace: tools # or wherever gitea is
|
||||||
|
annotations:
|
||||||
|
# Allow unlimited upload size
|
||||||
|
nginx.ingress.kubernetes.io/proxy-body-size: "0"
|
||||||
|
|
||||||
|
# Increase timeouts to 10 minutes
|
||||||
|
nginx.ingress.kubernetes.io/proxy-read-timeout: "600"
|
||||||
|
nginx.ingress.kubernetes.io/proxy-send-timeout: "600"
|
||||||
|
nginx.ingress.kubernetes.io/proxy-connect-timeout: "600"
|
||||||
|
|
||||||
|
# Enable chunked uploads
|
||||||
|
nginx.ingress.kubernetes.io/proxy-request-buffering: "off"
|
||||||
|
```
|
||||||
|
|
||||||
|
**For Traefik Ingress:**
|
||||||
|
```yaml
|
||||||
|
apiVersion: traefik.containo.us/v1alpha1
|
||||||
|
kind: Middleware
|
||||||
|
metadata:
|
||||||
|
name: gitea-buffering
|
||||||
|
namespace: tools
|
||||||
|
spec:
|
||||||
|
buffering:
|
||||||
|
maxRequestBodyBytes: 0 # Unlimited
|
||||||
|
memRequestBodyBytes: 2097152 # 2MB in memory, rest to disk
|
||||||
|
|
||||||
|
---
|
||||||
|
apiVersion: networking.k8s.io/v1
|
||||||
|
kind: Ingress
|
||||||
|
metadata:
|
||||||
|
name: gitea
|
||||||
|
namespace: tools
|
||||||
|
annotations:
|
||||||
|
traefik.ingress.kubernetes.io/router.middlewares: tools-gitea-buffering@kubernetescrd
|
||||||
|
```
|
||||||
|
|
||||||
|
### Steps to Fix:
|
||||||
|
|
||||||
|
1. **Find current Gitea ingress:**
|
||||||
|
```bash
|
||||||
|
kubectl get ingress -n tools
|
||||||
|
kubectl get ingress gitea -n tools -o yaml
|
||||||
|
```
|
||||||
|
|
||||||
|
2. **Identify ingress controller:**
|
||||||
|
```bash
|
||||||
|
kubectl get ingressclass
|
||||||
|
# Check which controller: nginx, traefik, etc.
|
||||||
|
```
|
||||||
|
|
||||||
|
3. **Update ingress with appropriate annotations** (see above)
|
||||||
|
|
||||||
|
4. **Apply changes:**
|
||||||
|
```bash
|
||||||
|
kubectl apply -f <your-gitea-ingress>.yaml
|
||||||
|
```
|
||||||
|
|
||||||
|
5. **Test push:**
|
||||||
|
```bash
|
||||||
|
docker push gitea.kazcloud.dev/ryan/turbovault-app:v1.0.0
|
||||||
|
```
|
||||||
|
|
||||||
|
### Alternative: Increase Gitea Service Timeouts
|
||||||
|
|
||||||
|
If using a LoadBalancer or NodePort directly:
|
||||||
|
|
||||||
|
Edit Gitea's `app.ini`:
|
||||||
|
```ini
|
||||||
|
[server]
|
||||||
|
LFS_MAX_FILE_SIZE = 0
|
||||||
|
HTTP_PORT = 3000
|
||||||
|
|
||||||
|
[packages]
|
||||||
|
ENABLED = true
|
||||||
|
CHUNKED_UPLOAD_PATH = /tmp/package-upload
|
||||||
|
LIMIT_TOTAL_OWNER_SIZE = -1
|
||||||
|
LIMIT_SIZE_CONTAINER = -1
|
||||||
|
```
|
||||||
|
|
||||||
|
Then restart Gitea pod.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Current Workaround
|
||||||
|
|
||||||
|
Using GitHub Container Registry (ghcr.io) for now:
|
||||||
|
- Image: `ghcr.io/ryankazokas/turbovault-app:latest`
|
||||||
|
- All k8s manifests updated to use ghcr.io
|
||||||
|
- GitHub Actions workflow configured
|
||||||
|
- Works perfectly, no timeout issues
|
||||||
|
|
||||||
|
Once Gitea ingress is fixed, can switch back by updating:
|
||||||
|
- k8s/deployment.yaml
|
||||||
|
- k8s/migrate-job.yaml
|
||||||
|
- .github/workflows/build-and-deploy.yml
|
||||||
|
- scripts/update-deployment.sh
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
**Priority:** Low (ghcr.io works fine for now)
|
||||||
|
**Complexity:** Medium (depends on ingress controller setup)
|
||||||
|
**Benefit:** Full control over container registry on your infrastructure
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
<div class="max-w-4xl mx-auto text-center py-16">
|
<div class="max-w-4xl mx-auto text-center py-16">
|
||||||
<h1 class="text-5xl font-bold text-gray-900 mb-6">Welcome to TurboVault</h1>
|
<h1 class="text-5xl font-bold text-gray-900 mb-6">Welcome to TurboVault</h1>
|
||||||
<p class="text-xl text-gray-600 mb-8">Track and manage your video game collection with ease</p>
|
<p class="text-xl text-gray-600 mb-8">Track and manage your video game collection with ease (Test Deployment v1.0.1)</p>
|
||||||
|
|
||||||
<div class="space-x-4">
|
<div class="space-x-4">
|
||||||
<%= link_to "Get Started", signup_path, class: "px-8 py-3 bg-indigo-600 text-white rounded-lg hover:bg-indigo-700 text-lg font-semibold" %>
|
<%= link_to "Get Started", signup_path, class: "px-8 py-3 bg-indigo-600 text-white rounded-lg hover:bg-indigo-700 text-lg font-semibold" %>
|
||||||
|
|||||||
@@ -1,202 +0,0 @@
|
|||||||
# Gitea Secrets Configuration
|
|
||||||
|
|
||||||
This document explains what secrets you need to configure in Gitea for automatic builds and deployments.
|
|
||||||
|
|
||||||
## Required Secrets
|
|
||||||
|
|
||||||
### 1. GITEA_TOKEN
|
|
||||||
|
|
||||||
**Purpose:** Allows Gitea Actions to push Docker images to Gitea Container Registry
|
|
||||||
|
|
||||||
**How to create:**
|
|
||||||
|
|
||||||
1. Go to Gitea → **Settings** → **Applications**
|
|
||||||
2. Under **"Generate New Token"**, enter name: `gitea-actions`
|
|
||||||
3. Select scopes:
|
|
||||||
- ✅ `write:package` (push container images)
|
|
||||||
- ✅ `read:package` (pull container images)
|
|
||||||
4. Click **"Generate Token"**
|
|
||||||
5. Copy the token (starts with `glpat-...` or similar)
|
|
||||||
|
|
||||||
**How to add to repository:**
|
|
||||||
|
|
||||||
1. Go to your Gitea repository: `gitea.kazcloud.dev/ryankazokas/turbovault-app`
|
|
||||||
2. Click **Settings** → **Secrets**
|
|
||||||
3. Click **"Add Secret"**
|
|
||||||
4. Name: `GITEA_TOKEN`
|
|
||||||
5. Value: Paste the token you copied
|
|
||||||
6. Click **"Add Secret"**
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### 2. KUBECONFIG
|
|
||||||
|
|
||||||
**Purpose:** Allows Gitea Actions to deploy to your Kubernetes cluster
|
|
||||||
|
|
||||||
**How to create:**
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# Export your kubeconfig as base64
|
|
||||||
cat ~/.kube/config | base64 -w 0 > kubeconfig-base64.txt
|
|
||||||
|
|
||||||
# Copy the contents of kubeconfig-base64.txt
|
|
||||||
cat kubeconfig-base64.txt
|
|
||||||
```
|
|
||||||
|
|
||||||
**How to add to repository:**
|
|
||||||
|
|
||||||
1. Go to your Gitea repository: `gitea.kazcloud.dev/ryankazokas/turbovault-app`
|
|
||||||
2. Click **Settings** → **Secrets**
|
|
||||||
3. Click **"Add Secret"**
|
|
||||||
4. Name: `KUBECONFIG`
|
|
||||||
5. Value: Paste the base64-encoded kubeconfig
|
|
||||||
6. Click **"Add Secret"**
|
|
||||||
|
|
||||||
**⚠️ Security Note:** This gives Gitea Actions full access to your Kubernetes cluster. Only add this to trusted repositories!
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Optional: Scoped Kubeconfig (More Secure)
|
|
||||||
|
|
||||||
Instead of using your full kubeconfig, create a limited service account:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# Create service account for deployments
|
|
||||||
kubectl create serviceaccount turbovault-deployer -n turbovault
|
|
||||||
|
|
||||||
# Create role with deployment permissions
|
|
||||||
cat <<EOF | kubectl apply -f -
|
|
||||||
apiVersion: rbac.authorization.k8s.io/v1
|
|
||||||
kind: Role
|
|
||||||
metadata:
|
|
||||||
name: turbovault-deployer
|
|
||||||
namespace: turbovault
|
|
||||||
rules:
|
|
||||||
- apiGroups: ["apps"]
|
|
||||||
resources: ["deployments"]
|
|
||||||
verbs: ["get", "list", "patch", "update"]
|
|
||||||
- apiGroups: [""]
|
|
||||||
resources: ["pods"]
|
|
||||||
verbs: ["get", "list"]
|
|
||||||
- apiGroups: ["apps"]
|
|
||||||
resources: ["deployments/status"]
|
|
||||||
verbs: ["get"]
|
|
||||||
EOF
|
|
||||||
|
|
||||||
# Bind role to service account
|
|
||||||
kubectl create rolebinding turbovault-deployer \
|
|
||||||
--role=turbovault-deployer \
|
|
||||||
--serviceaccount=turbovault:turbovault-deployer \
|
|
||||||
-n turbovault
|
|
||||||
|
|
||||||
# Get service account token
|
|
||||||
kubectl create token turbovault-deployer -n turbovault --duration=87600h > token.txt
|
|
||||||
|
|
||||||
# Create minimal kubeconfig
|
|
||||||
cat <<EOF > deployer-kubeconfig.yaml
|
|
||||||
apiVersion: v1
|
|
||||||
kind: Config
|
|
||||||
clusters:
|
|
||||||
- cluster:
|
|
||||||
server: https://100.101.31.99:6443
|
|
||||||
# Add certificate-authority-data from your main kubeconfig if needed
|
|
||||||
insecure-skip-tls-verify: true
|
|
||||||
name: k3s
|
|
||||||
contexts:
|
|
||||||
- context:
|
|
||||||
cluster: k3s
|
|
||||||
namespace: turbovault
|
|
||||||
user: turbovault-deployer
|
|
||||||
name: k3s
|
|
||||||
current-context: k3s
|
|
||||||
users:
|
|
||||||
- name: turbovault-deployer
|
|
||||||
user:
|
|
||||||
token: $(cat token.txt)
|
|
||||||
EOF
|
|
||||||
|
|
||||||
# Encode for Gitea
|
|
||||||
cat deployer-kubeconfig.yaml | base64 -w 0 > deployer-kubeconfig-base64.txt
|
|
||||||
|
|
||||||
# Use this in KUBECONFIG secret instead
|
|
||||||
cat deployer-kubeconfig-base64.txt
|
|
||||||
```
|
|
||||||
|
|
||||||
This limits Gitea Actions to only deploying TurboVault, not full cluster access.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Verifying Secrets
|
|
||||||
|
|
||||||
After adding secrets, you can verify they're set:
|
|
||||||
|
|
||||||
1. Go to repository → **Settings** → **Secrets**
|
|
||||||
2. You should see:
|
|
||||||
- `GITEA_TOKEN` ✅
|
|
||||||
- `KUBECONFIG` ✅
|
|
||||||
|
|
||||||
**Note:** You can't view secret values after creation (security feature).
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Testing the Workflow
|
|
||||||
|
|
||||||
After secrets are configured:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# Create a test tag
|
|
||||||
git tag v0.0.1-test
|
|
||||||
git push origin v0.0.1-test
|
|
||||||
```
|
|
||||||
|
|
||||||
Watch the workflow at:
|
|
||||||
`gitea.kazcloud.dev/ryankazokas/turbovault-app/actions`
|
|
||||||
|
|
||||||
The workflow should:
|
|
||||||
1. ✅ Build Docker image
|
|
||||||
2. ✅ Push to Gitea registry
|
|
||||||
3. ✅ Deploy to Kubernetes
|
|
||||||
4. ✅ Wait for rollout to complete
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Troubleshooting
|
|
||||||
|
|
||||||
### "Error: authentication required"
|
|
||||||
- Check `GITEA_TOKEN` is set and has `write:package` scope
|
|
||||||
|
|
||||||
### "Error: Unable to connect to the server"
|
|
||||||
- Check `KUBECONFIG` secret is set correctly
|
|
||||||
- Verify base64 encoding (no line breaks with `-w 0`)
|
|
||||||
- Test kubeconfig works locally: `kubectl --kubeconfig=<file> get pods -n turbovault`
|
|
||||||
|
|
||||||
### "Error: deployment not found"
|
|
||||||
- Make sure initial deployment is done first: `./scripts/deploy-k8s.sh`
|
|
||||||
- Workflow only updates existing deployments, doesn't create them
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Security Best Practices
|
|
||||||
|
|
||||||
✅ **DO:**
|
|
||||||
- Use service account with minimal permissions (Role, not ClusterRole)
|
|
||||||
- Rotate tokens regularly
|
|
||||||
- Only add secrets to repositories you control
|
|
||||||
|
|
||||||
❌ **DON'T:**
|
|
||||||
- Share secrets in code or documentation
|
|
||||||
- Use admin kubeconfig if possible
|
|
||||||
- Commit secrets to git
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Summary
|
|
||||||
|
|
||||||
**Two secrets required:**
|
|
||||||
|
|
||||||
1. **GITEA_TOKEN** - For pushing container images
|
|
||||||
2. **KUBECONFIG** - For deploying to Kubernetes
|
|
||||||
|
|
||||||
Both added at: `gitea.kazcloud.dev/ryankazokas/turbovault-app/settings/secrets`
|
|
||||||
|
|
||||||
After setup, just push tags to trigger automatic builds and deployments! 🚀
|
|
||||||
@@ -1,323 +0,0 @@
|
|||||||
# Gitea CI/CD Workflow
|
|
||||||
|
|
||||||
## Overview
|
|
||||||
|
|
||||||
TurboVault uses Gitea Actions for fully automated builds and deployments:
|
|
||||||
|
|
||||||
1. **Push code to GitHub** (primary repository)
|
|
||||||
2. **Gitea mirrors** from GitHub automatically
|
|
||||||
3. **Gitea Actions** builds Docker image and deploys to Kubernetes
|
|
||||||
|
|
||||||
All automatic! 🚀
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Setup (One-Time)
|
|
||||||
|
|
||||||
### 1. Mirror GitHub Repository to Gitea
|
|
||||||
|
|
||||||
In Gitea:
|
|
||||||
|
|
||||||
1. Go to `gitea.kazcloud.dev` → **New Repository**
|
|
||||||
2. Choose **"New Migration"** → **"GitHub"**
|
|
||||||
3. URL: `https://github.com/ryankazokas/turbovault-app`
|
|
||||||
4. Enable **"This repository will be a mirror"**
|
|
||||||
5. Set sync interval: **10 minutes** (or setup webhook for instant sync)
|
|
||||||
6. Click **"Migrate Repository"**
|
|
||||||
|
|
||||||
**Webhook for instant sync (optional):**
|
|
||||||
- In GitHub repo → Settings → Webhooks → Add webhook
|
|
||||||
- Payload URL: `https://gitea.kazcloud.dev/ryankazokas/turbovault-app/mirror-sync`
|
|
||||||
- Content type: `application/json`
|
|
||||||
- Events: Just the push event
|
|
||||||
|
|
||||||
### 2. Configure Gitea Secrets
|
|
||||||
|
|
||||||
See [GITEA_SECRETS.md](GITEA_SECRETS.md) for detailed instructions.
|
|
||||||
|
|
||||||
**Required secrets:**
|
|
||||||
- `GITEA_TOKEN` - For pushing images to registry
|
|
||||||
- `KUBECONFIG` - For deploying to Kubernetes
|
|
||||||
|
|
||||||
Add at: `gitea.kazcloud.dev/ryankazokas/turbovault-app/settings/secrets`
|
|
||||||
|
|
||||||
### 3. Initial Deployment to Kubernetes
|
|
||||||
|
|
||||||
Before automation works, do initial deployment:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# Build and push first image
|
|
||||||
docker build -t gitea.kazcloud.dev/ryankazokas/turbovault-app:v1.0.0 .
|
|
||||||
docker login gitea.kazcloud.dev
|
|
||||||
docker push gitea.kazcloud.dev/ryankazokas/turbovault-app:v1.0.0
|
|
||||||
|
|
||||||
# Configure secrets and database
|
|
||||||
cp k8s/secrets.yaml.example k8s/secrets.yaml
|
|
||||||
nano k8s/secrets.yaml # Add SECRET_KEY_BASE, DATABASE_PASSWORD, etc.
|
|
||||||
nano k8s/configmap.yaml # Add DATABASE_HOST, etc.
|
|
||||||
|
|
||||||
# Deploy to Kubernetes
|
|
||||||
./scripts/deploy-k8s.sh
|
|
||||||
```
|
|
||||||
|
|
||||||
When script asks for registry credentials:
|
|
||||||
- Registry: `gitea.kazcloud.dev`
|
|
||||||
- Username: `ryankazokas`
|
|
||||||
- Password: `<your-gitea-token>`
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Daily Workflow
|
|
||||||
|
|
||||||
After setup, deployments are fully automatic:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# 1. Make changes in GitHub
|
|
||||||
git add .
|
|
||||||
git commit -m "Feature: add new functionality"
|
|
||||||
git push origin main
|
|
||||||
|
|
||||||
# 2. When ready to deploy, create version tag
|
|
||||||
git tag v1.0.1
|
|
||||||
git push origin v1.0.1
|
|
||||||
|
|
||||||
# 3. That's it! ✅
|
|
||||||
# Gitea auto-syncs → builds → deploys to Kubernetes
|
|
||||||
```
|
|
||||||
|
|
||||||
**Watch build and deployment:**
|
|
||||||
`https://gitea.kazcloud.dev/ryankazokas/turbovault-app/actions`
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## How It Works
|
|
||||||
|
|
||||||
```
|
|
||||||
GitHub (code)
|
|
||||||
↓ (mirror sync)
|
|
||||||
Gitea (code mirror)
|
|
||||||
↓ (on tag push)
|
|
||||||
Gitea Actions:
|
|
||||||
1. Build Docker image
|
|
||||||
2. Push to gitea.kazcloud.dev registry
|
|
||||||
3. Deploy to Kubernetes (kubectl)
|
|
||||||
4. Wait for rollout
|
|
||||||
5. Show status
|
|
||||||
↓
|
|
||||||
Kubernetes pulls image and updates deployment ✅
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Workflow Features
|
|
||||||
|
|
||||||
### ✅ Automatic Rollout Status
|
|
||||||
Workflow waits for rollout to complete before marking as success.
|
|
||||||
|
|
||||||
### ✅ Automatic Rollback on Failure
|
|
||||||
If deployment fails, workflow automatically rolls back to previous version.
|
|
||||||
|
|
||||||
### ✅ Multiple Tags
|
|
||||||
Each version gets two tags:
|
|
||||||
- `v1.0.0` (specific version)
|
|
||||||
- `latest` (always points to most recent)
|
|
||||||
|
|
||||||
### ✅ Manual Trigger
|
|
||||||
Can manually trigger builds via Gitea Actions UI if needed.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Manual Deployment (If Needed)
|
|
||||||
|
|
||||||
If you want to deploy manually without waiting for Gitea sync:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# Build and push
|
|
||||||
docker build -t gitea.kazcloud.dev/ryankazokas/turbovault-app:v1.0.1 .
|
|
||||||
docker push gitea.kazcloud.dev/ryankazokas/turbovault-app:v1.0.1
|
|
||||||
|
|
||||||
# Deploy
|
|
||||||
./scripts/update-deployment.sh v1.0.1
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Version Management
|
|
||||||
|
|
||||||
### Semantic Versioning
|
|
||||||
|
|
||||||
Use semantic versioning for tags:
|
|
||||||
- `v1.0.0` - Major.Minor.Patch
|
|
||||||
- `v1.0.1` - Patch update (bug fixes)
|
|
||||||
- `v1.1.0` - Minor update (new features)
|
|
||||||
- `v2.0.0` - Major update (breaking changes)
|
|
||||||
|
|
||||||
### Viewing Deployed Version
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# Check current image
|
|
||||||
kubectl get deployment turbovault -n turbovault -o jsonpath='{.spec.template.spec.containers[0].image}'
|
|
||||||
|
|
||||||
# Check all pods
|
|
||||||
kubectl get pods -n turbovault -l app=turbovault
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Troubleshooting
|
|
||||||
|
|
||||||
### Workflow Fails at "Build and push"
|
|
||||||
|
|
||||||
**Issue:** Can't push to registry
|
|
||||||
|
|
||||||
**Fix:**
|
|
||||||
- Check `GITEA_TOKEN` secret is set
|
|
||||||
- Verify token has `write:package` scope
|
|
||||||
- Test: `docker login gitea.kazcloud.dev` with token
|
|
||||||
|
|
||||||
### Workflow Fails at "Deploy to Kubernetes"
|
|
||||||
|
|
||||||
**Issue:** Can't connect to Kubernetes
|
|
||||||
|
|
||||||
**Fix:**
|
|
||||||
- Check `KUBECONFIG` secret is set correctly
|
|
||||||
- Verify base64 encoding: `echo "$SECRET" | base64 -d | kubectl --kubeconfig=/dev/stdin get nodes`
|
|
||||||
- Check cluster is reachable from Gitea Actions runner
|
|
||||||
|
|
||||||
### Deployment Succeeds but Pods Not Starting
|
|
||||||
|
|
||||||
**Issue:** Image pull errors or configuration issues
|
|
||||||
|
|
||||||
**Check:**
|
|
||||||
```bash
|
|
||||||
kubectl get pods -n turbovault
|
|
||||||
kubectl describe pod <pod-name> -n turbovault
|
|
||||||
kubectl logs <pod-name> -n turbovault
|
|
||||||
```
|
|
||||||
|
|
||||||
**Common causes:**
|
|
||||||
- Image pull secret not configured (run `./scripts/deploy-k8s.sh` again)
|
|
||||||
- Database connection issues (check `k8s/configmap.yaml` and `k8s/secrets.yaml`)
|
|
||||||
- Missing environment variables
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Monitoring Deployments
|
|
||||||
|
|
||||||
### Watch Live Deployment
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# Watch pods update
|
|
||||||
kubectl get pods -n turbovault -w
|
|
||||||
|
|
||||||
# Watch rollout status
|
|
||||||
kubectl rollout status deployment/turbovault -n turbovault
|
|
||||||
|
|
||||||
# View logs
|
|
||||||
kubectl logs -f -l app=turbovault -n turbovault
|
|
||||||
```
|
|
||||||
|
|
||||||
### Deployment History
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# View rollout history
|
|
||||||
kubectl rollout history deployment/turbovault -n turbovault
|
|
||||||
|
|
||||||
# View specific revision
|
|
||||||
kubectl rollout history deployment/turbovault --revision=2 -n turbovault
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Rollback
|
|
||||||
|
|
||||||
### Automatic Rollback
|
|
||||||
Workflow automatically rolls back if deployment fails.
|
|
||||||
|
|
||||||
### Manual Rollback
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# Rollback to previous version
|
|
||||||
kubectl rollout undo deployment/turbovault -n turbovault
|
|
||||||
|
|
||||||
# Rollback to specific revision
|
|
||||||
kubectl rollout undo deployment/turbovault --to-revision=3 -n turbovault
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Security Considerations
|
|
||||||
|
|
||||||
### Secrets Management
|
|
||||||
- All secrets in Gitea are encrypted
|
|
||||||
- Secrets never appear in logs
|
|
||||||
- Use service account kubeconfig (not admin)
|
|
||||||
|
|
||||||
### Network Security
|
|
||||||
- Gitea Actions runners on internal network
|
|
||||||
- Can reach Kubernetes API (not exposed publicly)
|
|
||||||
- Images pulled from internal registry
|
|
||||||
|
|
||||||
### Access Control
|
|
||||||
- Only repository collaborators can trigger workflows
|
|
||||||
- Gitea token scoped to package registry only
|
|
||||||
- Kubeconfig scoped to turbovault namespace only (recommended)
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Advanced: Staging vs Production
|
|
||||||
|
|
||||||
To add staging environment:
|
|
||||||
|
|
||||||
1. Create `v*.*.*-rc*` tags for release candidates
|
|
||||||
2. Deploy to staging namespace
|
|
||||||
3. Update workflow to detect RC tags:
|
|
||||||
|
|
||||||
```yaml
|
|
||||||
- name: Determine environment
|
|
||||||
id: env
|
|
||||||
run: |
|
|
||||||
if [[ "${{ github.ref }}" =~ -rc ]]; then
|
|
||||||
echo "namespace=turbovault-staging" >> $GITHUB_OUTPUT
|
|
||||||
else
|
|
||||||
echo "namespace=turbovault" >> $GITHUB_OUTPUT
|
|
||||||
fi
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Quick Reference
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# Deploy new version
|
|
||||||
git tag v1.0.1
|
|
||||||
git push origin v1.0.1
|
|
||||||
|
|
||||||
# Watch deployment
|
|
||||||
kubectl get pods -n turbovault -w
|
|
||||||
|
|
||||||
# View logs
|
|
||||||
kubectl logs -f -l app=turbovault -n turbovault
|
|
||||||
|
|
||||||
# Rollback if needed
|
|
||||||
kubectl rollout undo deployment/turbovault -n turbovault
|
|
||||||
|
|
||||||
# Check current version
|
|
||||||
kubectl get deployment turbovault -n turbovault -o jsonpath='{.spec.template.spec.containers[0].image}'
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Summary
|
|
||||||
|
|
||||||
**Setup once:**
|
|
||||||
1. Mirror GitHub → Gitea
|
|
||||||
2. Add Gitea secrets (GITEA_TOKEN, KUBECONFIG)
|
|
||||||
3. Initial deployment with `./scripts/deploy-k8s.sh`
|
|
||||||
|
|
||||||
**Daily workflow:**
|
|
||||||
1. Push code to GitHub
|
|
||||||
2. Create version tag
|
|
||||||
3. Everything else is automatic! ✅
|
|
||||||
|
|
||||||
Questions? Check [GITEA_SECRETS.md](GITEA_SECRETS.md) for secret configuration details.
|
|
||||||
251
docs/GITHUB_SECRETS.md
Normal file
251
docs/GITHUB_SECRETS.md
Normal file
@@ -0,0 +1,251 @@
|
|||||||
|
# GitHub Secrets Configuration
|
||||||
|
|
||||||
|
This document explains what secrets you need to configure in GitHub for automatic builds and deployments.
|
||||||
|
|
||||||
|
## Required Secrets
|
||||||
|
|
||||||
|
Go to: **`https://github.com/ryan/turbovault-app/settings/secrets/actions`**
|
||||||
|
|
||||||
|
### 1. GITHUB_TOKEN (Built-in)
|
||||||
|
|
||||||
|
**Purpose:** Authenticate to GitHub Container Registry (ghcr.io)
|
||||||
|
|
||||||
|
**Value:** This is automatically provided by GitHub Actions - no setup needed!
|
||||||
|
|
||||||
|
**How to add:**
|
||||||
|
1. Go to GitHub repo → Settings → Secrets and variables → Actions
|
||||||
|
2. Click **"New repository secret"**
|
||||||
|
3. Name: `GITEA_USERNAME`
|
||||||
|
4. Secret: `ryan`
|
||||||
|
5. Click **"Add secret"**
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 2. TAILSCALE_CLIENT_ID
|
||||||
|
|
||||||
|
**Purpose:** Allows GitHub Actions to connect to your Tailscale network (to reach Kubernetes)
|
||||||
|
|
||||||
|
**How to create:**
|
||||||
|
|
||||||
|
1. Go to: https://login.tailscale.com/admin/settings/oauth
|
||||||
|
2. Click **"Generate OAuth client"**
|
||||||
|
3. Description: `GitHub Actions - TurboVault`
|
||||||
|
4. Select tags: **`tag:ci`** (or create if it doesn't exist)
|
||||||
|
5. Copy the **Client ID**
|
||||||
|
|
||||||
|
**How to add to GitHub:**
|
||||||
|
|
||||||
|
1. Go to GitHub repo → Settings → Secrets and variables → Actions
|
||||||
|
2. Click **"New repository secret"**
|
||||||
|
3. Name: `TAILSCALE_CLIENT_ID`
|
||||||
|
4. Secret: Paste the Client ID
|
||||||
|
5. Click **"Add secret"**
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 3. TAILSCALE_CLIENT_SECRET
|
||||||
|
|
||||||
|
**Purpose:** OAuth secret for Tailscale connection
|
||||||
|
|
||||||
|
**How to get:**
|
||||||
|
|
||||||
|
(You got this when creating the OAuth client in step 3 above)
|
||||||
|
|
||||||
|
**How to add to GitHub:**
|
||||||
|
|
||||||
|
1. Go to GitHub repo → Settings → Secrets and variables → Actions
|
||||||
|
2. Click **"New repository secret"**
|
||||||
|
3. Name: `TAILSCALE_CLIENT_SECRET`
|
||||||
|
4. Secret: Paste the Client Secret
|
||||||
|
5. Click **"Add secret"**
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 4. KUBECONFIG
|
||||||
|
|
||||||
|
**Purpose:** Allows kubectl to deploy to your Kubernetes cluster
|
||||||
|
|
||||||
|
**How to create:**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Encode your kubeconfig as base64
|
||||||
|
cat ~/.kube/config | base64 -w 0 > kubeconfig-base64.txt
|
||||||
|
|
||||||
|
# Copy the contents
|
||||||
|
cat kubeconfig-base64.txt
|
||||||
|
```
|
||||||
|
|
||||||
|
**How to add to GitHub:**
|
||||||
|
|
||||||
|
1. Go to GitHub repo → Settings → Secrets and variables → Actions
|
||||||
|
2. Click **"New repository secret"**
|
||||||
|
3. Name: `KUBECONFIG`
|
||||||
|
4. Secret: Paste the base64-encoded kubeconfig
|
||||||
|
5. Click **"Add secret"**
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Optional: Scoped Kubeconfig (More Secure)
|
||||||
|
|
||||||
|
Instead of using your full kubeconfig, create a limited service account:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Create service account
|
||||||
|
kubectl create serviceaccount turbovault-deployer -n turbovault
|
||||||
|
|
||||||
|
# Create role with deployment permissions only
|
||||||
|
cat <<EOF | kubectl apply -f -
|
||||||
|
apiVersion: rbac.authorization.k8s.io/v1
|
||||||
|
kind: Role
|
||||||
|
metadata:
|
||||||
|
name: turbovault-deployer
|
||||||
|
namespace: turbovault
|
||||||
|
rules:
|
||||||
|
- apiGroups: ["apps"]
|
||||||
|
resources: ["deployments"]
|
||||||
|
verbs: ["get", "list", "patch", "update"]
|
||||||
|
- apiGroups: [""]
|
||||||
|
resources: ["pods"]
|
||||||
|
verbs: ["get", "list"]
|
||||||
|
- apiGroups: ["apps"]
|
||||||
|
resources: ["deployments/status"]
|
||||||
|
verbs: ["get"]
|
||||||
|
EOF
|
||||||
|
|
||||||
|
# Bind role to service account
|
||||||
|
kubectl create rolebinding turbovault-deployer \
|
||||||
|
--role=turbovault-deployer \
|
||||||
|
--serviceaccount=turbovault:turbovault-deployer \
|
||||||
|
-n turbovault
|
||||||
|
|
||||||
|
# Get service account token (valid for 10 years)
|
||||||
|
kubectl create token turbovault-deployer -n turbovault --duration=87600h > token.txt
|
||||||
|
|
||||||
|
# Create minimal kubeconfig
|
||||||
|
cat <<EOF > deployer-kubeconfig.yaml
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Config
|
||||||
|
clusters:
|
||||||
|
- cluster:
|
||||||
|
server: https://100.101.31.99:6443
|
||||||
|
insecure-skip-tls-verify: true
|
||||||
|
name: k3s
|
||||||
|
contexts:
|
||||||
|
- context:
|
||||||
|
cluster: k3s
|
||||||
|
namespace: turbovault
|
||||||
|
user: turbovault-deployer
|
||||||
|
name: k3s
|
||||||
|
current-context: k3s
|
||||||
|
users:
|
||||||
|
- name: turbovault-deployer
|
||||||
|
user:
|
||||||
|
token: $(cat token.txt)
|
||||||
|
EOF
|
||||||
|
|
||||||
|
# Encode for GitHub
|
||||||
|
cat deployer-kubeconfig.yaml | base64 -w 0 > deployer-kubeconfig-base64.txt
|
||||||
|
|
||||||
|
# Use this in KUBECONFIG secret
|
||||||
|
cat deployer-kubeconfig-base64.txt
|
||||||
|
```
|
||||||
|
|
||||||
|
This limits GitHub Actions to only deploying TurboVault, not full cluster access.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Summary of Required Secrets
|
||||||
|
|
||||||
|
| Secret Name | Purpose | How to Get |
|
||||||
|
|-------------|---------|------------|
|
||||||
|
| `GITHUB_TOKEN` | Push to ghcr.io | Built-in (no setup needed!) |
|
||||||
|
| `TAILSCALE_CLIENT_ID` | Connect to Tailscale | Tailscale → OAuth clients |
|
||||||
|
| `TAILSCALE_CLIENT_SECRET` | Connect to Tailscale | Tailscale → OAuth clients |
|
||||||
|
| `KUBECONFIG` | Deploy to Kubernetes | `cat ~/.kube/config \| base64 -w 0` |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Verifying Secrets
|
||||||
|
|
||||||
|
After adding all secrets, you should see 3 secrets in GitHub:
|
||||||
|
|
||||||
|
1. Go to: `https://github.com/ryankazokas/turbovault-app/settings/secrets/actions`
|
||||||
|
2. Verify all 3 are listed:
|
||||||
|
- ✅ TAILSCALE_CLIENT_ID
|
||||||
|
- ✅ TAILSCALE_CLIENT_SECRET
|
||||||
|
- ✅ KUBECONFIG
|
||||||
|
|
||||||
|
Note: `GITHUB_TOKEN` is automatic - you don't need to add it!
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Testing the Workflow
|
||||||
|
|
||||||
|
After secrets are configured:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Create a test tag
|
||||||
|
git tag v0.0.1-test
|
||||||
|
git push origin v0.0.1-test
|
||||||
|
```
|
||||||
|
|
||||||
|
Watch the workflow at:
|
||||||
|
`https://github.com/ryan/turbovault-app/actions`
|
||||||
|
|
||||||
|
The workflow should:
|
||||||
|
1. ✅ Build Docker image
|
||||||
|
2. ✅ Push to Gitea registry (gitea.kazcloud.dev)
|
||||||
|
3. ✅ Connect to Tailscale
|
||||||
|
4. ✅ Deploy to Kubernetes
|
||||||
|
5. ✅ Wait for rollout to complete
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Troubleshooting
|
||||||
|
|
||||||
|
### "Error: authentication required" (Gitea)
|
||||||
|
- Check `GITEA_TOKEN` is set correctly
|
||||||
|
- Verify token has `write:package` scope
|
||||||
|
- Test: `docker login gitea.kazcloud.dev` with token
|
||||||
|
|
||||||
|
### "Error: Failed to connect to Tailscale"
|
||||||
|
- Check `TAILSCALE_CLIENT_ID` and `TAILSCALE_CLIENT_SECRET` are correct
|
||||||
|
- Verify OAuth client is active in Tailscale admin
|
||||||
|
- Check tags are configured correctly (tag:ci)
|
||||||
|
|
||||||
|
### "Error: Unable to connect to the server" (Kubernetes)
|
||||||
|
- Check `KUBECONFIG` secret is set correctly
|
||||||
|
- Verify base64 encoding (no line breaks with `-w 0`)
|
||||||
|
- Verify Tailscale connected (check logs)
|
||||||
|
- Test kubeconfig works: `kubectl --kubeconfig=<file> get pods -n turbovault`
|
||||||
|
|
||||||
|
### "Error: deployment not found"
|
||||||
|
- Make sure initial deployment is done first: `./scripts/deploy-k8s.sh`
|
||||||
|
- Workflow only updates existing deployments, doesn't create them
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Security Best Practices
|
||||||
|
|
||||||
|
✅ **DO:**
|
||||||
|
- Use service account with minimal permissions (recommended)
|
||||||
|
- Rotate tokens regularly
|
||||||
|
- Use OAuth for Tailscale (not auth keys)
|
||||||
|
- Only enable workflows on protected branches
|
||||||
|
|
||||||
|
❌ **DON'T:**
|
||||||
|
- Share secrets in code or documentation
|
||||||
|
- Use admin kubeconfig if possible
|
||||||
|
- Commit secrets to git
|
||||||
|
- Use long-lived Tailscale auth keys
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Next Steps
|
||||||
|
|
||||||
|
After configuring secrets:
|
||||||
|
1. Read [DEPLOYMENT.md](DEPLOYMENT.md) for initial deployment
|
||||||
|
2. Test workflow with a tag push
|
||||||
|
3. Monitor Actions tab for build status
|
||||||
|
|
||||||
|
Questions? Check the GitHub Actions logs for detailed error messages.
|
||||||
@@ -8,8 +8,7 @@ data:
|
|||||||
RAILS_LOG_TO_STDOUT: "true"
|
RAILS_LOG_TO_STDOUT: "true"
|
||||||
RAILS_SERVE_STATIC_FILES: "true"
|
RAILS_SERVE_STATIC_FILES: "true"
|
||||||
RAILS_MAX_THREADS: "5"
|
RAILS_MAX_THREADS: "5"
|
||||||
# Update these values for your environment
|
DATABASE_HOST: "aws-1-us-east-2.pooler.supabase.com" # Your PostgreSQL service name or external host
|
||||||
DATABASE_HOST: "db.rbeowfzliacsawrziniv.supabase.co" # Your PostgreSQL service name or external host
|
DATABASE_PORT: "6543"
|
||||||
DATABASE_PORT: "5432"
|
|
||||||
DATABASE_NAME: "postgres"
|
DATABASE_NAME: "postgres"
|
||||||
DATABASE_USERNAME: "postgres"
|
DATABASE_USERNAME: "postgres.rbeowfzliacsawrziniv"
|
||||||
|
|||||||
@@ -20,18 +20,20 @@ spec:
|
|||||||
labels:
|
labels:
|
||||||
app: turbovault
|
app: turbovault
|
||||||
spec:
|
spec:
|
||||||
# Pull images from container registry
|
# Deploy to cloud nodes only
|
||||||
# For private registries, uncomment and create secret:
|
nodeSelector:
|
||||||
# imagePullSecrets:
|
node-role: cloud
|
||||||
# - name: registry-secret
|
# Pull images from private GitHub Container Registry
|
||||||
|
imagePullSecrets:
|
||||||
|
- name: ghcr-secret
|
||||||
containers:
|
containers:
|
||||||
- name: turbovault
|
- name: turbovault
|
||||||
# UPDATE THIS: Replace with your registry path
|
# UPDATE THIS: Replace with your registry path
|
||||||
# Examples:
|
# Examples:
|
||||||
# - Gitea: gitea.kazcloud.dev/ryankazokas/turbovault-app:latest
|
# - Gitea: gitea.kazcloud.dev/ryan/turbovault-app:latest
|
||||||
# - GitHub Container Registry: ghcr.io/ryankazokas/turbovault-app:latest
|
# - GitHub Container Registry: ghcr.io/ryankazokas/turbovault-app:latest
|
||||||
# - Docker Hub: docker.io/username/turbovault:latest
|
# - Docker Hub: docker.io/username/turbovault:latest
|
||||||
image: gitea.kazcloud.dev/ryankazokas/turbovault-app:latest
|
image: ghcr.io/ryankazokas/turbovault-app:latest
|
||||||
imagePullPolicy: Always
|
imagePullPolicy: Always
|
||||||
ports:
|
ports:
|
||||||
- containerPort: 3000
|
- containerPort: 3000
|
||||||
|
|||||||
@@ -4,13 +4,13 @@ metadata:
|
|||||||
name: turbovault-ingress
|
name: turbovault-ingress
|
||||||
namespace: turbovault
|
namespace: turbovault
|
||||||
annotations:
|
annotations:
|
||||||
# Update these based on your ingress controller
|
# Use Traefik with Let's Encrypt (same as Gitea)
|
||||||
# nginx.ingress.kubernetes.io/ssl-redirect: "true"
|
traefik.ingress.kubernetes.io/router.tls: "true"
|
||||||
# cert-manager.io/cluster-issuer: "letsencrypt-prod"
|
traefik.ingress.kubernetes.io/router.tls.certresolver: letsencrypt
|
||||||
spec:
|
spec:
|
||||||
ingressClassName: nginx # Or traefik, depending on your setup
|
ingressClassName: traefik
|
||||||
rules:
|
rules:
|
||||||
- host: turbovault.example.com # Update with your domain
|
- host: turbo.kazcloud.dev
|
||||||
http:
|
http:
|
||||||
paths:
|
paths:
|
||||||
- path: /
|
- path: /
|
||||||
@@ -20,8 +20,3 @@ spec:
|
|||||||
name: turbovault-service
|
name: turbovault-service
|
||||||
port:
|
port:
|
||||||
number: 80
|
number: 80
|
||||||
# Uncomment for TLS/HTTPS
|
|
||||||
# tls:
|
|
||||||
# - hosts:
|
|
||||||
# - turbovault.example.com
|
|
||||||
# secretName: turbovault-tls
|
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ metadata:
|
|||||||
app: turbovault
|
app: turbovault
|
||||||
job: migrate
|
job: migrate
|
||||||
spec:
|
spec:
|
||||||
|
backoffLimit: 3
|
||||||
template:
|
template:
|
||||||
metadata:
|
metadata:
|
||||||
labels:
|
labels:
|
||||||
@@ -14,14 +15,14 @@ spec:
|
|||||||
job: migrate
|
job: migrate
|
||||||
spec:
|
spec:
|
||||||
restartPolicy: OnFailure
|
restartPolicy: OnFailure
|
||||||
# For private registries, uncomment and create secret:
|
# Pull images from private GitHub Container Registry
|
||||||
# imagePullSecrets:
|
imagePullSecrets:
|
||||||
# - name: registry-secret
|
- name: ghcr-secret
|
||||||
containers:
|
containers:
|
||||||
- name: migrate
|
- name: migrate
|
||||||
# UPDATE THIS: Replace with your registry path (same as deployment.yaml)
|
# UPDATE THIS: Replace with your registry path (same as deployment.yaml)
|
||||||
image: gitea.kazcloud.dev/ryankazokas/turbovault-app:latest
|
image: ghcr.io/ryankazokas/turbovault-app:latest
|
||||||
command: ["bundle", "exec", "rails", "db:migrate"]
|
command: ["bin/rails", "db:migrate"]
|
||||||
env:
|
env:
|
||||||
# Load from ConfigMap
|
# Load from ConfigMap
|
||||||
- name: RAILS_ENV
|
- name: RAILS_ENV
|
||||||
@@ -60,4 +61,3 @@ spec:
|
|||||||
secretKeyRef:
|
secretKeyRef:
|
||||||
name: turbovault-secrets
|
name: turbovault-secrets
|
||||||
key: SECRET_KEY_BASE
|
key: SECRET_KEY_BASE
|
||||||
backoffLimit: 3
|
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ set -e
|
|||||||
# Usage: ./scripts/update-deployment.sh v1.0.1
|
# Usage: ./scripts/update-deployment.sh v1.0.1
|
||||||
|
|
||||||
VERSION=${1:-latest}
|
VERSION=${1:-latest}
|
||||||
IMAGE="gitea.kazcloud.dev/ryankazokas/turbovault-app:${VERSION}"
|
IMAGE="ghcr.io/ryankazokas/turbovault-app:${VERSION}"
|
||||||
NAMESPACE="turbovault"
|
NAMESPACE="turbovault"
|
||||||
|
|
||||||
echo "🚀 Updating TurboVault deployment to ${VERSION}..."
|
echo "🚀 Updating TurboVault deployment to ${VERSION}..."
|
||||||
|
|||||||
Reference in New Issue
Block a user