# 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 ```bash 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) ```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) ```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) ```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) ```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) ```yaml 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 ```bash # 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) ```bash #!/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 ```makefile # 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: ```yaml REGISTRY_USERNAME: harborsmith-bot REGISTRY_PASSWORD: [secure-token] PRODUCTION_HOST: production.harborsmith.com STAGING_HOST: staging.harborsmith.com SSH_PRIVATE_KEY: [deployment-key] ``` --- ## 📝 .dockerignore ```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 ```bash 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 ```bash make deploy-staging # OR manually: ssh staging-server cd /opt/harborsmith docker-compose pull docker-compose up -d ``` ### 4. Deploy to production (after testing) ```bash 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) ```bash #!/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: ```yaml # 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 1. **Image pull authentication failed** ```bash docker logout gitea.yourdomain.com docker login gitea.yourdomain.com ``` 2. **Container fails to start** ```bash docker logs harborsmith-web docker-compose down docker-compose up -d ``` 3. **Database connection issues** ```bash docker exec harborsmith-db pg_isready docker-compose restart postgres ``` 4. **Build cache issues** ```bash docker builder prune -a docker-compose build --no-cache ``` --- *This workflow ensures automated, reliable deployments from your Gitea repository to production Docker containers.*