19 KiB
19 KiB
HarborSmith Gitea Docker Workflow
Automated Build & Deployment Pipeline
Version: 1.0
Date: September 2025
Purpose: Gitea repository setup with automated Docker image building and deployment
📋 Overview
This guide configures HarborSmith to work with your Gitea instance for:
- Source control management
- Automated Docker image building
- Container registry management
- Automated deployment to production
🏗️ Repository Structure
harborsmith/ # Main repository in Gitea
├── .gitea/ # Gitea-specific configuration
│ └── workflows/ # Gitea Actions (CI/CD)
│ ├── build.yaml # Build Docker images on push
│ ├── test.yaml # Run tests
│ └── deploy.yaml # Deploy to production
├── .dockerignore # Files to exclude from Docker builds
├── docker-compose.yml # Production orchestration
├── docker-compose.dev.yml # Development overrides
├── docker-compose.build.yml # Build configuration
├── Makefile # Build and deploy commands
└── [rest of project structure as defined]
🔧 Gitea Actions Workflow
Build Workflow (.gitea/workflows/build.yaml)
name: Build and Push Docker Images
on:
push:
branches: [main, develop]
tags:
- 'v*'
pull_request:
branches: [main]
jobs:
build-web:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v2
- name: Login to Gitea Registry
uses: docker/login-action@v2
with:
registry: gitea.yourdomain.com
username: ${{ secrets.REGISTRY_USERNAME }}
password: ${{ secrets.REGISTRY_PASSWORD }}
- name: Extract metadata
id: meta
uses: docker/metadata-action@v4
with:
images: gitea.yourdomain.com/harborsmith/web
tags: |
type=ref,event=branch
type=ref,event=pr
type=semver,pattern={{version}}
type=semver,pattern={{major}}.{{minor}}
type=sha,prefix={{branch}}-
type=raw,value=latest,enable={{is_default_branch}}
- name: Build and push Web
uses: docker/build-push-action@v4
with:
context: ./apps/web
file: ./apps/web/Dockerfile
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
cache-from: type=registry,ref=gitea.yourdomain.com/harborsmith/web:buildcache
cache-to: type=registry,ref=gitea.yourdomain.com/harborsmith/web:buildcache,mode=max
build-args: |
BUILDKIT_INLINE_CACHE=1
NODE_ENV=production
build-api:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v2
- name: Login to Gitea Registry
uses: docker/login-action@v2
with:
registry: gitea.yourdomain.com
username: ${{ secrets.REGISTRY_USERNAME }}
password: ${{ secrets.REGISTRY_PASSWORD }}
- name: Extract metadata
id: meta
uses: docker/metadata-action@v4
with:
images: gitea.yourdomain.com/harborsmith/api
- name: Build and push API
uses: docker/build-push-action@v4
with:
context: ./apps/api
file: ./apps/api/Dockerfile
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
cache-from: type=registry,ref=gitea.yourdomain.com/harborsmith/api:buildcache
cache-to: type=registry,ref=gitea.yourdomain.com/harborsmith/api:buildcache,mode=max
build-services:
runs-on: ubuntu-latest
strategy:
matrix:
service: [charter, maintenance, payments, notifications]
steps:
- uses: actions/checkout@v3
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v2
- name: Login to Gitea Registry
uses: docker/login-action@v2
with:
registry: gitea.yourdomain.com
username: ${{ secrets.REGISTRY_USERNAME }}
password: ${{ secrets.REGISTRY_PASSWORD }}
- name: Extract metadata
id: meta
uses: docker/metadata-action@v4
with:
images: gitea.yourdomain.com/harborsmith/${{ matrix.service }}
- name: Build and push ${{ matrix.service }}
uses: docker/build-push-action@v4
with:
context: ./services/${{ matrix.service }}
file: ./services/${{ matrix.service }}/Dockerfile
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
🐳 Optimized Dockerfiles
Multi-stage Dockerfile for Next.js (apps/web/Dockerfile)
# Dependencies stage
FROM node:20-alpine AS deps
RUN apk add --no-cache libc6-compat
WORKDIR /app
# Copy package files
COPY package.json pnpm-lock.yaml* ./
RUN corepack enable pnpm && pnpm i --frozen-lockfile
# Builder stage
FROM node:20-alpine AS builder
WORKDIR /app
COPY --from=deps /app/node_modules ./node_modules
COPY . .
# Build arguments for environment variables
ARG NEXT_PUBLIC_API_URL
ARG NEXT_PUBLIC_SUPABASE_URL
ARG NEXT_PUBLIC_SUPABASE_ANON_KEY
ARG NEXT_PUBLIC_STRIPE_PUBLIC_KEY
ARG NEXT_PUBLIC_KEYCLOAK_URL
ARG NEXT_PUBLIC_KEYCLOAK_REALM
ARG NEXT_PUBLIC_KEYCLOAK_CLIENT_ID
ENV NEXT_TELEMETRY_DISABLED 1
RUN corepack enable pnpm && pnpm build
# Runner stage
FROM node:20-alpine AS runner
WORKDIR /app
ENV NODE_ENV production
ENV NEXT_TELEMETRY_DISABLED 1
RUN addgroup --system --gid 1001 nodejs
RUN adduser --system --uid 1001 nextjs
# Copy built application
COPY --from=builder /app/public ./public
COPY --from=builder --chown=nextjs:nodejs /app/.next/standalone ./
COPY --from=builder --chown=nextjs:nodejs /app/.next/static ./.next/static
USER nextjs
EXPOSE 3000
ENV PORT 3000
ENV HOSTNAME "0.0.0.0"
CMD ["node", "server.js"]
Optimized API Dockerfile (apps/api/Dockerfile)
# Build stage
FROM node:20-alpine AS builder
RUN apk add --no-cache libc6-compat
WORKDIR /app
COPY package.json pnpm-lock.yaml* ./
RUN corepack enable pnpm && pnpm i --frozen-lockfile
COPY . .
RUN pnpm build
# Production stage
FROM node:20-alpine AS runner
RUN apk add --no-cache libc6-compat
WORKDIR /app
ENV NODE_ENV production
RUN addgroup --system --gid 1001 nodejs
RUN adduser --system --uid 1001 apiuser
COPY --from=builder /app/dist ./dist
COPY --from=builder /app/node_modules ./node_modules
COPY --from=builder /app/package.json ./package.json
USER apiuser
EXPOSE 4000
CMD ["node", "dist/server.js"]
Microservice Dockerfile Template (services/*/Dockerfile)
FROM node:20-alpine AS builder
WORKDIR /app
COPY package*.json ./
COPY pnpm-lock.yaml* ./
RUN corepack enable pnpm && pnpm i --frozen-lockfile
COPY . .
RUN pnpm build
FROM node:20-alpine
WORKDIR /app
RUN addgroup -g 1001 -S nodejs
RUN adduser -S nodejs -u 1001
COPY --from=builder /app/dist ./dist
COPY --from=builder /app/node_modules ./node_modules
USER nodejs
EXPOSE 5001
CMD ["node", "dist/index.js"]
📦 Production docker-compose.yml (Using Gitea Registry)
version: '3.9'
networks:
harborsmith:
driver: bridge
volumes:
postgres_data:
minio_data:
keycloak_data:
redis_data:
services:
# ===== FRONTEND =====
web:
image: gitea.yourdomain.com/harborsmith/web:latest
container_name: harborsmith-web
restart: unless-stopped
ports:
- "3000:3000"
env_file:
- .env.production
depends_on:
- api
- keycloak
networks:
- harborsmith
# ===== API GATEWAY =====
api:
image: gitea.yourdomain.com/harborsmith/api:latest
container_name: harborsmith-api
restart: unless-stopped
ports:
- "4000:4000"
env_file:
- .env.production
depends_on:
- postgres
- redis
- keycloak
networks:
- harborsmith
# ===== MICROSERVICES =====
charter-service:
image: gitea.yourdomain.com/harborsmith/charter:latest
container_name: harborsmith-charter
restart: unless-stopped
env_file:
- .env.production
depends_on:
- postgres
- redis
networks:
- harborsmith
maintenance-service:
image: gitea.yourdomain.com/harborsmith/maintenance:latest
container_name: harborsmith-maintenance
restart: unless-stopped
env_file:
- .env.production
depends_on:
- postgres
- redis
networks:
- harborsmith
payment-service:
image: gitea.yourdomain.com/harborsmith/payments:latest
container_name: harborsmith-payments
restart: unless-stopped
env_file:
- .env.production
depends_on:
- postgres
networks:
- harborsmith
notification-service:
image: gitea.yourdomain.com/harborsmith/notifications:latest
container_name: harborsmith-notifications
restart: unless-stopped
env_file:
- .env.production
networks:
- harborsmith
# ===== INFRASTRUCTURE SERVICES =====
# (These use public images, not built from source)
postgres:
image: supabase/postgres:15.1.0.117
container_name: harborsmith-db
restart: unless-stopped
ports:
- "5432:5432"
env_file:
- .env.production
volumes:
- postgres_data:/var/lib/postgresql/data
- ./migrations:/docker-entrypoint-initdb.d:ro
networks:
- harborsmith
redis:
image: redis:7-alpine
container_name: harborsmith-redis
restart: unless-stopped
ports:
- "6379:6379"
volumes:
- redis_data:/data
networks:
- harborsmith
keycloak:
image: quay.io/keycloak/keycloak:23.0
container_name: harborsmith-keycloak
restart: unless-stopped
ports:
- "8080:8080"
env_file:
- .env.production
volumes:
- keycloak_data:/opt/keycloak/data
depends_on:
- postgres
networks:
- harborsmith
minio:
image: minio/minio:latest
container_name: harborsmith-minio
restart: unless-stopped
ports:
- "9000:9000"
- "9001:9001"
env_file:
- .env.production
volumes:
- minio_data:/data
command: server /data --console-address ":9001"
networks:
- harborsmith
# Additional services as defined in main implementation plan...
🔄 Deployment Workflow
1. Initial Setup on Production Server
# On your production server
# 1. Install Docker and Docker Compose
curl -fsSL https://get.docker.com -o get-docker.sh
sh get-docker.sh
apt-get install docker-compose-plugin
# 2. Create project directory
mkdir -p /opt/harborsmith
cd /opt/harborsmith
# 3. Login to Gitea Registry
docker login gitea.yourdomain.com
# 4. Clone deployment files (not full source)
git clone https://gitea.yourdomain.com/harborsmith/deployment.git .
2. Deployment Script (deploy.sh)
#!/bin/bash
# HarborSmith Deployment Script
set -e
echo "🚀 Starting HarborSmith deployment..."
# Configuration
GITEA_REGISTRY="gitea.yourdomain.com"
PROJECT="harborsmith"
ENVIRONMENT=${1:-production}
# Colors for output
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
NC='\033[0m' # No Color
# Function to print colored output
print_status() {
echo -e "${GREEN}✓${NC} $1"
}
print_error() {
echo -e "${RED}✗${NC} $1"
}
print_warning() {
echo -e "${YELLOW}⚠${NC} $1"
}
# 1. Login to Gitea Registry
print_status "Logging into Gitea Registry..."
docker login ${GITEA_REGISTRY}
# 2. Pull latest images
print_status "Pulling latest images..."
SERVICES="web api charter maintenance payments notifications"
for SERVICE in $SERVICES; do
print_status "Pulling ${SERVICE}..."
docker pull ${GITEA_REGISTRY}/${PROJECT}/${SERVICE}:latest
done
# 3. Backup database (optional but recommended)
if [ "$ENVIRONMENT" = "production" ]; then
print_warning "Backing up database..."
docker exec harborsmith-db pg_dump -U postgres harborsmith > backup-$(date +%Y%m%d-%H%M%S).sql
fi
# 4. Stop running containers
print_status "Stopping current containers..."
docker-compose down
# 5. Start new containers
print_status "Starting new containers..."
docker-compose up -d
# 6. Run migrations
print_status "Running database migrations..."
docker exec harborsmith-db psql -U postgres -d harborsmith -f /docker-entrypoint-initdb.d/migrate.sql
# 7. Health checks
print_status "Performing health checks..."
sleep 10
# Check if services are running
HEALTH_CHECK_FAILED=0
for SERVICE in $SERVICES; do
if docker ps | grep -q "harborsmith-${SERVICE}"; then
print_status "${SERVICE} is running"
else
print_error "${SERVICE} is not running"
HEALTH_CHECK_FAILED=1
fi
done
# 8. Cleanup old images
print_status "Cleaning up old images..."
docker image prune -f
if [ $HEALTH_CHECK_FAILED -eq 0 ]; then
print_status "Deployment completed successfully! 🎉"
echo ""
echo "Services available at:"
echo " - Web: http://localhost:3000"
echo " - API: http://localhost:4000"
echo " - Keycloak: http://localhost:8080"
echo " - MinIO: http://localhost:9001"
else
print_error "Deployment completed with errors. Please check the logs."
exit 1
fi
🛠️ Makefile for Common Operations
# HarborSmith Makefile
.PHONY: help build push deploy logs restart clean
# Variables
GITEA_REGISTRY := gitea.yourdomain.com
PROJECT := harborsmith
VERSION := $(shell git describe --tags --always --dirty)
BRANCH := $(shell git rev-parse --abbrev-ref HEAD)
help: ## Show this help
@grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-20s\033[0m %s\n", $$1, $$2}'
build: ## Build all Docker images locally
docker-compose -f docker-compose.build.yml build
build-web: ## Build web service
docker build -t $(GITEA_REGISTRY)/$(PROJECT)/web:$(VERSION) ./apps/web
build-api: ## Build API service
docker build -t $(GITEA_REGISTRY)/$(PROJECT)/api:$(VERSION) ./apps/api
push: ## Push all images to Gitea registry
docker push $(GITEA_REGISTRY)/$(PROJECT)/web:$(VERSION)
docker push $(GITEA_REGISTRY)/$(PROJECT)/api:$(VERSION)
docker push $(GITEA_REGISTRY)/$(PROJECT)/charter:$(VERSION)
docker push $(GITEA_REGISTRY)/$(PROJECT)/maintenance:$(VERSION)
docker push $(GITEA_REGISTRY)/$(PROJECT)/payments:$(VERSION)
docker push $(GITEA_REGISTRY)/$(PROJECT)/notifications:$(VERSION)
deploy: ## Deploy to production
ssh production-server 'cd /opt/harborsmith && ./deploy.sh'
deploy-staging: ## Deploy to staging
ssh staging-server 'cd /opt/harborsmith && ./deploy.sh staging'
logs: ## Show logs from all services
docker-compose logs -f
logs-web: ## Show logs from web service
docker-compose logs -f web
restart: ## Restart all services
docker-compose restart
restart-web: ## Restart web service
docker-compose restart web
clean: ## Clean up Docker resources
docker system prune -f
docker volume prune -f
backup: ## Backup database
docker exec harborsmith-db pg_dump -U postgres harborsmith > backups/backup-$(shell date +%Y%m%d-%H%M%S).sql
restore: ## Restore database from latest backup
docker exec -i harborsmith-db psql -U postgres harborsmith < $(shell ls -t backups/*.sql | head -1)
dev: ## Start development environment
docker-compose -f docker-compose.dev.yml up
test: ## Run tests in containers
docker-compose -f docker-compose.test.yml up --abort-on-container-exit
migrate: ## Run database migrations
docker exec harborsmith-db psql -U postgres -d harborsmith -f /docker-entrypoint-initdb.d/migrate.sql
🔐 Gitea Repository Secrets
Configure these secrets in your Gitea repository settings:
REGISTRY_USERNAME: harborsmith-bot
REGISTRY_PASSWORD: [secure-token]
PRODUCTION_HOST: production.harborsmith.com
STAGING_HOST: staging.harborsmith.com
SSH_PRIVATE_KEY: [deployment-key]
📝 .dockerignore
# Dependencies
node_modules
npm-debug.log
yarn-error.log
.pnpm-store
# Next.js
.next
out
build
dist
# Testing
coverage
.nyc_output
# Environment
.env
.env.*
!.env.example
# Git
.git
.gitignore
.gitea
# Documentation
*.md
docs
# IDE
.vscode
.idea
*.swp
*.swo
# OS
.DS_Store
Thumbs.db
# Development
.docker
docker-compose.dev.yml
docker-compose.test.yml
# Temporary files
tmp
temp
*.tmp
🚀 Complete Workflow Example
1. Developer pushes code to Gitea
git add .
git commit -m "feat: add vessel booking feature"
git push origin develop
2. Gitea Actions automatically:
- Runs tests
- Builds Docker images
- Tags with branch name and commit SHA
- Pushes to Gitea container registry
3. Deploy to staging
make deploy-staging
# OR manually:
ssh staging-server
cd /opt/harborsmith
docker-compose pull
docker-compose up -d
4. Deploy to production (after testing)
git checkout main
git merge develop
git tag v1.2.0
git push origin main --tags
# Gitea Actions builds production images
make deploy
📊 Monitoring Container Health
Health Check Script (healthcheck.sh)
#!/bin/bash
# Container health monitoring
SERVICES=("web" "api" "charter" "maintenance" "payments" "notifications")
WEBHOOK_URL="https://your-monitoring-webhook.com"
for service in "${SERVICES[@]}"; do
if ! docker exec harborsmith-${service} curl -f http://localhost:${PORT}/health > /dev/null 2>&1; then
curl -X POST ${WEBHOOK_URL} \
-H "Content-Type: application/json" \
-d "{\"service\": \"${service}\", \"status\": \"unhealthy\", \"timestamp\": \"$(date -Iseconds)\"}"
# Attempt restart
docker-compose restart ${service}
fi
done
🔄 Rolling Updates
For zero-downtime deployments:
# docker-compose.production.yml
services:
web:
image: gitea.yourdomain.com/harborsmith/web:latest
deploy:
replicas: 2
update_config:
parallelism: 1
delay: 10s
order: start-first
restart_policy:
condition: any
delay: 5s
max_attempts: 3
✅ Deployment Checklist
- Gitea repository created
- Container registry enabled in Gitea
- Gitea Actions configured
- Secrets added to repository
- Production server has Docker installed
- Registry credentials configured on server
- Environment files prepared
- SSL certificates ready
- Database backups scheduled
- Monitoring configured
- Rollback plan documented
🆘 Troubleshooting
Common Issues
- Image pull authentication failed
docker logout gitea.yourdomain.com
docker login gitea.yourdomain.com
- Container fails to start
docker logs harborsmith-web
docker-compose down
docker-compose up -d
- Database connection issues
docker exec harborsmith-db pg_isready
docker-compose restart postgres
- Build cache issues
docker builder prune -a
docker-compose build --no-cache
This workflow ensures automated, reliable deployments from your Gitea repository to production Docker containers.